Does anyone know how to preload assets (mostly png) stored locally on AppLoading? I've already preloaded fonts and pasted the asset caching code snippet, what else?
This is how I preload my assets and you can refer doc
import React, { useState } from "react";
import { AppRegistry } from "react-native";
import { AppLoading } from "expo";
import * as Font from "expo-font";
import { Asset } from "expo-asset";
function App() {
const [assetsLoaded, setAssetsLoaded] = useState(false);
const _loadAssetsAsync = async () => {
const imageAssets = cacheImages([
require("./assets/images/car.png"),
require("./assets/images/game.png"),
require("./assets/images/home.png"),
require("./assets/images/wardrobe.png"),
]);
const fontAssets = cacheFonts([
{ "poppins-regular": require("./assets/fonts/regular.ttf") },
{ "poppins-bold": require("./assets/fonts/bold.ttf") },
{ "poppins-thin": require("./assets/fonts/thin.ttf") },
]);
await Promise.all([...imageAssets, ...fontAssets]);
};
if (!assetsLoaded) {
return (
<AppLoading
startAsync={_loadAssetsAsync}
onFinish={() => setAssetsLoaded(true)}
onError={console.warn}
/>
);
}
return (
<YourApp/>
);
}
function cacheImages(images) {
return images.map((image) => {
if (typeof image === "string") {
return Image.prefetch(image);
} else {
return Asset.fromModule(image).downloadAsync();
}
});
}
function cacheFonts(fonts) {
return fonts.map((font) => Font.loadAsync(font));
}
AppRegistry.registerComponent("App", () => App);
export default App;
Related
I'm trying to use the expo-video-thumbnails package to generate a thumbnail from a video uri. The video uri is retrieved from async-storage. I get the following error
Argument of an incompatible class: class java.util.HashMap cannot be
passed as an argument to parameter expecting class java.lang.String.
If I use a static video uri, it works fine. I can't seem to get this to work with the value from AsyncStorage. Here's my code:
import React, { useState, useEffect } from 'react';
import { View, Image } from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
import * as VideoThumbnails from 'expo-video-thumbnails';
export default function ThumbnailsScreen() {
// video uri
const [videoUri, setVideoUri] = React.useState({});
const getData = async () => {
try {
const value = await AsyncStorage.getItem('#lastRecordedVideo')
if(value !== null) {
setVideoUri(value)
}
} catch(e) {
console.log(e);
}
}
getData();
// thumbnails
const [image, setImage] = useState(null);
const generateThumbnail = async () => {
try {
const { uri } = await VideoThumbnails.getThumbnailAsync(
videoUri,
{
time: 1000,
}
);
setImage(uri);
} catch (e) {
console.warn(e);
}
};
useEffect(() => { generateThumbnail(); }, [])
return (
<View>
{image && <Image source={{ uri: image }} /> }
</View>
)
}
When I try to enter username and then go on next screen for live chating then I facing this error.
Here is code for ChatScreen.js file.
TypeError: undefined is not a function (near '..._fire.default.get...').
ChatScreen.js
import React,{Component} from "react";
import {Platform,KeyboardAvoidingView} from 'react-native';
import {GiftedChat}from 'react-native-gifted-chat-fix';
import{SafeAreaView}from 'react-native-safe-area-view';
import Video from 'react-native-video';
import Fire from '../fire';
export default class ChatScreen extends Component{
state={
messages:[]
}
get user(){
return{
_id:Fire.uid,
name:this.props.navigation.state.params.name
}
}
componentDidMount(){
Fire.get(message=>this.setState(previous=>({
messages:GiftedChat.append(previous.messages,message)
}))
);
}
componentWillUnmount(){
Fire.off()
}
render(){
const chat=<GiftedChat messages={this.state.messages} onSend={Fire.send} user={this.user}/>;
if(Platform.OS=='android'){
return(
<KeyboardAvoidingView style={{flex:1}}behavior="padding" keyboardVerticalOffset={30} enabled>
{chat}
</KeyboardAvoidingView>
);
}
return<SafeAreaView style={{flex:1}}>{chat}</SafeAreaView>;
}
}
Try changing the code in both files
At first in Fire.js
import firebase from 'firebase'; // 4.8.1
class Fire {
constructor() {
this.init();
this.observeAuth();
}
init = () => {
if (!firebase.apps.length) {
firebase.initializeApp({
apiKey:'AIzaSyAPfes9_2EwZESX1puYMUv29yunzK9Ve5U',
authDomain:'docman-31d96.firebaseapp.com',
databaseURL: "https://docman-31d96.firebaseio.com",
projectId: "docman-31d96",
storageBucket: "docman-31d96.appspot.com",
messagingSenderId: "649332068608",
appId:'1:649332068608:android:08c080ee6a4e521f5323e5'
});
}
};
observeAuth = () =>
firebase.auth().onAuthStateChanged(this.onAuthStateChanged);
onAuthStateChanged = user => {
if (!user) {
try {
firebase.auth().signInAnonymously();
} catch ({ message }) {
alert(message);
}
}
};
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get ref() {
return firebase.database().ref('messages');
}
parse = snapshot => {
const { timestamp: numberStamp, text, user } = snapshot.val();
const { key: _id } = snapshot;
const timestamp = new Date(numberStamp);
const message = {
_id,
timestamp,
text,
user,
};
return message;
};
on = callback =>
this.ref
.limitToLast(20)
.on('child_added', snapshot => callback(this.parse(snapshot)));
get timestamp() {
return firebase.database.ServerValue.TIMESTAMP;
}
// send the message to the Backend
send = messages => {
for (let i = 0; i < messages.length; i++) {
const { text, user } = messages[i];
const message = {
text,
user,
timestamp: this.timestamp,
};
this.append(message);
}
};
append = message => this.ref.push(message);
// close the connection to the Backend
off() {
this.ref.off();
}
}
Fire.shared = new Fire();
export default Fire;
and then in ChatScreen.js
import * as React from 'react';
import { Platform , KeyboardAvoidingView,SafeAreaView } from 'react-native';
// #flow
import { GiftedChat } from 'react-native-gifted-chat'; // 0.3.0
import Fire from '../fire';
type Props = {
name?: string,
};
class ChatScreen extends React.Component<Props> {
static navigationOptions = ({ navigation }) => ({
title: (navigation.state.params || {}).name || 'Chat!',
});
state = {
messages: [],
};
get user() {
return {
name: this.props.navigation.state.params.name,
_id: Fire.shared.uid,
};
}
render() {
const chat=<GiftedChat messages={this.state.messages} onSend={Fire.shared.send} user={this.user}/>;
if(Platform.OS=='android'){
return(
<KeyboardAvoidingView style={{flex:1}}behavior="padding" keyboardVerticalOffset={0} enabled>
{chat}
</KeyboardAvoidingView>
);
}
return<SafeAreaView style={{flex:1}}>{chat}</SafeAreaView>;
}
componentDidMount() {
Fire.shared.on(message =>
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, message),
}))
);
}
componentWillUnmount() {
Fire.shared.off();
}
}
export default ChatScreen;
This helped for me It should work for you too
To see my chat app just visit https://snack.expo.io/#habibishaikh1/chatapp
React-admin version 2 used redux-form. Together with the documentation "Altering the Form Values before Submitting" i created a custom button that returns a form error from a custom function, or does a save.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { crudCreate, SaveButton, Toolbar } from 'react-admin';
import { SubmissionError } from 'redux-form';
const myValidate = (values) => {
const errors = {};
if (values.files < 1) errors.files = 'resources.Order.errors.files';
return errors;
};
// A custom action creator which modifies the values before calling the default crudCreate action creator
const saveWithNote = (values, basePath, redirectTo) =>
crudCreate('posts', { ...values, average_note: 10 }, basePath, redirectTo);
class SaveWithNoteButtonView extends Component {
handleClick = () => {
const { basePath, handleSubmit, redirect, saveWithNote } = this.props;
return handleSubmit(values => {
return new Promise((resolve, reject) => {
const errors = myValidate(values);
if (errors) {
reject(new SubmissionError(errors))
} else {
resolve( saveWithNote(values, basePath, redirect) );
};
}
});
});
};
render() {
const { handleSubmitWithRedirect, saveWithNote, ...props } = this.props;
return (
<SaveButton
handleSubmitWithRedirect={this.handleClick}
{...props}
/>
);
}
}
const SaveWithNoteButton = connect(
undefined,
{ saveWithNote }
)(SaveWithNoteButtonView);
Now in React-admin version 3 "Altering the Form Values before Submitting" Can't I do this anymore?
This code does not work:(
import React, { useCallback } from 'react';
import ProcessIcon from '#material-ui/icons/HeadsetMic';
import { useForm, useFormState } from 'react-final-form';
import { SaveButton } from 'react-admin';
const validateProcess = (values) => {
const errors = {};
if (values.files < 1) errors.files = ['resources.Order.errors.files'];
return errors
};
const SaveWithProcessButton = ({ handleSubmitWithRedirect, ...props }) => {
const form = useForm();
const formState = useFormState();
const handleClick = useCallback(() => {
return new Promise((resolve, reject) => {
const errors = validateProcess(formState.values);
if (errors) {
reject(errors)
} else {
form.change('status', "DRAFT");
resolve( handleSubmitWithRedirect('show') );
};
});
}, [form]);
return <SaveButton {...props} handleSubmitWithRedirect={handleClick} label="ra.action.process" icon={<ProcessIcon />} />;
};
export default SaveWithProcessButton;
I manage to do this. Try my code below, I hope it will works for also for you.
const handleClick = useCallback(() => {
if (!formState.valid) {
form.submit();
return;
} else { ... your code goes here }
}, [form]);
I've been working with React/React-Native for a while now, but I'm new to Redux and I cannot find the problem. I have a RESTFull API and two main modules: the service model and the price model. Once the admin user adds a new service the user can also associate a price for that service. The problema is that when I add a service (in the NewServiceScreen) my code dispatches an action to change the redux store and therefore update the service list on the NewPriceScreen for the user to associate a price with the service that was just added.
NewPriceScreen.js
function mapStateToProps(state){
return {
newPrice: state.newPriceReducer
}
}
// Exports the connected NewPriceScreen
export default connect(mapStateToProps)(NewPriceScreen);
NewServiceScreen
...
handleSubmit = async() => {
const { descricao } = this.props.newService;
const userToken = await AsyncStorage.getItem('token');
axios.post('/estabelecimento/servicos/',{descricao: descricao}, {
headers: {
"Authorization": `Token ${userToken}`
}
})
.then(res => {
Alert.alert(
'Deu tudo certo :)',
'Dados salvos com sucesso !',
);
console.log(res.data);
this.props.dispatch({type: 'addService', newService: res.data});
})
.catch(error =>{
Alert.alert(
'Ops ! Algo aconteceu :(',
error.message,
);
})
}
...
const mapStateToProps = state => ({
newService: state.newService
});
export default connect(mapStateToProps)(NewServiceScreen);
Reducers.js
const initialState = {
servicos: [],
// Database variables
servico: 0,
duracao: '',
custo: '',
comissao: ''
}
export default function newPriceReducer(state = initialState, action){
// console.log("My state")
// console.log(state);
switch(action.type){
case 'setState': {
return {
...state,
servico: action.descricao,
duracao: action.duracao,
custo: action.custo,
comissao: action.comissao
}
}
case "ADD_SERVICES": {
// console.log("Servicos");
const newState = {
...state,
servicos: action.servicos
}
// console.log(newState);
// console.log(newState === initialState)
return newState;
}
case 'addService': {
// console.log("ADD Service");
servicos = state.servicos;
servicos.push(action.newService);
const newState = {
...state,
servicos: servicos
}
// console.log(newState);
// console.log(newState === initialState);
return newState
}
default:
return state;
}
}
const initialState = {
descricao: ''
}
export default function newServiceReducer(state = initialState, action){
switch(action.type){
case 'setDescricao': {
return {
...state,
descricao: action.descricao
}
}
default:
return state;
}
}
App.js
import { createStore, applyMiddleware, combineReducers } from "redux";
import thunkMiddleware from 'redux-thunk'
import newServiceReducer from '../reducers/NewService';
import newPriceReducer from "../reducers/NewPrice";
import logger from 'redux-logger';
const mainReducer = combineReducers({
newService: newServiceReducer,
newPriceReducer
})
const store = createStore(mainReducer, applyMiddleware(logger));
export default store
import React from 'react';
import { Platform, StatusBar, StyleSheet, View, AsyncStorage, ImageBackground} from 'react-native';
import { AppLoading, Asset, Font, Icon } from 'expo';
import AppNavigator from './navigation/AppNavigator';
// Redux Stuff
import {Provider} from 'react-redux';
import AppStore from './store/App';
export default class App extends React.Component {
state = {
isLoadingComplete: false,
isLoggedIn: false,
};
render() {
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
return (
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
/>
);
} else {
return (
<Provider store={AppStore}>
<ImageBackground source={require('./assets/images/back.png')} style={{width: '100%', height: '100%'}}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<AppNavigator />
</ImageBackground>
</Provider>
);
}
}
}
In lines:
servicos = state.servicos;
servicos.push(action.newService);
I was making some sort mutation. I just changed it to:
const newState = {
...state,
servicos: [...state.servicos, action.newService]
}
I'm trying to use react-native-flash-message to provide little toasts in my app, and I am supposed to add the flash message to my root view. I cannot figure out where that is in my app. I used examples to get up and running with mobx/react-navigation/react-native, and so my app.js actually just exports an index.js that looks like this:
import React from 'react';
import { createRootNavigator } from './router';
import { isSignedIn } from './auth';
import { Font, SplashScreen } from 'expo';
import { library } from '#fortawesome/fontawesome-svg-core';
import { faCheckSquare, faCoffee, faHome } from '#fortawesome/free-solid-svg-icons';
import { configure } from 'mobx';
import { Provider } from 'mobx-react';
import _ from 'lodash';
import { RootStore } from './stores/RootStore';
import { getDecoratedStores } from './stores/util/store-decorator';
import { AsyncStorage } from 'react-native';
import FlashMessage from "react-native-flash-message";
configure({ enforceActions: 'observed' });
const rootStore = new RootStore();
const stores = getDecoratedStores(rootStore);
//Library of Icons
library.add(faCheckSquare, faCoffee, faHome);
export default class App extends React.Component<
{},
{ checkedSignIn: boolean; signedIn: boolean; loaded: boolean }
> {
constructor(props: any) {
super(props);
this.state = {
signedIn: false,
checkedSignIn: false,
loaded: false,
};
}
componentWillMount() {
this._loadFontsAsync();
}
_loadFontsAsync = async () => {
await Font.loadAsync({ robotoBold: require('../app/uiComponents/fonts/Roboto-Bold.ttf') });
await Font.loadAsync({
robotoRegular: require('../app/uiComponents/fonts/Roboto-Regular.ttf'),
});
this.setState({ loaded: true });
};
componentDidMount() {
isSignedIn()
.then(res => {
SplashScreen.hide();
this.setState({ signedIn: res as boolean, checkedSignIn: true });
})
.catch(err => {console.log(err); alert('Error')});
}
render() {
const { checkedSignIn, signedIn } = this.state;
// If we haven't checked AsyncStorage yet, don't render anything (better ways to do this)
if (!checkedSignIn) {
return null;
}
AsyncStorage.getItem('auth-demo-key').then((data) => console.log("Async Storage: " + data));
const Layout = createRootNavigator(signedIn);
return (
<Provider {...stores}>
<Layout />
</Provider>
);
}
}
Can anyone help me figure out how to add my flash message in this return statement? I tried wrapping the provider in a view, but that failed and crashed my app, same with adding it within the provider (a view), also tried just adding flash message here in the provider, but that failed, too. Can anyone help?