Files
notesnook/apps/mobile/app/services/navigation.ts
2025-12-12 09:37:20 +05:00

213 lines
6.3 KiB
TypeScript
Executable File

/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { NavigationHelpers, StackActions } from "@react-navigation/native";
import { NativeStackScreenProps } from "@react-navigation/native-stack";
import { useFavoriteStore } from "../stores/use-favorite-store";
import useNavigationStore, {
GenericRouteParam,
RouteName,
RouteParams
} from "../stores/use-navigation-store";
import { useNotebookStore } from "../stores/use-notebook-store";
import { useNoteStore } from "../stores/use-notes-store";
import { useReminderStore } from "../stores/use-reminder-store";
import { useTagStore } from "../stores/use-tag-store";
import { useTrashStore } from "../stores/use-trash-store";
import { eOnRefreshSearch, eUpdateNotebookRoute } from "../utils/events";
import {
appNavigatorRef,
fluidTabsRef,
rootNavigatorRef
} from "../utils/global-refs";
import { eSendEvent } from "./event-manager";
import { useArchivedStore } from "../stores/use-archived-store";
/**
* Routes that should be updated on focus
*/
let routesUpdateQueue: RouteName[] = [];
const routeNames = {
Notes: "Notes",
Notebooks: "Notebooks",
Notebook: "Notebook",
NotesPage: "NotesPage",
Tags: "Tags",
Favorites: "Favorites",
Trash: "Trash",
Search: "Search",
Settings: "Settings",
TaggedNotes: "TaggedNotes",
ColoredNotes: "ColoredNotes",
TopicNotes: "TopicNotes",
Monographs: "Monographs",
Auth: "Auth",
Intro: "Intro",
Welcome: "Welcome",
AppLock: "AppLock",
Login: "Login",
Signup: "Signup",
Reminders: "Reminders",
MoveNotebook: "MoveNotebook",
LinkNotebooks: "LinkNotebooks",
MoveNotes: "MoveNotes",
Archive: "Archive",
ManageTags: "ManageTags",
AddReminder: "AddReminder",
PayWall: "PayWall",
Wrapped: "Wrapped"
};
export type NavigationProps<T extends RouteName> = NativeStackScreenProps<
RouteParams,
T
>;
/**
* Functions to update each route when required.
*/
const routeUpdateFunctions: {
[name: string]: (...params: GenericRouteParam[]) => void;
} = {
Notes: () => useNoteStore.getState().refresh(),
Notebooks: () => useNotebookStore.getState().refresh(),
Tags: () => useTagStore.getState().refresh(),
Favorites: () => useFavoriteStore.getState().refresh(),
Trash: () => useTrashStore.getState().refresh(),
Notebook: (params) => eSendEvent(eUpdateNotebookRoute, params),
NotesPage: (params) => eSendEvent("NotesPage", params),
TaggedNotes: (params) => eSendEvent("TaggedNotes", params),
ColoredNotes: (params) => eSendEvent("ColoredNotes", params),
TopicNotes: (params) => eSendEvent("TopicNotes", params),
Monographs: (params) => eSendEvent("Monographs", params),
Reminders: () => useReminderStore.getState().refresh(),
Search: () => eSendEvent(eOnRefreshSearch),
Archive: () => useArchivedStore.getState().refresh()
};
function clearRouteFromQueue(routeName: RouteName) {
if (routesUpdateQueue.indexOf(routeName) !== -1) {
routesUpdateQueue = [...new Set(routesUpdateQueue)];
routesUpdateQueue.splice(routesUpdateQueue.indexOf(routeName), 1);
}
}
/**
* Check if a route needs update
*/
function routeNeedsUpdate(routeName: RouteName, callback: () => void) {
if (routesUpdateQueue.indexOf(routeName) > -1) {
clearRouteFromQueue(routeName);
callback();
}
}
function queueRoutesForUpdate(...routesToUpdate: RouteName[]) {
const routes =
routesToUpdate?.length > 0
? routesToUpdate
: (Object.keys(routeNames) as (keyof RouteParams)[]);
const currentRoute = useNavigationStore.getState().currentRoute;
if (routes.indexOf(currentRoute) > -1) {
routeUpdateFunctions[currentRoute]?.();
clearRouteFromQueue(currentRoute);
// Remove focused screen from queue
routes.splice(routes.indexOf(currentRoute), 1);
}
routesUpdateQueue = routesUpdateQueue.concat(routes);
routesUpdateQueue = [...new Set(routesUpdateQueue)];
}
function navigate<T extends RouteName>(screen: T, params?: RouteParams[T]) {
console.log(`Navigation.navigate ${screen} route`);
rootNavigatorRef.current?.navigate(screen as any, params);
}
function goBack() {
rootNavigatorRef.current?.goBack();
}
function push<T extends RouteName>(screen: T, params: RouteParams[T]) {
console.log(`Navigation.push ${screen} route`);
rootNavigatorRef.current?.dispatch(StackActions.push(screen as any, params));
}
function replace<T extends RouteName>(screen: T, params: RouteParams[T]) {
console.log(`Navigation.replace ${screen} route`);
rootNavigatorRef.current?.dispatch(
StackActions.replace(screen as string, params)
);
}
function popToTop() {
console.log(`Navigation.popToTop`);
appNavigatorRef.current?.dispatch(StackActions.popToTop());
}
function openDrawer() {
fluidTabsRef.current?.openDrawer();
}
function closeDrawer() {
fluidTabsRef.current?.closeDrawer();
}
function resetRootState(
_state?: ReturnType<NavigationHelpers<any, any>["getState"]>
) {
const state = _state || rootNavigatorRef.getState();
const focusedRoute = state.routes[state.index];
if (state.routes.length < 2) return;
const routes = state.routes.filter(
(route) =>
(route.name !== "Auth" && route.name !== "Welcome") ||
route.key === focusedRoute.key
);
if (routes.length === state.routes.length) return;
if (routes.length === 0) {
routes.push(focusedRoute);
}
const newIndex = routes.findIndex((route) => route.key === focusedRoute.key);
rootNavigatorRef.reset({
...state,
routes: routes,
index: newIndex
});
}
const Navigation = {
navigate,
goBack,
push,
openDrawer,
closeDrawer,
replace,
popToTop,
queueRoutesForUpdate,
routeNeedsUpdate,
routeNames,
routeUpdateFunctions,
resetRootState
};
export default Navigation;