Skip to content
This repository has been archived by the owner on Jun 15, 2022. It is now read-only.

Commit

Permalink
feature: preserve keyboard type in authentication screen
Browse files Browse the repository at this point in the history
  • Loading branch information
radko93 committed Jul 31, 2020
1 parent 5b2a622 commit ee94632
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 17 deletions.
24 changes: 24 additions & 0 deletions src/lib/ApplicationState.ts
Expand Up @@ -62,6 +62,15 @@ export enum UnlockTiming {
OnQuit = 'on-quit',
}

export enum PasscodeKeyboardType {
Default = 'default',
Numeric = 'numeric',
}

export enum MobileStorageKey {
PasscodeKeyboardTypeKey = 'passcodeKeyboardType',
}

type EventObserverCallback = (
event: AppStateEventType,
data?: TabletModeChangeData
Expand Down Expand Up @@ -574,6 +583,21 @@ export class ApplicationState extends ApplicationService {
this.setScreenshotPrivacy();
}

public async getPasscodeKeyboardType(): Promise<PasscodeKeyboardType> {
return this.application.getValue(
MobileStorageKey.PasscodeKeyboardTypeKey,
StorageValueModes.Nonwrapped
);
}

public async setPasscodeKeyboardType(type: PasscodeKeyboardType) {
await this.application.setValue(
MobileStorageKey.PasscodeKeyboardTypeKey,
type,
StorageValueModes.Nonwrapped
);
}

public onDrawerOpen() {
this.notifyEventObservers(AppStateEventType.DrawerOpen);
}
Expand Down
35 changes: 31 additions & 4 deletions src/screens/Authenticate/Authenticate.tsx
Expand Up @@ -2,7 +2,7 @@ import { ButtonCell } from '@Components/ButtonCell';
import { SectionedAccessoryTableCell } from '@Components/SectionedAccessoryTableCell';
import { SectionedTableCell } from '@Components/SectionedTableCell';
import { SectionHeader } from '@Components/SectionHeader';
import { AppStateType } from '@Lib/ApplicationState';
import { AppStateType, PasscodeKeyboardType } from '@Lib/ApplicationState';
import { MobileDeviceInterface } from '@Lib/interface';
import { useFocusEffect } from '@react-navigation/native';
import { ModalStackNavigationProp } from '@Root/App';
Expand Down Expand Up @@ -54,6 +54,9 @@ export const Authenticate = ({
const [supportsBiometrics, setSupportsBiometrics] = useState<
boolean | undefined
>(undefined);
const [keyboardType, setKeyboardType] = useState<
PasscodeKeyboardType | undefined
>(undefined);
const [{ challengeValues, challengeValueStates }, dispatch] = useReducer(
authenticationReducer,
{
Expand Down Expand Up @@ -120,6 +123,11 @@ export const Authenticate = ({
[application]
);

const checkPasscodeKeyboardType = useCallback(
async () => application?.getAppState().getPasscodeKeyboardType(),
[application]
);

const authenticateBiometrics = useCallback(
async (challengeValue: ChallengeValue) => {
let hasBiometrics = supportsBiometrics;
Expand Down Expand Up @@ -307,6 +315,9 @@ export const Authenticate = ({
if (state === AppStateType.ResumingFromBackground) {
beginAuthenticatingForNextChallengeReason();
}
if (state === AppStateType.EnteringBackground) {
FingerprintScanner.release();
}
});

return removeAppStateSubscriber;
Expand Down Expand Up @@ -334,10 +345,17 @@ export const Authenticate = ({
}
};
setBiometricsAsync();
const setInitialKeyboardType = async () => {
const initialKeyboardType = await checkPasscodeKeyboardType();
if (mounted) {
setKeyboardType(initialKeyboardType);
}
};
setInitialKeyboardType();
return () => {
mounted = false;
};
}, [checkForBiometrics]);
}, [checkForBiometrics, checkPasscodeKeyboardType]);

useEffect(() => {
beginAuthenticatingForNextChallengeReason();
Expand Down Expand Up @@ -395,6 +413,14 @@ export const Authenticate = ({
validateChallengeValue(challengeValue);
};

const switchKeyboard = () => {
if (keyboardType === PasscodeKeyboardType.Default) {
setKeyboardType(PasscodeKeyboardType.Numeric);
} else if (keyboardType === PasscodeKeyboardType.Numeric) {
setKeyboardType(PasscodeKeyboardType.Default);
}
};

const renderAuthenticationSource = (
challengeValue: ChallengeValue,
index: number
Expand All @@ -420,7 +446,7 @@ export const Authenticate = ({
? 'Change Keyboard'
: undefined
}
buttonAction={() => {}} // TODO: change keyboard
buttonAction={switchKeyboard}
buttonStyles={
challengeValue.type === ChallengeType.LocalPasscode
? {
Expand All @@ -434,6 +460,7 @@ export const Authenticate = ({
<SectionContainer last={last}>
<SectionedTableCell textInputCell={true} first={true}>
<Input
key={Platform.OS === 'android' ? keyboardType : undefined}
ref={
challengeValue.type === ChallengeType.LocalPasscode
? localPasscodeRef
Expand All @@ -452,7 +479,7 @@ export const Authenticate = ({
autoFocus={false}
autoCapitalize={'none'}
secureTextEntry={true}
// keyboardType={inputSource.keyboardType || 'default'}
keyboardType={keyboardType}
keyboardAppearance={styleKit?.keyboardColorForActiveTheme()}
underlineColorAndroid={'transparent'}
onSubmitEditing={() => {
Expand Down
31 changes: 18 additions & 13 deletions src/screens/InputModal/PasscodeInputModal.tsx
Expand Up @@ -5,13 +5,13 @@ import {
} from '@Components/SectionedOptionsTableCell';
import { SectionedTableCell } from '@Components/SectionedTableCell';
import { TableSection } from '@Components/TableSection';
import { UnlockTiming } from '@Lib/ApplicationState';
import { PasscodeKeyboardType, UnlockTiming } from '@Lib/ApplicationState';
import { ModalStackNavigationProp } from '@Root/App';
import { ApplicationContext } from '@Root/ApplicationContext';
import { SCREEN_INPUT_MODAL_PASSCODE } from '@Screens/screens';
import { StyleKitContext } from '@Style/StyleKit';
import React, { useContext, useMemo, useRef, useState } from 'react';
import { Keyboard, KeyboardType, Platform, TextInput } from 'react-native';
import { KeyboardType, Platform, TextInput } from 'react-native';
import { Container, Input } from './InputModal.styled';

type Props = ModalStackNavigationProp<typeof SCREEN_INPUT_MODAL_PASSCODE>;
Expand Down Expand Up @@ -63,12 +63,12 @@ export const PasscodeInputModal = (props: Props) => {
() => [
{
title: 'General',
key: 'default',
key: 'default' as PasscodeKeyboardType,
selected: keyboardType === 'default',
},
{
title: 'Numeric',
key: 'numeric',
key: 'numeric' as PasscodeKeyboardType,
selected: keyboardType === 'numeric',
},
],
Expand All @@ -77,28 +77,32 @@ export const PasscodeInputModal = (props: Props) => {

const onKeyboardTypeSelect = (option: Option) => {
setKeyboardType(option.key as KeyboardType);
if (Platform.OS === 'ios') {
// on Android, keyboard will update right away
Keyboard.dismiss();
setTimeout(() => {
textRef.current?.focus();
}, 100);
}
application
?.getAppState()
.setPasscodeKeyboardType(option.key as PasscodeKeyboardType);
};

const mapKeyboardTypeForOS = useMemo(() => {
if (keyboardType === 'numeric') {
return 'number-pad';
}
return keyboardType;
}, [keyboardType]);

return (
<Container>
<TableSection>
<SectionedTableCell textInputCell first={true}>
<Input
ref={textRef}
key={Platform.OS === 'android' ? keyboardType + '1' : undefined}
placeholder="Enter a passcode"
onChangeText={setText}
value={text}
secureTextEntry
autoCorrect={false}
autoCapitalize={'none'}
keyboardType={keyboardType}
keyboardType={mapKeyboardTypeForOS}
keyboardAppearance={styleKit?.keyboardColorForActiveTheme()}
autoFocus={true}
underlineColorAndroid={'transparent'}
Expand All @@ -109,13 +113,14 @@ export const PasscodeInputModal = (props: Props) => {
<SectionedTableCell textInputCell first={false}>
<Input
ref={confirmTextRef}
key={Platform.OS === 'android' ? keyboardType + '2' : undefined}
placeholder="Confirm passcode"
onChangeText={setConfirmText}
value={confirmText}
secureTextEntry
autoCorrect={false}
autoCapitalize={'none'}
keyboardType={keyboardType}
keyboardType={mapKeyboardTypeForOS}
keyboardAppearance={styleKit?.keyboardColorForActiveTheme()}
underlineColorAndroid={'transparent'}
onSubmitEditing={onSubmit}
Expand Down

0 comments on commit ee94632

Please sign in to comment.