2021-09-13 20:41:05 +00:00
|
|
|
import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react';
|
|
|
|
import { Col, Grid, Row } from 'react-native-easy-grid';
|
|
|
|
import range from 'lodash/range';
|
2022-03-23 00:43:59 +00:00
|
|
|
import { View } from 'react-native';
|
2021-09-13 20:41:05 +00:00
|
|
|
import * as Animatable from 'react-native-animatable';
|
|
|
|
import * as Haptics from 'expo-haptics';
|
|
|
|
|
|
|
|
import styles from './styles';
|
|
|
|
import Button from './Button';
|
|
|
|
import Dots from './Dots';
|
|
|
|
import { TYPE } from '../constants';
|
|
|
|
import { themes } from '../../../constants/colors';
|
|
|
|
import { PASSCODE_LENGTH } from '../../../constants/localAuthentication';
|
2022-03-23 00:43:59 +00:00
|
|
|
import { useTheme } from '../../../theme';
|
2021-09-13 20:41:05 +00:00
|
|
|
import LockIcon from './LockIcon';
|
|
|
|
import Title from './Title';
|
|
|
|
import Subtitle from './Subtitle';
|
|
|
|
|
|
|
|
interface IPasscodeBase {
|
|
|
|
type: string;
|
|
|
|
previousPasscode?: string;
|
|
|
|
title: string;
|
|
|
|
subtitle?: string;
|
2021-12-02 13:26:02 +00:00
|
|
|
showBiometry?: boolean;
|
2021-09-13 20:41:05 +00:00
|
|
|
onEndProcess: Function;
|
|
|
|
onError?: Function;
|
|
|
|
onBiometryPress?(): void;
|
|
|
|
}
|
|
|
|
|
2022-03-23 00:43:59 +00:00
|
|
|
export interface IBase {
|
|
|
|
clearPasscode: () => void;
|
|
|
|
wrongPasscode: () => void;
|
|
|
|
animate: (animation: Animatable.Animation, duration?: number) => void;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Base = forwardRef<IBase, IPasscodeBase>(
|
|
|
|
({ type, onEndProcess, previousPasscode, title, subtitle, onError, showBiometry, onBiometryPress }, ref) => {
|
|
|
|
const { theme } = useTheme();
|
|
|
|
|
|
|
|
const rootRef = useRef<Animatable.View & View>(null);
|
|
|
|
const dotsRef = useRef<Animatable.View & View>(null);
|
2021-09-13 20:41:05 +00:00
|
|
|
const [passcode, setPasscode] = useState('');
|
|
|
|
|
|
|
|
const clearPasscode = () => setPasscode('');
|
|
|
|
|
|
|
|
const wrongPasscode = () => {
|
|
|
|
clearPasscode();
|
2022-03-23 00:43:59 +00:00
|
|
|
dotsRef?.current?.shake?.(500);
|
2021-09-13 20:41:05 +00:00
|
|
|
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
|
|
|
|
};
|
|
|
|
|
2022-03-23 00:43:59 +00:00
|
|
|
const animate = (animation: Animatable.Animation, duration = 500) => {
|
|
|
|
rootRef?.current?.[animation]?.(duration);
|
2021-09-13 20:41:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const onPressNumber = (text: string) =>
|
|
|
|
setPasscode(p => {
|
|
|
|
const currentPasscode = p + text;
|
|
|
|
if (currentPasscode?.length === PASSCODE_LENGTH) {
|
|
|
|
switch (type) {
|
|
|
|
case TYPE.CHOOSE:
|
|
|
|
onEndProcess(currentPasscode);
|
|
|
|
break;
|
|
|
|
case TYPE.CONFIRM:
|
|
|
|
if (currentPasscode !== previousPasscode) {
|
|
|
|
onError?.();
|
|
|
|
} else {
|
|
|
|
onEndProcess(currentPasscode);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TYPE.ENTER:
|
|
|
|
onEndProcess(currentPasscode);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return currentPasscode;
|
|
|
|
});
|
|
|
|
|
|
|
|
const onPressDelete = () =>
|
|
|
|
setPasscode(p => {
|
|
|
|
if (p?.length > 0) {
|
|
|
|
const newPasscode = p.slice(0, -1);
|
|
|
|
return newPasscode;
|
|
|
|
}
|
|
|
|
return '';
|
|
|
|
});
|
|
|
|
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
|
|
wrongPasscode,
|
|
|
|
animate,
|
|
|
|
clearPasscode
|
|
|
|
}));
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Animatable.View ref={rootRef} style={styles.container}>
|
|
|
|
<Grid style={[styles.grid, { backgroundColor: themes[theme].passcodeBackground }]}>
|
2022-03-23 00:43:59 +00:00
|
|
|
<LockIcon />
|
|
|
|
<Title text={title} />
|
|
|
|
{subtitle ? <Subtitle text={subtitle} /> : null}
|
2021-09-13 20:41:05 +00:00
|
|
|
<Row style={styles.row}>
|
|
|
|
<Animatable.View ref={dotsRef}>
|
2022-03-23 00:43:59 +00:00
|
|
|
<Dots passcode={passcode} length={PASSCODE_LENGTH} />
|
2021-09-13 20:41:05 +00:00
|
|
|
</Animatable.View>
|
|
|
|
</Row>
|
|
|
|
<Row style={[styles.row, styles.buttonRow]}>
|
2022-03-23 00:43:59 +00:00
|
|
|
{range(1, 4).map(i => (
|
2021-09-13 20:41:05 +00:00
|
|
|
<Col key={i} style={styles.colButton}>
|
2022-03-23 00:43:59 +00:00
|
|
|
<Button text={i.toString()} onPress={onPressNumber} />
|
2021-09-13 20:41:05 +00:00
|
|
|
</Col>
|
|
|
|
))}
|
|
|
|
</Row>
|
|
|
|
<Row style={[styles.row, styles.buttonRow]}>
|
2022-03-23 00:43:59 +00:00
|
|
|
{range(4, 7).map(i => (
|
2021-09-13 20:41:05 +00:00
|
|
|
<Col key={i} style={styles.colButton}>
|
2022-03-23 00:43:59 +00:00
|
|
|
<Button text={i.toString()} onPress={onPressNumber} />
|
2021-09-13 20:41:05 +00:00
|
|
|
</Col>
|
|
|
|
))}
|
|
|
|
</Row>
|
|
|
|
<Row style={[styles.row, styles.buttonRow]}>
|
2022-03-23 00:43:59 +00:00
|
|
|
{range(7, 10).map(i => (
|
2021-09-13 20:41:05 +00:00
|
|
|
<Col key={i} style={styles.colButton}>
|
2022-03-23 00:43:59 +00:00
|
|
|
<Button text={i.toString()} onPress={onPressNumber} />
|
2021-09-13 20:41:05 +00:00
|
|
|
</Col>
|
|
|
|
))}
|
|
|
|
</Row>
|
|
|
|
<Row style={[styles.row, styles.buttonRow]}>
|
|
|
|
{showBiometry ? (
|
|
|
|
<Col style={styles.colButton}>
|
2022-03-23 00:43:59 +00:00
|
|
|
<Button icon='fingerprint' onPress={onBiometryPress} />
|
2021-09-13 20:41:05 +00:00
|
|
|
</Col>
|
|
|
|
) : (
|
|
|
|
<Col style={styles.colButton} />
|
|
|
|
)}
|
|
|
|
<Col style={styles.colButton}>
|
2022-03-23 00:43:59 +00:00
|
|
|
<Button text='0' onPress={onPressNumber} />
|
2021-09-13 20:41:05 +00:00
|
|
|
</Col>
|
|
|
|
<Col style={styles.colButton}>
|
2022-03-23 00:43:59 +00:00
|
|
|
<Button icon='backspace' onPress={onPressDelete} />
|
2021-09-13 20:41:05 +00:00
|
|
|
</Col>
|
|
|
|
</Row>
|
|
|
|
</Grid>
|
|
|
|
</Animatable.View>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
export default Base;
|