React Native how to get the local time format of device? - react-native

I need to get the time format from local device . And I have tried this "https://www.npmjs.com/package/react-native-device-time-format?activeTab=readme"
And also install the moment API and follow what the document said ,however ,when I tried ,it got an error like "
TypeError: null is not an object (evaluating 'RNDeviceTimeFormat.is24HourFormat')
"
I attached my code ,could you please help me to take a look ? Thank you so much !!
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { is24HourFormat } from 'react-native-device-time-format';
import moment from 'moment'
function TryTime(props) {
const getCurrentHourFormat = async (date) => {
const is24Hour = await is24HourFormat();
return (moment(date).format(is24Hour ? 'HH:mm' : 'h:mm A'));
}
return (
<View style={styles.container}>
<Text>{is24Hour}</Text>
</View>
);
}
const styles = StyleSheet.create({
container : {
flex : 1,
justifyContent : 'center',
alignItems : 'center',
}
})
export default TryTime;

There are a few things wrong with your code: you defined a function getCurrentHourFormat but haven't run it yet, so is24Hour is undefined.
function TryTime(props) {
const [currentTime, setCurrentTime] = useState("");
const getCurrentHourFormat = async (date) => {
const is24Hour = await is24HourFormat();
return (moment(date).format(is24Hour ? 'HH:mm' : 'h:mm A'));
}
useEffect(() => {
(async () => {
const timeNow = await TryTime(Date.now);
setCurrentTime(timeNow);
})();
}, []);
return (
<View style={styles.container}>
<Text>{currentTime}</Text>
</View>
);
}
You might want to check useEffect and how functional component work though

Related

Does react-native supports Pintura Editor?

I want to use Pintura Editor in my react-native project, But it's not working and also didn't getting any error.
I am not able to understand where i am going wrong and does react-native supports Pintura ?
Is there any way i can solve this issue?
Any lead would be highly appreciated. Thank you in advance.
React-Native doesn't supports Pintura Editor yet. But we can use pintura with WebView, as Pintura is based on html technologies it will have to run in a WebView to work. Here is an example
Pintura_Editor.js
import { WebView } from 'react-native-webview';
import { View } from 'react-native';
import React, { forwardRef, useRef, useEffect,useState } from 'react';
const noop = () => {};
//For Making First letter uppercase.
const upperCaseFirstLetter = (str) => str.charAt(0).toUpperCase() + str.slice(1);
// PATH_TO_PINTURA.HTML file (need to download paid version)
const PinturaEditorProxy = require('./pintura.html');
const Editor = forwardRef((props, ref) => {
const { style, ...options } = props;
const webViewRef = useRef(null);
const [isStatus, setStatus] = useState(false)
setInterval(()=> {
setStatus(true)
}, 3000)
// this passes options to the editor
useEffect(() => {
clearInterval();
// setup proxy to call functions on editor
const handler = {
get: (target, prop) => {
if (prop === 'history') return new Proxy({ group: 'history' }, handler);
return (...args) => {
const name = [target.group, prop].filter(Boolean).join('.');
webViewRef.current.postMessage(
JSON.stringify({
fn: [name, ...args],
})
);
};
},
};
webViewRef.current.editor = new Proxy({}, handler);
// post new options
webViewRef.current.postMessage(JSON.stringify({ options: options }));
},[isStatus]);
return (
<View ref={ref} style={style}>
<WebView
ref={webViewRef}
javaScriptEnabled={true}
scrollEnabled={false}
domStorageEnabled={true}
allowFileAccess={true}
allowUniversalAccessFromFileURLs={true}
allowsLinkPreview={false}
automaticallyAdjustContentInsets={false}
originWhitelist={['*']}
textZoom={100}
source={PinturaEditorProxy}
onMessage={async (event) => {
// message from WebView
const { type, detail } = JSON.parse(event.nativeEvent.data);
const handler = await options[`on${upperCaseFirstLetter(type)}`] || noop;
// call handler
handler(detail);
}}
/>
</View>
);
});
export default Editor;
Now, import this editor to your app.js
import PinturaEditor from 'PATH_TO_PINTURA_EDITOR'
const editorRef = null;
....
....
render() {
return (
<PinturaEditor
ref={editorRef}
style={{ margin:40, width: '80%', height: '80%', borderWidth: 2, borderColor: '#eee' }}
imageCropAspectRatio={1}
// Image should be base64 or blob type
src={base64Image}
onLoad={(img) => {
// do something
}}
onProcess={async (image) => {
// do something with edited image
}}
/>)
}

Check the render method of `InstanceImage` while testing using testing-library/react-native

I am trying to test a functional component with Redux using testing-library/react-native.
//InstanceImage.component.js
export default InstanceImage = (props) => {
// <props init, code reduced >
const { deviceId, instanceId } = DeviceUtils.parseDeviceInstanceId(deviceInstanceId)
const deviceMap = useSelector(state => {
return CommonUtils.returnDefaultOnUndefined((state) => {
return state.deviceReducer.deviceMap
}, state, {})
})
const device = deviceMap[deviceId]
const instanceDetail = device.reported.instances[instanceId]
if (device.desired.instances[instanceId] !== undefined) {
return (
<View
height={height}
width={width}
>
<ActivityIndicator
testID={testID}
size={loadingIconSize}
color={fill}
/>
</View>
)
}
const CardImage = ImageUtils[instanceDetail.instanceImage] === undefined ? ImageUtils.custom : ImageUtils[instanceDetail.instanceImage]
return (
<CardImage
testID={testID}
height={height}
width={width}
fill={fill}
style={style}
/>
)
}
And the test file is
//InstanceImage.component.test.js
import React from 'react'
import { StyleSheet } from 'react-native';
import { color } from '../../../../src/utils/Color.utils';
import ConstantsUtils from '../../../../src/utils/Constants.utils';
import { default as Helper } from '../../../helpers/redux/device/UpdateDeviceInstanceIfLatestHelper';
import InstanceImage from '../../../../src/components/Switches/InstanceImage.component';
import { Provider } from 'react-redux';
import { render } from '#testing-library/react-native';
import configureMockStore from "redux-mock-store";
import TestConstants from '../../../../e2e/TestConstants';
const mockStore = configureMockStore();
const store = mockStore({
deviceReducer: {
deviceMap: Helper.getDeviceMap()
}
});
const currentState = ConstantsUtils.constant.OFF
const styles = StyleSheet.create({
// styles init
})
const props = {
//props init
}
describe('Render InstanceImage', () => {
it('InstanceImage renders correctly with values from props and Redux', () => {
const rendered = render(<Provider store={store}>
<InstanceImage {...props}/>
</Provider>)
const testComponent = rendered.getByTestId(TestConstants.icons.INSTANCE_IMAGE)
});
})
And when I run the test file it gives the following error
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of `InstanceImage`.
The component runs correctly when the app is run and there aren't any crashes. Still, this error occurs while performing tests.I am new to creating test cases for react native app so not able to debug this issue.
Found the error, the CardImage returns a custom svg image which was causing the issue. I used the jest-svg-transformer and it solved the issue.
Reference: https://stackoverflow.com/a/63042067/4795837

NavigationEvents is not working when use going back

I am building a small sound player page. I am using expo-av library.
I got noticed when the user going forward {NavigationEvents onWillBlur } is working and when he goes backward it's not executing.
What I need to reach are :
1) Stop sound playing when the user leave page either backward or forward.
2) If user presses play twice the sound is being played twice so I don't want it to be played again if it's already running
If there is any other library could be use instead of expo-av ?
import React, {useState} from 'react';
import {View, Text, Button, StyleSheet, TouchableOpacity } from 'react-native';
import { NavigationEvents } from 'react-navigation';
import { Audio } from 'expo-av';
import {AntDesign, Entypo} from '#expo/vector-icons';
const PlaySound = ({link}) => {
const [error, setError] = useState('')
const soundObject = new Audio.Sound();
const mySound = async () => {
try {
await soundObject.loadAsync({ uri : link });
await soundObject.playAsync();
} catch (err) {
setError('Wait while uploading your sound');
}
}
const stopSound = async () => {
try {
await soundObject.stopAsync(mySound);
} catch (error) {
setError('You must Play Sound First')
}
}
const pause = async () => {
try {
await soundObject.pauseAsync(mySound);
} catch (error) {
setError('Something went wrong !!! Please try again');
}
}
return (
<View>
<NavigationEvents onWillBlur = {stopSound} />
<Text>Play Sound</Text>
<View style = {styles.row}>
<TouchableOpacity
onPress = {mySound}>
<AntDesign name = 'caretright' size = {25} />
</TouchableOpacity>
<TouchableOpacity
onPress = {stopSound} >
<Entypo name = 'controller-stop' size = {25}/>
</TouchableOpacity>
<TouchableOpacity
onPress = {pause}>
<AntDesign name = 'pause' size = {25} />
</TouchableOpacity>
</View>
{error ? <Text>{error} </Text> : null }
</View>
);
};
const styles = StyleSheet.create({
row : {
flexDirection : 'row',
justifyContent : 'space-between',
marginVertical : 10
}
});
export default PlaySound;
For the problem 1 in which you have to stop player when user leaves the page. You can use useEffect hook. It will be something like that,
useEffect(() => {
return () => {
stopSound();
}
}, []);
So in the above useEffect hook, the returned function will run when component will unmount from screen (forward or backward).
For the 2nd problem, you have to disable play button to avoid multiple clicks. You can create a state using useState hook and make it false on Play button click and pass this playButtonState to disable prop of Play Button Touchable Opacity.
I hope it's clear to you now.

Lodash debounce not working all of a sudden?

I'm using a component I wrote for one app, in a newer app. The code is like 99% identical between the first app, which is working, and the second app. Everything is fine except that debounce is not activating in the new app. What am I doing wrong?
// #flow
import type { Location } from "../redux/reducers/locationReducer";
import * as React from "react";
import { Text, TextInput, View, TouchableOpacity } from "react-native";
import { Input } from "react-native-elements";
import { GoogleMapsApiKey } from "../../.secrets";
import _, { debounce } from "lodash";
import { connect } from "react-redux";
import { setCurrentRegion } from "../redux/actions/locationActions";
export class AutoFillMapSearch extends React.Component<Props, State> {
textInput: ?TextInput;
state: State = {
address: "",
addressPredictions: [],
showPredictions: false
};
async handleAddressChange() {
console.log("handleAddressChange");
const url = `https://maps.googleapis.com/maps/api/place/autocomplete/json?key=${GoogleMapsApiKey}&input=${this.state.address}`;
try {
const result = await fetch(url);
const json = await result.json();
if (json.error_message) throw Error(json.error_message);
this.setState({
addressPredictions: json.predictions,
showPredictions: true
});
// debugger;
} catch (err) {
console.warn(err);
}
}
onChangeText = async (address: string) => {
await this.setState({ address });
console.log("onChangeText");
debounce(this.handleAddressChange.bind(this), 800); // console.log(debounce) confirms that the function is importing correctly.
};
render() {
const predictions = this.state.addressPredictions.map(prediction => (
<TouchableOpacity
style={styles.prediction}
key={prediction.id}
onPress={() => {
this.props.beforeOnPress();
this.onPredictionSelect(prediction);
}}
>
<Text style={text.prediction}>{prediction.description}</Text>
</TouchableOpacity>
));
return (
<View>
<TextInput
ref={ref => (this.textInput = ref)}
onChangeText={this.onChangeText}
value={this.state.address}
style={[styles.input, this.props.style]}
placeholder={"Search"}
autoCorrect={false}
clearButtonMode={"while-editing"}
onBlur={() => {
this.setState({ showPredictions: false });
}}
/>
{this.state.showPredictions && (
<View style={styles.predictionsContainer}>{predictions}</View>
)}
</View>
);
}
}
export default connect(
null,
{ setCurrentRegion }
)(AutoFillMapSearch);
I noticed that the difference in the code was that the older app called handleAddressChange as a second argument to setState. Flow was complaining about this in the new app so I thought async/awaiting setState would work the same way.
So changing it to this works fine (with no flow complaints for some reason. maybe because I've since installed flow-typed lodash. God I love flow-typed!):
onChangeText = async (address: string) => {
this.setState(
{ address },
_.debounce(this.handleAddressChange.bind(this), 800)
);
};

How do I take a screenshot of View in React Native?

I want to share screenshot of particular View Component instead of whole screen.
Any one help me out with this.
Take a look a picture. Want screenshot of Red mark area which is within View Component.
You can use library named react-native-view-shot
You just have to give wrap your View inside ViewShot, take a reference of that and call capture()
Here is example of code taken from that library
import ViewShot from "react-native-view-shot";
class ExampleCaptureOnMountManually extends Component {
componentDidMount () {
this.refs.viewShot.capture().then(uri => {
console.log("do something with ", uri);
});
}
render() {
return (
<ViewShot ref="viewShot" options={{ format: "jpg", quality: 0.9 }}>
<Text>...Something to rasterize...</Text>
</ViewShot>
);
}
}
Here is a working example example of code using react-native-view-shot with hooks
import React, { useState, useRef, useEffect } from "react";
import { View, Image, ScrollView, TouchableOpacity } from "react-native";
import ViewShot from "react-native-view-shot";
var RNFS = require("react-native-fs");
import Share from "react-native-share";
const TransactionReceipt = () => {
const viewShotRef = useRef(null);
const [isSharingView, setSharingView] = useState(false);
useEffect(() => {
if (isSharingView) {
const shareScreenshot = async () => {
try {
const uri = await viewShotRef.current.capture();
const res = await RNFS.readFile(uri, "base64");
const urlString = `data:image/jpeg;base64,${res}`;
const info = '...';
const filename = '...';
const options = {
title: info,
message: info,
url: urlString,
type: "image/jpeg",
filename: filename,
subject: info,
};
await Share.open(options);
setSharingView(false);
} catch (error) {
setSharingView(false);
console.log("shareScreenshot error:", error);
}
};
shareScreenshot();
}
}, [isSharingView]);
return (
<ViewShot ref={viewShotRef} options={{ format: "jpg", quality: 0.9 }}>
<View>
{!isSharingView && (
<TouchableOpacity onPress={() => setSharingView(true)}>
<Image source={Images.shareIcon} />
</TouchableOpacity>
)}
<ScrollView />
</View>
</ViewShot>);
}