2022-08-31 06:33:37 +05:00
|
|
|
/*
|
|
|
|
|
This file is part of the Notesnook project (https://notesnook.com/)
|
|
|
|
|
|
2023-01-16 13:44:52 +05:00
|
|
|
Copyright (C) 2023 Streetwriters (Private) Limited
|
2022-08-31 06:33:37 +05:00
|
|
|
|
|
|
|
|
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/>.
|
|
|
|
|
*/
|
2022-08-30 16:13:11 +05:00
|
|
|
|
2024-04-09 15:35:07 +05:00
|
|
|
import { resolveItems } from "@notesnook/common";
|
2023-11-22 11:16:15 +05:00
|
|
|
import { VirtualizedGrouping } from "@notesnook/core";
|
2024-09-23 15:18:44 +05:00
|
|
|
import { Color, Note } from "@notesnook/core";
|
2022-08-29 16:19:17 +05:00
|
|
|
import React, { useEffect, useRef, useState } from "react";
|
2024-04-09 15:35:07 +05:00
|
|
|
import { db } from "../../common/database";
|
2022-08-26 16:19:39 +05:00
|
|
|
import { FloatingButton } from "../../components/container/floating-button";
|
|
|
|
|
import DelayLayout from "../../components/delay-layout";
|
2023-11-22 11:16:15 +05:00
|
|
|
import { Header } from "../../components/header";
|
2022-08-26 16:19:39 +05:00
|
|
|
import List from "../../components/list";
|
2023-11-22 11:16:15 +05:00
|
|
|
import { PlaceholderData } from "../../components/list/empty";
|
2024-04-09 15:35:07 +05:00
|
|
|
import SelectionHeader from "../../components/selection-header";
|
2022-08-26 16:19:39 +05:00
|
|
|
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
|
|
|
|
import {
|
|
|
|
|
eSubscribeEvent,
|
|
|
|
|
eUnSubscribeEvent
|
|
|
|
|
} from "../../services/event-manager";
|
2022-08-30 18:27:09 +05:00
|
|
|
import Navigation, { NavigationProps } from "../../services/navigation";
|
2022-08-26 16:19:39 +05:00
|
|
|
import useNavigationStore, {
|
|
|
|
|
HeaderRightButton,
|
2022-08-30 18:27:09 +05:00
|
|
|
NotesScreenParams,
|
2022-08-26 16:19:39 +05:00
|
|
|
RouteName
|
|
|
|
|
} from "../../stores/use-navigation-store";
|
2023-11-22 11:16:15 +05:00
|
|
|
import { setOnFirstSave } from "./common";
|
2024-08-13 15:13:46 +05:00
|
|
|
import { strings } from "@notesnook/intl";
|
2022-04-24 05:59:14 +05:00
|
|
|
|
2022-04-25 00:37:09 +05:00
|
|
|
export interface RouteProps<T extends RouteName> extends NavigationProps<T> {
|
2023-11-16 08:54:37 +05:00
|
|
|
get: (
|
|
|
|
|
params: NotesScreenParams,
|
|
|
|
|
grouped?: boolean
|
|
|
|
|
) => Promise<VirtualizedGrouping<Note> | Note[]>;
|
|
|
|
|
placeholder: PlaceholderData;
|
2022-04-24 05:59:14 +05:00
|
|
|
onPressFloatingButton: () => void;
|
|
|
|
|
focusControl?: boolean;
|
|
|
|
|
canGoBack?: boolean;
|
|
|
|
|
rightButtons?: (params: NotesScreenParams) => HeaderRightButton[];
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-08 20:54:55 +05:00
|
|
|
function getItemType(routeName: RouteName) {
|
2022-08-26 16:19:39 +05:00
|
|
|
if (routeName === "TaggedNotes") return "tag";
|
|
|
|
|
if (routeName === "ColoredNotes") return "color";
|
|
|
|
|
if (routeName === "Monographs") return "monograph";
|
|
|
|
|
return "note";
|
2022-07-08 20:54:55 +05:00
|
|
|
}
|
|
|
|
|
|
2022-04-24 05:59:14 +05:00
|
|
|
const NotesPage = ({
|
|
|
|
|
route,
|
|
|
|
|
navigation,
|
|
|
|
|
get,
|
2023-11-16 08:54:37 +05:00
|
|
|
placeholder,
|
2022-04-24 05:59:14 +05:00
|
|
|
onPressFloatingButton,
|
2022-06-13 10:55:34 +05:00
|
|
|
focusControl = true,
|
2022-04-24 05:59:14 +05:00
|
|
|
rightButtons
|
2024-04-09 15:35:07 +05:00
|
|
|
}: RouteProps<"NotesPage" | "TaggedNotes" | "Monographs" | "ColoredNotes">) => {
|
2022-04-24 05:59:14 +05:00
|
|
|
const params = useRef<NotesScreenParams>(route?.params);
|
2023-11-16 08:54:37 +05:00
|
|
|
const [notes, setNotes] = useState<VirtualizedGrouping<Note>>();
|
|
|
|
|
const [loadingNotes, setLoadingNotes] = useState(true);
|
2022-08-26 16:19:39 +05:00
|
|
|
const isMonograph = route.name === "Monographs";
|
2023-11-22 11:16:15 +05:00
|
|
|
const title =
|
|
|
|
|
params.current?.item.type === "tag"
|
|
|
|
|
? "#" + params.current?.item.title
|
|
|
|
|
: params.current?.item.title;
|
|
|
|
|
const accentColor =
|
|
|
|
|
route.name === "ColoredNotes"
|
|
|
|
|
? (params.current?.item as Color)?.colorCode
|
|
|
|
|
: undefined;
|
2024-04-30 20:15:21 +05:00
|
|
|
const updateOnFocus = useRef(false);
|
2022-04-24 05:59:14 +05:00
|
|
|
const isFocused = useNavigationFocus(navigation, {
|
2022-08-26 16:19:39 +05:00
|
|
|
onFocus: (prev) => {
|
2024-04-30 20:15:21 +05:00
|
|
|
if (updateOnFocus.current) {
|
|
|
|
|
onRequestUpdate();
|
|
|
|
|
updateOnFocus.current = false;
|
|
|
|
|
} else {
|
|
|
|
|
Navigation.routeNeedsUpdate(route.name, onRequestUpdate);
|
|
|
|
|
}
|
2022-04-24 05:59:14 +05:00
|
|
|
syncWithNavigation();
|
2022-06-11 15:12:50 +05:00
|
|
|
if (focusControl) return !prev.current;
|
2022-04-24 05:59:14 +05:00
|
|
|
return false;
|
|
|
|
|
},
|
|
|
|
|
onBlur: () => {
|
2024-04-30 20:15:21 +05:00
|
|
|
updateOnFocus.current = false;
|
2022-04-24 05:59:14 +05:00
|
|
|
setOnFirstSave(null);
|
|
|
|
|
return false;
|
|
|
|
|
},
|
|
|
|
|
focusOnInit: !focusControl
|
|
|
|
|
});
|
|
|
|
|
|
2022-08-30 18:27:09 +05:00
|
|
|
const syncWithNavigation = React.useCallback(() => {
|
2023-11-22 11:16:15 +05:00
|
|
|
const { item } = params.current;
|
|
|
|
|
useNavigationStore
|
|
|
|
|
.getState()
|
|
|
|
|
.setFocusedRouteId(params?.current?.item?.id || route.name);
|
2022-04-24 05:59:14 +05:00
|
|
|
|
|
|
|
|
!isMonograph &&
|
|
|
|
|
setOnFirstSave({
|
2022-07-08 20:54:55 +05:00
|
|
|
type: getItemType(route.name),
|
2023-11-22 11:16:15 +05:00
|
|
|
id: item.id
|
2022-04-24 05:59:14 +05:00
|
|
|
});
|
2023-11-24 15:11:38 +05:00
|
|
|
}, [isMonograph, route.name]);
|
2022-08-30 18:27:09 +05:00
|
|
|
|
|
|
|
|
const onRequestUpdate = React.useCallback(
|
2023-11-16 08:54:37 +05:00
|
|
|
async (data?: NotesScreenParams) => {
|
2024-04-30 20:15:21 +05:00
|
|
|
if (
|
|
|
|
|
useNavigationStore.getState().focusedRouteId !==
|
|
|
|
|
params.current.item.id &&
|
|
|
|
|
!data
|
|
|
|
|
) {
|
|
|
|
|
updateOnFocus.current = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-08-30 18:27:09 +05:00
|
|
|
const isNew = data && data?.item?.id !== params.current?.item?.id;
|
|
|
|
|
if (data) params.current = data;
|
2024-02-15 10:30:07 +05:00
|
|
|
|
2022-08-30 18:27:09 +05:00
|
|
|
try {
|
|
|
|
|
if (isNew) setLoadingNotes(true);
|
2023-11-16 08:54:37 +05:00
|
|
|
const notes = (await get(
|
|
|
|
|
params.current,
|
|
|
|
|
true
|
|
|
|
|
)) as VirtualizedGrouping<Note>;
|
|
|
|
|
|
2024-02-15 10:30:07 +05:00
|
|
|
if (route.name === "TaggedNotes" || route.name === "ColoredNotes") {
|
|
|
|
|
const item = await (db as any)[params.current.item.type + "s"][
|
|
|
|
|
params.current.item.type
|
|
|
|
|
](params.current.item.id);
|
|
|
|
|
|
|
|
|
|
if (!item) {
|
|
|
|
|
Navigation.goBack();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
params.current.item = item;
|
|
|
|
|
params.current.title = item.title;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-27 09:40:15 +05:00
|
|
|
if (notes.placeholders.length === 0) setLoadingNotes(false);
|
2022-08-30 18:27:09 +05:00
|
|
|
setNotes(notes);
|
2023-12-16 11:30:41 +05:00
|
|
|
await notes.item(0, resolveItems);
|
|
|
|
|
setLoadingNotes(false);
|
2022-08-30 18:27:09 +05:00
|
|
|
syncWithNavigation();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
2022-04-24 05:59:14 +05:00
|
|
|
}
|
2022-08-30 18:27:09 +05:00
|
|
|
},
|
2024-02-15 10:30:07 +05:00
|
|
|
[get, route.name, syncWithNavigation]
|
2022-08-30 18:27:09 +05:00
|
|
|
);
|
2022-04-24 05:59:14 +05:00
|
|
|
|
2022-06-13 10:55:34 +05:00
|
|
|
useEffect(() => {
|
2023-12-16 14:58:32 +05:00
|
|
|
if (loadingNotes) {
|
2023-11-16 08:54:37 +05:00
|
|
|
get(params.current, true)
|
2023-12-16 11:30:41 +05:00
|
|
|
.then(async (items) => {
|
2023-11-16 08:54:37 +05:00
|
|
|
setNotes(items as VirtualizedGrouping<Note>);
|
2023-12-16 11:30:41 +05:00
|
|
|
await (items as VirtualizedGrouping<Note>).item(0, resolveItems);
|
2023-11-16 08:54:37 +05:00
|
|
|
setLoadingNotes(false);
|
|
|
|
|
})
|
|
|
|
|
.catch((e) => {
|
|
|
|
|
setLoadingNotes(false);
|
|
|
|
|
});
|
2022-07-09 17:30:14 +05:00
|
|
|
}
|
2023-12-16 14:58:32 +05:00
|
|
|
}, [loadingNotes, get]);
|
2022-06-13 10:55:34 +05:00
|
|
|
|
2022-04-24 05:59:14 +05:00
|
|
|
useEffect(() => {
|
|
|
|
|
eSubscribeEvent(route.name, onRequestUpdate);
|
|
|
|
|
return () => {
|
2022-08-04 19:25:02 +05:00
|
|
|
setOnFirstSave(null);
|
2022-04-24 05:59:14 +05:00
|
|
|
eUnSubscribeEvent(route.name, onRequestUpdate);
|
|
|
|
|
};
|
2022-08-30 18:27:09 +05:00
|
|
|
}, [onRequestUpdate, route.name]);
|
2022-04-24 05:59:14 +05:00
|
|
|
|
|
|
|
|
return (
|
2023-11-22 11:16:15 +05:00
|
|
|
<>
|
2024-02-15 10:30:07 +05:00
|
|
|
<SelectionHeader
|
|
|
|
|
id={route.params?.item?.id}
|
|
|
|
|
items={notes}
|
|
|
|
|
type="note"
|
|
|
|
|
renderedInRoute={route.name}
|
|
|
|
|
/>
|
2023-11-22 11:16:15 +05:00
|
|
|
<Header
|
|
|
|
|
renderedInRoute={route.name}
|
2024-08-13 15:13:46 +05:00
|
|
|
title={
|
2024-11-27 13:55:41 +05:00
|
|
|
route.name === "Monographs" ? strings.routes[route.name]() : title
|
2024-08-13 15:13:46 +05:00
|
|
|
}
|
2023-11-22 11:16:15 +05:00
|
|
|
canGoBack={params?.current?.canGoBack}
|
|
|
|
|
hasSearch={true}
|
|
|
|
|
id={
|
|
|
|
|
route.name === "Monographs" ? "Monographs" : params?.current.item?.id
|
2023-11-16 08:54:37 +05:00
|
|
|
}
|
2023-11-22 11:16:15 +05:00
|
|
|
onSearch={() => {
|
2023-12-26 15:17:56 +05:00
|
|
|
const selector =
|
|
|
|
|
route.name === "Monographs"
|
|
|
|
|
? db.monographs.all
|
|
|
|
|
: db.relations.from(params.current.item, "note").selector;
|
|
|
|
|
|
2023-11-22 11:16:15 +05:00
|
|
|
Navigation.push("Search", {
|
2024-08-13 15:13:46 +05:00
|
|
|
placeholder: strings.searchInRoute(title || route.name),
|
2023-11-22 11:16:15 +05:00
|
|
|
type: "note",
|
|
|
|
|
title: title,
|
|
|
|
|
route: route.name,
|
2023-12-26 15:17:56 +05:00
|
|
|
items: selector
|
2023-11-22 11:16:15 +05:00
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
accentColor={accentColor}
|
|
|
|
|
onPressDefaultRightButton={onPressFloatingButton}
|
|
|
|
|
headerRightButtons={rightButtons?.(params?.current)}
|
2022-04-24 05:59:14 +05:00
|
|
|
/>
|
|
|
|
|
|
2023-12-16 14:58:32 +05:00
|
|
|
<DelayLayout color={accentColor} wait={loadingNotes}>
|
2023-11-22 11:16:15 +05:00
|
|
|
<List
|
|
|
|
|
data={notes}
|
|
|
|
|
dataType="note"
|
|
|
|
|
onRefresh={onRequestUpdate}
|
2023-12-16 14:58:32 +05:00
|
|
|
loading={!isFocused}
|
2023-11-24 15:11:38 +05:00
|
|
|
renderedInRoute={route.name}
|
2023-12-16 11:30:41 +05:00
|
|
|
id={params.current.item?.id}
|
2024-08-13 15:13:46 +05:00
|
|
|
headerTitle={title || "Monographs"}
|
2023-11-22 11:16:15 +05:00
|
|
|
customAccentColor={accentColor}
|
|
|
|
|
placeholder={placeholder}
|
2023-11-16 08:54:37 +05:00
|
|
|
/>
|
2023-11-22 11:16:15 +05:00
|
|
|
|
|
|
|
|
{!isMonograph &&
|
2023-12-27 09:40:15 +05:00
|
|
|
((notes?.placeholders && (notes?.placeholders?.length || 0) > 0) ||
|
|
|
|
|
isFocused) ? (
|
2024-08-13 15:13:46 +05:00
|
|
|
<FloatingButton color={accentColor} onPress={onPressFloatingButton} />
|
2023-11-22 11:16:15 +05:00
|
|
|
) : null}
|
|
|
|
|
</DelayLayout>
|
|
|
|
|
</>
|
2022-04-24 05:59:14 +05:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default NotesPage;
|