Files
notesnook/apps/mobile/src/utils/useAppEvents.js

536 lines
16 KiB
JavaScript
Raw Normal View History

2021-10-02 10:09:12 +05:00
import NetInfo from '@react-native-community/netinfo';
2022-01-22 09:32:12 +05:00
import { EV, EVENTS } from 'notes-core/common';
import React, { useEffect, useRef } from 'react';
2021-10-18 15:02:03 +05:00
import {
Appearance,
AppState,
Linking,
NativeEventEmitter,
NativeModules,
2021-11-08 15:06:13 +05:00
Platform,
View
2021-10-18 15:02:03 +05:00
} from 'react-native';
2021-10-02 10:09:12 +05:00
import RNExitApp from 'react-native-exit-app';
import * as RNIap from 'react-native-iap';
2022-01-22 09:32:12 +05:00
import { enabled } from 'react-native-privacy-snapshot';
import { doInBackground, editing } from '.';
import { ProFeatures } from '../components/ResultDialog/pro-features';
2021-10-02 10:09:12 +05:00
import {
clearAllStores,
initialize,
2021-10-18 15:02:03 +05:00
useAttachmentStore,
2021-10-02 10:09:12 +05:00
useNoteStore,
useUserStore
} from '../provider/stores';
import Backup from '../services/Backup';
2021-10-02 10:09:12 +05:00
import BiometricService from '../services/BiometricService';
import {
eSendEvent,
eSubscribeEvent,
eUnSubscribeEvent,
2021-11-09 09:44:48 +05:00
presentSheet,
2021-10-02 10:09:12 +05:00
ToastEvent
} from '../services/EventManager';
import {
clearMessage,
setEmailVerifyMessage,
2022-01-02 02:02:18 +05:00
setLoginMessage,
setRecoveryKeyMessage
2021-10-02 10:09:12 +05:00
} from '../services/Message';
import Navigation from '../services/Navigation';
import PremiumService from '../services/PremiumService';
import SettingsService from '../services/SettingsService';
import Sync from '../services/Sync';
import {
EditorWebView,
getNote,
getWebviewInit,
updateNoteInEditor
} from '../views/Editor/Functions';
import tiny from '../views/Editor/tiny/tiny';
2022-01-22 09:32:12 +05:00
import { updateStatusBarColor } from './Colors';
import { db } from './database';
2022-01-22 12:57:05 +05:00
import { eClearEditor, eCloseProgressDialog, eOpenLoginDialog, refreshNotesPage } from './Events';
2022-01-22 09:32:12 +05:00
import { MMKV } from './mmkv';
import Storage from './storage';
2022-01-22 09:32:12 +05:00
import { sleep } from './TimeUtils';
2021-10-02 10:09:12 +05:00
2021-10-18 15:02:03 +05:00
const SodiumEventEmitter = new NativeEventEmitter(NativeModules.Sodium);
2021-10-02 10:09:12 +05:00
export const useAppEvents = () => {
const loading = useNoteStore(state => state.loading);
const setLastSynced = useUserStore(state => state.setLastSynced);
const setUser = useUserStore(state => state.setUser);
const setSyncing = useUserStore(state => state.setSyncing);
2021-12-09 00:14:15 +05:00
const syncedOnLaunch = useRef(false);
2021-10-02 10:09:12 +05:00
const refValues = useRef({
subsriptionSuccessListener: null,
subsriptionErrorListener: null,
isUserReady: false,
prevState: null,
showingDialog: false,
2021-12-09 00:14:15 +05:00
removeInternetStateListener: null,
isReconnecting: false
2021-10-02 10:09:12 +05:00
});
2022-01-22 12:57:05 +05:00
const onMediaDownloaded = ({ hash, groupId, src }) => {
if (groupId?.startsWith('monograph')) return;
2021-10-02 10:09:12 +05:00
tiny.call(
EditorWebView,
`
(function(){
2022-01-22 12:57:05 +05:00
let image = ${JSON.stringify({ hash, src })};
tinymce.activeEditor._replaceImage(image);
2021-10-02 10:09:12 +05:00
})();
`
);
};
const onLoadingAttachment = data => {
2022-01-22 12:57:05 +05:00
useAttachmentStore.getState().setLoading(data.total === data.current ? null : data);
2021-10-18 15:02:03 +05:00
};
2022-01-22 12:57:05 +05:00
const onSodiumProgress = ({ total, progress }) => {
2021-10-18 15:02:03 +05:00
console.log('encryption progress: ', (progress / total).toFixed(2));
2022-01-22 12:57:05 +05:00
useAttachmentStore.getState().setEncryptionProgress((progress / total).toFixed(2));
2021-10-02 10:09:12 +05:00
};
useEffect(() => {
Appearance.addChangeListener(SettingsService.setTheme);
Linking.addEventListener('url', onUrlRecieved);
EV.subscribe(EVENTS.appRefreshRequested, onSyncComplete);
EV.subscribe(EVENTS.databaseSyncRequested, partialSync);
EV.subscribe(EVENTS.userLoggedOut, onLogout);
EV.subscribe(EVENTS.userEmailConfirmed, onEmailVerified);
EV.subscribe(EVENTS.userSessionExpired, onSessionExpired);
EV.subscribe(EVENTS.userCheckStatus, PremiumService.onUserStatusCheck);
EV.subscribe(EVENTS.userSubscriptionUpdated, onAccountStatusChange);
EV.subscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded);
EV.subscribe(EVENTS.attachmentsLoading, onLoadingAttachment);
2022-01-22 12:57:05 +05:00
let ubsubsodium = SodiumEventEmitter.addListener('onSodiumProgress', onSodiumProgress);
2021-10-18 15:02:03 +05:00
2021-10-02 10:09:12 +05:00
eSubscribeEvent('userLoggedIn', setCurrentUser);
2021-12-09 00:14:15 +05:00
2021-10-02 10:09:12 +05:00
return () => {
2021-10-18 15:02:03 +05:00
ubsubsodium?.remove();
2021-10-02 10:09:12 +05:00
eUnSubscribeEvent('userLoggedIn', setCurrentUser);
EV.unsubscribe(EVENTS.userSessionExpired, onSessionExpired);
EV.unsubscribe(EVENTS.appRefreshRequested, onSyncComplete);
EV.unsubscribe(EVENTS.databaseSyncRequested, partialSync);
EV.unsubscribe(EVENTS.userLoggedOut, onLogout);
EV.unsubscribe(EVENTS.userEmailConfirmed, onEmailVerified);
EV.unsubscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded);
EV.subscribe(EVENTS.attachmentsLoading, onLoadingAttachment);
EV.unsubscribe(EVENTS.userCheckStatus, PremiumService.onUserStatusCheck);
EV.unsubscribe(EVENTS.userSubscriptionUpdated, onAccountStatusChange);
Appearance.removeChangeListener(SettingsService.setTheme);
Linking.removeEventListener('url', onUrlRecieved);
};
}, []);
const onSessionExpired = async () => {
await Storage.write('loginSessionHasExpired', 'expired');
eSendEvent(eOpenLoginDialog, 4);
};
2022-01-22 12:57:05 +05:00
// const onNoteRemoved = async id => {
// try {
// await db.notes.remove(id);
// Navigation.setRoutesToUpdate([
// Navigation.routeNames.Favorites,
// Navigation.routeNames.Notes,
// Navigation.routeNames.NotesPage,
// Navigation.routeNames.Trash,
// Navigation.routeNames.Notebook
// ]);
// eSendEvent(eClearEditor, id);
// } catch (e) {}
// };
2021-10-02 10:09:12 +05:00
useEffect(() => {
if (!loading) {
AppState.addEventListener('change', onAppStateChanged);
(async () => {
try {
let url = await Linking.getInitialURL();
if (url?.startsWith('https://app.notesnook.com/account/verified')) {
await onEmailVerified();
}
await setCurrentUser();
} catch (e) {}
})();
2022-01-22 12:57:05 +05:00
refValues.current.removeInternetStateListener =
NetInfo.addEventListener(onInternetStateChanged);
2021-10-02 10:09:12 +05:00
}
return () => {
refValues.current?.removeInternetStateListener &&
refValues.current?.removeInternetStateListener();
AppState.removeEventListener('change', onAppStateChanged);
unsubIAP();
};
}, [loading]);
const onInternetStateChanged = async state => {
2021-12-09 00:14:15 +05:00
if (!syncedOnLaunch.current) return;
2021-10-02 10:09:12 +05:00
reconnectSSE(state);
};
const onSyncComplete = async () => {
initialize();
setLastSynced(await db.lastSynced());
if (getNote()) {
await updateNoteInEditor();
}
};
const onUrlRecieved = async res => {
let url = res ? res.url : '';
try {
if (url.startsWith('https://app.notesnook.com/account/verified')) {
await onEmailVerified();
} else {
return;
}
} catch (e) {}
};
const onEmailVerified = async () => {
let user = await db.user.getUser();
setUser(user);
if (!user) return;
2021-11-08 11:57:24 +05:00
MMKV.setItem('isUserEmailConfirmed', 'yes');
2021-10-02 10:09:12 +05:00
await PremiumService.setPremiumStatus();
2022-01-22 12:57:05 +05:00
let message = 'You have been rewarded 7 more days of free trial. Enjoy using Notesnook!';
2021-11-09 09:44:48 +05:00
presentSheet({
2021-10-02 10:09:12 +05:00
title: 'Email confirmed!',
paragraph: message,
2021-11-08 15:06:13 +05:00
component: (
<View
style={{
paddingHorizontal: 12,
paddingBottom: 15,
alignItems: 'center'
2022-01-22 12:57:05 +05:00
}}
>
2021-11-08 15:06:13 +05:00
<ProFeatures />
</View>
)
2021-10-02 10:09:12 +05:00
});
if (user?.isEmailConfirmed) {
clearMessage();
}
};
const attachIAPListeners = async () => {
await RNIap.initConnection()
.catch(e => {
console.log(e);
})
.then(async () => {
refValues.current.subsriptionSuccessListener =
RNIap.purchaseUpdatedListener(onSuccessfulSubscription);
refValues.current.subsriptionErrorListener =
RNIap.purchaseErrorListener(onSubscriptionError);
});
};
const onAccountStatusChange = async userStatus => {
if (!PremiumService.get() && userStatus.type === 5) {
PremiumService.subscriptions.clear();
2021-11-09 09:44:48 +05:00
presentSheet({
2021-10-02 10:09:12 +05:00
title: 'Notesnook Pro',
paragraph: `Your Notesnook Pro subscription has been successfully activated.`,
action: async () => {
eSendEvent(eCloseProgressDialog);
},
icon: 'check',
2022-01-22 09:32:12 +05:00
actionText: 'Continue'
2021-10-02 10:09:12 +05:00
});
}
await PremiumService.setPremiumStatus();
};
const partialSync = async () => {
try {
setSyncing(true);
let res = await doInBackground(async () => {
try {
await db.sync(false);
return true;
} catch (e) {
return e.message;
}
});
if (res !== true) throw new Error(res);
setLastSynced(await db.lastSynced());
} catch (e) {
setSyncing(false);
let status = await NetInfo.fetch();
if (status.isConnected && status.isInternetReachable) {
ToastEvent.show({
heading: 'Sync failed',
message: e.message,
context: 'global'
});
}
} finally {
setSyncing(false);
}
};
const onLogout = async reason => {
setUser(null);
clearAllStores();
SettingsService.init();
setSyncing(false);
setLoginMessage();
await PremiumService.setPremiumStatus();
await MMKV.setItem('introCompleted', 'true');
2021-11-09 09:44:48 +05:00
presentSheet({
2021-10-02 10:09:12 +05:00
title: reason ? reason : 'User logged out',
paragraph: `You have been logged out of your account.`,
action: async () => {
eSendEvent(eCloseProgressDialog);
await sleep(300);
eSendEvent(eOpenLoginDialog);
},
icon: 'logout',
2022-01-22 09:32:12 +05:00
actionText: 'Login'
2021-10-02 10:09:12 +05:00
});
setTimeout(() => {
initialize();
}, 1000);
};
2022-01-22 12:57:05 +05:00
const unsubIAP = () => {
2021-10-02 10:09:12 +05:00
if (refValues.current?.subsriptionSuccessListener) {
refValues.current.subsriptionSuccessListener?.remove();
refValues.current.subsriptionSuccessListener = null;
}
if (refValues.current?.subsriptionErrorListener) {
refValues.current.subsriptionErrorListener?.remove();
refValues.current.subsriptionErrorListener = null;
}
};
const setCurrentUser = async login => {
try {
let user = await db.user.getUser();
2021-11-08 11:57:24 +05:00
2022-01-22 12:57:05 +05:00
let isUserEmailConfirmed = await MMKV.getStringAsync('isUserEmailConfirmed');
2021-11-08 11:57:24 +05:00
2021-10-02 10:09:12 +05:00
if ((await MMKV.getItem('loginSessionHasExpired')) === 'expired') {
setUser(user);
2021-12-09 00:14:15 +05:00
syncedOnLaunch.current = true;
2021-10-02 10:09:12 +05:00
return;
}
if (user) {
setUser(user);
clearMessage();
attachIAPListeners();
2021-12-14 23:46:50 +05:00
user = await db.user.fetchUser();
if (user.isEmailConfirmed && isUserEmailConfirmed === 'no') {
setTimeout(() => {
onEmailVerified();
}, 1000);
}
2022-01-02 02:02:18 +05:00
if (user.isEmailConfirmed) {
2022-01-22 12:57:05 +05:00
let hasSavedRecoveryKey = await MMKV.getItem('userHasSavedRecoveryKey');
2022-01-02 02:02:18 +05:00
if (!hasSavedRecoveryKey) {
setRecoveryKeyMessage();
}
}
2021-10-02 10:09:12 +05:00
await Sync.run();
if (!user.isEmailConfirmed) {
setEmailVerifyMessage();
2021-11-08 11:57:24 +05:00
MMKV.setItem('isUserEmailConfirmed', 'no');
2021-10-02 10:09:12 +05:00
return;
2021-11-08 11:57:24 +05:00
} else {
MMKV.setItem('isUserEmailConfirmed', 'yes');
2021-10-02 10:09:12 +05:00
}
setUser(user);
} else {
setLoginMessage();
}
} catch (e) {
let user = await db.user.getUser();
2022-01-02 02:02:18 +05:00
if (user?.isEmailConfirmed) {
let hasSavedRecoveryKey = await MMKV.getItem('userHasSavedRecoveryKey');
if (!hasSavedRecoveryKey) {
setRecoveryKeyMessage();
}
}
2021-10-02 10:09:12 +05:00
if (user && !user.isEmailConfirmed) {
setEmailVerifyMessage();
} else if (!user) {
setLoginMessage();
} else {
console.log('unknown error', e);
}
} finally {
await PremiumService.setPremiumStatus();
if (PremiumService.get()) {
2021-12-09 00:14:15 +05:00
if (SettingsService.get().reminder === 'off') {
await SettingsService.set('reminder', 'daily');
sleep(2000).then(() => Backup.checkAndRun());
}
}
2021-10-02 10:09:12 +05:00
refValues.current.isUserReady = true;
if (login) {
eSendEvent(eCloseProgressDialog);
}
2021-12-09 00:14:15 +05:00
syncedOnLaunch.current = true;
2021-10-02 10:09:12 +05:00
}
};
const onSuccessfulSubscription = async subscription => {
await PremiumService.subscriptions.set(subscription);
await PremiumService.subscriptions.verify(subscription);
};
const onSubscriptionError = async error => {
ToastEvent.show({
heading: 'Failed to subscribe',
type: 'error',
message: error.message,
context: 'local'
});
};
const onAppStateChanged = async state => {
2021-12-14 23:46:50 +05:00
console.log('onAppStateChanged');
2021-10-02 10:09:12 +05:00
if (state === 'active') {
updateStatusBarColor();
if (
SettingsService.get().appLockMode !== 'background' &&
!SettingsService.get().privacyScreen
) {
enabled(false);
}
if (SettingsService.get().appLockMode === 'background') {
2022-01-22 12:57:05 +05:00
if (refValues.current?.prevState === 'background' && !refValues.current?.showingDialog) {
2021-10-02 10:09:12 +05:00
refValues.current.showingDialog = true;
refValues.current.prevState = 'active';
2022-01-22 09:32:12 +05:00
eSendEvent('load_overlay', 'hide');
2022-01-22 12:57:05 +05:00
let result = await BiometricService.validateUser('Unlock to access your notes');
2021-10-02 10:09:12 +05:00
if (result) {
refValues.current.showingDialog = false;
2022-01-22 09:32:12 +05:00
eSendEvent('load_overlay', 'show');
2021-10-02 10:09:12 +05:00
} else {
RNExitApp.exitApp();
return;
}
}
}
refValues.current.prevState = 'active';
2021-12-14 23:46:50 +05:00
console.log('reconnect sse');
2021-10-02 10:09:12 +05:00
await reconnectSSE();
2021-12-14 23:46:50 +05:00
2021-10-02 10:09:12 +05:00
await checkIntentState();
if (getWebviewInit()) {
await MMKV.removeItem('appState');
}
let user = await db.user.getUser();
if (user && !user.isEmailConfirmed) {
try {
let user = await db.user.fetchUser();
if (user?.isEmailConfirmed) {
onEmailVerified();
}
} catch (e) {}
}
} else {
refValues.current.prevState = 'background';
2022-01-22 12:57:05 +05:00
if (getNote()?.locked && SettingsService.get().appLockMode === 'background') {
2021-10-02 10:09:12 +05:00
eSendEvent(eClearEditor);
}
await storeAppState();
if (
SettingsService.get().privacyScreen ||
SettingsService.get().appLockMode === 'background'
) {
enabled(true);
}
}
};
async function reconnectSSE(connection) {
2021-12-09 00:14:15 +05:00
if (refValues.current?.isReconnecting) return;
2021-10-02 10:09:12 +05:00
if (!refValues.current?.isUserReady) {
return;
}
if ((await MMKV.getItem('loginSessionHasExpired')) === 'expired') {
refValues.current.isReconnecting = false;
return;
}
2021-12-09 00:14:15 +05:00
refValues.current.isReconnecting = true;
2021-10-02 10:09:12 +05:00
let state = connection;
2021-12-14 23:46:50 +05:00
console.log('SSE:', 'TRYING TO RECONNECT');
2021-10-02 10:09:12 +05:00
try {
if (!state) {
state = await NetInfo.fetch();
}
let user = await db.user.getUser();
if (user && state.isConnected && state.isInternetReachable) {
2021-12-14 23:46:50 +05:00
await db.connectSSE();
2021-10-02 10:09:12 +05:00
}
2021-12-09 00:14:15 +05:00
refValues.current.isReconnecting = false;
} catch (e) {
2021-12-14 23:46:50 +05:00
refValues.current.isReconnecting = false;
2021-12-09 00:14:15 +05:00
}
2021-10-02 10:09:12 +05:00
}
async function storeAppState() {
if (editing.currentlyEditing) {
if (getNote()?.locked) return;
let state = JSON.stringify({
editing: editing.currentlyEditing,
note: getNote(),
movedAway: editing.movedAway,
timestamp: Date.now()
});
await MMKV.setItem('appState', state);
}
}
async function checkIntentState() {
try {
let notesAddedFromIntent = await MMKV.getItem('notesAddedFromIntent');
let shareExtensionOpened = await MMKV.getItem('shareExtensionOpened');
if (notesAddedFromIntent) {
2021-10-02 10:09:12 +05:00
if (Platform.OS === 'ios') {
await db.init();
await db.notes.init();
}
useNoteStore.getState().setNotes();
eSendEvent(refreshNotesPage);
MMKV.removeItem('notesAddedFromIntent');
initialize();
eSendEvent(refreshNotesPage);
}
if (notesAddedFromIntent || shareExtensionOpened) {
2022-01-22 09:32:12 +05:00
eSendEvent('loadingNote', getNote());
eSendEvent('webviewreset', true);
MMKV.removeItem('shareExtensionOpened');
}
} catch (e) {
console.log(e);
}
2021-10-02 10:09:12 +05:00
}
return true;
};