Chore: Evaluate Passcode - TypeScript (#3931)
* Chore: Migrate containers: Passcode to Typescript * minor tweak * minor tweak
This commit is contained in:
parent
cbe2b23e27
commit
4d3c440892
|
@ -5,16 +5,18 @@ import styles from './styles';
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
import Touch from '../../../utils/touch';
|
import Touch from '../../../utils/touch';
|
||||||
import { CustomIcon } from '../../../lib/Icons';
|
import { CustomIcon } from '../../../lib/Icons';
|
||||||
|
import { useTheme } from '../../../theme';
|
||||||
|
|
||||||
interface IPasscodeButton {
|
interface IPasscodeButton {
|
||||||
text?: string;
|
text?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
theme: string;
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onPress?: Function;
|
onPress?: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Button = React.memo(({ text, disabled, theme, onPress, icon }: IPasscodeButton) => {
|
const Button = React.memo(({ text, disabled, onPress, icon }: IPasscodeButton) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
const press = () => onPress && onPress(text);
|
const press = () => onPress && onPress(text);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -4,47 +4,51 @@ import range from 'lodash/range';
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
|
import { useTheme } from '../../../theme';
|
||||||
|
|
||||||
const SIZE_EMPTY = 12;
|
const SIZE_EMPTY = 12;
|
||||||
const SIZE_FULL = 16;
|
const SIZE_FULL = 16;
|
||||||
|
|
||||||
interface IPasscodeDots {
|
interface IPasscodeDots {
|
||||||
passcode: string;
|
passcode: string;
|
||||||
theme: string;
|
|
||||||
length: number;
|
length: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Dots = React.memo(({ passcode, theme, length }: IPasscodeDots) => (
|
const Dots = React.memo(({ passcode, length }: IPasscodeDots) => {
|
||||||
<View style={styles.dotsContainer}>
|
const { theme } = useTheme();
|
||||||
{range(length).map(val => {
|
|
||||||
const lengthSup = passcode.length >= val + 1;
|
return (
|
||||||
const height = lengthSup ? SIZE_FULL : SIZE_EMPTY;
|
<View style={styles.dotsContainer}>
|
||||||
const width = lengthSup ? SIZE_FULL : SIZE_EMPTY;
|
{range(length).map(val => {
|
||||||
let backgroundColor = '';
|
const lengthSup = passcode.length >= val + 1;
|
||||||
if (lengthSup && passcode.length > 0) {
|
const height = lengthSup ? SIZE_FULL : SIZE_EMPTY;
|
||||||
backgroundColor = themes[theme].passcodeDotFull;
|
const width = lengthSup ? SIZE_FULL : SIZE_EMPTY;
|
||||||
} else {
|
let backgroundColor = '';
|
||||||
backgroundColor = themes[theme].passcodeDotEmpty;
|
if (lengthSup && passcode.length > 0) {
|
||||||
}
|
backgroundColor = themes[theme].passcodeDotFull;
|
||||||
const borderRadius = lengthSup ? SIZE_FULL / 2 : SIZE_EMPTY / 2;
|
} else {
|
||||||
const marginRight = lengthSup ? 10 - (SIZE_FULL - SIZE_EMPTY) / 2 : 10;
|
backgroundColor = themes[theme].passcodeDotEmpty;
|
||||||
const marginLeft = lengthSup ? 10 - (SIZE_FULL - SIZE_EMPTY) / 2 : 10;
|
}
|
||||||
return (
|
const borderRadius = lengthSup ? SIZE_FULL / 2 : SIZE_EMPTY / 2;
|
||||||
<View style={styles.dotsView}>
|
const marginRight = lengthSup ? 10 - (SIZE_FULL - SIZE_EMPTY) / 2 : 10;
|
||||||
<View
|
const marginLeft = lengthSup ? 10 - (SIZE_FULL - SIZE_EMPTY) / 2 : 10;
|
||||||
style={{
|
return (
|
||||||
height,
|
<View style={styles.dotsView}>
|
||||||
width,
|
<View
|
||||||
borderRadius,
|
style={{
|
||||||
backgroundColor,
|
height,
|
||||||
marginRight,
|
width,
|
||||||
marginLeft
|
borderRadius,
|
||||||
}}
|
backgroundColor,
|
||||||
/>
|
marginRight,
|
||||||
</View>
|
marginLeft
|
||||||
);
|
}}
|
||||||
})}
|
/>
|
||||||
</View>
|
</View>
|
||||||
));
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
export default Dots;
|
export default Dots;
|
||||||
|
|
|
@ -5,13 +5,18 @@ import { Row } from 'react-native-easy-grid';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
import { CustomIcon } from '../../../lib/Icons';
|
import { CustomIcon } from '../../../lib/Icons';
|
||||||
|
import { useTheme } from '../../../theme';
|
||||||
|
|
||||||
const LockIcon = React.memo(({ theme }: { theme: string }) => (
|
const LockIcon = React.memo(() => {
|
||||||
<Row style={styles.row}>
|
const { theme } = useTheme();
|
||||||
<View style={styles.iconView}>
|
|
||||||
<CustomIcon name='auth' size={40} color={themes[theme].passcodeLockIcon} />
|
return (
|
||||||
</View>
|
<Row style={styles.row}>
|
||||||
</Row>
|
<View style={styles.iconView}>
|
||||||
));
|
<CustomIcon name='auth' size={40} color={themes[theme].passcodeLockIcon} />
|
||||||
|
</View>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
export default LockIcon;
|
export default LockIcon;
|
||||||
|
|
|
@ -6,36 +6,35 @@ import { resetAttempts } from '../../../utils/localAuthentication';
|
||||||
import { TYPE } from '../constants';
|
import { TYPE } from '../constants';
|
||||||
import { getDiff, getLockedUntil } from '../utils';
|
import { getDiff, getLockedUntil } from '../utils';
|
||||||
import I18n from '../../../i18n';
|
import I18n from '../../../i18n';
|
||||||
|
import { useTheme } from '../../../theme';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import Title from './Title';
|
import Title from './Title';
|
||||||
import Subtitle from './Subtitle';
|
import Subtitle from './Subtitle';
|
||||||
import LockIcon from './LockIcon';
|
import LockIcon from './LockIcon';
|
||||||
|
|
||||||
interface IPasscodeTimer {
|
interface IPasscodeTimer {
|
||||||
time: string;
|
time: Date | null;
|
||||||
theme: string;
|
|
||||||
setStatus: Function;
|
setStatus: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPasscodeLocked {
|
interface IPasscodeLocked {
|
||||||
theme: string;
|
|
||||||
setStatus: Function;
|
setStatus: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Timer = React.memo(({ time, theme, setStatus }: IPasscodeTimer) => {
|
const Timer = React.memo(({ time, setStatus }: IPasscodeTimer) => {
|
||||||
const calcTimeLeft = () => {
|
const calcTimeLeft = () => {
|
||||||
const diff = getDiff(time);
|
const diff = getDiff(time || 0);
|
||||||
if (diff > 0) {
|
if (diff > 0) {
|
||||||
return Math.floor((diff / 1000) % 60);
|
return Math.floor((diff / 1000) % 60);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const [timeLeft, setTimeLeft] = useState<any>(calcTimeLeft());
|
const [timeLeft, setTimeLeft] = useState(calcTimeLeft());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setTimeLeft(calcTimeLeft());
|
setTimeLeft(calcTimeLeft());
|
||||||
if (timeLeft <= 1) {
|
if (timeLeft && timeLeft <= 1) {
|
||||||
resetAttempts();
|
resetAttempts();
|
||||||
setStatus(TYPE.ENTER);
|
setStatus(TYPE.ENTER);
|
||||||
}
|
}
|
||||||
|
@ -46,11 +45,12 @@ const Timer = React.memo(({ time, theme, setStatus }: IPasscodeTimer) => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Subtitle text={I18n.t('Passcode_app_locked_subtitle', { timeLeft })} theme={theme} />;
|
return <Subtitle text={I18n.t('Passcode_app_locked_subtitle', { timeLeft })} />;
|
||||||
});
|
});
|
||||||
|
|
||||||
const Locked = React.memo(({ theme, setStatus }: IPasscodeLocked) => {
|
const Locked = React.memo(({ setStatus }: IPasscodeLocked) => {
|
||||||
const [lockedUntil, setLockedUntil] = useState<any>(null);
|
const [lockedUntil, setLockedUntil] = useState<Date | null>(null);
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
const readItemFromStorage = async () => {
|
const readItemFromStorage = async () => {
|
||||||
const l = await getLockedUntil();
|
const l = await getLockedUntil();
|
||||||
|
@ -63,9 +63,9 @@ const Locked = React.memo(({ theme, setStatus }: IPasscodeLocked) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid style={[styles.grid, { backgroundColor: themes[theme].passcodeBackground }]}>
|
<Grid style={[styles.grid, { backgroundColor: themes[theme].passcodeBackground }]}>
|
||||||
<LockIcon theme={theme} />
|
<LockIcon />
|
||||||
<Title text={I18n.t('Passcode_app_locked_title')} theme={theme} />
|
<Title text={I18n.t('Passcode_app_locked_title')} />
|
||||||
<Timer theme={theme} time={lockedUntil} setStatus={setStatus} />
|
<Timer time={lockedUntil} setStatus={setStatus} />
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,18 +4,22 @@ import { Row } from 'react-native-easy-grid';
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
|
import { useTheme } from '../../../theme';
|
||||||
|
|
||||||
interface IPasscodeSubtitle {
|
interface IPasscodeSubtitle {
|
||||||
text: string;
|
text: string;
|
||||||
theme: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Subtitle = React.memo(({ text, theme }: IPasscodeSubtitle) => (
|
const Subtitle = React.memo(({ text }: IPasscodeSubtitle) => {
|
||||||
<Row style={styles.row}>
|
const { theme } = useTheme();
|
||||||
<View style={styles.subtitleView}>
|
|
||||||
<Text style={[styles.textSubtitle, { color: themes[theme].passcodeSecondary }]}>{text}</Text>
|
return (
|
||||||
</View>
|
<Row style={styles.row}>
|
||||||
</Row>
|
<View style={styles.subtitleView}>
|
||||||
));
|
<Text style={[styles.textSubtitle, { color: themes[theme].passcodeSecondary }]}>{text}</Text>
|
||||||
|
</View>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
export default Subtitle;
|
export default Subtitle;
|
||||||
|
|
|
@ -4,18 +4,22 @@ import { Row } from 'react-native-easy-grid';
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
|
import { useTheme } from '../../../theme';
|
||||||
|
|
||||||
interface IPasscodeTitle {
|
interface IPasscodeTitle {
|
||||||
text: string;
|
text: string;
|
||||||
theme: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Title = React.memo(({ text, theme }: IPasscodeTitle) => (
|
const Title = React.memo(({ text }: IPasscodeTitle) => {
|
||||||
<Row style={styles.row}>
|
const { theme } = useTheme();
|
||||||
<View style={styles.titleView}>
|
|
||||||
<Text style={[styles.textTitle, { color: themes[theme].passcodePrimary }]}>{text}</Text>
|
return (
|
||||||
</View>
|
<Row style={styles.row}>
|
||||||
</Row>
|
<View style={styles.titleView}>
|
||||||
));
|
<Text style={[styles.textTitle, { color: themes[theme].passcodePrimary }]}>{text}</Text>
|
||||||
|
</View>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
export default Title;
|
export default Title;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react';
|
import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react';
|
||||||
import { Col, Grid, Row } from 'react-native-easy-grid';
|
import { Col, Grid, Row } from 'react-native-easy-grid';
|
||||||
import range from 'lodash/range';
|
import range from 'lodash/range';
|
||||||
|
import { View } from 'react-native';
|
||||||
import * as Animatable from 'react-native-animatable';
|
import * as Animatable from 'react-native-animatable';
|
||||||
import * as Haptics from 'expo-haptics';
|
import * as Haptics from 'expo-haptics';
|
||||||
|
|
||||||
|
@ -10,12 +11,12 @@ import Dots from './Dots';
|
||||||
import { TYPE } from '../constants';
|
import { TYPE } from '../constants';
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
import { PASSCODE_LENGTH } from '../../../constants/localAuthentication';
|
import { PASSCODE_LENGTH } from '../../../constants/localAuthentication';
|
||||||
|
import { useTheme } from '../../../theme';
|
||||||
import LockIcon from './LockIcon';
|
import LockIcon from './LockIcon';
|
||||||
import Title from './Title';
|
import Title from './Title';
|
||||||
import Subtitle from './Subtitle';
|
import Subtitle from './Subtitle';
|
||||||
|
|
||||||
interface IPasscodeBase {
|
interface IPasscodeBase {
|
||||||
theme: string;
|
|
||||||
type: string;
|
type: string;
|
||||||
previousPasscode?: string;
|
previousPasscode?: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -26,25 +27,30 @@ interface IPasscodeBase {
|
||||||
onBiometryPress?(): void;
|
onBiometryPress?(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Base = forwardRef(
|
export interface IBase {
|
||||||
(
|
clearPasscode: () => void;
|
||||||
{ theme, type, onEndProcess, previousPasscode, title, subtitle, onError, showBiometry, onBiometryPress }: IPasscodeBase,
|
wrongPasscode: () => void;
|
||||||
ref
|
animate: (animation: Animatable.Animation, duration?: number) => void;
|
||||||
) => {
|
}
|
||||||
const rootRef = useRef<any>();
|
|
||||||
const dotsRef = useRef<any>();
|
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);
|
||||||
const [passcode, setPasscode] = useState('');
|
const [passcode, setPasscode] = useState('');
|
||||||
|
|
||||||
const clearPasscode = () => setPasscode('');
|
const clearPasscode = () => setPasscode('');
|
||||||
|
|
||||||
const wrongPasscode = () => {
|
const wrongPasscode = () => {
|
||||||
clearPasscode();
|
clearPasscode();
|
||||||
dotsRef?.current?.shake(500);
|
dotsRef?.current?.shake?.(500);
|
||||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
|
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
|
||||||
};
|
};
|
||||||
|
|
||||||
const animate = (animation: string, duration = 500) => {
|
const animate = (animation: Animatable.Animation, duration = 500) => {
|
||||||
rootRef?.current?.[animation](duration);
|
rootRef?.current?.[animation]?.(duration);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPressNumber = (text: string) =>
|
const onPressNumber = (text: string) =>
|
||||||
|
@ -90,48 +96,48 @@ const Base = forwardRef(
|
||||||
return (
|
return (
|
||||||
<Animatable.View ref={rootRef} style={styles.container}>
|
<Animatable.View ref={rootRef} style={styles.container}>
|
||||||
<Grid style={[styles.grid, { backgroundColor: themes[theme].passcodeBackground }]}>
|
<Grid style={[styles.grid, { backgroundColor: themes[theme].passcodeBackground }]}>
|
||||||
<LockIcon theme={theme} />
|
<LockIcon />
|
||||||
<Title text={title} theme={theme} />
|
<Title text={title} />
|
||||||
<Subtitle text={subtitle!} theme={theme} />
|
{subtitle ? <Subtitle text={subtitle} /> : null}
|
||||||
<Row style={styles.row}>
|
<Row style={styles.row}>
|
||||||
<Animatable.View ref={dotsRef}>
|
<Animatable.View ref={dotsRef}>
|
||||||
<Dots passcode={passcode} theme={theme} length={PASSCODE_LENGTH} />
|
<Dots passcode={passcode} length={PASSCODE_LENGTH} />
|
||||||
</Animatable.View>
|
</Animatable.View>
|
||||||
</Row>
|
</Row>
|
||||||
<Row style={[styles.row, styles.buttonRow]}>
|
<Row style={[styles.row, styles.buttonRow]}>
|
||||||
{range(1, 4).map((i: any) => (
|
{range(1, 4).map(i => (
|
||||||
<Col key={i} style={styles.colButton}>
|
<Col key={i} style={styles.colButton}>
|
||||||
<Button text={i} theme={theme} onPress={onPressNumber} />
|
<Button text={i.toString()} onPress={onPressNumber} />
|
||||||
</Col>
|
</Col>
|
||||||
))}
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
<Row style={[styles.row, styles.buttonRow]}>
|
<Row style={[styles.row, styles.buttonRow]}>
|
||||||
{range(4, 7).map((i: any) => (
|
{range(4, 7).map(i => (
|
||||||
<Col key={i} style={styles.colButton}>
|
<Col key={i} style={styles.colButton}>
|
||||||
<Button text={i} theme={theme} onPress={onPressNumber} />
|
<Button text={i.toString()} onPress={onPressNumber} />
|
||||||
</Col>
|
</Col>
|
||||||
))}
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
<Row style={[styles.row, styles.buttonRow]}>
|
<Row style={[styles.row, styles.buttonRow]}>
|
||||||
{range(7, 10).map((i: any) => (
|
{range(7, 10).map(i => (
|
||||||
<Col key={i} style={styles.colButton}>
|
<Col key={i} style={styles.colButton}>
|
||||||
<Button text={i} theme={theme} onPress={onPressNumber} />
|
<Button text={i.toString()} onPress={onPressNumber} />
|
||||||
</Col>
|
</Col>
|
||||||
))}
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
<Row style={[styles.row, styles.buttonRow]}>
|
<Row style={[styles.row, styles.buttonRow]}>
|
||||||
{showBiometry ? (
|
{showBiometry ? (
|
||||||
<Col style={styles.colButton}>
|
<Col style={styles.colButton}>
|
||||||
<Button icon='fingerprint' theme={theme} onPress={onBiometryPress} />
|
<Button icon='fingerprint' onPress={onBiometryPress} />
|
||||||
</Col>
|
</Col>
|
||||||
) : (
|
) : (
|
||||||
<Col style={styles.colButton} />
|
<Col style={styles.colButton} />
|
||||||
)}
|
)}
|
||||||
<Col style={styles.colButton}>
|
<Col style={styles.colButton}>
|
||||||
<Button text='0' theme={theme} onPress={onPressNumber} />
|
<Button text='0' onPress={onPressNumber} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col style={styles.colButton}>
|
<Col style={styles.colButton}>
|
||||||
<Button icon='backspace' theme={theme} onPress={onPressDelete} />
|
<Button icon='backspace' onPress={onPressDelete} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -2,24 +2,23 @@ import React, { useRef, useState } from 'react';
|
||||||
import * as Haptics from 'expo-haptics';
|
import * as Haptics from 'expo-haptics';
|
||||||
import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
|
import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
|
||||||
|
|
||||||
import Base from './Base';
|
import Base, { IBase } from './Base';
|
||||||
import { TYPE } from './constants';
|
import { TYPE } from './constants';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
|
|
||||||
interface IPasscodeChoose {
|
interface IPasscodeChoose {
|
||||||
theme: string;
|
|
||||||
force?: boolean;
|
force?: boolean;
|
||||||
finishProcess: Function;
|
finishProcess: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PasscodeChoose = ({ theme, finishProcess, force = false }: IPasscodeChoose) => {
|
const PasscodeChoose = ({ finishProcess, force = false }: IPasscodeChoose) => {
|
||||||
const chooseRef = useRef<any>(null);
|
const chooseRef = useRef<IBase>(null);
|
||||||
const confirmRef = useRef<any>(null);
|
const confirmRef = useRef<IBase>(null);
|
||||||
const [subtitle, setSubtitle] = useState(null);
|
const [subtitle, setSubtitle] = useState(null);
|
||||||
const [status, setStatus] = useState(TYPE.CHOOSE);
|
const [status, setStatus] = useState(TYPE.CHOOSE);
|
||||||
const [previousPasscode, setPreviouPasscode] = useState<any>(null);
|
const [previousPasscode, setPreviouPasscode] = useState('');
|
||||||
|
|
||||||
const firstStep = (p: any) => {
|
const firstStep = (p: string) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setStatus(TYPE.CONFIRM);
|
setStatus(TYPE.CONFIRM);
|
||||||
setPreviouPasscode(p);
|
setPreviouPasscode(p);
|
||||||
|
@ -43,7 +42,6 @@ const PasscodeChoose = ({ theme, finishProcess, force = false }: IPasscodeChoose
|
||||||
return (
|
return (
|
||||||
<Base
|
<Base
|
||||||
ref={confirmRef}
|
ref={confirmRef}
|
||||||
theme={theme}
|
|
||||||
type={TYPE.CONFIRM}
|
type={TYPE.CONFIRM}
|
||||||
onEndProcess={changePasscode}
|
onEndProcess={changePasscode}
|
||||||
previousPasscode={previousPasscode}
|
previousPasscode={previousPasscode}
|
||||||
|
@ -56,7 +54,6 @@ const PasscodeChoose = ({ theme, finishProcess, force = false }: IPasscodeChoose
|
||||||
return (
|
return (
|
||||||
<Base
|
<Base
|
||||||
ref={chooseRef}
|
ref={chooseRef}
|
||||||
theme={theme}
|
|
||||||
type={TYPE.CHOOSE}
|
type={TYPE.CHOOSE}
|
||||||
onEndProcess={firstStep}
|
onEndProcess={firstStep}
|
||||||
title={I18n.t('Passcode_choose_title')}
|
title={I18n.t('Passcode_choose_title')}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
|
||||||
import * as Haptics from 'expo-haptics';
|
import * as Haptics from 'expo-haptics';
|
||||||
import { sha256 } from 'js-sha256';
|
import { sha256 } from 'js-sha256';
|
||||||
|
|
||||||
import Base from './Base';
|
import Base, { IBase } from './Base';
|
||||||
import Locked from './Base/Locked';
|
import Locked from './Base/Locked';
|
||||||
import { TYPE } from './constants';
|
import { TYPE } from './constants';
|
||||||
import { ATTEMPTS_KEY, LOCKED_OUT_TIMER_KEY, MAX_ATTEMPTS, PASSCODE_KEY } from '../../constants/localAuthentication';
|
import { ATTEMPTS_KEY, LOCKED_OUT_TIMER_KEY, MAX_ATTEMPTS, PASSCODE_KEY } from '../../constants/localAuthentication';
|
||||||
|
@ -14,18 +14,17 @@ import { useUserPreferences } from '../../lib/userPreferences';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
|
|
||||||
interface IPasscodePasscodeEnter {
|
interface IPasscodePasscodeEnter {
|
||||||
theme: string;
|
|
||||||
hasBiometry: boolean;
|
hasBiometry: boolean;
|
||||||
finishProcess: Function;
|
finishProcess: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PasscodeEnter = ({ theme, hasBiometry, finishProcess }: IPasscodePasscodeEnter) => {
|
const PasscodeEnter = ({ hasBiometry, finishProcess }: IPasscodePasscodeEnter) => {
|
||||||
const ref = useRef(null);
|
const ref = useRef<IBase>(null);
|
||||||
let attempts: any = 0;
|
let attempts = 0;
|
||||||
let lockedUntil: any = false;
|
let lockedUntil: any = false;
|
||||||
const [passcode] = useUserPreferences(PASSCODE_KEY);
|
const [passcode] = useUserPreferences(PASSCODE_KEY);
|
||||||
const [status, setStatus] = useState(null);
|
const [status, setStatus] = useState<TYPE | null>(null);
|
||||||
const { getItem: getAttempts, setItem: setAttempts } = useAsyncStorage(ATTEMPTS_KEY);
|
const { setItem: setAttempts } = useAsyncStorage(ATTEMPTS_KEY);
|
||||||
const { setItem: setLockedUntil } = useAsyncStorage(LOCKED_OUT_TIMER_KEY);
|
const { setItem: setLockedUntil } = useAsyncStorage(LOCKED_OUT_TIMER_KEY);
|
||||||
|
|
||||||
const biometry = async () => {
|
const biometry = async () => {
|
||||||
|
@ -45,7 +44,6 @@ const PasscodeEnter = ({ theme, hasBiometry, finishProcess }: IPasscodePasscodeE
|
||||||
await resetAttempts();
|
await resetAttempts();
|
||||||
setStatus(TYPE.ENTER);
|
setStatus(TYPE.ENTER);
|
||||||
} else {
|
} else {
|
||||||
attempts = await getAttempts();
|
|
||||||
setStatus(TYPE.LOCKED);
|
setStatus(TYPE.LOCKED);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -58,7 +56,7 @@ const PasscodeEnter = ({ theme, hasBiometry, finishProcess }: IPasscodePasscodeE
|
||||||
readStorage();
|
readStorage();
|
||||||
}, [status]);
|
}, [status]);
|
||||||
|
|
||||||
const onEndProcess = (p: any) => {
|
const onEndProcess = (p: string) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (sha256(p) === passcode) {
|
if (sha256(p) === passcode) {
|
||||||
finishProcess();
|
finishProcess();
|
||||||
|
@ -69,8 +67,7 @@ const PasscodeEnter = ({ theme, hasBiometry, finishProcess }: IPasscodePasscodeE
|
||||||
setLockedUntil(new Date().toISOString());
|
setLockedUntil(new Date().toISOString());
|
||||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
|
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
ref?.current?.wrongPasscode();
|
||||||
ref.current.wrongPasscode();
|
|
||||||
setAttempts(attempts?.toString());
|
setAttempts(attempts?.toString());
|
||||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
|
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
|
||||||
}
|
}
|
||||||
|
@ -79,13 +76,12 @@ const PasscodeEnter = ({ theme, hasBiometry, finishProcess }: IPasscodePasscodeE
|
||||||
};
|
};
|
||||||
|
|
||||||
if (status === TYPE.LOCKED) {
|
if (status === TYPE.LOCKED) {
|
||||||
return <Locked theme={theme} setStatus={setStatus} />;
|
return <Locked setStatus={setStatus} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Base
|
<Base
|
||||||
ref={ref}
|
ref={ref}
|
||||||
theme={theme}
|
|
||||||
type={TYPE.ENTER}
|
type={TYPE.ENTER}
|
||||||
title={I18n.t('Passcode_enter_title')}
|
title={I18n.t('Passcode_enter_title')}
|
||||||
showBiometry={hasBiometry}
|
showBiometry={hasBiometry}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export const TYPE: any = {
|
export enum TYPE {
|
||||||
CHOOSE: 'choose',
|
CHOOSE = 'choose',
|
||||||
CONFIRM: 'confirm',
|
CONFIRM = 'confirm',
|
||||||
ENTER: 'enter',
|
ENTER = 'enter',
|
||||||
LOCKED: 'locked'
|
LOCKED = 'locked'
|
||||||
};
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ import moment from 'moment';
|
||||||
import { LOCKED_OUT_TIMER_KEY, TIME_TO_LOCK } from '../../constants/localAuthentication';
|
import { LOCKED_OUT_TIMER_KEY, TIME_TO_LOCK } from '../../constants/localAuthentication';
|
||||||
|
|
||||||
export const getLockedUntil = async () => {
|
export const getLockedUntil = async () => {
|
||||||
const t: any = await AsyncStorage.getItem(LOCKED_OUT_TIMER_KEY);
|
const t = await AsyncStorage.getItem(LOCKED_OUT_TIMER_KEY);
|
||||||
if (t) {
|
if (t) {
|
||||||
return moment(t).add(TIME_TO_LOCK);
|
return moment(t).add(TIME_TO_LOCK).toDate();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
// @ts-ignore
|
|
||||||
export const getDiff = t => new Date(t) - new Date();
|
export const getDiff = (t: string | number | Date) => new Date(t).getTime() - new Date().getTime();
|
||||||
|
|
|
@ -80,7 +80,7 @@ const ChangePasscodeView = React.memo(() => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal useNativeDriver isVisible={visible} hideModalContentWhileAnimating style={styles.modal}>
|
<Modal useNativeDriver isVisible={visible} hideModalContentWhileAnimating style={styles.modal}>
|
||||||
<PasscodeChoose theme={theme} finishProcess={onSubmit} force={data?.force} />
|
<PasscodeChoose finishProcess={onSubmit} force={data?.force} />
|
||||||
{!data?.force ? (
|
{!data?.force ? (
|
||||||
<Touchable onPress={onCancel} style={styles.close}>
|
<Touchable onPress={onCancel} style={styles.close}>
|
||||||
<CustomIcon name='close' color={themes[theme].passcodePrimary} size={30} />
|
<CustomIcon name='close' color={themes[theme].passcodePrimary} size={30} />
|
||||||
|
|
|
@ -4,7 +4,6 @@ import useDeepCompareEffect from 'use-deep-compare-effect';
|
||||||
import isEmpty from 'lodash/isEmpty';
|
import isEmpty from 'lodash/isEmpty';
|
||||||
import Orientation from 'react-native-orientation-locker';
|
import Orientation from 'react-native-orientation-locker';
|
||||||
|
|
||||||
import { useTheme } from '../theme';
|
|
||||||
import EventEmitter from '../utils/events';
|
import EventEmitter from '../utils/events';
|
||||||
import { LOCAL_AUTHENTICATE_EMITTER } from '../constants/localAuthentication';
|
import { LOCAL_AUTHENTICATE_EMITTER } from '../constants/localAuthentication';
|
||||||
import { isTablet } from '../utils/deviceInfo';
|
import { isTablet } from '../utils/deviceInfo';
|
||||||
|
@ -19,8 +18,6 @@ const ScreenLockedView = (): JSX.Element => {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [data, setData] = useState<IData>({});
|
const [data, setData] = useState<IData>({});
|
||||||
|
|
||||||
const { theme } = useTheme();
|
|
||||||
|
|
||||||
useDeepCompareEffect(() => {
|
useDeepCompareEffect(() => {
|
||||||
if (!isEmpty(data)) {
|
if (!isEmpty(data)) {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
|
@ -62,7 +59,7 @@ const ScreenLockedView = (): JSX.Element => {
|
||||||
style={{ margin: 0 }}
|
style={{ margin: 0 }}
|
||||||
animationIn='fadeIn'
|
animationIn='fadeIn'
|
||||||
animationOut='fadeOut'>
|
animationOut='fadeOut'>
|
||||||
<PasscodeEnter theme={theme} hasBiometry={!!data?.hasBiometry} finishProcess={onSubmit} />
|
<PasscodeEnter hasBiometry={!!data?.hasBiometry} finishProcess={onSubmit} />
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue