Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TW-346: Fix unlock after minimize #731

Merged
merged 8 commits into from
Jan 30, 2023
9 changes: 9 additions & 0 deletions .editorconfig copy
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Editor configuration, see http://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
1 change: 1 addition & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ dependencies {

//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation project(':react-native-keychain')

implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
implementation "androidx.core:core-splashscreen:1.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.soloader.SoLoader;
import com.oblador.keychain.KeychainPackage;
import com.oblador.keychain.KeychainModuleBuilder;
import com.templewallet.newarchitecture.MainApplicationReactNativeHost;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
Expand All @@ -28,6 +30,11 @@ public boolean getUseDeveloperSupport() {
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(
new KeychainPackage(
new KeychainModuleBuilder().withoutWarmUp()
)
);
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages;
Expand Down
4 changes: 4 additions & 0 deletions android/settings.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
rootProject.name = 'TempleWallet'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'

include ':react-native-keychain'
project(':react-native-keychain').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keychain/android')

includeBuild('../node_modules/react-native-gradle-plugin')

if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
Expand Down
9 changes: 8 additions & 1 deletion react-native.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
module.exports = {
assets: ['./src/assets/fonts/']
assets: ['./src/assets/fonts/'],
dependencies: {
'react-native-keychain': {
platforms: {
android: null
}
}
}
};
48 changes: 22 additions & 26 deletions src/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { AnalyticsProvider } from '@segment/analytics-react-native';
import React from 'react';
import { LogBox } from 'react-native';
import { hide } from 'react-native-bootsplash';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { enableScreens } from 'react-native-screens';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';

import { BiometryAvailabilityProvider } from '../biometry/biometry-availability.provider';
import { HIDE_SPLASH_SCREEN_TIMEOUT } from '../config/animation';
import { HideBalanceProvider } from '../hooks/hide-balance/hide-balance.provider';
import { useDelayedEffect } from '../hooks/use-delayed-effect.hook';
import { HideBootsplashProvider } from '../hooks/use-hide-bootsplash';
import { RootStackScreen } from '../navigator/root-stack';
import { AppLockContextProvider } from '../shelter/app-lock/app-lock';
import { persistor, store } from '../store/store';
Expand All @@ -24,27 +22,25 @@ initSentry();
enableScreens();
LogBox.ignoreAllLogs();

export const App = () => {
useDelayedEffect(HIDE_SPLASH_SCREEN_TIMEOUT, () => void hide({ fade: true }), []);

return (
<GestureHandlerRootView style={AppStyles.root}>
<AnalyticsProvider client={segmentClient}>
<Provider store={store}>
<PersistGate persistor={persistor} loading={null}>
<BiometryAvailabilityProvider>
<HideBalanceProvider>
<AppLockContextProvider>
<SafeAreaProvider>
export const App = () => (
<GestureHandlerRootView style={AppStyles.root}>
<AnalyticsProvider client={segmentClient}>
<Provider store={store}>
<PersistGate persistor={persistor} loading={null}>
<BiometryAvailabilityProvider>
<HideBalanceProvider>
<AppLockContextProvider>
<SafeAreaProvider>
<HideBootsplashProvider>
<RootStackScreen />
<ToastProvider />
</SafeAreaProvider>
</AppLockContextProvider>
</HideBalanceProvider>
</BiometryAvailabilityProvider>
</PersistGate>
</Provider>
</AnalyticsProvider>
</GestureHandlerRootView>
);
};
</HideBootsplashProvider>
<ToastProvider />
</SafeAreaProvider>
</AppLockContextProvider>
</HideBalanceProvider>
</BiometryAvailabilityProvider>
</PersistGate>
</Provider>
</AnalyticsProvider>
</GestureHandlerRootView>
);
9 changes: 0 additions & 9 deletions src/hooks/use-delayed-effect.hook.ts

This file was deleted.

23 changes: 23 additions & 0 deletions src/hooks/use-hide-bootsplash.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { createContext, FC, useContext, useEffect, useState } from 'react';
import { hide } from 'react-native-bootsplash';

import { HIDE_SPLASH_SCREEN_TIMEOUT } from '../config/animation';

const context = createContext(true);

const Provider = context.Provider;

export const HideBootsplashProvider: FC = ({ children }) => {
const [atBootsplash, setAtBootsplash] = useState(true);

useEffect(() => {
(async () => {
await hide({ fade: true });
setTimeout(() => void setAtBootsplash(false), HIDE_SPLASH_SCREEN_TIMEOUT);
})();
}, []);

return <Provider value={atBootsplash}>{children}</Provider>;
};

export const useAtBootsplash = () => useContext(context);
14 changes: 8 additions & 6 deletions src/screens/enter-password/enter-password.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Formik } from 'formik';
import React from 'react';
import React, { useEffect } from 'react';
import { Text, View } from 'react-native';

import { useBiometryAvailability } from '../../biometry/use-biometry-availability.hook';
Expand All @@ -13,10 +13,9 @@ import { InsetSubstitute } from '../../components/inset-substitute/inset-substit
import { Label } from '../../components/label/label';
import { Quote } from '../../components/quote/quote';
import { ScreenContainer } from '../../components/screen-container/screen-container';
import { HIDE_SPLASH_SCREEN_TIMEOUT } from '../../config/animation';
import { MAX_PASSWORD_ATTEMPTS } from '../../config/security';
import { FormPasswordInput } from '../../form/form-password-input';
import { useDelayedEffect } from '../../hooks/use-delayed-effect.hook';
import { useAtBootsplash } from '../../hooks/use-hide-bootsplash';
import { usePasswordLock } from '../../hooks/use-password-lock.hook';
import { useResetDataHandler } from '../../hooks/use-reset-data-handler.hook';
import { OverlayEnum } from '../../navigator/enums/overlay.enum';
Expand All @@ -36,6 +35,8 @@ import { useEnterPasswordStyles } from './enter-password.styles';
export const EnterPassword = () => {
const styles = useEnterPasswordStyles();

const atBootsplash = useAtBootsplash();

const { unlock, unlockWithBiometry } = useAppLock();

const { biometryType } = useBiometryAvailability();
Expand All @@ -51,9 +52,10 @@ export const EnterPassword = () => {

usePageAnalytic(OverlayEnum.EnterPassword);

useDelayedEffect(HIDE_SPLASH_SCREEN_TIMEOUT, () => void (isBiometryAvailable && unlockWithBiometry()), [
isBiometryAvailable
]);
useEffect(
() => void (!atBootsplash && isBiometryAvailable && unlockWithBiometry()),
[isBiometryAvailable, atBootsplash]
);

return (
<ScreenContainer style={styles.root} keyboardBehavior="padding" isFullScreenMode={true}>
Expand Down
2 changes: 1 addition & 1 deletion src/shelter/app-lock/app-lock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const AppLockContextProvider: FC = ({ children }) => {

return undefined;
})
.catch(() => undefined);
.catch(error => void console.error(error));

isDefined(password) && unlock(password);
}, [unlock]);
Expand Down
2 changes: 1 addition & 1 deletion src/shelter/shelter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export class Shelter {

static disableBiometryPassword$ = () => from(Keychain.resetGenericPassword(getKeychainOptions(PASSWORD_STORAGE_KEY)));

static getBiometryPassword = () => Keychain.getGenericPassword(biometryKeychainOptions);
static getBiometryPassword = async () => Keychain.getGenericPassword(biometryKeychainOptions);

static isPasswordCorrect$ = (password: string) =>
hashPassword$(password).pipe(map(passwordHash => passwordHash === Shelter._passwordHash$.getValue()));
Expand Down