Expo Signature - Crash onChange content - react-native

I wrote this code for get the signature of a person:
import * as ExpoPixi from 'expo-pixi';
import React, { Component } from 'react';
import { Platform, AppState, StyleSheet, Text, View } from 'react-native';
const isAndroid = Platform.OS === 'android';
function uuidv4() {
// https://stackoverflow.com/a/2117523/4047926
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
export default class App extends Component {
state = {
signature: null,
appState: AppState.currentState,
};
handleAppStateChangeAsync = nextAppState => {
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
if (isAndroid && this.sketch) {
this.setState({ appState: nextAppState, id: uuidv4(), lines: this.sketch.lines });
return;
}
}
this.setState({ appState: nextAppState });
};
componentDidMount() {
AppState.addEventListener('change', this.handleAppStateChangeAsync);
}
componentWillUnmount() {
AppState.removeEventListener('change', this.handleAppStateChangeAsync);
}
onChange = async () => {
const { uri } = await this.sketch.takeSnapshotAsync();
this.setState({
signature: { uri },
}, () => console.log(this.state.signature));
}
render() {
return (
<View style={{flex: 1, backgroundColor: 'white'}}>
<View style={{flex: 1, left: '5%'}}>
<ExpoPixi.Signature
ref={signature => (this.sketch = signature)}
style={styles.pad}
strokeColor={'black'}
strokeAlpha={0.5}
onChange={this.onChange}
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
pad: {
flex: 1,
width: '90%',
borderWidth: 0.6,
borderColor: '#b3b3b5',
borderRadius: 10,
backgroundColor: 'white'
},
});
Running this simple code that is inspired on this library example, I notice that the borderRadius is ignored (the corner of the View are missing) and when I try to write the signature the app crash.
A side note: is it possible to get a base64-encoded version of the pad content instead of the uri?

Related

React Native Modal not displaying using context and redux

I created a custom ModalContext.js but my test modal does not seem to be showing when I trigger a button's onPress
// ModalContext.js
import createDataContext from './createDataContext';
const modalReducer = (state, action) => {
switch (action.type) {
case 'openModal':
return { ...state, component: action.payload };
case 'hideModal':
return { ...state, component: null };
default:
return state;
}
};
const openModal = (dispatch) => (component) => {
console.log('hey there');
dispatch({ type: 'openModal', payload: component });
};
const hideModal = (dispatch) => () => {
dispatch({ type: 'hideModal' });
};
export const { Provider, Context } = createDataContext(
modalReducer,
{
openModal,
hideModal,
},
{ component: null }
);
// createDataContext.js
import React, { useReducer } from 'react';
export default (reducer, actions, defaultValue) => {
const Context = React.createContext();
const Provider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, defaultValue);
const boundActions = {};
for (let key in actions) {
boundActions[key] = actions[key](dispatch);
}
return (
<Context.Provider value={{ state, ...boundActions }}>
{children}
</Context.Provider>
);
};
return { Context, Provider };
};
// App.js
const App = createAppContainer(navigator);
export default () => {
return (
<ModalProvider>
<AuthProvider>
<App
ref={(navigator) => {
setNavigator(navigator);
}}
/>
</AuthProvider>
</ModalProvider>
);
};
I have a button on a test screen to check if it works or not.
// WebViewScreen.js
import React, { useState, useContext } from 'react';
import { StyleSheet, Modal, View, Text, Button } from 'react-native';
import { Context as ModalContext } from '../context/ModalContext';
const WebViewScreen = ({ navigation }) => {
const { state, openModal } = useContext(ModalContext);
const errorModal = (
<View>
<Modal animationType='slide' visible={true}>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text>Hello</Text>
</View>
</View>
</Modal>
</View>
);
return (
<>
<Button
onPress={() => {
openModal(errorModal);
}}
title='button'
/>
</>
);
};
WebViewScreen.navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('title'),
};
};
const styles = StyleSheet.create({
view: {
backgroundColor: '#f1f3f4',
},
centeredView: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginTop: 22,
},
modalView: {
margin: 20,
backgroundColor: 'white',
borderRadius: 20,
padding: 35,
alignItems: 'center',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5,
},
});
export default WebViewScreen;
It seems to actually call the function as I can see "hey there" on the console but no modals appear.
I am not sure this is what you are looking for or not but I manage my details like following.
class Abc {
var1;
var2;
var3 = new B();
var4 = new C();
var5 = {}
var6 = [];
success = a => {
//your logic
}
}
class B {
varA;
varB;
varC = false;
}
I hope this is helpful.

Pause video when out of screen view in RecyclerListView in react native

I am implementing video playing app(like Instagram Reels or tik tok) using RecyclerListView in React-Native. In the development of app, I am facing the problem that all the videos in the list play simultaneously. I want to pause all other videos which are out of the screen and play only when scrolled to a particular video and video is visible on screen.
How to do it? I have tried a lot of things but could not find solution for RecyclerListView.
I have used react-native-video for playing video.
App.js
import VideoPlayer from './ViewVideo';
const fakeData = [
{
type: 'NORMAL',
item: {
uri: require('./images/likd2.mp4'),
},
},
{
type: 'NORMAL',
item: {
uri: require('./images/Linkd.mp4'),
},
},
{
type: 'NORMAL',
item: {
uri: require('./images/PlayDate.mp4'),
},
},
];
export default class Myworld extends React.Component {
dataProvider = new DataProvider((r1, r2) => {
return r1 !== r2;
}).cloneWithRows(fakeData);
layoutProvider = new LayoutProvider(
(i) => {
return this.dataProvider.getDataForIndex(i).type;
},
(type, dim) => {
switch (type) {
case 'NORMAL':
dim.width = '100%';
dim.height = '100%';
break;
default:
dim.width = '100%';
dim.height = '100%';
break;
}
},
);
rowRenderer = (type, data, index) => {
switch (type) {
case 'NORMAL':
return (
<View>
<VideoPlayer source={uri} />
</View>
);
}
};
render() {
return (
<>
<SafeAreaView style={styles.container}>
<RecyclerListView
style={styles.videolistcontainer}
rowRenderer={this.rowRenderer}
dataProvider={this.dataProvider}
layoutProvider={this.layoutProvider}
initialOffset={1}
pagingEnabled={true}
showsVerticalScrollIndicator={false}
/>
</SafeAreaView>
</>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
backgroundColor: '#14171A',
},
});
ViewVideo.js
const VideoPlayer = (props) => {
const [paused, setPause] = useState(false);
return (
<>
<TouchableOpacity
style={{height: height, width: width}}
onPress={() => setPause(!paused)}>
<Video
ref={(ref) => {
setVideoRef(ref);
}}
source={props.source}
style={styles.backgroundVideo}
resizeMode={'cover'}
onError={onError(videoRef)}
paused={paused}
onLoad={onLoad}
onProgress={onProgress}
onEnd={onEnd}
repeat={false}
rate={1.0}
volume={1.0}
muted={false}
onLayout={onVideoLayout}
/>
</TouchableOpacity>
</>
);
};
export default VideoPlayer;
const styles = StyleSheet.create({
backgroundVideo: {
position: 'absolute',
width: WP('100%'),
height: HP('100%'),
left: 0,
right: 0,
top: 0,
bottom: 0,
},
});
You can use AppState of React-Native.
It indicate the future state of app: active, background or inactive(IOS only)
Example:
import React, { useRef, useState, useEffect } from "react";
import { AppState, Text, View } from "react-native";
const AppInactiveHandleExample = () => {
const appState = useRef(AppState.currentState);
const [appStateVisible, setAppStateVisible] = useState(appState.current);
useEffect(() => {
AppState.addEventListener("change", handleAppStateChange);
// Return for clear the cache of action
return () => {
AppState.removeEventListener("change", handleAppStateChange);
};
}, []);
const handleAppStateChange = nextAppState => {
if (
appState.current.match(/inactive|background/) &&
nextAppState === "active"
) {
// Execute here your action
onAppInactive()
}
appState.current = nextAppState;
setAppStateVisible(appState.current);
};
// Action executed when app was inactive or background
const onAppInactive = () => {
// Your code here
}
return (
<View>
<Text>Current state is: {appStateVisible}</Text>
</View>
);
};
export default AppInactiveHandleExample;
https://reactnative.dev/docs/appstate

React Native net-info

I'm trying to add an offline notification bar into my app, I have the following code that is called from my App.js.
import React, { PureComponent } from 'react';
import { View, Text, Dimensions, StyleSheet,Alert } from 'react-native';
import NetInfo from "#react-native-community/netinfo";
const dimensions = Dimensions.get('window');
let outofaction = 1;
NetInfo.fetch().then(state => {
console.log("Connection type", state.type);
console.log("Is connected?", state.isConnected);
if (state.isConnected == false) {
outofaction = 0;
} else {
outofaction = 1;
}
});
//class OfflineNotice extends PureComponent {
const OfflineNotice = () => {
NetInfo.fetch().then(state => {
console.log("Connection type", state.type);
console.log("Is connected?", state.isConnected);
if (state.isConnected == false) {
outofaction = 0;
} else {
outofaction = 1;
}
});
// Subscribe
const unsubscribe = NetInfo.addEventListener(state => {
console.log("Connection type", state.type);
console.log("Is connected?", state.isConnected);
if (state.isConnected == false) {
outofaction = 0;
} else {
outofaction = 1;
}
});
// Unsubscribe
unsubscribe();
function MiniOfflineSign() {
if (outofaction == 0) {
return (
<View style={styles.offlineContainer}>
<Text style={styles.offlineText}>Offline</Text>
</View>
);
} else {
return (
<View style={styles.offlineContainer}>
<Text style={styles.offlineText}>Online</Text>
</View>
);
}
}
return (
<MiniOfflineSign />
)};
const styles = StyleSheet.create({
offlineContainer: {
backgroundColor: '#b52424',
height: 30,
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
width: dimensions.width,
position: 'absolute',
top:40,
zIndex:1
},
offlineText: { color: '#fff' }
});
export default OfflineNotice;
The code works partially. I start Online, then turn off my internet on my laptop, and if I refresh / reload, then it will show offline.
Two problems I have;
I want it to update in near real-time when the isConnected changes (this doesn't appear to be happening)
It doesn't get stuck on one state (though item 1 above would fix that)
I made something similar, this might help you with things.
NoInternetMessageBar component
// NoInternetMessageBar.js
import Netinfo from '#react-native-community/netinfo';
import React, { useContext, useEffect } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Store } from 'store/Store';
export default function NoInternetMessageBar() {
const {
state,
actions: { networkConnectionChanged },
} = useContext(Store);
useEffect(() => {
const unsubscribe = Netinfo.addEventListener(({ isConnected }) => networkConnectionChanged(isConnected));
return () => {
unsubscribe();
};
}, []);
if (state.isConnected) return null;
return (
<View style={styles.container}>
<Text style={styles.message}>Cannot reach internet</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
position: 'absolute',
bottom: 0,
height: 40,
width: '100%',
backgroundColor: 'gray',
},
message: {
color: 'white',
marginLeft: 20,
},
});
action
const networkConnectionChanged = async isConnected => {
return dispatch({
type: NETWORK_CHANGED,
payload: isConnected,
});
};
reducer
case NETWORK_CHANGED:
return {
...state,
isConnected: action.payload,
};
On top level use it like this.
<>
<AppContainer />
<NoInternetMessageBar />
</>
You are unsubscribing from NetInfo updates immediately after subscribing to them. Functional components are just that - functions. The code you wrote in there will be executed every time that component renders.
You should instead put your subscribe/unsubscribe in a useEffect hook, so that you subscribe on mount and unsubscribe on unmount.
useEffect(() => {
const unsubscribe = NetInfo.addEventListener(state => {
...
});
return () => {
unsubscribe();
}
}, []);
Subscribe in componentDidMount() and Unsubscribe in componentWillUnmount(), like this -
class A extends React.Component {
constructor() {
this.unsubscribe;
}
componentDidMount(){
this.unsubscribe = NetInfo.addEventListener(...);
}
componentWillUnmount() {
this.unsubscribe && this.unsubscribe();
}
}

How to make a QR code scanner in React native using expo?

When I run https://snack.expo.io/#sushil62/qr-code-scanner in the expo which works fine, but when copy the same code given in App.js file, after running the application the camera opens but it shows no result while scanning, and
in expo also when changing the snack version 33 or higher it does not work there too.
import React, { Component } from 'react';
import { Alert, Linking, Dimensions, LayoutAnimation, Text, View, StatusBar, StyleSheet, TouchableOpacity } from 'react-native';
import { BarCodeScanner, Permissions } from 'expo';
export default class App extends Component {
state = {
hasCameraPermission: null,
lastScannedUrl: null,
};
componentDidMount() {
this._requestCameraPermission();
}
_requestCameraPermission = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({
hasCameraPermission: status === 'granted',
});
};
_handleBarCodeRead = result => {
if (result.data !== this.state.lastScannedUrl) {
LayoutAnimation.spring();
this.setState({ lastScannedUrl: result.data });
}
};
render() {
return (
<View style={styles.container}>
{this.state.hasCameraPermission === null
? <Text>Requesting for camera permission</Text>
: this.state.hasCameraPermission === false
? <Text style={{ color: '#fff' }}>
Camera permission is not granted
</Text>
: <BarCodeScanner
onBarCodeRead={this._handleBarCodeRead}
style={{
height: Dimensions.get('window').height,
width: Dimensions.get('window').width,
}}
/>}
{this._maybeRenderUrl()}
<StatusBar hidden />
</View>
);
}
_handlePressUrl = () => {
Alert.alert(
'Open this URL?',
this.state.lastScannedUrl,
[
{
text: 'Yes',
onPress: () => Linking.openURL(this.state.lastScannedUrl),
},
{ text: 'No', onPress: () => {} },
],
{ cancellable: false }
);
};
_handlePressCancel = () => {
this.setState({ lastScannedUrl: null });
};
_maybeRenderUrl = () => {
if (!this.state.lastScannedUrl) {
return;
}
return (
<View style={styles.bottomBar}>
<TouchableOpacity style={styles.url} onPress={this._handlePressUrl}>
<Text numberOfLines={1} style={styles.urlText}>
{this.state.lastScannedUrl}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.cancelButton}
onPress={this._handlePressCancel}>
<Text style={styles.cancelButtonText}>
Cancel
</Text>
</TouchableOpacity>
</View>
);
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#000',
},
bottomBar: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(0,0,0,0.5)',
padding: 15,
flexDirection: 'row',
},
url: {
flex: 1,
},
urlText: {
color: '#fff',
fontSize: 20,
},
cancelButton: {
marginLeft: 10,
alignItems: 'center',
justifyContent: 'center',
},
cancelButtonText: {
color: 'rgba(255,255,255,0.8)',
fontSize: 18,
},
});
It would be very nice if someone suggests me to solve this or give me an example(such as downgrading the expo version) so that I can implement this.
You can use
expo-barcode-scanner
Run expo install expo-barcode-scanner
Usage
You must request permission to access the user's camera before attempting to get it. To do this, you will want to use the Permissions API. You can see this in practice in the following example.
import * as React from 'react';
import {
Text,
View,
StyleSheet,
Button
} from 'react-native';
import Constants from 'expo-constants';
import * as Permissions from 'expo-permissions';
import {
BarCodeScanner
} from 'expo-barcode-scanner';
export default class BarcodeScannerExample extends React.Component {
state = {
hasCameraPermission: null,
scanned: false,
};
async componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async() => {
const {
status
} = await Permissions.askAsync(Permissions.CAMERA);
this.setState({
hasCameraPermission: status === 'granted'
});
};
render() {
const {
hasCameraPermission,
scanned
} = this.state;
if (hasCameraPermission === null) {
return <Text > Requesting
for camera permission < /Text>;
}
if (hasCameraPermission === false) {
return <Text > No access to camera < /Text>;
}
return ( <
View style = {
{
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
}
} >
<
BarCodeScanner onBarCodeScanned = {
scanned ? undefined : this.handleBarCodeScanned
}
style = {
StyleSheet.absoluteFillObject
}
/>
{
scanned && ( <
Button title = {
'Tap to Scan Again'
}
onPress = {
() => this.setState({
scanned: false
})
}
/>
)
} <
/View>
);
}
handleBarCodeScanned = ({
type,
data
}) => {
this.setState({
scanned: true
});
alert(`Bar code with type ${type} and data ${data} has been scanned!`);
};
}
Note: Passing undefined to the onBarCodeScanned prop will result in no scanning. This can be used to effectively "pause" the scanner so that it doesn't continually scan even after data has been retrieved.
Allow all the permisions which gets popped.
You're good to go!!
Hope this helps.

Redux Persist saving multiple data

I am making use of https://github.com/cinder92/react-native-get-music-files to get the music files on a user's device with my app, I am making of use of redux persist so that when the music loads once on the user's phone and the user comes back to the app, it will just check for new music not in the tracks state array, it won't have to rescan for all the music, it will just check for new music in the background, but the state usually contains double data(it usually reloads the music, it will show music 1-5, then music 1-10) and It doesn't load all the music on the person's phone it just stops halfway, when I use normal states, i.e this.setState all the music on the users phone usually loads please what may I be doing wrong
This is my code below
Store - index.js
import { createStore } from "redux";
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import rootReducer from "../reducers/index";
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const persistConfig = {
key: 'root',
storage,
// stateReconciler: autoMergeLevel2,
timeout: 0,
}
const persistedReducer = persistReducer(persistConfig, rootReducer)
export default () => {
let store = createStore(persistedReducer)
let persistor = persistStore(store)
return { store, persistor }
}
Actions- index.js
export const addSong = song => ({type:
"ADD_SONG", payload: song
});
export const RESET_ACTION = {
type: "RESET"
}
Reducers- index.js
import{ADD_SONG,RESET} from "../constants/action-types";
const initialState = {
tracks: []
};
const rootReducer = (state = initialState, action) => {
switch (action.type){
case ADD_SONG:
let index = state.tracks.findIndex(tracks => tracks.id == action.payload.id);
if(index != -1){
return state;
}else{
return {
...state,
tracks: [...state.songs, action.payload]
}
}
case RESET:
return initialState;
default:
return state
}
}
export default rootReducer;
App.js
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
Image,
Dimensions,
StatusBar,
ScrollView,
View,
DeviceEventEmitter,
FlatList,
ActivityIndicator,
AsyncStorage
} from 'react-native';
import Splash from './components/Splash';
import Home from './components/Home';
import MusicFiles from 'react-native-get-music-files';
import Permissions from 'react-native-permissions';
import { PersistGate } from 'redux-persist/integration/react';
//import store from "./store/index";
import index from './store/index';
const {store, persistor} = index();
import {connect, Provider} from 'react-redux';
import {addSong, RESET_ACTION
} from "./actions/index";
const mapStateToProps = state => {
return {
tracks: state.tracks
};
};
const mapDispatchToProps = dispatch => {
return {
addSong: song => dispatch(addSong(song)),
RESET_ACTION
};
};
class reduxApp extends Component{
millisToMinutesAndSeconds(millis) {
var minutes = Math.floor(millis / 60000);
var seconds = ((millis % 60000) / 1000).toFixed(0);
return (seconds == 60 ? (minutes+1) + ":00" : minutes + ":" + (seconds < 10 ? "0" : "") + seconds);
}
componentDidMount() {
this.props.RESET_ACTION;
this.setState({loaded: false});
if(this.props.songs && this.props.songs.length > 0){
this.setState({loaded: true})
}else{
this.musicGetter();
}
}
musicGetter(){
Permissions.request('storage').then(response => {
this.setState({ photoPermission: response })
})
MusicFiles.getAll({
id : true,
blured : false,
artist : true,
duration : true, //default : true
cover : true, //default : true,
title : true,
cover : true,
batchNumber : 1, //get 5 songs per batch
minimumSongDuration : 10000, //in miliseconds,
fields : ['title','artwork','duration','artist','genre','lyrics','albumTitle']
})
}
componentWillMount() {
/* DeviceEventEmitter.addListener(
'onBatchReceived',
(params) => {
this.setState({songs : [
...this.state.songs,
...params.batch
]},this.setState({loaded: true}));
}
);*/
DeviceEventEmitter.addListener(
'onBatchReceived',
(params) => {
console.log(params.batch);
this.props.addSong(params.batch);
this.setState({loaded: true});
},
);
}
async asynccer(){
try {
await AsyncStorage.setItem('#MySuperStore:songs', JSON.stringify(this.state.songs));
} catch (error) {
// Error saving data
}
}
constructor(props) {
super(props);
this.state = {
timePassed: false,
photoPermission: '',
songs: [],
loaded: true,
loading: false
};
}
render() {
if (!this.state.loaded) {
return (
<Splash/>
);
} else {
return (
<View style={styles.linearGradient}>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<Home songs={this.props.tracks}/>
</PersistGate>
</Provider>
</View>
);
}
}
}
function connectWithStore(store, WrappedComponent, ...args) {
var ConnectedWrappedComponent = connect(...args)(WrappedComponent)
return function (props) {
return <ConnectedWrappedComponent {...props} store={store} />
}
}
const App = connectWithStore(store, reduxApp,mapStateToProps, mapDispatchToProps);
export default App;
Home.js
render() {
const lyrics = this.props.songs.map((song, index) =>
<View style={styles.musicBox} key={index}>
<View style={{width: 57, height: 59, borderRadius: 9, marginLeft: 15}}>
<Image resizeMode="contain"
style={{alignSelf: 'center', borderRadius: 9, width: 57, height: 59}}
source={{uri: song[0].cover}}/>
</View>
<View style={styles.TextBox}>
<Text
numberOfLines={1}
style={{fontFamily: 'nexaBold', fontSize: 20, color: 'white', flex: 1}}>
{song[0].title}
</Text>
<View style={{flexDirection: 'row', }}>
<Text
numberOfLines={1}
style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D',
marginRight: 5, }}>
{song[0].author}
</Text>
<View style={{alignSelf:'center',width: 2, height: 2, borderRadius: 1, backgroundColor: '#917D7D',marginRight: 5}}>
</View>
<Text style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D'}}>
{this.millisToMinutesAndSeconds(song.duration)}
</Text></View>
</View>
</View>
);
const music =
<ScrollView overScrollMode={'never'} keyboardShouldPersistTaps='always'>
{lyrics}</ScrollView>;
const shadowOpt = {
color: "#000",
border: 12,
opacity: '0.08',
radius: 12,
x: 0,
y: 1,
};
return (
<View style={{flex: 1}}>
<View style={styles.linearGradient}>
{music}
</View>
</View>
);
}
}