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

384 lines
12 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';
import { editorState } from '../../screens/editor/tiptap/utils';
2022-03-03 18:03:03 +05:00
import SettingsBackupAndRestore from '../../screens/settings/backup-restore';
import BackupService from '../../services/backup';
2022-03-03 18:03:03 +05:00
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';
2022-04-24 05:59:14 +05:00
import { initialize } from '../../stores';
import { useFavoriteStore } from '../../stores/use-favorite-store';
import { useMessageStore } from '../../stores/use-message-store';
2022-04-24 05:59:14 +05:00
import { useNoteStore } from '../../stores/use-notes-store';
import { useSettingStore } from '../../stores/use-setting-store';
2022-04-24 05:59:14 +05:00
import { useThemeStore } from '../../stores/use-theme-store';
import { useUserStore } from '../../stores/use-user-store';
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 NewFeature from '../sheets/new-feature/index';
2022-03-03 18:03:03 +05:00
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-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();
2022-04-24 05:59:14 +05:00
const introCompleted = SettingsService.get().introCompleted;
const [requireIntro, setRequireIntro] = useState({
2022-04-24 05:59:14 +05:00
updated: introCompleted,
value: !introCompleted
});
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();
2022-04-24 05:59:14 +05:00
setImmediate(() => {
db.notes.init().then(() => {
setNotes();
setFavorites();
setLoading(false);
Walkthrough.init();
});
});
};
2022-01-25 10:25:23 +05:00
const init = async () => {
if (!dbInitCompleted.current) {
await db.init();
initialize();
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 () => {
2022-04-24 05:59:14 +05:00
if (requireIntro.value) await sleep(500);
await RNBootSplash.hide({ fade: true });
setTimeout(async () => {
if (Platform.OS === 'android') {
NativeModules.RNBars.setStatusBarStyle(!colors.night ? 'light-content' : 'dark-content');
2022-04-05 12:24:42 +05:00
NativeModules.RNBars.setNavigationBarStyle(
!colors.night ? 'light-content' : 'dark-content'
);
await sleep(5);
NativeModules.RNBars.setStatusBarStyle(colors.night ? 'light-content' : 'dark-content');
2022-04-05 12:24:42 +05:00
NativeModules.RNBars.setNavigationBarStyle(
colors.night ? 'light-content' : 'dark-content'
);
} else {
StatusBar.setBarStyle(colors.night ? 'light-content' : 'dark-content');
2022-03-10 23:24:55 +05:00
}
2022-04-24 05:59:14 +05:00
}, 1000);
};
2021-10-05 12:53:08 +05:00
useEffect(() => {
2022-04-24 05:59:14 +05:00
console.log('hide splash', requireIntro.updated);
if (requireIntro.updated) {
hideSplashScreen();
2022-04-24 05:59:14 +05:00
return;
}
let introCompleted = SettingsService.get().introCompleted;
2022-04-24 05:59:14 +05:00
console.log(requireIntro);
setRequireIntro({
updated: true,
value: !introCompleted
2022-01-04 13:08:02 +05:00
});
2022-04-24 05:59:14 +05:00
}, [requireIntro, verifyUser]);
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();
2022-04-14 01:25:03 +05:00
if (PremiumService.get() && user) {
if (SettingsService.get().reminder === 'off') {
SettingsService.set({ reminder: 'daily' });
}
if (BackupService.checkBackupRequired()) {
sleep(2000).then(() => BackupService.checkAndRun());
}
}
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 () => {
2022-04-13 03:00:04 +05:00
let appState = MMKV.getString('appState');
if (appState) {
appState = JSON.parse(appState);
if (
appState.note &&
!appState.note.locked &&
!appState.movedAway &&
Date.now() < appState.timestamp + 3600000
) {
2022-03-26 16:05:58 +05:00
editorState().currentlyEditing = true;
editorState().isRestoringState = true;
editorState().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;