React Native Speech to text - GoogleCloudSpeechToText - react-native

I am new to react native and am trying to develop a voice transcription function in my application.
I would like to get a string when people use the microphone.
I have found several solutions on the net but for native apps, I am using EXPO.
I am using "react-native-google-cloud-speech-to-text" but I keep getting this error:
TypeError: null is not an object (evaluating 'GoogleCloudSpeechToText.setApiKey')
Have you ever faced this problem?
export default function Notes() {
const [transcript, setResult] = useState("");
const [fileId, setId] = useState("");
const [file, setFile] = useState("");
const API_KEY = '**************************';
useEffect(() => {
PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, {
title: "Cool Photo App Camera Permission",
message:
"Cool Photo App needs access to your camera " +
"so you can take awesome pictures.",
buttonNeutral: "Ask Me Later",
buttonNegative: "Cancel",
buttonPositive: "OK",
});
}, []);
useEffect(() => {
GoogleCloudSpeechToText.setApiKey(API_KEY);
GoogleCloudSpeechToText.onVoice(onVoice);
GoogleCloudSpeechToText.onVoiceStart(onVoiceStart);
GoogleCloudSpeechToText.onVoiceEnd(onVoiceEnd);
GoogleCloudSpeechToText.onSpeechError(onSpeechError);
GoogleCloudSpeechToText.onSpeechRecognized(onSpeechRecognized);
GoogleCloudSpeechToText.onSpeechRecognizing(onSpeechRecognizing);
return () => {
GoogleCloudSpeechToText.removeListeners();
};
}, []);
const onSpeechError = (_error) => {
console.log("onSpeechError: ", _error);
};
const onSpeechRecognized = (result) => {
console.log("onSpeechRecognized: ", result);
setResult(result.transcript);
};
const onSpeechRecognizing = (result) => {
console.log("onSpeechRecognizing: ", result);
setResult(result.transcript);
};
const onVoiceStart = (_event) => {
console.log("onVoiceStart", _event);
};
const onVoice = (_event) => {
console.log("onVoice", _event);
};
const onVoiceEnd = () => {
console.log("onVoiceEnd: ");
};
const startRecognizing = async () => {
const result = await GoogleCloudSpeechToText.start({
speechToFile: true,
});
console.log("startRecognizing", result);
if (result.fileId) setId(result.fileId);
};
const stopRecognizing = async () => {
await GoogleCloudSpeechToText.stop();
};
const getAudioFile = async () => {
if (fileId) {
const result = await GoogleCloudSpeechToText.getAudioFile(fileId, {
channel: 2,
bitrate: 96000,
sampleRate: 44100,
});
console.log(result);
if (result.path) {
setFile(result.path);
}
}
};
return (
<SafeAreaView style={styles.container}>
<View>
<Text style={styles.title}>{transcript}</Text>
<Button title="Start me" onPress={startRecognizing} />
</View>
<Separator />
<View>
<Text style={styles.title}>
Adjust the color in a way that looks standard on each platform. On
iOS, the color prop controls the color of the text. On Android, the
color adjusts the background color of the button.
</Text>
<Button title="Stop me" color="#f194ff" onPress={stopRecognizing} />
</View>
<Separator />
<View>
<Text style={styles.title}>{file}</Text>
<Button
disabled={transcript === ""}
title="Get file audio"
color="#f194ff"
onPress={getAudioFile}
/>
</View>
{/*{file && (*/}
{/* <>*/}
{/* <Separator />*/}
{/* <Text style={styles.title}>file</Text>*/}
{/* <View>*/}
{/* <Button*/}
{/* disabled={transcript === ''}*/}
{/* title="Play"*/}
{/* color="#f194ff"*/}
{/* onPress={playAudio}*/}
{/* />*/}
{/* </View>*/}
{/* </>*/}
{/*)}*/}
</SafeAreaView>
);
}

I have not faced this problem, but I see a different error when clicking 'run code snippet' in StackOverflow:
Error: {
"message": "Uncaught SyntaxError: Unexpected token 'export'",
"filename": "https://stacksnippets.net/js",
"lineno": 12,
"colno": 9
}
Perhaps a stack trace would help?

Related

How to use asyncStorage inside useEffect

I'm building a mobile game using react native and I'm trying to retrieve the best value storage on it to display on the screen. The problem is that it seems that react native is rendering the screen before it retrieves the value and then it doesn't re-render when the value is updated using setBest(), so no value is displayed.
Here is the code:
const navigation = useNavigation()
const [result, setResult] = useState('')
const [best, setBest] = useState('')
useEffect(() => {
const Storage = async (key,value) => {
await AsyncStorage.setItem(key,value)
}
const Retrieve = async (key) => {
const value = await AsyncStorage.getItem(key)
setBest(()=>value)
}
Retrieve('1').catch(console.error)
setResult(route.params.paramKey)
if(route.params.paramKey>best){
var aux = result.toString()
Storage('1',aux)
console.log(best)
}
}, [])
return (
<View style={styles.container}>
<View style={styles.textView}>
<Text style={styles.tituloText}>Melhor pontuação</Text>
<Text style={styles.tituloText}>{best}</Text>
<Text style={styles.tituloText}>Sua pontuação</Text>
<Text style={styles.resultText}>{result}</Text>
<View style={styles.viewBtn}>
<TouchableOpacity style={styles.viewBack} onPress={() => navigation.navigate('Modo1')}>
<Icon style={styles.iconBack} name="backward" />
</TouchableOpacity>
<TouchableOpacity style={styles.viewHome} onPress={() => navigation.dispatch(StackActions.popToTop)}>
<Icon style={styles.iconBack} name="home" />
</TouchableOpacity>
</View>
</View>
</View>
);
}
Thanks for the help guys! I've been struggling with this for days and any help will be appreciated!
This is how you retrieve the value..
useEffect(() => {
AsyncStorage.getItem('key').then(value => {
if (value != null) {
console.log(value);
setBest(value);
}
});
}, []);
also don't forget to add the import statement..
To set the value you must use
AsyncStorage.setItem('key', value);
You can use Async Functions inside of ~useEffect()` like this:
useEffect(() => {
(async () => {
async function getData() {
try {
const value = await AsyncStorage.getItem('myKey');
if (value !== null) {
setData(value);
}
} catch (error) {
console.log(error);
}
}
getData();
})();
}, []);
}

how to refresh the list after submitting a form in react-native?

when redirecting to index screen after submitting a post-form, the index screen does not show the newly added item in the list, can anyone help?
here is my Customer.js page
export default function Customer({ navigation }) {
const [customers, setCustomers] = useState([]);
const [isLoading, setLoading] = useState(true);
const getCustomers = async () => {
try {
const response = await fetch("http://localhost:3001/api/customers");
const json = await response.json();
setCustomers(json);
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
};
useEffect(() => {
getCustomers();
}, []);
return (
<View style={styles.item}>
<TouchableOpacity
onPress={() => navigation.navigate("AddCustomer")}
style={styles.btn}
>
<Text style={styles.btnText}>Add New Customer</Text>
</TouchableOpacity>
<FlatList
data={customers}
extraData={customers}
renderItem={({ item }) => (
<TouchableOpacity
onPress={() => navigation.navigate("CustomerDetails", item)}
>
<Text style={styles.item}>{item.name}</Text>
</TouchableOpacity>
)}
keyExtractor={(item) => item._id}
/>
</View>
);
}
}
and here is my AddCustomer.js page
const AddCustomer = ({ navigation, route }) => {
const [name, setName] = useState("");
const [phone, setPhone] = useState(0);
const [isGold, setIsGold] = useState(false);
const handleSubmit = async () => {
// e.preventDefault();
return await fetch("http://localhost:3001/api/customers", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: name,
phone: phone,
isGold: isGold,
}),
}).then(() => {
navigation.navigate("Customer", { customers: [name, phone, isGold] });
});
};
return (
<View>
<Text style={styles.title}>Add New Customer</Text>
<View>
<TextInput
style={styles.input}
onChangeText={(val) => setName(val)}
value={name}
placeholder="Your name"
onBlur={Keyboard.dismiss}
/>
<TextInput
style={styles.input}
onChangeText={(val) => setPhone(val)}
value={phone}
placeholder="phone number"
/>
<TextInput
style={styles.input}
onChangeText={(val) => setIsGold(val)}
value={isGold}
placeholder="is gold member"
autoCorrect={false}
autoCapitalize={false}
/>
</View>
<View style={styles.inputContainer}>
<TouchableOpacity style={styles.saveButton} onPress={handleSubmit}>
<Text style={styles.saveButtonText}>Add Customer</Text>
</TouchableOpacity>
</View>
</View>
);
};
new customer would be added and everything else work fine but the Customer page does not get re-rendered or refresh or reload.
In your Customer.js do it like below -
useEffect(() => {
const unsubscribe = navigation.addListener('focus', async () => {
getCustomers();
});
return unsubscribe ;
}, [navigation]);
import { useFocusEffect } from '#react-navigation/native';
useFocusEffect(
React.useCallback(() => {
// Do something when the screen is focused
getCustomers();
return () => {
// Do something when the screen is unfocused
};
}, []),
);

improving elements styles to make a full screen scan

I will need a helping hand to edit this page. i have all the elements but i need help styling.
I would like to have the camera (the image you see is the typical emulator camera, that's why it makes an image) in full screen and from above at the top, the message in red and the 'autocomplete.
If you want, to explain better, I would like to respect the image below: autocomplete at the top left above the camera in full screen.
would it be possible for you to help me, I'm getting a little confused. I tried to do a snack but failed. I will add it later if i can.
const autocompletes = [...Array(10).keys()];
const apiUrl = "https://5b927fd14c818e001456e967.mockapi.io/branches";
class Tickets extends Component {
constructor(props) {
super(props);
this.state = {
Press: false,
hasCameraPermission: null,
reference: '',
lastScannedUrl:null,
displayArray: []
};
}
initListData = async () => {
let list = await getProductByRef(1);
if (list) {
this.setState({
displayArray: list,
reference: list.reference
});
}
// console.log('reference dans initListData =', list.reference)
};
async UNSAFE_componentWillMount() {
this.initListData();
// console.log('reference dans le state =', this.state.reference)
};
componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === "granted" });
};
_onPress_Scan = () => {
this.setState({
Press: true
});
}
handleBarCodeScanned = ({ type, data }) => {
this.setState({ Press: false, scanned: true, reference: data });
this.props.navigation.navigate('ProductDetails', {reference : parseInt(this.state.state.reference)})
};
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
if (hasCameraPermission === null) {
return <Text>{i18n.t("scan.request")}</Text>;
}
if (hasCameraPermission === false) {
return <Text>{i18n.t("scan.noaccess")}</Text>;
}
return (
<View
style={{
flex: 1,
...StyleSheet.absoluteFillObject
}}
>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
style={{ flex:1, height:'100%', ...StyleSheet.absoluteFillObject}}
/>
{scanned && (
<Button
title={"Tap to Scan Again"}
onPress={() => this.setState({ scanned: false })}
/>
)}
</View>
);
}
handleSelectItem(item, index) {
const {onDropdownClose} = this.props;
onDropdownClose();
console.log(item);
}
render() {
const { hasCameraPermission, scanned, Press } = this.state;
let marker = null;
const {scrollToInput, onDropdownClose, onDropdownShow} = this.props;
// console.log('displayArray', this.state.displayArray, 'reference', this.state.displayArray.reference)
return (
<View style={styles.container}>
{Press ? (
<View style={{flex:1}}>
<View style={styles.dropdownContainerStyle}>
<Autocomplete
key={shortid.generate()}
containerStyle={styles.autocompleteContainer}
inputStyle={{ borderWidth: 1, borderColor: '#F78400'}}
placeholder={i18n.t("tickets.warning")}
pickerStyle={styles.autocompletePicker}
scrollStyle={styles.autocompleteScroll}
scrollToInput={ev => scrollToInput(ev)}
handleSelectItem={(item, id) => this.handleSelectItem(item, id)}
onDropdownClose={() => onDropdownClose()}
onDropdownShow={() => onDropdownShow()}
fetchDataUrl={apiUrl}
minimumCharactersCount={2}
highlightText
valueExtractor={item => item.name}
rightContent
rightTextExtractor={item => item.properties}
/>
</View>
{this.renderBarcodeReader()}
</View>
) : (
<View style={{flex:1, justifyContent:'center', alignItems:'center'}}>
<Button
color="#F78400"
title={i18n.t("scan.scan")}
onPress={this._onPress_Scan}>
</Button>
</View>
)}
</View>
);
}
}
export default Tickets;
This gives me (after pressing the button) :
SNACK CODE TEST
I notice You are using a component from Expo called BarCodeScanner
There's a github issue open about the fact that this component is not possible to be styled for full screen: https://github.com/expo/expo/issues/5212
However one user proposes a good solution: replace BarCodeScanner with Camera and use barcodescannersettings
Here's a link for the answer on the gitHub issue: https://github.com/expo/expo/issues/5212#issuecomment-653478266
Your code should look something like:
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
[ ... ] // the rest of your code here
return (
<View
style={{
flex: 1,
...StyleSheet.absoluteFillObject
}}
>
<Camera
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
style={{ flex:1}}
barCodeScannerSettings={{
barCodeTypes: [BarCodeScanner.Constants.BarCodeType.qr],
}}
/>
</View>
);
}

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application

I want to login to my app but when I first login it works correctly but once I logout from my app and again try to login I get the following error 'Can't perform a state update on an unmount component'. Even though second time it also enters in the app but with the error which should be not there. Only one time it works correctly.
/*Component*/
const LoginScreen = props => {
let _isMounted = false;
const [isLoading , setIsLoading] = useState(false);
const [error , setError] = useState();
const [token , setToken] = useState();
const [url , setUrl] = useState({});
const dispatch = useDispatch();
/*Receiving the token*/
useEffect(() => {
let _isMounted = false;
const tokenReceive = () => {
if(Object.entries(url).length !== 0)
{
const getTokenFromUrl = url['url'].split('=')[1].split('&')[0];
if(getTokenFromUrl !== '')
{
setToken(getTokenFromUrl)
}
}
}
tokenReceive();
return(() => {
_isMounted = true
} )
}, [url ])
/*Dispatching after receiving token*/
useEffect(() =>{
_isMounted = true;
const loginHandler = async ()=> {
if(token !== undefined)
{
setError(null)
setIsLoading(true);
try{
await dispatch(authActions.login(token))
// if(_isMounted){
// props.navigation.navigate('afterAuth')
// }
}
catch(err)
{
setError(err.message)
}
setIsLoading(false)
if(_isMounted){
props.navigation.navigate('afterAuth')
}
}
}
loginHandler()
return(() => {
_isMounted = false
} )
} , [token ])
/*If any error occur*/
useEffect(() => {
if (error) {
Alert.alert('An error occured',error,[{text : 'Okay'}]);
}
return(() => {
console.log('Error'),
error
})
} , [error])
/*Event listener when url changes*/
useEffect(() => {
Expo.Linking.addEventListener('url', (url) => {
setUrl(url);
})
return () => {
Expo.Linking.removeEventListener('url' , (url) => {
setUrl(url)
})
};
} , [])
const prefix = Expo.Linking.makeUrl('token');
const _handlePressButtonAsync = async () => {
let result = await WebBrowser.openBrowserAsync(`https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=**********&response_type=id_token&redirect_uri=${prefix}&scope=openid email profile&response_mode=fragment&state=*****&nonce=****`);
};
return(
<ScrollView >
<TouchableWithoutFeedback onPress={() => {Keyboard.dismiss()}} >
<View style={styles.screen}>
<CircleDiv style={styles.userlogoDiv}>
<View style={styles.userLogo}>
<AntDesign name="user" size={RFValue(39)} color='#4D4848'/>
</View>
</CircleDiv>
<BackgroundUpper style={styles.upperDiv}>
<LogoLong style={ {marginTop : RFValue(100)}}/>
</BackgroundUpper>
<BackgroundLower >
<ScrollView style={{ flex : 1 } } decelerationRate='fast' >
<KeyboardAvoidingView behavior='position' keyboardVerticalOffset={Dimensions.get('screen').height / RFValue(10)}>
<View style={styles.loginDiv}>
<View style={styles.headingDiv}>
<Text style={styles.heading}>LOGIN</Text>
</View>
<View style={styles.buttonDiv}>
<TouchableOpacity>
{!isLoading ? <Button
style={styles.button}
title='LOGIN'
color= '#00B49D'
//onPress = {navigate}
onPress={_handlePressButtonAsync}
/> : <ActivityIndicator size="small" color={Colors.GREEN}/>}
</TouchableOpacity>
</View>
<View style={styles.forgetDiv}>
<Text style={styles.forget}>Forget Password</Text>
</View>
</View>
</KeyboardAvoidingView>
</ScrollView>
</BackgroundLower>
</View>
</TouchableWithoutFeedback>
</ScrollView>
)
};
Error - Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, a useEffect cleanup function,

How to get ref in flat list item onpress?

I am trying to capture screen with react-native-view-shot. On press this.refs.viewShot.capture showing undefined.
Here is my code
Flat list code:
<FlatList
ref={(list) => this.myFlatList = list}
data={this.state.newsListArray}
keyExtractor={this._keyExtractor}
renderItem={this.renderRowItem}
/>
render on press link:
<TouchableOpacity onPress={ () => {
Platform.OS === 'ios' ?
this._captureScreenIos('5c63f7307518134a2aa288ce') :
this._captureScreenAndroid('5c63f7307518134a2aa288ce')
}}>
<View style={{flexDirection:'row'}}>
<Icon name="share-alt" size={16} color="#ffb6cf" />
<Text style={{paddingLeft:6,fontSize:12,fontWeight:'500'}}>Share News</Text>
</View>
</TouchableOpacity>
And that's the function:
_captureScreenIos = (refId) => {
console.log("Clicked for IOS");
this.changeLoaderStatus();
var thisFun = this;
var viewShotRef = 'viewShot-5c63f7307518134a2aa288ce';
this.myFlatList.viewShot.capture({width: 2048 / PixelRatio.get(), height: 2048 / PixelRatio.get()}).then(res => {
RNFetchBlob.fs.readFile(res, 'base64').then((base64data) => {
console.log("base64data",base64data)
let base64Image = `data:image/jpeg;base64,${base64data}`;
const shareOptions = {
title: "My Beauty Squad",
//message: "Download my beauty squad with below link."+ "\n" + "https://itunes.apple.com/uk/app/my-beauty-squad/id1454212046?mt=8" ,
url: base64Image,
subject: "Share news feed"
};
Share.open(shareOptions);
thisFun.changeLoaderStatus();
})
}).catch(error => {
console.log(error, 'this is error');
this.changeLoaderStatus();
})
}
Please let me know if anyone having a solution for the same.
**This is my app screen **
It's blur when we have long list items.
Try this:
import { captureRef } from react-native-view-shot
constructor(props) {
super(props);
this.refs = {};
}
renderItem = ({item, index}) => (
<TouchableOpacity
onPress={ () => {
captureRef(this.refs[`${index}`], options).then(.....)
}
>
<View
style={{flexDirection:'row'}}
ref={shot => this.refs[`${index}`] = shot}
>
...........
</View>
</TouchableOpacity>
)
React Native View Shot
I hope it help you.
That is a good amount of code. Try https://reactnativecode.com/take-screenshot-of-app-programmatically/
setting the state and try passing in the object you are referencing.
export default class App extends Component {
constructor(){
super();
this.state={
imageURI : 'https://reactnativecode.com/wp-content/uploads/2018/02/motorcycle.jpg'
}
}
captureScreenFunction=()=>{
captureScreen({
format: "jpg",
quality: 0.8
})
.then(
uri => this.setState({ imageURI : uri }),
error => console.error("Oops, Something Went Wrong", error)
);
}
Here is answer:
constructor(props) {
this.screenshot = {};
}
This is my function:
_captureScreenIos(itemId) {
this.changeLoaderStatus();
var thisFun = this;
var viewShotRef = itemId;
captureRef(this.screenshot[itemId],{format: 'jpg',quality: 0.8}).then(res => {
RNFetchBlob.fs.readFile(res, 'base64').then((base64data) => {
console.log("base64data",base64data)
let base64Image = `data:image/jpeg;base64,${base64data}`;
const shareOptions = {
title: "My Beauty Squad",
//message: "Download my beauty squad with below link."+ "\n" + "https://itunes.apple.com/uk/app/my-beauty-squad/id1454212046?mt=8" ,
url: base64Image,
subject: "Share news feed"
};
Share.open(shareOptions);
thisFun.changeLoaderStatus();
})
}).catch(error => {
console.log(error, 'this is error');
this.changeLoaderStatus();
})
}
This is the view:
<View collapsable={false} ref={(shot) => { this.screenshot[itemId] = shot; }} >
//some content here
<TouchableOpacity onPress={ () => {
Platform.OS === 'ios' ?
this._captureScreenIos(itemData.item._id) :
this._captureScreenAndroid(itemData.item._id)
}}>
<View style={{flexDirection:'row'}}>
<Icon name="share-alt" size={16} color="#ffb6cf" />
<Text style={{paddingLeft:6,fontSize:12,fontWeight:'500'}}>Share News</Text>
</View>
</TouchableOpacity>
</View>