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

366 lines
11 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-03-03 18:03:03 +05:00
import SettingsBackupAndRestore from '../../screens/settings/backup-restore';
import BiometricService from '../../services/biometrics';
import { DDS } from '../../services/device-detection';
import { eSendEvent, presentSheet, ToastEvent } from '../../services/event-manager';
import { setRateAppMessage } from '../../services/message';
import PremiumService from '../../services/premium';
import SettingsService from '../../services/settings';
2021-06-11 09:16:04 +05:00
import {
2022-03-03 18:03:03 +05:00
initialize,
2021-06-11 09:16:04 +05:00
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
2022-02-28 23:25:18 +05:00
} from '../../stores/stores';
2022-03-03 18:03:03 +05:00
import { useThemeStore } from '../../stores/theme';
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';
2022-02-28 13:48:59 +05:00
import { MMKV } from '../../utils/database/mmkv';
2022-03-03 18:03:03 +05:00
import { eOpenAnnouncementDialog } from '../../utils/events';
2022-02-28 13:48:59 +05:00
import { tabBarRef } from '../../utils/global-refs';
import { SIZE } from '../../utils/size';
import { sleep } from '../../utils/time';
2022-03-03 18:03:03 +05:00
import { SVG } from '../auth/background';
import Intro from '../intro';
import { Update } from '../sheets/update';
2022-02-28 13:48:59 +05:00
import { Button } from '../ui/button';
2022-03-03 18:03:03 +05:00
import { IconButton } from '../ui/icon-button';
2022-02-28 13:48:59 +05:00
import Input from '../ui/input';
import Seperator from '../ui/seperator';
2022-03-03 18:03:03 +05:00
import { SvgView } from '../ui/svg';
2022-02-28 13:48:59 +05:00
import Heading from '../ui/typography/heading';
import Paragraph from '../ui/typography/paragraph';
import { Walkthrough } from '../walkthroughs';
2022-03-09 19:04:01 +05:00
import NewFeature from '../sheets/new-feature/index';
2022-01-25 10:25:23 +05:00
const Launcher = React.memo(
() => {
const colors = useThemeStore(state => state.colors);
const setNotes = useNoteStore(state => state.setNotes);
const setFavorites = useFavoriteStore(state => state.setFavorites);
const setLoading = useNoteStore(state => state.setLoading);
const loading = useNoteStore(state => state.loading);
const user = useUserStore(state => state.user);
const verifyUser = useUserStore(state => state.verifyUser);
const setVerifyUser = useUserStore(state => state.setVerifyUser);
const deviceMode = useSettingStore(state => state.deviceMode);
const passwordInputRef = useRef();
const password = useRef();
const [requireIntro, setRequireIntro] = useState({
updated: false,
value: false
});
const dbInitCompleted = useRef(false);
2021-10-05 12:53:08 +05:00
const loadNotes = async () => {
if (verifyUser) {
return;
2022-02-14 14:54:15 +05:00
}
await restoreEditorState();
await db.notes.init();
setNotes();
setFavorites();
setLoading(false);
Walkthrough.init();
};
2022-01-25 10:25:23 +05:00
const init = async () => {
if (!dbInitCompleted.current) {
await db.init();
initialize();
useUserStore.getState().setUser(await db.user.getUser());
dbInitCompleted.current = true;
}
2021-12-02 21:21:00 +05:00
if (!verifyUser) {
loadNotes();
}
2022-03-07 15:19:07 +05:00
};
2022-03-03 18:03:03 +05:00
const hideSplashScreen = async () => {
await sleep(requireIntro.value ? 500 : 0);
await RNBootSplash.hide({ fade: true });
setTimeout(async () => {
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-03-10 23:24:55 +05:00
}
}, 500);
};
2021-10-05 12:53:08 +05:00
useEffect(() => {
if (requireIntro.updated) {
hideSplashScreen();
}
}, [requireIntro, verifyUser]);
useEffect(() => {
let introCompleted = SettingsService.get().introCompleted;
setRequireIntro({
updated: true,
value: !introCompleted
2022-01-04 13:08:02 +05:00
});
}, []);
2022-01-04 13:08:02 +05:00
useEffect(() => {
if (!loading) {
doAppLoadActions();
}
return () => {
dbInitCompleted.current = false;
};
}, [loading]);
2022-01-04 13:08:02 +05:00
const doAppLoadActions = async () => {
await sleep(500);
if (SettingsService.get().sessionExpired) {
eSendEvent('session_expired');
return;
}
if (NewFeature.present()) return;
if (await checkAppUpdateAvailable()) return;
if (await checkForRateAppRequest()) return;
if (await checkNeedsBackup()) return;
if (await PremiumService.getRemainingTrialDaysStatus()) return;
await useMessageStore.getState().setAnnouncement();
if (!requireIntro?.value) {
useMessageStore.subscribe(state => {
let dialogs = state.dialogs;
if (dialogs.length > 0) {
eSendEvent(eOpenAnnouncementDialog, dialogs[0]);
}
});
}
};
2021-10-05 12:53:08 +05:00
const checkAppUpdateAvailable = async () => {
try {
const version = await checkVersion();
if (!version.needsUpdate) return false;
2021-11-09 09:44:48 +05:00
presentSheet({
component: ref => <Update version={version} fwdRef={ref} />
2021-07-25 11:32:04 +05:00
});
2021-10-05 12:53:08 +05:00
return true;
} catch (e) {
return false;
2021-06-10 13:16:22 +05:00
}
};
2021-02-25 12:16:38 +05:00
const restoreEditorState = async () => {
let appState = await MMKV.getItem('appState');
if (appState) {
appState = JSON.parse(appState);
if (
appState.note &&
!appState.note.locked &&
!appState.movedAway &&
Date.now() < appState.timestamp + 3600000
) {
editing.isRestoringState = true;
editing.currentlyEditing = true;
editing.movedAway = false;
if (!DDS.isTab) {
tabBarRef.current?.goToPage(1);
}
eSendEvent('loadingNote', appState.note);
}
}
};
const checkForRateAppRequest = async () => {
let rateApp = SettingsService.get().rateApp;
2022-03-18 14:40:15 +05:00
if (rateApp && rateApp < Date.now() && !useMessageStore.getState().message?.visible) {
setRateAppMessage();
return true;
}
return false;
};
2021-06-11 09:16:04 +05:00
const checkNeedsBackup = async () => {
let { nextBackupRequestTime, reminder } = SettingsService.get();
if (reminder === 'off' || !reminder) {
if (nextBackupRequestTime < Date.now()) {
presentSheet({
title: 'Backup & restore',
paragraph: 'Please enable automatic backups to keep your data safe',
component: <SettingsBackupAndRestore isSheet={true} />
});
2022-03-03 18:03:03 +05:00
return true;
}
}
return false;
};
const onUnlockBiometrics = async () => {
if (!(await BiometricService.isBiometryAvailable())) {
ToastEvent.show({
heading: 'Biometrics unavailable',
message: 'Try unlocking the app with your account password'
});
return;
}
let verified = await BiometricService.validateUser('Unlock to access your notes', '');
2021-06-11 09:16:04 +05:00
if (verified) {
setVerifyUser(false);
2022-03-03 18:03:03 +05:00
password.current = null;
2021-06-11 09:16:04 +05:00
}
};
2022-03-03 18:03:03 +05:00
useEffect(() => {
if (verifyUser) {
onUnlockBiometrics();
}
init();
}, [verifyUser]);
2022-02-11 10:38:14 +05:00
const onSubmit = async () => {
if (!password.current) return;
try {
let verified = await db.user.verifyPassword(password.current);
if (verified) {
setVerifyUser(false);
password.current = null;
}
} catch (e) {}
};
return verifyUser ? (
2022-02-11 10:38:14 +05:00
<View
2021-02-25 12:16:38 +05:00
style={{
backgroundColor: colors.bg,
width: '100%',
height: '100%',
position: 'absolute',
zIndex: 999
2022-01-22 12:57:05 +05:00
}}
>
<View
2022-01-25 10:25:23 +05:00
style={{
height: 250,
overflow: 'hidden'
2022-01-25 10:25:23 +05:00
}}
>
<SvgView src={SVG(colors.night ? 'white' : 'black')} height={700} />
</View>
2021-11-18 14:52:07 +05:00
2022-02-11 10:38:14 +05:00
<View
style={{
flex: 1,
justifyContent: 'center',
width: deviceMode !== 'mobile' ? '50%' : Platform.OS == 'ios' ? '95%' : '100%',
paddingHorizontal: 12,
marginBottom: 30,
marginTop: 15
2022-02-11 10:38:14 +05:00
}}
>
<IconButton
name="fingerprint"
size={100}
customStyle={{
width: 100,
height: 100,
marginBottom: 20,
marginTop: user ? 0 : 50
}}
onPress={onUnlockBiometrics}
color={colors.border}
/>
<Heading
color={colors.heading}
style={{
alignSelf: 'center',
textAlign: 'center'
}}
>
Unlock to access your notes
</Heading>
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 />
2022-02-11 10:38:14 +05:00
<View
style={{
width: '100%',
padding: 12,
backgroundColor: colors.bg,
flexGrow: 1
2022-02-11 10:38:14 +05:00
}}
>
{user ? (
<>
<Input
fwdRef={passwordInputRef}
secureTextEntry
placeholder="Enter account password"
onChangeText={v => (password.current = v)}
onSubmit={onSubmit}
2022-02-11 10:38:14 +05:00
/>
</>
) : null}
2021-06-11 09:16:04 +05:00
<View
2022-02-11 10:38:14 +05:00
style={{
marginTop: user ? 50 : 25
2022-02-11 10:38:14 +05:00
}}
>
{user ? (
<>
<Button
title="Continue"
type="accent"
onPress={onSubmit}
width={250}
height={45}
style={{
borderRadius: 150,
marginBottom: 10
}}
fontSize={SIZE.md}
/>
</>
) : null}
<Button
title="Unlock with Biometrics"
width={250}
height={45}
style={{
borderRadius: 100
}}
onPress={onUnlockBiometrics}
icon={'fingerprint'}
type={user ? 'grayAccent' : 'accent'}
fontSize={SIZE.md}
/>
</View>
2022-02-11 10:38:14 +05:00
</View>
</View>
</View>
) : requireIntro.value && !loading ? (
<Intro />
) : null;
},
() => true
);
2021-02-25 12:16:38 +05:00
2022-02-28 13:48:59 +05:00
export default Launcher;