Detox - Enter on Numpad - react-native

I wonder how to enter the number using native keyboard and then enter it in just like typeText on a normal string on Detox using "\n"
// await typeText('${screen_id}_screen_question_${question_id}_answer_input_', '\n');
How can I achieve this with number?
Whenever I do the typeText ('n') it will give me GREYKeyboard: No known SHIFT key was found in the hierarchy..
In my assumption, because the numpad key doesn't have Enter key. But still not sure why it look for a Shift key.
Thanks

Use Keyboard module from react-native to hide the keyboard.
It's a similar problem to this one: detox-how-to-test-multiline-textinput
Example:
import {Keyboard} from 'react-native'
import React, { Component } from 'react'
import {
AppRegistry,
StyleSheet,
Alert,
TouchableWithoutFeedback,
TouchableOpacity,
View,
Text,
TextInput
} from 'react-native'
class example extends Component {
constructor(props) {
super(props)
}
render() {
return (
<TouchableWithoutFeedback
onPress={Keyboard.dismiss}
style={styles.container}
>
<View style={styles.form}>
<View style={styles.input}>
<TextInput
testID='input'
style={styles.inputText}
keyboardType="numeric"
/>
</View>
<TouchableOpacity
testID='next'
style={styles.button}
onPress={() => Alert.alert("Button pressed")}
>
<Text>Next</Text>
</TouchableOpacity>
</View>
</TouchableWithoutFeedback>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
form: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
input: {
height: 20,
width: 200,
borderColor: 'gray',
borderWidth: 1
},
inputText: {
flex: 1
},
button: {
margin: 20,
padding: 5,
borderColor: 'gray',
borderWidth: 1
}
})
AppRegistry.registerComponent('example', () => example)
Test:
it('Hide num keyboard', async () => {
const inputElement = element(by.id('input'));
await expect(inputElement).toBeVisible();
await inputElement.typeText('1234567890');
// click somewhere outside the input
await inputElement.tapAtPoint({x: 0, y: -1});
const buttonElement = element(by.id('next'));
await expect(buttonElement).toBeVisible();
await buttonElement.tap();
});
Result:

Related

How can I send different functions from index in order to re use the footer code?

Im new in React, and Im starting with React native.
I'm working in my project, and in order to re-use code, I'm reading about HOC.
My use case is: I have a lot of views with a footer that have some buttons (one or two, it depends. They might have different actions, some of them navigates to another activity, other execute functions or state updates).
Im trying to execute a navigation.navigate from the "main" view, but I got an error: "Cant find variable: navigation".
This is my code:
index.js
import {
Text,
StyleSheet,
View,
TouchableOpacity,
ScrollView
} from 'react-native';
import withFooter from '../../components/withFooter';
const SignUp = ({ navigation }) => {
return (
<View style={styles.container}>
<View style={{ flex: 3 }}>
<Text>Test</Text>
</View>
</View>
)
};
export default withFooter(SignUp, {
buttons: [
{
text: 'Exit',
action: () => console.log('Exit'),
},
{
text: 'Accept',
action: () => navigation.navigate('PersonalDataSignUp'),
}
]
});
withFooter.js
import { Text, View, TouchableOpacity, StyleSheet } from 'react-native';
const withFooter = (WrappedComponent, { buttons }) => {
const WithFooter = props => {
return (
<>
<WrappedComponent {...props} />
<View style={{
flexDirection: 'row',
padding: 20
}}>
{
buttons.map(button => (
<TouchableOpacity style={[styles.button]} onPress={button.action}>
<Text style={{ fontWeight: '900' }}>{button.text}</Text>
</TouchableOpacity>
))
}
</View>
</>
)
};
return WithFooter;
};
const styles = StyleSheet.create({
button: {
flex: 1,
height: 50,
borderRadius: 5,
backgroundColor: '#FCCC00',
justifyContent: 'center',
alignItems: 'center',
borderColor: 'black',
borderWidth: 1
},
})
export default withFooter;
How can I send different functions from index in order to re use the footer code? Is there any other way to do it?. Thanks in advance!

Change component style when state is set to certain value

I have a counter that counts down, when the counter hits zero, I would like a style to change. The counter displays properly but the style never changes. How can I get the style to change when the counter hits a certain value?
Below is the code for a very basic example.
import React, { useState, useEffect } from "react";
import { Text, StyleSheet, SafeAreaView, TouchableOpacity, View } from "react-native";
const ActionScreen = () => {
const [timeLeft, setTimeLeft] = useState(4);
const [opac, setOpac] = useState(0.8);
useEffect(() => {
const interval = setInterval(() => setTimeLeft(timeLeft - 1), 1000);
if (timeLeft > 2) {
setOpac(0.8);
console.log("GT");
} else {
setOpac(0.5);
console.log("LT");
}
console.log("opac: ", opac);
if (timeLeft === 0) {
// clearInterval(interval);
setTimeLeft(4);
// setOpac(0.5);
}
return () => {
clearInterval(interval);
};
}, [timeLeft]);
return (
<SafeAreaView style={styles.container}>
<View style={styles.subActionContainer}>
<TouchableOpacity
style={[
styles.topButtons,
{
opacity: opac,
}
]}
>
<Text
style={styles.buttonText}>
{timeLeft}
</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 25,
backgroundColor: 'black',
},
subActionContainer: {
flexDirection: "row",
alignContent: 'space-between',
},
topButtons: {
flex: 1,
backgroundColor: 'orange',
},
buttonText: {
fontSize: 18,
textAlign: 'center',
padding: 10,
color: 'white',
},
buttonFail: {
borderWidth: 1,
marginHorizontal: 5,
}
});
export default ActionScreen;
I'm fairly new to React-Native but read somewhere that some styles are set when the app loads and thus don't change but I have also implemented a Dark Mode on my app that sets inline styling, which works well. Why isn't the styling above changing?
Thank you.
you can create your timer and create a method isTimeOut and when it is true you can change the background
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import {useTimerCountDown} from './useCountDownTimer'
export default function App() {
const {minutes, seconds, setSeconds} = useTimerCountDown(0, 10);
const isTimeOut = Boolean(minutes === 0 && seconds === 0);
const handleRestartTimer = () => setSeconds(10);
return (
<View style={styles.container}>
<View style={[styles.welcomeContainer,isTimeOut &&
styles.timeOutStyle]}>
<Text>welcome</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: 10,
backgroundColor: '#ecf0f1',
padding: 8,
},
welcomeContainer:{
backgroundColor:'red',
},
timeOutStyle:{
backgroundColor:'blue',
}
});
See the useTimerCountDown hook here in this
working example

In React Native, is there anything similar to the activeOpacity prop in the new Pressable component?

In TouchableOpacity, it is possible to set the value of the activeOpacity prop to dim the button after it was pressed, so the user had feedback that their touch was registered and does not pressing the same button repeatedly.
Is there anything similar in the new Pressable component? Or any way to easily achieve the same effect?
You can try following example to achieve same functionality:
import React, { useState } from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';
const App = () => {
const [timesPressed, setTimesPressed] = useState(0);
let textLog = '';
if (timesPressed > 1) {
textLog = timesPressed + 'x onPress';
} else if (timesPressed > 0) {
textLog = 'onPress';
}
return (
<View style={styles.container}>
<Pressable
onPress={() => {
setTimesPressed((current) => current + 1);
}}
style={({ pressed }) => [
{
backgroundColor: 'gray',
opacity: pressed ? 0.2 : 1
},
styles.wrapperCustom
]}>
{({ pressed }) => (
<Text style={styles.text}>
{pressed ? 'Pressed!' : 'Press Me'}
</Text>
)}
</Pressable>
<View style={styles.logBox}>
<Text testID="pressable_press_console">{textLog}</Text>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
},
text: {
fontSize: 16
},
wrapperCustom: {
borderRadius: 8,
padding: 6
},
logBox: {
padding: 20,
margin: 10,
borderWidth: StyleSheet.hairlineWidth,
borderColor: '#f0f0f0',
backgroundColor: '#f9f9f9'
}
});
export default App;

Why is React Native FlatList not working on Android but it is for Web?

I am using Expo to build a react native app with AWS for the backend.
I am trying to display a list of friends using FlatList and the AWS data. The list works and is visible on my web browser, but for some reason, it is not displaying on my Android phone. What might the issue be?
FriendsList.tsx
import { API, graphqlOperation } from 'aws-amplify';
import * as React from 'react';
import {useEffect, useState} from 'react';
import { FlatList, View, ScrollView, Text, StyleSheet } from 'react-native';
import { listUsers } from '../graphql/queries';
import FriendsListItem from '../components/FriendsListItem';
export default function FriendsList() {
const [ users, setUsers ] = useState([]);
useEffect( () => {
const fetchUsers = async () => {
try {
const usersData = await API.graphql(
graphqlOperation(
listUsers
)
)
setUsers(usersData.data.listUsers.items);
} catch (e) {
}
}
fetchUsers();
},[])
return (
<View style={ styles.container }>
<FlatList
style={{ width: '100%' }}
data={users}
renderItem={({ item }) => <FriendsListItem user={item} />}
keyExtractor={(item) => item.id}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
FriendsListItem.tsx
import * as React from 'react';
import { View, Text, StyleSheet, Image, TouchableWithoutFeedback } from 'react-native';
import { API, graphqlOperation, Auth } from "aws-amplify";
import { User } from './types';
export type FriendsListItemProps = {
user: User;
}
const FriendsListItem = ( props: FriendsListItemProps ) => {
const { user } = props;
return (
<TouchableWithoutFeedback>
<View style={styles.container}>
<View style={styles.lefContainer}>
<Image source={{ uri: user.imageUri }} style={styles.avatar}/>
<View style={styles.midContainer}>
<Text style={styles.username}>{user.name}</Text>
<Text numberOfLines={2} style={styles.status}>{user.email}</Text>
</View>
</View>
</View>
</TouchableWithoutFeedback>
);
}
export default FriendsListItem;
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
width: "100%",
justifyContent: 'space-between',
//height: '100%',
},
lefContainer: {
flexDirection: 'row',
padding: 16,
},
midContainer: {
justifyContent: 'space-around'
},
avatar: {
width: 60,
height: 60,
borderRadius: 50,
marginRight: 15,
},
username: {
fontWeight: 'bold',
fontSize: 16,
},
status: {
fontSize: 16,
color: 'grey',
},
});
Looking at the code example, in your FriendsListItem component, any time you use your "user" prop, you need to change it. For example, change this:
user.imageUri
to this:
user.item.imageUri
What you are passing in is an object (e.g. user), which then contains another object (e.g. item), which finally contains your data (e.g. imageUri).
I figured it out. Turns out I am just an idiot. The expo app on my phone was logged into a different account so that's why it wasn't showing any friends for that user.

How view saved data by AsyncStorage?

I have a code that saves and reads the value of a state through AsyncStorage, however when closing the app or changing the screen the value returns to the original state value, which in my case is zero. How do I change the screen or close the app so the value remains the last changed? What alternative to state variables?
My code is:
import React, { Component } from 'react'
import { Text, View, AsyncStorage, TextInput, StyleSheet, TouchableOpacity } from 'react-native'
export default class App extends Component {
constructor(props){
super(props);
this.state = {
txtInputData: '',
getValue: '',
}
}
saveValue = () => {
if(this.state.txtInputData){
AsyncStorage.setItem('key_default', this.state.txtInputData)
this.setState({txtInputData: ''})
alert('Data salved!')
}else{
alert('Please, fill the data!')
}
}
getValue = () => {
AsyncStorage.getItem('key_default').then(value => this.setState({getValue: value}))
}
render() {
return (
<View style={styles.mainContainer}>
<Text>Using AsyncStorage</Text>
<TextInput
style={styles.textInput}
placeholder = 'type here'
value = {this.state.txtInputData}
onChangeText={data => this.setState({txtInputData: data})}
/>
<TouchableOpacity
onPress={this.saveValue}
style={styles.TouchableOpacity}
>
<Text>Save value</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.getValue}
style={styles.TouchableOpacity}
>
<Text> Read value</Text>
</TouchableOpacity>
<Text>Value read:{this.state.getValue}</Text>
</View>
)
}
}
const styles = StyleSheet.create({
mainContainer: {
flex: 1,
padding: 20,
},
textInput: {
marginTop: 10,
borderWidth: 1,
borderColor: '#fa19',
fontSize: 15
},
TouchableOpacity: {
width: '50%',
marginTop: 10,
borderWidth: 1,
borderColor: '#fa19',
padding: 10,
alignSelf: 'center',
alignItems: 'center'
}
})
Just setStat of txtInputData instead of getValue like this
getValue = () => {
AsyncStorage.getItem('key_default').then(value => this.setState({txtInputData: value}))
}