import React, { useEffect, useRef, useState } from 'react';
import { Platform, View } from 'react-native';
import RNBootSplash from 'react-native-bootsplash';
import { checkVersion } from 'react-native-check-version';
import { editorState } from '../../screens/editor/tiptap/utils';
import BackupService from '../../services/backup';
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';
import { initialize } from '../../stores';
import { useMessageStore } from '../../stores/use-message-store';
import { useNoteStore } from '../../stores/use-notes-store';
import { useSettingStore } from '../../stores/use-setting-store';
import { useThemeStore } from '../../stores/use-theme-store';
import { useUserStore } from '../../stores/use-user-store';
import { db, loadDatabase } from '../../utils/database';
import { MMKV } from '../../utils/database/mmkv';
import { eOpenAnnouncementDialog } from '../../utils/events';
import { tabBarRef } from '../../utils/global-refs';
import { SIZE } from '../../utils/size';
import { sleep } from '../../utils/time';
import { SVG } from '../auth/background';
import Intro from '../intro';
import NewFeature from '../sheets/new-feature/index';
import { Update } from '../sheets/update';
import { Button } from '../ui/button';
import { IconButton } from '../ui/icon-button';
import Input from '../ui/input';
import Seperator from '../ui/seperator';
import { SvgView } from '../ui/svg';
import Heading from '../ui/typography/heading';
import Paragraph from '../ui/typography/paragraph';
import { Walkthrough } from '../walkthroughs';
const Launcher = React.memo(
() => {
const colors = useThemeStore(state => state.colors);
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 introCompleted = false; //SettingsService.get().introCompleted;
const dbInitCompleted = useRef(false);
const loadNotes = async () => {
if (verifyUser) {
return;
}
await restoreEditorState();
setImmediate(() => {
db.notes.init().then(() => {
Walkthrough.init();
initialize();
setImmediate(() => {
setLoading(false);
setImmediate(() => doAppLoadActions());
});
});
});
};
const init = async () => {
if (!dbInitCompleted.current) {
if (!verifyUser) await RNBootSplash.hide({ fade: true });
await loadDatabase();
await db.init();
dbInitCompleted.current = true;
}
if (!verifyUser) {
loadNotes();
}
};
// useEffect(() => {
// hideSplashScreen();
// }, [verifyUser]);
useEffect(() => {
if (!loading) {
doAppLoadActions();
}
return () => {
dbInitCompleted.current = false;
};
}, [loading]);
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 (PremiumService.get() && user) {
if (SettingsService.get().reminder === 'off') {
SettingsService.set({ reminder: 'daily' });
}
if (BackupService.checkBackupRequired()) {
sleep(2000).then(() => BackupService.checkAndRun());
}
}
if (introCompleted) {
useMessageStore.subscribe(state => {
let dialogs = state.dialogs;
if (dialogs.length > 0) {
eSendEvent(eOpenAnnouncementDialog, dialogs[0]);
}
});
}
};
const checkAppUpdateAvailable = async () => {
try {
const version = await checkVersion();
if (!version.needsUpdate) return false;
presentSheet({
component: ref =>
});
return true;
} catch (e) {
return false;
}
};
const restoreEditorState = async () => {
let appState = MMKV.getString('appState');
if (appState) {
appState = JSON.parse(appState);
if (
appState.note &&
!appState.note.locked &&
!appState.movedAway &&
Date.now() < appState.timestamp + 3600000
) {
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;
if (rateApp && rateApp < Date.now() && !useMessageStore.getState().message?.visible) {
setRateAppMessage();
return true;
}
return false;
};
const checkNeedsBackup = async () => {
return false;
// 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:
// });
// 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', '');
if (verified) {
setVerifyUser(false);
password.current = null;
}
};
useEffect(() => {
if (verifyUser) {
onUnlockBiometrics();
}
init();
}, [verifyUser]);
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 ? (
Unlock to access your notes
Please verify it's you
{user ? (
<>
(password.current = v)}
onSubmit={onSubmit}
/>
>
) : null}
{user ? (
<>
>
) : null}
) : null;
},
() => true
);
export default Launcher;