Files
notesnook/apps/mobile/src/components/AppLoader/index.js

363 lines
10 KiB
JavaScript
Raw Normal View History

2022-01-22 12:57:05 +05:00
import React, { useEffect, useRef, useState } from 'react';
2022-02-14 14:54:15 +05:00
import { NativeModules, Platform, StatusBar, View } from 'react-native';
2022-01-25 10:25:23 +05:00
import RNBootSplash from 'react-native-bootsplash';
import { checkVersion } from 'react-native-check-version';
2022-01-22 12:57:05 +05:00
import { useTracked } from '../../provider';
2021-06-11 09:16:04 +05:00
import {
useFavoriteStore,
2021-12-02 21:21:00 +05:00
useMessageStore,
2021-06-11 09:16:04 +05:00
useNoteStore,
2021-07-25 11:32:04 +05:00
useSettingStore,
useUserStore
2021-06-11 09:16:04 +05:00
} from '../../provider/stores';
import BiometricService from '../../services/BiometricService';
2022-01-22 12:57:05 +05:00
import { DDS } from '../../services/DeviceDetection';
2021-02-25 12:16:38 +05:00
import {
eSendEvent,
eSubscribeEvent,
eUnSubscribeEvent,
2021-11-09 09:44:48 +05:00
presentSheet,
ToastEvent
2021-02-25 12:16:38 +05:00
} from '../../services/EventManager';
2022-01-25 10:25:23 +05:00
import { setRateAppMessage } from '../../services/Message';
2021-11-15 15:24:48 +05:00
import PremiumService from '../../services/PremiumService';
2022-01-25 10:25:23 +05:00
import { editing } from '../../utils';
2022-01-22 12:57:05 +05:00
import { db } from '../../utils/database';
import { eOpenAnnouncementDialog } from '../../utils/Events';
2022-01-22 12:57:05 +05:00
import { MMKV } from '../../utils/mmkv';
import { tabBarRef } from '../../utils/Refs';
import { SIZE } from '../../utils/SizeUtils';
import { sleep } from '../../utils/TimeUtils';
2021-11-24 10:13:42 +05:00
import SettingsBackupAndRestore from '../../views/Settings/backup-restore';
2022-02-11 10:38:14 +05:00
import { ActionIcon } from '../ActionIcon';
2022-01-22 12:57:05 +05:00
import { Button } from '../Button';
2021-06-11 09:16:04 +05:00
import Input from '../Input';
2022-02-11 10:38:14 +05:00
import { SvgToPngView } from '../ListPlaceholders';
2022-02-17 00:02:41 +05:00
import { SVG } from '../Auth/background';
2021-06-11 09:16:04 +05:00
import Seperator from '../Seperator';
2021-04-19 12:13:42 +05:00
import SplashScreen from '../SplashScreen';
2021-06-11 09:16:04 +05:00
import Heading from '../Typography/Heading';
import Paragraph from '../Typography/Paragraph';
2022-01-22 12:57:05 +05:00
import { Update } from '../Update';
2021-06-11 09:16:04 +05:00
let passwordValue = null;
2021-06-11 10:38:35 +05:00
let didVerifyUser = false;
2022-01-25 10:25:23 +05:00
2022-01-22 12:57:05 +05:00
const AppLoader = ({ onLoad }) => {
2021-06-26 08:47:52 +05:00
const [state] = useTracked();
2021-02-25 12:16:38 +05:00
const colors = state.colors;
2021-06-05 21:10:20 +05:00
const setNotes = useNoteStore(state => state.setNotes);
const setFavorites = useFavoriteStore(state => state.setFavorites);
2021-06-10 12:59:05 +05:00
const _setLoading = useNoteStore(state => state.setLoading);
2021-10-05 12:53:08 +05:00
const _loading = useNoteStore(state => state.loading);
2021-06-26 08:47:52 +05:00
const user = useUserStore(state => state.user);
2021-06-11 09:16:04 +05:00
const verifyUser = useUserStore(state => state.verifyUser);
const setVerifyUser = useUserStore(state => state.setVerifyUser);
2021-11-18 14:52:07 +05:00
const deviceMode = useSettingStore(state => state.deviceMode);
2021-08-17 11:49:02 +05:00
const pwdInput = useRef();
2022-01-25 10:25:23 +05:00
const [requireIntro, setRequireIntro] = useState({
updated: false,
value: false
});
2021-06-11 09:16:04 +05:00
2022-01-25 10:25:23 +05:00
const load = async () => {
if (verifyUser) {
2021-03-01 14:53:37 +05:00
return;
}
2021-10-05 12:53:08 +05:00
await restoreEditorState();
await db.notes.init();
setNotes();
setFavorites();
_setLoading(false);
};
2022-01-25 10:25:23 +05:00
const hideSplashScreen = async () => {
await sleep(requireIntro.value ? 500 : 0);
await RNBootSplash.hide({ fade: true });
setTimeout(async () => {
2022-02-14 14:54:15 +05:00
if (Platform.OS === 'android') {
NativeModules.RNBars.setStatusBarStyle(!colors.night ? 'light-content' : 'dark-content');
await sleep(5);
NativeModules.RNBars.setStatusBarStyle(colors.night ? 'light-content' : 'dark-content');
} else {
StatusBar.setBarStyle(colors.night ? 'light-content' : 'dark-content');
}
2022-01-25 10:25:23 +05:00
}, 500);
};
2021-10-05 12:53:08 +05:00
useEffect(() => {
2022-01-25 10:25:23 +05:00
if (requireIntro.updated) {
hideSplashScreen();
}
}, [requireIntro, verifyUser]);
useEffect(() => {
(async () => {
let introCompleted = await MMKV.getItem('introCompleted');
setRequireIntro({
updated: true,
value: !introCompleted
});
})();
2021-10-05 12:53:08 +05:00
if (!_loading) {
(async () => {
await sleep(500);
if ((await MMKV.getItem('loginSessionHasExpired')) === 'expired') {
2022-02-07 14:44:48 +05:00
eSendEvent('session_expired');
2021-10-05 12:53:08 +05:00
return;
}
2021-12-02 21:21:00 +05:00
2022-01-04 13:08:02 +05:00
if (await checkAppUpdateAvailable()) return;
2021-10-05 12:53:08 +05:00
if (await checkForRateAppRequest()) return;
2021-11-11 13:09:20 +05:00
if (await checkNeedsBackup()) return;
2021-12-02 21:21:00 +05:00
if (await PremiumService.getRemainingTrialDaysStatus()) return;
await useMessageStore.getState().setAnnouncement();
2022-01-25 10:25:23 +05:00
if (!requireIntro) {
2021-12-02 21:21:00 +05:00
let dialogs = useMessageStore.getState().dialogs;
if (dialogs.length > 0) {
eSendEvent(eOpenAnnouncementDialog, dialogs[0]);
}
}
2021-10-05 12:53:08 +05:00
})();
}
}, [_loading]);
2022-01-04 13:08:02 +05:00
const checkAppUpdateAvailable = async () => {
try {
const version = await checkVersion();
if (!version.needsUpdate) return false;
presentSheet({
component: ref => <Update version={version} fwdRef={ref} />
2022-01-04 13:08:02 +05:00
});
return true;
} catch (e) {
return false;
}
};
2021-10-05 12:53:08 +05:00
const restoreEditorState = async () => {
let appState = await MMKV.getItem('appState');
if (appState) {
appState = JSON.parse(appState);
2021-06-10 12:59:05 +05:00
if (
appState.note &&
2021-07-07 11:13:04 +05:00
!appState.note.locked &&
2021-06-10 12:59:05 +05:00
!appState.movedAway &&
Date.now() < appState.timestamp + 3600000
) {
editing.isRestoringState = true;
editing.currentlyEditing = true;
2021-07-07 11:13:04 +05:00
editing.movedAway = false;
2021-06-08 12:50:41 +05:00
if (!DDS.isTab) {
tabBarRef.current?.goToPage(1);
}
eSendEvent('loadingNote', appState.note);
}
2021-06-10 12:59:05 +05:00
}
2021-10-05 12:53:08 +05:00
};
2021-10-05 12:53:08 +05:00
const checkForRateAppRequest = async () => {
let askForRating = await MMKV.getItem('askForRating');
if (askForRating !== 'never' || askForRating !== 'completed') {
askForRating = JSON.parse(askForRating);
if (askForRating?.timestamp < Date.now()) {
if (!useMessageStore.getState().message.visible) {
setRateAppMessage();
}
2021-10-05 12:53:08 +05:00
return true;
}
}
2021-10-05 12:53:08 +05:00
return false;
};
const checkNeedsBackup = async () => {
let settingsStore = useSettingStore.getState();
2021-07-25 11:32:04 +05:00
let askForBackup = await MMKV.getItem('askForBackup');
2022-01-22 12:57:05 +05:00
if (settingsStore.settings.reminder === 'off' || !settingsStore.settings.reminder) {
2021-07-25 11:32:04 +05:00
askForBackup = JSON.parse(askForBackup);
if (askForBackup?.timestamp < Date.now()) {
2021-11-09 09:44:48 +05:00
presentSheet({
2021-07-25 11:32:04 +05:00
title: 'Backup & restore',
paragraph: 'Please enable automatic backups to keep your data safe',
component: <SettingsBackupAndRestore isSheet={true} />
});
2021-10-05 12:53:08 +05:00
return true;
2021-06-10 13:16:22 +05:00
}
}
2021-10-05 12:53:08 +05:00
return false;
2021-02-25 12:16:38 +05:00
};
2021-06-11 09:16:04 +05:00
useEffect(() => {
2021-06-14 14:41:57 +05:00
eSubscribeEvent('load_overlay', load);
2021-06-11 09:16:04 +05:00
if (!verifyUser) {
2021-06-11 12:14:07 +05:00
if (!didVerifyUser) {
onLoad();
2021-06-14 14:41:57 +05:00
} else {
load();
2021-06-11 12:14:07 +05:00
}
2021-06-11 09:16:04 +05:00
}
if (verifyUser) {
onUnlockBiometrics();
}
2021-02-25 12:16:38 +05:00
return () => {
eUnSubscribeEvent('load_overlay', load);
};
2021-06-11 09:16:04 +05:00
}, [verifyUser]);
const onUnlockBiometrics = async () => {
if (!(await BiometricService.isBiometryAvailable())) {
ToastEvent.show({
heading: 'Biometrics unavailable',
message: 'Try unlocking the app with your account password'
});
return;
}
2022-01-22 12:57:05 +05:00
let verified = await BiometricService.validateUser('Unlock to access your notes', '');
2021-06-11 10:38:35 +05:00
if (verified) {
didVerifyUser = true;
2021-06-11 09:16:04 +05:00
setVerifyUser(false);
2021-06-11 10:38:35 +05:00
passwordValue = null;
2021-06-11 09:16:04 +05:00
}
};
const onSubmit = async () => {
if (!passwordValue) return;
try {
let verified = await db.user.verifyPassword(passwordValue);
if (verified) {
2021-06-11 10:38:35 +05:00
didVerifyUser = true;
2021-06-11 09:16:04 +05:00
setVerifyUser(false);
2021-06-11 10:38:35 +05:00
passwordValue = null;
2021-06-11 09:16:04 +05:00
}
} catch (e) {}
};
2022-01-25 10:25:23 +05:00
return verifyUser ? (
2022-02-11 10:38:14 +05:00
<View
2021-04-19 12:13:42 +05:00
style={{
2022-02-11 10:38:14 +05:00
backgroundColor: colors.bg,
2021-04-19 12:13:42 +05:00
width: '100%',
height: '100%',
position: 'absolute',
2022-02-11 10:38:14 +05:00
zIndex: 999
2022-01-22 12:57:05 +05:00
}}
>
2022-02-11 10:38:14 +05:00
<View
style={{
height: 250,
overflow: 'hidden'
}}
>
<SvgToPngView src={SVG(colors.night ? 'white' : 'black')} height={700} />
</View>
<View
2021-02-25 12:16:38 +05:00
style={{
2022-02-11 10:38:14 +05:00
flex: 1,
2021-04-19 12:13:42 +05:00
justifyContent: 'center',
2022-02-11 10:38:14 +05:00
width: deviceMode !== 'mobile' ? '50%' : Platform.OS == 'ios' ? '95%' : '100%',
paddingHorizontal: 12,
marginBottom: 30,
marginTop: 15
2022-01-22 12:57:05 +05:00
}}
>
2022-02-11 10:38:14 +05:00
<ActionIcon
name="fingerprint"
size={100}
customStyle={{
width: 100,
height: 100,
marginBottom: 20,
marginTop: user ? 0 : 50
}}
onPress={onUnlockBiometrics}
color={colors.border}
/>
<Heading
color={colors.heading}
2022-01-25 10:25:23 +05:00
style={{
2022-02-11 10:38:14 +05:00
alignSelf: 'center',
textAlign: 'center'
2022-01-25 10:25:23 +05:00
}}
>
2022-02-11 10:38:14 +05:00
Unlock to access your notes
</Heading>
2021-11-18 14:52:07 +05:00
2022-02-11 10:38:14 +05:00
<Paragraph
style={{
alignSelf: 'center',
textAlign: 'center',
fontSize: SIZE.md,
maxWidth: '90%'
}}
>
Please verify it's you
</Paragraph>
<Seperator />
<View
style={{
width: '100%',
padding: 12,
backgroundColor: colors.bg,
flexGrow: 1
}}
>
2022-01-25 10:25:23 +05:00
{user ? (
<>
<Input
fwdRef={pwdInput}
secureTextEntry
placeholder="Enter account password"
onChangeText={v => (passwordValue = v)}
onSubmit={onSubmit}
/>
</>
2022-02-11 10:38:14 +05:00
) : null}
<View
style={{
marginTop: user ? 50 : 25
}}
>
{user ? (
<>
<Button
title="Continue"
type="accent"
onPress={onSubmit}
width={250}
height={45}
style={{
borderRadius: 150,
marginBottom: 10
}}
fontSize={SIZE.md}
/>
</>
) : null}
2021-06-11 09:16:04 +05:00
2022-02-11 10:38:14 +05:00
<Button
title="Unlock with Biometrics"
width={250}
height={45}
style={{
borderRadius: 100
}}
onPress={onUnlockBiometrics}
icon={'fingerprint'}
type={user ? 'grayAccent' : 'accent'}
fontSize={SIZE.md}
/>
</View>
</View>
</View>
</View>
2022-01-25 10:25:23 +05:00
) : requireIntro.value && !_loading ? (
2021-04-19 12:13:42 +05:00
<SplashScreen />
2022-01-25 10:25:23 +05:00
) : null;
2021-02-25 12:16:38 +05:00
};
export default AppLoader;