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

Commit

Permalink
feature: passcode support
Browse files Browse the repository at this point in the history
  • Loading branch information
radko93 committed Jun 30, 2020
1 parent 05d83ea commit 036f8bf
Show file tree
Hide file tree
Showing 9 changed files with 360 additions and 49 deletions.
67 changes: 64 additions & 3 deletions src/App.tsx
Expand Up @@ -13,10 +13,12 @@ import {
SCREEN_NOTES,
SCREEN_COMPOSE,
SCREEN_SETTINGS,
SCREEN_INPUT_MODAL_PASSCODE,
SCREEN_INPUT_MODAL_TAG,
} from './screens2/screens';
import { HeaderTitleView } from '@Components/HeaderTitleView';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import { ICON_MENU, ICON_CHECKMARK } from '@Style/icons';
import { ICON_MENU, ICON_CHECKMARK, ICON_CLOSE } from '@Style/icons';
import { StyleKit } from '@Style/StyleKit';
import { enableScreens } from 'react-native-screens';
import DrawerLayout from 'react-native-gesture-handler/DrawerLayout';
Expand All @@ -28,6 +30,8 @@ import { IoniconsHeaderButton } from '@Components/IoniconsHeaderButton';
import { Settings } from '@Screens/Settings/Settings';
import { ApplicationGroup } from '@Lib/applicationGroup';
import { MobileApplication } from '@Lib/application';
import { TagInputModal } from '@Screens/InputModal/TagInputModal';
import { PasscodeInputModal } from '@Screens/InputModal/PasscodeInputModal';

enableScreens();

Expand All @@ -50,7 +54,11 @@ type AppStackNavigatorParamList = {

type ModalStackNavigatorParamList = {
AppStack: undefined;
[SCREEN_SETTINGS]: HeaderTitleParams;
[SCREEN_SETTINGS]: undefined;
[SCREEN_INPUT_MODAL_TAG]: HeaderTitleParams & {
initialValue?: string;
};
[SCREEN_INPUT_MODAL_PASSCODE]: undefined;
};
export type AppStackNavigationProp<
T extends keyof AppStackNavigatorParamList
Expand Down Expand Up @@ -160,7 +168,6 @@ const AppStackComponent = () => {
})}
component={Compose}
/>
{/* <AppStack.Screen name={SCREEN_INPUT_MODAL} component={InputModal} /> */}
</AppStack.Navigator>
</DrawerLayout>
);
Expand Down Expand Up @@ -201,6 +208,60 @@ const MainStackComponent = () => (
})}
component={Settings}
/>
<MainStack.Screen
name={SCREEN_INPUT_MODAL_PASSCODE}
options={{
title: 'Setup Passcode',
gestureEnabled: false,
headerTitle: ({ children }) => {
return <HeaderTitleView title={children || ''} />;
},
headerLeft: ({ disabled, onPress }) => (
<HeaderButtons HeaderButtonComponent={IoniconsHeaderButton}>
<Item
testID="headerButton"
disabled={disabled}
title={Platform.OS === 'ios' ? 'Cancel' : ''}
iconName={
Platform.OS === 'ios'
? undefined
: StyleKit.nameForIcon(ICON_CLOSE)
}
onPress={onPress}
/>
</HeaderButtons>
),
}}
component={PasscodeInputModal}
/>
<MainStack.Screen
name={SCREEN_INPUT_MODAL_TAG}
options={({ route }) => ({
title: 'Tag',
gestureEnabled: false,
headerTitle: ({ children }) => {
return (
<HeaderTitleView title={route.params?.title ?? (children || '')} />
);
},
headerLeft: ({ disabled, onPress }) => (
<HeaderButtons HeaderButtonComponent={IoniconsHeaderButton}>
<Item
testID="headerButton"
disabled={disabled}
title={Platform.OS === 'ios' ? 'Cancel' : ''}
iconName={
Platform.OS === 'ios'
? undefined
: StyleKit.nameForIcon(ICON_CLOSE)
}
onPress={onPress}
/>
</HeaderButtons>
),
})}
component={TagInputModal}
/>
</MainStack.Navigator>
);

Expand Down
6 changes: 2 additions & 4 deletions src/components/SectionedOptionsTableCell.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import styled, { css } from 'styled-components/native';

type Option = { selected: boolean; key: string; title: string };
export type Option = { selected: boolean; key: string; title: string };

type Props = {
title: string;
Expand All @@ -28,7 +28,6 @@ export const Container = styled.View<ContainerProps>`
css`
height: ${height}px;
`};
flex: 1;
flex-direction: row;
justify-content: center;
align-items: center;
Expand All @@ -42,13 +41,13 @@ export const Container = styled.View<ContainerProps>`
const Title = styled.Text`
font-size: ${props => props.theme.mainTextFontSize}px;
color: ${props => props.theme.stylekitForegroundColor};
text-align: center;
width: 42%;
min-width: 0px;
`;

const OptionsContainer = styled.View`
width: 58%;
flex: 1;
flex-direction: row;
align-items: center;
justify-content: center;
Expand All @@ -60,7 +59,6 @@ const ButtonTouchable = styled.TouchableHighlight.attrs(props => ({
}))`
border-left-color: ${props => props.theme.stylekitBorderColor};
border-left-width: 1px;
height: 100%;
flex-grow: 1;
padding: 10px;
padding-top: 12px;
Expand Down
15 changes: 15 additions & 0 deletions src/screens/InputModal/InputModal.styled.ts
@@ -0,0 +1,15 @@
import styled from 'styled-components/native';

export const Container = styled.View`
flex: 1;
background-color: ${({ theme }) => theme.stylekitBackgroundColor};
`;

export const Input = styled.TextInput.attrs(({ theme }) => ({
placeholderTextColor: theme.stylekitNeutralColor,
}))`
font-size: ${({ theme }) => theme.mainTextFontSize}px;
padding: 0px;
color: ${({ theme }) => theme.stylekitForegroundColor};
height: 100%;
`;
140 changes: 140 additions & 0 deletions src/screens/InputModal/PasscodeInputModal.tsx
@@ -0,0 +1,140 @@
import React, { useContext, useState, useRef, useMemo } from 'react';
import { TextInput, KeyboardType, Keyboard, Platform } from 'react-native';
import { ApplicationContext } from '@Root/ApplicationContext';
import { Container, Input } from './InputModal.styled';
import { TableSection } from '@Components/TableSection';
import { SectionedTableCell } from '@Components/SectionedTableCell';
import { ButtonCell } from '@Components/ButtonCell';
import { SCREEN_INPUT_MODAL_PASSCODE } from '@Root/screens2/screens';
import { ModalStackNavigationProp } from '@Root/App';
import {
SectionedOptionsTableCell,
Option,
} from '@Components/SectionedOptionsTableCell';

type Props = ModalStackNavigationProp<typeof SCREEN_INPUT_MODAL_PASSCODE>;
export const PasscodeInputModal = (props: Props) => {
// Context
const application = useContext(ApplicationContext);

// State
const [settingPassocode, setSettingPassocode] = useState(false);
const [text, setText] = useState('');
const [confirmText, setConfirmText] = useState('');
const [keyboardType, setKeyboardType] = useState<KeyboardType>('default');

// Refs
const textRef = useRef<TextInput>(null);
const confirmTextRef = useRef<TextInput>(null);

const onTextSubmit = () => {
if (!confirmText) {
confirmTextRef.current?.focus();
} else {
// this.submit();
}
};

const onSubmit = async () => {
if (settingPassocode) {
return;
}
setSettingPassocode(true);
if (text !== confirmText) {
application?.alertService?.alert(
'The two values you entered do not match. Please try again.',
'Invalid Confirmation',
'OK'
);
setSettingPassocode(false);
} else {
await application?.setPasscode(text);
setSettingPassocode(false);
props.navigation.goBack();
}
};

const keyboardOptions: Option[] = useMemo(
() => [
{
title: 'General',
key: 'default',
selected: keyboardType === 'default',
},
{
title: 'Numeric',
key: 'numeric',
selected: keyboardType === 'numeric',
},
],
[keyboardType]
);

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);
}
};

return (
<Container>
<TableSection>
<SectionedTableCell textInputCell first={true}>
<Input
ref={textRef}
placeholder="Enter a passcode"
onChangeText={setText}
value={text}
secureTextEntry
autoCorrect={false}
autoCapitalize={'none'}
keyboardType={keyboardType}
keyboardAppearance={application
?.getThemeService()
.keyboardColorForActiveTheme()}
autoFocus={true}
underlineColorAndroid={'transparent'}
onSubmitEditing={onTextSubmit}
/>
</SectionedTableCell>

<SectionedTableCell textInputCell first={false}>
<Input
ref={confirmTextRef}
placeholder="Confirm passcode"
onChangeText={setConfirmText}
value={confirmText}
secureTextEntry
autoCorrect={false}
autoCapitalize={'none'}
keyboardType={keyboardType}
keyboardAppearance={application
?.getThemeService()
.keyboardColorForActiveTheme()}
underlineColorAndroid={'transparent'}
onSubmitEditing={onSubmit}
/>
</SectionedTableCell>

<SectionedOptionsTableCell
title={'Keyboard Type'}
options={keyboardOptions}
onPress={onKeyboardTypeSelect}
/>

<ButtonCell
maxHeight={45}
disabled={settingPassocode || text.length === 0}
title={'Save'}
bold
onPress={onSubmit}
/>
</TableSection>
</Container>
);
};
56 changes: 56 additions & 0 deletions src/screens/InputModal/TagInputModal.tsx
@@ -0,0 +1,56 @@
import React, { useContext, useState, useRef } from 'react';
import { TextInput } from 'react-native';
import { ApplicationContext } from '@Root/ApplicationContext';
import { Container, Input } from './InputModal.styled';
import { TableSection } from '@Components/TableSection';
import { SectionedTableCell } from '@Components/SectionedTableCell';
import { ButtonCell } from '@Components/ButtonCell';
import { SCREEN_INPUT_MODAL_TAG } from '@Root/screens2/screens';
import { ModalStackNavigationProp } from '@Root/App';

type Props = ModalStackNavigationProp<typeof SCREEN_INPUT_MODAL_TAG>;
export const TagInputModal = (props: Props) => {
// Context
const application = useContext(ApplicationContext);

// State
const [text, setText] = useState('');

// Refs
const textRef = useRef<TextInput>(null);

const onSubmit = () => {};

return (
<Container>
<TableSection>
<SectionedTableCell textInputCell first={true}>
<Input
ref={textRef}
placeholder={
props.route.params.initialValue ? 'Tag name' : 'New tag name'
}
onChangeText={setText}
value={text}
autoCorrect={false}
autoCapitalize={'none'}
keyboardAppearance={application
?.getThemeService()
.keyboardColorForActiveTheme()}
autoFocus
underlineColorAndroid={'transparent'}
onSubmitEditing={onSubmit}
/>
</SectionedTableCell>

<ButtonCell
maxHeight={45}
disabled={text.length === 0}
title={'Save'}
bold
onPress={() => {}}
/>
</TableSection>
</Container>
);
};

0 comments on commit 036f8bf

Please sign in to comment.