Skip to content

Commit

Permalink
feat: allow to disable the password prompt at application open and re…
Browse files Browse the repository at this point in the history
…sume (#250)

## Description

Closes: DPM-160

This PR introduces a setting in the Security section that enables the user to disable the password prompt for unlocking the application when it is started and when it is resumed from the background.
Here the final result:
![screen-20231030-113942 mp4](https://github.com/desmos-labs/dpm/assets/6245917/0fb278fe-e53f-4be8-975e-24704a1de0e4)




---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

- [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] provided a link to the relevant issue or specification
- [x] reviewed "Files changed" and left comments if necessary
- [x] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed all author checklist items have been addressed
  • Loading branch information
manu0466 authored Nov 2, 2023
1 parent a98fd6d commit 9f87b7d
Show file tree
Hide file tree
Showing 12 changed files with 155 additions and 11 deletions.
4 changes: 3 additions & 1 deletion src/assets/locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,7 @@
"analytics": "Analytics",
"enable analytics": "Enable analytics",
"enable analytics message": "By enabling in-app analytics, we'll track only anonymous data on how you use the app—like feature engagement and navigation patterns.\nNo personal info is collected.\nDo you want to enable the analytics?",
"notifications": "Notifications"
"notifications": "Notifications",
"disable app lock": "Disable app lock",
"disable app lock message": "If you turn off the app lock:\n\n• You won't need to enter your password every time you open the app.\n• But you'll still need to enter your password when making a transaction.\n\nKeep in mind that with the app lock off, anyone who can access your phone can open the app and see your personal information, including token holdings and your DTag."
}
8 changes: 4 additions & 4 deletions src/components/Flexible/SectionSwitch/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { View } from 'react-native';
import { StyleProp, View, ViewStyle } from 'react-native';
import Switch from 'components/Switch';
import Typography from 'components/Typography';
import useStyles from './useStyles';
Expand All @@ -9,14 +9,14 @@ export type Props = {
value: boolean;
isDisabled: boolean;
onPress: () => void;
style?: StyleProp<ViewStyle>;
};

const SectionSwitch: React.FC<Props> = (props) => {
const { label, value, isDisabled, onPress } = props;
const SectionSwitch: React.FC<Props> = ({ label, value, isDisabled, onPress, style }) => {
const styles = useStyles();

return (
<View style={styles.root}>
<View style={[styles.root, style]}>
<Typography.Body1 style={[styles.label, isDisabled ? styles.disabled : null]}>
{label}
</Typography.Body1>
Expand Down
14 changes: 12 additions & 2 deletions src/hooks/useLockApplicationOnBlur.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import ROUTES from 'navigation/routes';
import { useNavigation } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack/lib/typescript/src/types';
import { useHasAccount } from '@recoil/accounts';
import { useSetting } from '@recoil/settings';

const useLockApplicationOnBlur = () => {
const navigation = useNavigation<StackNavigationProp<RootNavigatorParamList>>();
const appState = useAppState();
const setAppState = useSetAppState();
const hasAccount = useHasAccount();
const lockApplication = useSetting('autoAppLock');

const showSplashScreen = useCallback(() => {
setAppState((currentState) => {
Expand Down Expand Up @@ -67,7 +69,7 @@ const useLockApplicationOnBlur = () => {
...currentState,
noLockOnBackground: false,
// Lock only if we shouldn't ignore the app state change.
locked: !currentState.noLockOnBackground,
locked: lockApplication && !currentState.noLockOnBackground,
lastObBlur: undefined,
};
}
Expand All @@ -88,7 +90,15 @@ const useLockApplicationOnBlur = () => {
blurSubscription?.remove();
focusSubscription?.remove();
};
}, [hasAccount, navigation, setAppState, appState, showSplashScreen, removeSplashScreen]);
}, [
hasAccount,
navigation,
setAppState,
appState,
showSplashScreen,
removeSplashScreen,
lockApplication,
]);

useEffect(() => {
if (appState.locked) {
Expand Down
10 changes: 8 additions & 2 deletions src/modals/TwoButtonModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback } from 'react';
import { View } from 'react-native';
import { StyleProp, TextStyle, View } from 'react-native';
import Typography from 'components/Typography';
import Button from 'components/Button';
import { ModalComponentProps } from 'modals/ModalScreen';
Expand All @@ -14,6 +14,10 @@ export type TwoButtonModalParams = {
* Modal message.
*/
message: string | React.ReactNode;
/**
* Optional style that will be applied to the message text view.
*/
messageStyle?: StyleProp<TextStyle>;
/**
* Text displayed on the positive action button.
*/
Expand Down Expand Up @@ -53,7 +57,9 @@ const TwoButtonModal: React.FC<ModalComponentProps<TwoButtonModalParams>> = (pro
return (
<View style={styles.root}>
<Typography.Title style={[styles.centred, styles.title]}>{params.title}</Typography.Title>
<Typography.Body style={styles.message}>{params.message}</Typography.Body>
<Typography.Body style={[styles.message, params.messageStyle]}>
{params.message}
</Typography.Body>
<View style={styles.buttonsRow}>
<Button mode="contained" onPress={negativeAction} accent>
{params.negativeActionLabel}
Expand Down
8 changes: 7 additions & 1 deletion src/navigation/RootNavigator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ import GovernanceProposalDetails, {
} from 'screens/GovernanceProposalDetails';
import ScanQr, { ScanQrCodeParams } from 'screens/ScanQr';
import { NavigatorScreenParams } from '@react-navigation/native';
import { useSetting } from '@recoil/settings';
import SettingsSwitchScreen, { SettingsSwitchScreenProps } from 'screens/SettingsSwitchScreen';

export type RootNavigatorParamList = {
[ROUTES.DEV_SCREEN]: undefined;
Expand Down Expand Up @@ -92,12 +94,14 @@ export type RootNavigatorParamList = {
[ROUTES.TRANSACTION_DETAILS]: TransactionDetailsParams;
[ROUTES.MODAL]: ModalScreenParams;

// -------------- Settings related screens ---------------
[ROUTES.SETTINGS]: undefined;
[ROUTES.SETTINGS_DISPLAY_MODE]: undefined;
[ROUTES.SETTINGS_SWITCH_CHAIN]: undefined;
[ROUTES.SETTINGS_ENABLE_BIOMETRICS_AUTHORIZATION]: EnableBiometricsAuthorizationParams;
[ROUTES.SETTINGS_CHANGE_APPLICATION_PASSWORD]: undefined;
[ROUTES.SETTINGS_JOIN_COMMUNITY]: undefined;
[ROUTES.SETTINGS_SWITCH_SCREEN]: SettingsSwitchScreenProps;

[ROUTES.MARKDOWN_TEXT]: MarkdownTextProps;

Expand All @@ -118,6 +122,7 @@ export type RootNavigatorParamList = {
const Stack = createStackNavigator<RootNavigatorParamList>();

const RootNavigator = () => {
const showUnlockApplicationScreen = useSetting('autoAppLock');
const activeAccount = useActiveAccount();
const initWalletConnect = useInitWalletConnectClient();
// Hook to update all the profiles, this will also take care of updating
Expand All @@ -133,7 +138,7 @@ const RootNavigator = () => {
return ROUTES.LANDING;
}

return ROUTES.UNLOCK_APPLICATION;
return showUnlockApplicationScreen ? ROUTES.UNLOCK_APPLICATION : ROUTES.HOME_TABS;

// Safe to ignore the activeAccount deps since we need to check
// just if exists when the apps opens.
Expand Down Expand Up @@ -228,6 +233,7 @@ const RootNavigator = () => {
name={ROUTES.SETTINGS_CHANGE_APPLICATION_PASSWORD}
component={SettingsChangeWalletPassword}
/>
<Stack.Screen name={ROUTES.SETTINGS_SWITCH_SCREEN} component={SettingsSwitchScreen} />

<Stack.Screen name={ROUTES.UNLOCK_APPLICATION} component={UnlockApplication} />

Expand Down
5 changes: 5 additions & 0 deletions src/navigation/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ enum ROUTES {
SETTINGS_ENABLE_BIOMETRICS_AUTHORIZATION = 'SETTINGS_ENABLE_BIOMETRICS_AUTHORIZATION',
SETTINGS_CHANGE_APPLICATION_PASSWORD = 'SETTINGS_CHANGE_APPLICATION_PASSWORD',
SETTINGS_JOIN_COMMUNITY = 'SETTINGS_JOIN_COMMUNITY',
/**
* Screen that display a switch with a detailed description
* about the setting that the user can change.
*/
SETTINGS_SWITCH_SCREEN = 'SETTINGS_SWITCH_SCREEN',

/**
* Screen that allows rendering a Markdown text.
Expand Down
1 change: 1 addition & 0 deletions src/recoil/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const DefaultAppSettings: AppSettings = {
currentTimezone: '',
analyticsEnabled: true,
hideBalance: false,
autoAppLock: true,
};

/**
Expand Down
28 changes: 28 additions & 0 deletions src/screens/Settings/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import React from 'react';
import TwoButtonModal from 'modals/TwoButtonModal';
import { useTranslation } from 'react-i18next';
import { usePostHog } from 'posthog-react-native';
import { useNavigation } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import { RootNavigatorParamList } from 'navigation/RootNavigator';
import ROUTES from 'navigation/routes';

/**
* Hooks that provides a function to enable or disable the analytics
Expand Down Expand Up @@ -36,3 +40,27 @@ export const useToggleAnalytics = () => {

return { analyticsEnabled, toggleAnalytics };
};

/**
* Hook that provides a function to enable or disable the
* prompt for unlocking the application and the current status.
*/
export const useToggleAppLock = () => {
const { t } = useTranslation('settings');
const navigation = useNavigation<StackNavigationProp<RootNavigatorParamList>>();
const appLockEnabled = useSetting('autoAppLock');
const setAppLockEnabled = useSetSetting('autoAppLock');

const toggleAppLock = React.useCallback(() => {
navigation.navigate(ROUTES.SETTINGS_SWITCH_SCREEN, {
title: t('disable app lock'),
description: t('disable app lock message'),
intialValue: !appLockEnabled,
toggleSetting: () => {
setAppLockEnabled((currentValue) => !currentValue);
},
});
}, [appLockEnabled, navigation, setAppLockEnabled, t]);

return toggleAppLock;
};
4 changes: 3 additions & 1 deletion src/screens/Settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { BiometricAuthorizations } from 'types/settings';
import useDeletePasswordFromBiometrics from 'hooks/useDelletPasswordFromBiometrics';
import useShowPrivacyPolicy from 'hooks/legal/useShowPrivacyPolicy';
import useShowToS from 'hooks/legal/useShowToS';
import { useToggleAnalytics } from 'screens/Settings/hooks';
import { useToggleAnalytics, useToggleAppLock } from 'screens/Settings/hooks';
import useToggleNotifications from 'hooks/notifications/useToggleNotifications';
import useStyles from './useStyles';

Expand Down Expand Up @@ -43,6 +43,7 @@ const Settings = (props: NavProps) => {
const deletePasswordFromBiometrics = useDeletePasswordFromBiometrics();
const { toggleAnalytics, analyticsEnabled } = useToggleAnalytics();
const { toggleNotifications, notificationsEnabled } = useToggleNotifications();
const toggleAppLock = useToggleAppLock();

// --------------------------------------------------------------------------------------
// --- Local state
Expand Down Expand Up @@ -152,6 +153,7 @@ const Settings = (props: NavProps) => {

{/* Security section */}
<Flexible.Section style={styles.sectionMargin} title={t('security')}>
<Flexible.SectionButton label={t('disable app lock')} onPress={toggleAppLock} />
<OpenSettingScreenButton
title={t('change application password')}
route={ROUTES.SETTINGS_CHANGE_APPLICATION_PASSWORD}
Expand Down
70 changes: 70 additions & 0 deletions src/screens/SettingsSwitchScreen/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { StackScreenProps } from '@react-navigation/stack';
import Flexible from 'components/Flexible';
import Spacer from 'components/Spacer';
import StyledSafeAreaView from 'components/StyledSafeAreaView';
import TopBar from 'components/TopBar';
import Typography from 'components/Typography';
import { RootNavigatorParamList } from 'navigation/RootNavigator';
import ROUTES from 'navigation/routes';
import React from 'react';
import useStyles from './useStyles';

export interface SettingsSwitchScreenProps {
/**
* Text that will be displayed in the top bar and
* as a label for the toggle.
*/
readonly title: string;
/**
* Description text that will be displayed above the
* switch.
*/
readonly description: string;
/**
* Initial setting value.
*/
readonly intialValue: boolean;
/**
* Function to toggle the setting.
*/
readonly toggleSetting: () => any;
}

type NavProps = StackScreenProps<RootNavigatorParamList, ROUTES.SETTINGS_SWITCH_SCREEN>;

/**
* Screen that display a switch with a detailed description about
* what the switch does.
*/
const SettingsSwitchScreen: React.FC<NavProps> = (props) => {
const { route } = props;
const { title, description, intialValue, toggleSetting } = route.params;
const styles = useStyles();
const [settingValue, setSettingValue] = React.useState(intialValue);

const onSwitchPress = React.useCallback(async () => {
try {
await toggleSetting();
setSettingValue((currentValue) => !currentValue);
} catch (e) {
// Ingnored.
}
}, [toggleSetting]);

return (
<StyledSafeAreaView topBar={<TopBar stackProps={props} title={title} />}>
<Typography.Regular16>{description}</Typography.Regular16>
<Spacer paddingTop={16} />
<Flexible.SectionSwitch
style={styles.switch}
title={title}
label={title}
value={settingValue}
isDisabled={false}
onPress={onSwitchPress}
/>
</StyledSafeAreaView>
);
};

export default SettingsSwitchScreen;
9 changes: 9 additions & 0 deletions src/screens/SettingsSwitchScreen/useStyles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { makeStyle } from 'config/theme';

const useStyles = makeStyle(() => ({
switch: {
paddingHorizontal: 0,
},
}));

export default useStyles;
5 changes: 5 additions & 0 deletions src/types/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ export type AppSettings = {
currentTimezone: '';
analyticsEnabled: boolean;
hideBalance: boolean;
/**
* Indicates whether the application will be locked when started and whether it will be
* automatically locked when it loses focus.
*/
autoAppLock: boolean;
};

0 comments on commit 9f87b7d

Please sign in to comment.