Files
notesnook/apps/mobile/app/hooks/use-app-events.js

463 lines
14 KiB
JavaScript
Raw Normal View History

import NetInfo from "@react-native-community/netinfo";
import { EV, EVENTS } from "@notesnook/core/common";
import { useEffect, useRef } from "react";
2021-10-18 15:02:03 +05:00
import {
Appearance,
AppState,
Linking,
NativeEventEmitter,
NativeModules,
2022-02-28 13:48:59 +05:00
Platform
} from "react-native";
import * as RNIap from "react-native-iap";
import { enabled } from "react-native-privacy-snapshot";
import { Walkthrough } from "../components/walkthroughs";
import { editorState } from "../screens/editor/tiptap/utils";
2021-10-02 10:09:12 +05:00
import {
clearMessage,
setEmailVerifyMessage,
2022-01-02 02:02:18 +05:00
setLoginMessage,
setRecoveryKeyMessage
} from "../services/message";
import PremiumService from "../services/premium";
import SettingsService from "../services/settings";
import { updateStatusBarColor } from "../utils/color-scheme";
import { db } from "../common/database";
import { MMKV } from "../common/database/mmkv";
import {
eClearEditor,
eCloseProgressDialog,
refreshNotesPage
} from "../utils/events";
import Sync from "../services/sync";
import { initAfterSync } from "../stores";
import { useUserStore } from "../stores/use-user-store";
import { useMessageStore } from "../stores/use-message-store";
import { useSettingStore } from "../stores/use-setting-store";
import { useAttachmentStore } from "../stores/use-attachment-store";
import { useNoteStore } from "../stores/use-notes-store";
import {
eSendEvent,
eSubscribeEvent,
eUnSubscribeEvent,
ToastEvent
} from "../services/event-manager";
import { useEditorStore } from "../stores/use-editor-store";
import { useDragState } from "../screens/settings/editor/state";
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);
2021-12-09 00:14:15 +05:00
const syncedOnLaunch = useRef(false);
const verify = useUserStore((state) => state.verifyUser);
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
});
const onLoadingAttachmentProgress = (data) => {
console.log("loading", data);
useAttachmentStore
.getState()
.setLoading(data.total === data.current ? null : data);
2021-10-18 15:02:03 +05:00
};
2022-03-03 18:03:03 +05:00
const onFileEncryptionProgress = ({ total, progress }) => {
console.log("encryption progress: ", (progress / total).toFixed(2));
useAttachmentStore
.getState()
.setEncryptionProgress((progress / total).toFixed(2));
2021-10-02 10:09:12 +05:00
};
const onSyncProgress = ({ type, total, current }) => {
console.log(type, total, current);
if (type !== "download") return;
if (total < 10 || current % 10 === 0) {
2022-07-20 22:24:58 +05:00
initAfterSync();
}
};
useEffect(() => {
if (!loading) {
const eventManager = db?.eventManager;
eventManager?.subscribe(EVENTS.syncCompleted, onSyncComplete);
2022-07-15 19:14:40 +05:00
db?.eventManager?.subscribe(EVENTS.syncProgress, onSyncProgress);
db?.eventManager?.subscribe(
EVENTS.databaseSyncRequested,
onRequestPartialSync
);
}
return () => {
const eventManager = db?.eventManager;
eventManager?.unsubscribe(EVENTS.syncCompleted, onSyncComplete);
eventManager?.unsubscribe(EVENTS.syncProgress, onSyncProgress);
eventManager?.unsubscribe(
EVENTS.databaseSyncRequested,
onRequestPartialSync
);
};
}, [loading]);
2021-10-02 10:09:12 +05:00
useEffect(() => {
2022-03-03 18:03:03 +05:00
let subs = [
Appearance.addChangeListener(SettingsService.setTheme),
Linking.addEventListener("url", onUrlRecieved),
SodiumEventEmitter.addListener(
"onSodiumProgress",
onFileEncryptionProgress
)
2022-03-03 18:03:03 +05:00
];
2022-07-15 19:14:40 +05:00
2021-10-02 10:09:12 +05:00
EV.subscribe(EVENTS.appRefreshRequested, onSyncComplete);
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);
2022-03-03 18:03:03 +05:00
EV.subscribe(EVENTS.attachmentsLoading, onLoadingAttachmentProgress);
eSubscribeEvent("userLoggedIn", onUserUpdated);
2021-12-09 00:14:15 +05:00
2021-10-02 10:09:12 +05:00
return () => {
eUnSubscribeEvent("userLoggedIn", onUserUpdated);
2021-10-02 10:09:12 +05:00
EV.unsubscribe(EVENTS.appRefreshRequested, onSyncComplete);
EV.unsubscribe(EVENTS.userSessionExpired, onSessionExpired);
2021-10-02 10:09:12 +05:00
EV.unsubscribe(EVENTS.userLoggedOut, onLogout);
EV.unsubscribe(EVENTS.userEmailConfirmed, onEmailVerified);
2022-03-03 18:03:03 +05:00
EV.subscribe(EVENTS.attachmentsLoading, onLoadingAttachmentProgress);
2021-10-02 10:09:12 +05:00
EV.unsubscribe(EVENTS.userCheckStatus, PremiumService.onUserStatusCheck);
EV.unsubscribe(EVENTS.userSubscriptionUpdated, onAccountStatusChange);
2022-03-03 18:03:03 +05:00
EV.unsubscribeAll();
2021-10-02 10:09:12 +05:00
subs.forEach((sub) => sub?.remove());
2021-10-02 10:09:12 +05:00
};
}, []);
const onSessionExpired = async () => {
2022-03-03 18:03:03 +05:00
await SettingsService.set({
sessionExpired: true
});
eSendEvent("session_expired");
2021-10-02 10:09:12 +05:00
};
useEffect(() => {
2022-03-03 22:31:23 +05:00
let sub;
2022-08-08 11:12:27 +05:00
if (!loading && !verify) {
setTimeout(() => {
sub = AppState.addEventListener("change", onAppStateChanged);
2022-08-08 11:12:27 +05:00
}, 1000);
2021-10-02 10:09:12 +05:00
(async () => {
try {
let url = await Linking.getInitialURL();
if (url?.startsWith("https://app.notesnook.com/account/verified")) {
2021-10-02 10:09:12 +05:00
await onEmailVerified();
}
2022-03-16 13:21:05 +05:00
await onUserUpdated();
} catch (e) {
console.error(e);
}
2021-10-02 10:09:12 +05:00
})();
refValues.current.removeInternetStateListener = NetInfo.addEventListener(
onInternetStateChanged
);
2021-10-02 10:09:12 +05:00
}
return () => {
refValues.current?.removeInternetStateListener &&
refValues.current?.removeInternetStateListener();
2022-03-03 22:31:23 +05:00
sub?.remove();
2021-10-02 10:09:12 +05:00
unsubIAP();
};
2022-08-08 11:12:27 +05:00
}, [loading, verify]);
2021-10-02 10:09:12 +05:00
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 () => {
console.log("sync complete");
2022-07-20 22:24:58 +05:00
initAfterSync();
2021-10-02 10:09:12 +05:00
setLastSynced(await db.lastSynced());
eSendEvent(eCloseProgressDialog, "sync_progress");
2022-03-26 16:05:58 +05:00
let id = useEditorStore.getState().currentEditingNote;
let note = id && db.notes.note(id).data;
if (note) {
//await updateNoteInEditor();
2021-10-02 10:09:12 +05:00
}
};
const onUrlRecieved = async (res) => {
let url = res ? res.url : "";
2021-10-02 10:09:12 +05:00
try {
if (url.startsWith("https://app.notesnook.com/account/verified")) {
2021-10-02 10:09:12 +05:00
await onEmailVerified();
} else {
return;
}
} catch (e) {
console.error(e);
}
2021-10-02 10:09:12 +05:00
};
const onEmailVerified = async () => {
let user = await db.user.getUser();
setUser(user);
if (!user) return;
2022-03-03 15:09:30 +05:00
SettingsService.set({
userEmailConfirmed: true
});
2021-10-02 10:09:12 +05:00
await PremiumService.setPremiumStatus();
Walkthrough.present("emailconfirmed", false, true);
2021-10-02 10:09:12 +05:00
if (user?.isEmailConfirmed) {
clearMessage();
}
};
const attachIAPListeners = async () => {
await RNIap.initConnection()
.catch(() => null)
2021-10-02 10:09:12 +05:00
.then(async () => {
refValues.current.subsriptionSuccessListener =
RNIap.purchaseUpdatedListener(onSuccessfulSubscription);
refValues.current.subsriptionErrorListener =
RNIap.purchaseErrorListener(onSubscriptionError);
});
};
const onAccountStatusChange = async (userStatus) => {
2021-10-02 10:09:12 +05:00
if (!PremiumService.get() && userStatus.type === 5) {
PremiumService.subscriptions.clear();
Walkthrough.present("prouser", false, true);
2021-10-02 10:09:12 +05:00
}
await PremiumService.setPremiumStatus();
};
2022-03-08 15:17:03 +05:00
const onRequestPartialSync = async (full, force) => {
console.log("auto sync request", full, force);
2022-04-01 11:24:15 +05:00
if (full || force) {
await Sync.run("global", force, full);
2022-04-01 11:24:15 +05:00
} else {
await Sync.run("global", false, false);
2021-10-02 10:09:12 +05:00
}
};
const onLogout = async (reason) => {
console.log("LOGOUT", reason);
2021-10-02 10:09:12 +05:00
};
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 onUserUpdated = async (login) => {
2022-03-16 13:21:05 +05:00
console.log(`onUserUpdated: ${login}`);
let user;
2021-10-02 10:09:12 +05:00
try {
user = await db.user.getUser();
await PremiumService.setPremiumStatus();
setLastSynced(await db.lastSynced());
2022-07-01 16:08:59 +05:00
await useDragState.getState().init();
2022-03-03 18:03:03 +05:00
if (!user) {
return setLoginMessage();
}
2021-11-08 11:57:24 +05:00
2022-03-03 18:03:03 +05:00
let userEmailConfirmed = SettingsService.get().userEmailConfirmed;
setUser(user);
if (SettingsService.get().sessionExpired) {
2021-12-09 00:14:15 +05:00
syncedOnLaunch.current = true;
2021-10-02 10:09:12 +05:00
return;
}
2021-12-14 23:46:50 +05:00
2022-03-03 18:03:03 +05:00
clearMessage();
attachIAPListeners();
2022-01-02 02:02:18 +05:00
if (!login) {
user = await db.user.fetchUser();
setUser(user);
}
await PremiumService.setPremiumStatus();
2022-07-09 09:45:16 +05:00
if (user?.isEmailConfirmed && !userEmailConfirmed) {
2022-03-03 18:03:03 +05:00
setTimeout(() => {
onEmailVerified();
}, 1000);
2022-03-03 15:09:30 +05:00
SettingsService.set({
2022-03-03 18:03:03 +05:00
userEmailConfirmed: true
2022-03-03 15:09:30 +05:00
});
2022-01-02 02:02:18 +05:00
}
2022-04-12 13:30:35 +05:00
} catch (e) {
ToastEvent.error(e, "An error occured", "global");
2022-04-12 13:30:35 +05:00
}
2022-03-03 18:03:03 +05:00
user = await db.user.getUser();
2022-03-18 14:40:15 +05:00
if (
user?.isEmailConfirmed &&
!SettingsService.get().recoveryKeySaved &&
!useMessageStore.getState().message?.visible
) {
2022-03-03 18:03:03 +05:00
setRecoveryKeyMessage();
}
2022-07-09 09:45:16 +05:00
if (!user?.isEmailConfirmed) setEmailVerifyMessage();
2022-03-03 18:03:03 +05:00
refValues.current.isUserReady = true;
2022-03-03 18:03:03 +05:00
syncedOnLaunch.current = true;
2021-10-02 10:09:12 +05:00
};
const onSuccessfulSubscription = async (subscription) => {
2021-10-02 10:09:12 +05:00
await PremiumService.subscriptions.set(subscription);
await PremiumService.subscriptions.verify(subscription);
};
const onSubscriptionError = async (error) => {
2021-10-02 10:09:12 +05:00
ToastEvent.show({
heading: "Failed to subscribe",
type: "error",
2021-10-02 10:09:12 +05:00
message: error.message,
context: "local"
2021-10-02 10:09:12 +05:00
});
};
const onAppStateChanged = async (state) => {
console.log("onAppStateChanged");
if (state === "active") {
2021-10-02 10:09:12 +05:00
updateStatusBarColor();
if (
SettingsService.get().appLockMode !== "background" &&
2021-10-02 10:09:12 +05:00
!SettingsService.get().privacyScreen
) {
enabled(false);
}
if (SettingsService.get().appLockMode === "background") {
if (useSettingStore.getState().requestBiometrics) {
useSettingStore.getState().setRequestBiometrics(false);
return;
}
2021-10-02 10:09:12 +05:00
}
await reconnectSSE();
2021-10-02 10:09:12 +05:00
await checkIntentState();
MMKV.removeItem("appState");
2021-10-02 10:09:12 +05:00
let user = await db.user.getUser();
2022-07-09 09:45:16 +05:00
if (user && !user?.isEmailConfirmed) {
2021-10-02 10:09:12 +05:00
try {
let user = await db.user.fetchUser();
if (user?.isEmailConfirmed) {
onEmailVerified();
}
} catch (e) {
console.error(e);
}
2021-10-02 10:09:12 +05:00
}
} else {
2022-03-26 16:05:58 +05:00
let id = useEditorStore.getState().currentEditingNote;
let note = id && db.notes.note(id).data;
if (note?.locked && SettingsService.get().appLockMode === "background") {
2021-10-02 10:09:12 +05:00
eSendEvent(eClearEditor);
}
await storeAppState();
if (
SettingsService.get().appLockMode === "background" &&
!useSettingStore.getState().requestBiometrics &&
!useUserStore.getState().verifyUser
) {
useUserStore.getState().setVerifyUser(true);
}
if (
SettingsService.get().privacyScreen ||
SettingsService.get().appLockMode === "background"
2021-10-02 10:09:12 +05:00
) {
!useSettingStore.getState().requestBiometrics ? enabled(true) : null;
2021-10-02 10:09:12 +05:00
}
}
};
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;
}
2022-03-03 18:03:03 +05:00
if (SettingsService.get().sessionExpired) {
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;
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() {
2022-03-26 16:05:58 +05:00
if (editorState().currentlyEditing) {
let id = useEditorStore.getState().currentEditingNote;
let note = id && db.notes.note(id).data;
if (note?.locked) return;
2021-10-02 10:09:12 +05:00
let state = JSON.stringify({
2022-03-26 16:05:58 +05:00
editing: editorState().currentlyEditing,
note: note,
movedAway: editorState().movedAway,
2021-10-02 10:09:12 +05:00
timestamp: Date.now()
});
MMKV.setString("appState", state);
2021-10-02 10:09:12 +05:00
}
}
async function checkIntentState() {
try {
let notesAddedFromIntent = MMKV.getString("notesAddedFromIntent");
let shareExtensionOpened = MMKV.getString("shareExtensionOpened");
if (notesAddedFromIntent) {
if (Platform.OS === "ios") {
2021-10-02 10:09:12 +05:00
await db.init();
await db.notes.init();
}
useNoteStore.getState().setNotes();
eSendEvent(refreshNotesPage);
MMKV.removeItem("notesAddedFromIntent");
2022-07-20 22:24:58 +05:00
initAfterSync();
2021-10-02 10:09:12 +05:00
eSendEvent(refreshNotesPage);
}
console.log(
"CHECK INTENT STATE",
notesAddedFromIntent || shareExtensionOpened
);
if (notesAddedFromIntent || shareExtensionOpened) {
2022-03-26 16:05:58 +05:00
let id = useEditorStore.getState().currentEditingNote;
let note = id && db.notes.note(id).data;
eSendEvent("loadingNote", note);
eSendEvent("webview_reset");
MMKV.removeItem("shareExtensionOpened");
}
} catch (e) {
console.log(e);
}
2021-10-02 10:09:12 +05:00
}
return true;
};