diff --git a/app/containers/Passcode/ButtonNumber.js b/app/containers/Passcode/ButtonNumber.js new file mode 100644 index 000000000..1d72c01dd --- /dev/null +++ b/app/containers/Passcode/ButtonNumber.js @@ -0,0 +1,40 @@ +import React from 'react'; +import { TouchableHighlight, Text } from 'react-native'; + +import styles from './styles'; + +const ButtonNumber = ({ text }) => ( + this.setState({ textButtonSelected: text })} + // onHideUnderlay={() => this.setState({ textButtonSelected: "" })} + // onPress={() => { + // this.onPressButtonNumber(text); + // }} + // accessible + // accessibilityLabel={text} + > + + {text} + + +); + +export default ButtonNumber; diff --git a/app/containers/Passcode/PasscodeDots.js b/app/containers/Passcode/PasscodeDots.js new file mode 100644 index 000000000..11c7bf4f4 --- /dev/null +++ b/app/containers/Passcode/PasscodeDots.js @@ -0,0 +1,62 @@ +import React from 'react'; +import { View } from 'react-native'; +import _ from 'lodash'; + +import styles from './styles'; +import { themes } from '../../constants/colors'; + +const PASSWORD_LENGTH = 6; +const SIZE_EMPTY = 8; +const SIZE_FULL = 12; + +const PasscodeDots = ({ + password, + moveData, + showError, + changeScreen, + attemptFailed, + theme +}) => ( + + {_.range(PASSWORD_LENGTH).map((val) => { + const lengthSup = ((password.length >= val + 1 && !changeScreen) || showError) && !attemptFailed; + const opacity = lengthSup ? 1 : 0.5; + const height = lengthSup ? SIZE_FULL : SIZE_EMPTY; + const width = lengthSup ? SIZE_FULL : SIZE_EMPTY; + let color = ''; + if (showError) { + color = themes[theme].dangerColor; + } else if (lengthSup && password.length > 0) { + color = themes[theme].titleText; + } else { + color = themes[theme].bodyText; + } + const borderRadius = lengthSup + ? SIZE_FULL / 2 + : SIZE_EMPTY / 2; + const marginRight = lengthSup + ? 10 - (SIZE_FULL - SIZE_EMPTY) / 2 + : 10; + const marginLeft = lengthSup + ? 10 - (SIZE_FULL - SIZE_EMPTY) / 2 + : 10; + return ( + + + + ); + })} + +); + +export default PasscodeDots; diff --git a/app/containers/Passcode/Subtitle.js b/app/containers/Passcode/Subtitle.js new file mode 100644 index 000000000..26f6b8053 --- /dev/null +++ b/app/containers/Passcode/Subtitle.js @@ -0,0 +1,23 @@ +import React from 'react'; +import { Text } from 'react-native'; + +import styles from './styles'; +import { themes } from '../../constants/colors'; + +const Subtitle = ({ theme }) => ( + + {/* {attemptFailed || showError + ? this.props.subtitleError + : this.props.subtitle} */} + Subtitle + +); +export default Subtitle; diff --git a/app/containers/Passcode/Title.js b/app/containers/Passcode/Title.js new file mode 100644 index 000000000..4b87579e4 --- /dev/null +++ b/app/containers/Passcode/Title.js @@ -0,0 +1,24 @@ +import React from 'react'; +import { Text } from 'react-native'; + +import styles from './styles'; +import { themes } from '../../constants/colors'; + +const Title = ({ theme }) => ( + + {/* {(attemptFailed && this.props.titleAttemptFailed) || + (showError && this.props.titleConfirmFailed) || + (showError && this.props.titleValidationFailed) || + this.props.sentenceTitle} */} + Title + +); +export default Title; diff --git a/app/containers/Passcode/grid.js b/app/containers/Passcode/grid.js new file mode 100644 index 000000000..5c3bd065d --- /dev/null +++ b/app/containers/Passcode/grid.js @@ -0,0 +1,17 @@ +const grid = { + unit: 16, + headline: 32, + title: 24, + subheader: 18, + body: 14, + caption: 12, + label: 10, + lineHeight: 1.5, + navIcon: 20, + border: 2, + borderRadius: 2, + lowOpacity: 0.4, + mediumOpacity: 0.6, + highOpacity: 0.8 +}; +export default grid; diff --git a/app/containers/Passcode/index.js b/app/containers/Passcode/index.js new file mode 100644 index 000000000..82c3c69df --- /dev/null +++ b/app/containers/Passcode/index.js @@ -0,0 +1,118 @@ +import React from 'react'; +import { View } from 'react-native'; +import { Col, Row, Grid } from 'react-native-easy-grid'; +import _ from 'lodash'; + +import styles from './styles'; +import ButtonNumber from './ButtonNumber'; +import PasscodeDots from './PasscodeDots'; +import Title from './Title'; +import Subtitle from './Subtitle'; + +const Passcode = ({ theme }) => { + return ( + + + + + <Subtitle theme={theme} /> + </View> + <View style={styles.flexCirclePassword}> + <PasscodeDots password='123' theme={theme} /> + </View> + <Grid style={styles.grid}> + <Row + style={[ + styles.row + ]} + > + {_.range(1, 4).map(i => ( + <Col + key={i} + style={[ + styles.colButtonCircle + ]} + > + <ButtonNumber text={i} /> + </Col> + ))} + </Row> + <Row + style={[ + styles.row + ]} + > + {_.range(4, 7).map(i => ( + <Col + key={i} + style={[ + styles.colButtonCircle + ]} + > + <ButtonNumber text={i} /> + </Col> + ))} + </Row> + <Row + style={[ + styles.row + ]} + > + {_.range(7, 10).map(i => ( + <Col + key={i} + style={[ + styles.colButtonCircle + ]} + > + <ButtonNumber text={i} /> + </Col> + ))} + </Row> + <Row + style={[ + styles.row + ]} + > + <Col + style={[ + styles.colButtonCircle + ]} + /> + <Col + style={[ + styles.colButtonCircle + ]} + > + <ButtonNumber text='0' /> + </Col> + <Col + style={[ + styles.colButtonCircle + ]} + > + <ButtonNumber text='X' /> + </Col> + </Row> + </Grid> + </View> + </View> + ); +}; + +export default Passcode; diff --git a/app/containers/Passcode/styles.js b/app/containers/Passcode/styles.js new file mode 100644 index 000000000..03f7b4d61 --- /dev/null +++ b/app/containers/Passcode/styles.js @@ -0,0 +1,95 @@ +import { StyleSheet } from 'react-native'; + +import grid from './grid'; + +export default StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + // width: '100%' + }, + viewTitle: { + flexDirection: 'column', + justifyContent: 'flex-end', + alignItems: 'center', + flex: 2 + }, + row: { + flex: 0, + flexShrink: 1, + alignItems: 'center', + height: grid.unit * 5.5 + }, + rowWithEmpty: { + flexShrink: 0, + justifyContent: 'flex-end' + }, + colButtonCircle: { + flex: 0, + marginLeft: grid.unit / 2, + marginRight: grid.unit / 2, + alignItems: 'center', + width: grid.unit * 4, + height: grid.unit * 4 + }, + colEmpty: { + flex: 0, + marginLeft: grid.unit / 2, + marginRight: grid.unit / 2, + width: grid.unit * 4, + height: grid.unit * 4 + }, + colIcon: { + alignSelf: 'center', + justifyContent: 'center', + alignItems: 'center', + flexDirection: 'column' + }, + text: { + fontSize: grid.unit * 2, + fontWeight: '200' + }, + buttonCircle: { + alignItems: 'center', + justifyContent: 'center', + width: grid.unit * 4, + height: grid.unit * 4, + backgroundColor: 'rgb(242, 245, 251)', + borderRadius: grid.unit * 2 + }, + textTitle: { + fontSize: 20, + fontWeight: '200', + lineHeight: grid.unit * 2.5 + }, + textSubtitle: { + fontSize: grid.unit, + fontWeight: '200', + textAlign: 'center' + }, + flexCirclePassword: { + flex: 2, + justifyContent: 'center', + alignItems: 'center' + }, + topViewCirclePassword: { + flexDirection: 'row', + height: 'auto', + justifyContent: 'center', + alignItems: 'center' + }, + viewCircles: { + justifyContent: 'center', + alignItems: 'center' + }, + textDeleteButton: { + fontWeight: '200', + marginTop: 5 + }, + grid: { + justifyContent: 'flex-start', + width: '100%', + flex: 7 + } +}); diff --git a/app/utils/localAuthentication.js b/app/utils/localAuthentication.js index e621c791d..b9239ef0e 100644 --- a/app/utils/localAuthentication.js +++ b/app/utils/localAuthentication.js @@ -64,18 +64,18 @@ export const localAuthenticate = async(server) => { const isSupported = await LocalAuthentication.supportedAuthenticationTypesAsync(); // if biometry is enabled and enrolled on OS - if (isEnrolled && isSupported) { - // opens biometry prompt - const authResult = await LocalAuthentication.authenticateAsync({ disableDeviceFallback: true }); - if (authResult?.success) { - await resetAttempts(); - await saveLastLocalAuthenticationSession(server, serverRecord); - } else { - await localPasscode(); - } - } else { - await localPasscode(); - } + // if (isEnrolled && isSupported) { + // // opens biometry prompt + // const authResult = await LocalAuthentication.authenticateAsync({ disableDeviceFallback: true }); + // if (authResult?.success) { + // await resetAttempts(); + // await saveLastLocalAuthenticationSession(server, serverRecord); + // } else { + // await localPasscode(); + // } + // } else { + await localPasscode(); + // } } } }; diff --git a/app/views/ScreenLockedView.js b/app/views/ScreenLockedView.js index e10ccb142..b7b13bc7c 100644 --- a/app/views/ScreenLockedView.js +++ b/app/views/ScreenLockedView.js @@ -23,6 +23,7 @@ import { import { resetAttempts } from '../utils/localAuthentication'; import { isTablet } from '../utils/deviceInfo'; import Orientation from 'react-native-orientation-locker'; +import Passcode from '../containers/Passcode'; const MAX_ATTEMPTS = 6; const TIME_TO_LOCK = 30000; @@ -169,7 +170,7 @@ const ScreenLockedView = ({ theme }) => { style={{ margin: 0 }} > <View style={[styles.container, { backgroundColor: themes[theme].auxiliaryBackground }]}> - <PINCode + {/* <PINCode status={PinStatus.enter} passwordLength={PASSCODE_LENGTH} customBackSpaceIcon={() => null} @@ -199,7 +200,8 @@ const ScreenLockedView = ({ theme }) => { timePinLockedAsyncStorageName={LOCKED_OUT_TIMER_KEY} pinAttemptsAsyncStorageName={ATTEMPTS_KEY} lockedPage={<AppLocked />} - /> + /> */} + <Passcode theme={theme} /> </View> </Modal> ); diff --git a/package.json b/package.json index 04f00be36..f434e4638 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "react-native-console-time-polyfill": "^1.2.1", "react-native-device-info": "^2.3.0", "react-native-document-picker": "^3.2.4", + "react-native-easy-grid": "^0.2.2", "react-native-easy-toast": "^1.2.0", "react-native-fast-image": "^7.0.2", "react-native-firebase": "^5.5.5",