mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
mobile: refactor zustand stores
This commit is contained in:
committed by
Abdullah Atta
parent
787c36c754
commit
c444f7ddb8
@@ -31,16 +31,16 @@ import { RNSqliteDriver } from "./sqlite.kysely";
|
||||
database.host(
|
||||
__DEV__
|
||||
? {
|
||||
API_HOST: "https://api.notesnook.com",
|
||||
AUTH_HOST: "https://auth.streetwriters.co",
|
||||
SSE_HOST: "https://events.streetwriters.co",
|
||||
SUBSCRIPTIONS_HOST: "https://subscriptions.streetwriters.co",
|
||||
ISSUES_HOST: "https://issues.streetwriters.co"
|
||||
// API_HOST: "http://192.168.43.5:5264",
|
||||
// AUTH_HOST: "http://192.168.43.5:8264",
|
||||
// SSE_HOST: "http://192.168.43.5:7264",
|
||||
// SUBSCRIPTIONS_HOST: "http://192.168.43.5:9264",
|
||||
// ISSUES_HOST: "http://192.168.43.5:2624"
|
||||
// API_HOST: "https://api.notesnook.com",
|
||||
// AUTH_HOST: "https://auth.streetwriters.co",
|
||||
// SSE_HOST: "https://events.streetwriters.co",
|
||||
// SUBSCRIPTIONS_HOST: "https://subscriptions.streetwriters.co",
|
||||
// ISSUES_HOST: "https://issues.streetwriters.co"
|
||||
API_HOST: "http://192.168.43.5:5264",
|
||||
AUTH_HOST: "http://192.168.43.5:8264",
|
||||
SSE_HOST: "http://192.168.43.5:7264",
|
||||
SUBSCRIPTIONS_HOST: "http://192.168.43.5:9264",
|
||||
ISSUES_HOST: "http://192.168.43.5:2624"
|
||||
}
|
||||
: {
|
||||
API_HOST: "https://api.notesnook.com",
|
||||
@@ -59,7 +59,7 @@ database.setup({
|
||||
compress: Gzip.deflate,
|
||||
decompress: Gzip.inflate
|
||||
},
|
||||
batchSize: 500,
|
||||
batchSize: 100,
|
||||
sqliteOptions: {
|
||||
dialect: (name) => ({
|
||||
createDriver: () => {
|
||||
|
||||
@@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { useNoteStore } from "../../stores/use-notes-store";
|
||||
import { AnnouncementDialog } from "../announcements";
|
||||
import AuthModal from "../auth/auth-modal";
|
||||
import { SessionExpired } from "../auth/session-expired";
|
||||
@@ -40,7 +39,6 @@ import RestoreDataSheet from "../sheets/restore-data";
|
||||
|
||||
const DialogProvider = () => {
|
||||
const { colors } = useThemeColors();
|
||||
const loading = useNoteStore((state) => state.loading);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -57,7 +55,7 @@ const DialogProvider = () => {
|
||||
<VaultDialog colors={colors} />
|
||||
<RateAppSheet />
|
||||
<ImagePreview />
|
||||
{loading ? null : <Expiring />}
|
||||
<Expiring />
|
||||
<AnnouncementDialog />
|
||||
<SessionExpired />
|
||||
<PDFPreview />
|
||||
|
||||
@@ -57,7 +57,7 @@ export const openNotebook = (item: Notebook | BaseTrashItem<Notebook>) => {
|
||||
},
|
||||
onClose: async () => {
|
||||
await db.trash.delete(item.id);
|
||||
useTrashStore.getState().setTrash();
|
||||
useTrashStore.getState().refresh();
|
||||
useSelectionStore.getState().setSelectionMode(undefined);
|
||||
ToastManager.show({
|
||||
heading: "Permanently deleted items",
|
||||
|
||||
@@ -35,6 +35,12 @@ import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
import {
|
||||
NotebooksWithDateEdited,
|
||||
TagsWithDateEdited,
|
||||
isNoteResolvedData,
|
||||
resolveItems
|
||||
} from "../../stores/resolve-items";
|
||||
import { RouteName } from "../../stores/use-navigation-store";
|
||||
import { eOpenJumpToDialog } from "../../utils/events";
|
||||
import { SectionHeader } from "../list-items/headers/section-header";
|
||||
@@ -43,10 +49,6 @@ import { NotebookWrapper } from "../list-items/notebook/wrapper";
|
||||
import ReminderItem from "../list-items/reminder";
|
||||
import TagItem from "../list-items/tag";
|
||||
|
||||
export type WithDateEdited<T> = { items: T[]; dateEdited: number };
|
||||
export type NotebooksWithDateEdited = WithDateEdited<Notebook>;
|
||||
export type TagsWithDateEdited = WithDateEdited<Tag>;
|
||||
|
||||
type ListItemWrapperProps<TItem = Item> = {
|
||||
group?: GroupingKey;
|
||||
items: VirtualizedGrouping<TItem> | undefined;
|
||||
@@ -279,137 +281,3 @@ function getDate(item: Item, groupType?: GroupingKey): number {
|
||||
) || 0
|
||||
);
|
||||
}
|
||||
|
||||
function withDateEdited<
|
||||
T extends { dateEdited: number } | { dateModified: number }
|
||||
>(items: T[]): WithDateEdited<T> {
|
||||
let latestDateEdited = 0;
|
||||
items.forEach((item) => {
|
||||
const date = "dateEdited" in item ? item.dateEdited : item.dateModified;
|
||||
if (latestDateEdited < date) latestDateEdited = date;
|
||||
});
|
||||
return { dateEdited: latestDateEdited, items };
|
||||
}
|
||||
|
||||
export async function resolveItems(ids: string[], items: Item[]) {
|
||||
if (!ids.length || !items.length) return [];
|
||||
|
||||
const { type } = items[0];
|
||||
if (type === "note") return resolveNotes(ids);
|
||||
else if (type === "notebook") {
|
||||
return Promise.all(ids.map((id) => db.notebooks.totalNotes(id)));
|
||||
} else if (type === "tag") {
|
||||
return Promise.all(
|
||||
ids.map((id) => db.relations.from({ id, type: "tag" }, "note").count())
|
||||
);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
type NoteResolvedData = {
|
||||
notebooks?: NotebooksWithDateEdited;
|
||||
reminder?: Reminder;
|
||||
color?: Color;
|
||||
tags?: TagsWithDateEdited;
|
||||
attachmentsCount?: number;
|
||||
};
|
||||
async function resolveNotes(ids: string[]) {
|
||||
console.time("relations");
|
||||
const relations = [
|
||||
...(await db.relations
|
||||
.to({ type: "note", ids }, ["notebook", "tag", "color"])
|
||||
.get()),
|
||||
...(await db.relations.from({ type: "note", ids }, "reminder").get())
|
||||
];
|
||||
console.timeEnd("relations");
|
||||
const relationIds: {
|
||||
notebooks: Set<string>;
|
||||
colors: Set<string>;
|
||||
tags: Set<string>;
|
||||
reminders: Set<string>;
|
||||
} = {
|
||||
colors: new Set(),
|
||||
notebooks: new Set(),
|
||||
tags: new Set(),
|
||||
reminders: new Set()
|
||||
};
|
||||
|
||||
const grouped: Record<
|
||||
string,
|
||||
{
|
||||
notebooks: string[];
|
||||
color?: string;
|
||||
tags: string[];
|
||||
reminder?: string;
|
||||
}
|
||||
> = {};
|
||||
for (const relation of relations) {
|
||||
const noteId =
|
||||
relation.toType === "reminder" ? relation.fromId : relation.toId;
|
||||
const data = grouped[noteId] || {
|
||||
notebooks: [],
|
||||
tags: []
|
||||
};
|
||||
|
||||
if (relation.toType === "reminder" && !data.reminder) {
|
||||
data.reminder = relation.toId;
|
||||
relationIds.reminders.add(relation.toId);
|
||||
} else if (relation.fromType === "notebook" && data.notebooks.length < 2) {
|
||||
data.notebooks.push(relation.fromId);
|
||||
relationIds.notebooks.add(relation.fromId);
|
||||
} else if (relation.fromType === "tag" && data.tags.length < 3) {
|
||||
data.tags.push(relation.fromId);
|
||||
relationIds.tags.add(relation.fromId);
|
||||
} else if (relation.fromType === "color" && !data.color) {
|
||||
data.color = relation.fromId;
|
||||
relationIds.colors.add(relation.fromId);
|
||||
}
|
||||
grouped[noteId] = data;
|
||||
}
|
||||
|
||||
console.time("resolve");
|
||||
const resolved = {
|
||||
notebooks: await db.notebooks.all.records(
|
||||
Array.from(relationIds.notebooks)
|
||||
),
|
||||
tags: await db.tags.all.records(Array.from(relationIds.tags)),
|
||||
colors: await db.colors.all.records(Array.from(relationIds.colors)),
|
||||
reminders: await db.reminders.all.records(Array.from(relationIds.reminders))
|
||||
};
|
||||
console.timeEnd("resolve");
|
||||
|
||||
const data: NoteResolvedData[] = [];
|
||||
for (const noteId of ids) {
|
||||
const group = grouped[noteId];
|
||||
if (!group) {
|
||||
data.push({});
|
||||
continue;
|
||||
}
|
||||
|
||||
data.push({
|
||||
color: group.color ? resolved.colors[group.color] : undefined,
|
||||
reminder: group.reminder ? resolved.reminders[group.reminder] : undefined,
|
||||
tags: withDateEdited(
|
||||
group.tags.map((id) => resolved.tags[id]).filter(Boolean)
|
||||
),
|
||||
notebooks: withDateEdited(
|
||||
group.notebooks.map((id) => resolved.notebooks[id]).filter(Boolean)
|
||||
),
|
||||
attachmentsCount:
|
||||
(await db.attachments?.ofNote(noteId, "all").ids())?.length || 0
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export function isNoteResolvedData(data: unknown): data is NoteResolvedData {
|
||||
return (
|
||||
typeof data === "object" &&
|
||||
!!data &&
|
||||
"notebooks" in data &&
|
||||
"reminder" in data &&
|
||||
"color" in data &&
|
||||
"tags" in data
|
||||
);
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ export default function NotePreview({ session, content, note }) {
|
||||
context: "local",
|
||||
positivePress: async () => {
|
||||
await db.trash.delete(note.id);
|
||||
useTrashStore.getState().setTrash();
|
||||
useTrashStore.getState().refresh();
|
||||
useSelectionStore.getState().setSelectionMode(false);
|
||||
ToastManager.show({
|
||||
heading: "Permanently deleted items",
|
||||
|
||||
@@ -20,13 +20,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { Note } from "@notesnook/core";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { RefObject, useCallback, useEffect } from "react";
|
||||
import { Keyboard, TouchableOpacity, View } from "react-native";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Keyboard,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from "react-native";
|
||||
import { ActionSheetRef, FlashList } from "react-native-actions-sheet";
|
||||
import { db } from "../../../common/database";
|
||||
import { presentSheet } from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import { ItemSelection } from "../../../stores/item-selection-store";
|
||||
import { useNotebookStore } from "../../../stores/use-notebook-store";
|
||||
import {
|
||||
useNotebookStore,
|
||||
useNotebooks
|
||||
} from "../../../stores/use-notebook-store";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { useSettingStore } from "../../../stores/use-setting-store";
|
||||
@@ -39,6 +47,7 @@ import { IconButton } from "../../ui/icon-button";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { NotebookItem } from "./notebook-item";
|
||||
import { useNotebookItemSelectionStore } from "./store";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
|
||||
async function updateInitialSelectionState(items: string[]) {
|
||||
const relations = await db.relations
|
||||
@@ -85,7 +94,7 @@ const MoveNoteSheet = ({
|
||||
actionSheetRef: RefObject<ActionSheetRef>;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const notebooks = useNotebookStore((state) => state.notebooks);
|
||||
const [notebooks, loading] = useNotebooks();
|
||||
const dimensions = useSettingStore((state) => state.dimensions);
|
||||
const selectedItemsList = useSelectionStore(
|
||||
(state) => state.selectedItemsList
|
||||
@@ -234,7 +243,16 @@ const MoveNoteSheet = ({
|
||||
height: 200
|
||||
}}
|
||||
>
|
||||
<Paragraph color={colors.primary.icon}>No notebooks</Paragraph>
|
||||
{loading ? (
|
||||
<ActivityIndicator
|
||||
size={SIZE.lg}
|
||||
color={colors.primary.accent}
|
||||
/>
|
||||
) : (
|
||||
<Paragraph color={colors.primary.icon}>
|
||||
No notebooks
|
||||
</Paragraph>
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
ListFooterComponent={<View style={{ height: 50 }} />}
|
||||
|
||||
@@ -177,7 +177,7 @@ const ManageTagsSheet = (props: {
|
||||
}
|
||||
|
||||
useRelationStore.getState().update();
|
||||
useTagStore.getState().setTags();
|
||||
useTagStore.getState().refresh();
|
||||
setQuery(undefined);
|
||||
} catch (e) {
|
||||
ToastManager.show({
|
||||
@@ -225,7 +225,7 @@ const ManageTagsSheet = (props: {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
useTagStore.getState().setTags();
|
||||
useTagStore.getState().refresh();
|
||||
useRelationStore.getState().update();
|
||||
refreshTags();
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -26,7 +26,7 @@ import { ColoredNotes } from "../../screens/notes/colored";
|
||||
import Navigation from "../../services/navigation";
|
||||
import { useMenuStore } from "../../stores/use-menu-store";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useNoteStore } from "../../stores/use-notes-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { SIZE, normalize } from "../../utils/size";
|
||||
import { presentDialog } from "../dialog/functions";
|
||||
import { PressableButton } from "../ui/pressable";
|
||||
@@ -35,8 +35,11 @@ import Paragraph from "../ui/typography/paragraph";
|
||||
|
||||
export const ColorSection = React.memo(
|
||||
function ColorSection() {
|
||||
const colorNotes = useMenuStore((state) => state.colorNotes);
|
||||
const loading = useNoteStore((state) => state.loading);
|
||||
const [colorNotes, loadingColors] = useMenuStore((state) => [
|
||||
state.colorNotes,
|
||||
state.loadingColors
|
||||
]);
|
||||
const loading = useSettingStore((state) => state.isAppLoading);
|
||||
const setColorNotes = useMenuStore((state) => state.setColorNotes);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -45,9 +48,11 @@ export const ColorSection = React.memo(
|
||||
}
|
||||
}, [loading, setColorNotes]);
|
||||
|
||||
return colorNotes.map((item) => {
|
||||
return <ColorItem key={item.id} item={item} />;
|
||||
});
|
||||
return !loadingColors
|
||||
? colorNotes.map((item) => {
|
||||
return <ColorItem key={item.id} item={item} />;
|
||||
})
|
||||
: null;
|
||||
},
|
||||
() => true
|
||||
);
|
||||
|
||||
@@ -17,6 +17,7 @@ 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 { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback } from "react";
|
||||
import { FlatList, View } from "react-native";
|
||||
import { notesnook } from "../../../e2e/test.ids";
|
||||
@@ -24,18 +25,16 @@ import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
import Navigation from "../../services/navigation";
|
||||
import { useNoteStore } from "../../stores/use-notes-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { MenuItemsList } from "../../utils/menu-items";
|
||||
import { SUBSCRIPTION_STATUS } from "../../utils/constants";
|
||||
import { eOpenPremiumDialog } from "../../utils/events";
|
||||
import { MenuItemsList } from "../../utils/menu-items";
|
||||
import { ColorSection } from "./color-section";
|
||||
import { MenuItem } from "./menu-item";
|
||||
import { TagsSection } from "./pinned-section";
|
||||
import { UserStatus } from "./user-status";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
|
||||
export const SideMenu = React.memo(
|
||||
function SideMenu() {
|
||||
@@ -44,7 +43,8 @@ export const SideMenu = React.memo(
|
||||
const subscriptionType = useUserStore(
|
||||
(state) => state.user?.subscription?.type
|
||||
);
|
||||
const loading = useNoteStore((state) => state.loading);
|
||||
const isAppLoading = useSettingStore((state) => state.isAppLoading);
|
||||
|
||||
const introCompleted = useSettingStore(
|
||||
(state) => state.settings.introCompleted
|
||||
);
|
||||
@@ -96,7 +96,7 @@ export const SideMenu = React.memo(
|
||||
[noTextMode]
|
||||
);
|
||||
|
||||
return !loading && introCompleted ? (
|
||||
return !isAppLoading && introCompleted ? (
|
||||
<View
|
||||
style={{
|
||||
height: "100%",
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { Notebook, Tag } from "@notesnook/core";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { FlatList, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../../common/database";
|
||||
@@ -28,7 +28,7 @@ import { TaggedNotes } from "../../screens/notes/tagged";
|
||||
import Navigation from "../../services/navigation";
|
||||
import { useMenuStore } from "../../stores/use-menu-store";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useNoteStore } from "../../stores/use-notes-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { SIZE, normalize } from "../../utils/size";
|
||||
import { Properties } from "../properties";
|
||||
import { Button } from "../ui/button";
|
||||
@@ -41,8 +41,8 @@ import Paragraph from "../ui/typography/paragraph";
|
||||
|
||||
export const TagsSection = React.memo(
|
||||
function TagsSection() {
|
||||
const menuPins = useMenuStore((state) => state.menuPins);
|
||||
const loading = useNoteStore((state) => state.loading);
|
||||
const [menuPins] = useMenuStore((state) => [state.menuPins]);
|
||||
const loading = useSettingStore((state) => state.isAppLoading);
|
||||
const setMenuPins = useMenuStore((state) => state.setMenuPins);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -192,7 +192,7 @@ export const useActions = ({
|
||||
});
|
||||
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
useTagStore.getState().setTags();
|
||||
useTagStore.getState().refresh();
|
||||
useMenuStore.getState().setMenuPins();
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useRelationStore.getState().update();
|
||||
@@ -223,7 +223,7 @@ export const useActions = ({
|
||||
await db.tags.remove(item.id);
|
||||
}
|
||||
setImmediate(() => {
|
||||
useTagStore.getState().setTags();
|
||||
useTagStore.getState().refresh();
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useRelationStore.getState().update();
|
||||
});
|
||||
|
||||
@@ -78,11 +78,10 @@ import {
|
||||
import PremiumService from "../services/premium";
|
||||
import SettingsService from "../services/settings";
|
||||
import Sync from "../services/sync";
|
||||
import { initAfterSync, initialize } from "../stores";
|
||||
import { initAfterSync } from "../stores";
|
||||
import { useAttachmentStore } from "../stores/use-attachment-store";
|
||||
import { useEditorStore } from "../stores/use-editor-store";
|
||||
import { useMessageStore } from "../stores/use-message-store";
|
||||
import { useNoteStore } from "../stores/use-notes-store";
|
||||
import { useSettingStore } from "../stores/use-setting-store";
|
||||
import { SyncStatus, useUserStore } from "../stores/use-user-store";
|
||||
import { updateStatusBarColor } from "../utils/colors";
|
||||
@@ -278,7 +277,7 @@ const onSubscriptionError = async (error: RNIap.PurchaseError) => {
|
||||
const SodiumEventEmitter = new NativeEventEmitter(NativeModules.Sodium);
|
||||
|
||||
export const useAppEvents = () => {
|
||||
const loading = useNoteStore((state) => state.loading);
|
||||
const loading = useSettingStore((state) => state.isAppLoading);
|
||||
const [setLastSynced, setUser, appLocked, syncing] = useUserStore((state) => [
|
||||
state.setLastSynced,
|
||||
state.setUser,
|
||||
@@ -628,8 +627,7 @@ export const useAppEvents = () => {
|
||||
if (!db.isInitialized) {
|
||||
await db.init();
|
||||
}
|
||||
await initialize();
|
||||
useNoteStore.getState().setLoading(false);
|
||||
useSettingStore.getState().setAppLoading(false);
|
||||
},
|
||||
disableClosing: true
|
||||
});
|
||||
@@ -657,9 +655,8 @@ export const useAppEvents = () => {
|
||||
}
|
||||
}
|
||||
if (IsDatabaseMigrationRequired()) return;
|
||||
initialize();
|
||||
setImmediate(() => {
|
||||
useNoteStore.getState().setLoading(false);
|
||||
useSettingStore.getState().setAppLoading(false);
|
||||
});
|
||||
Walkthrough.init();
|
||||
} catch (e) {
|
||||
@@ -675,7 +672,7 @@ export const useAppEvents = () => {
|
||||
if (
|
||||
!state.appLocked &&
|
||||
db.isInitialized &&
|
||||
useNoteStore.getState().loading
|
||||
useSettingStore.getState().isAppLoading
|
||||
) {
|
||||
initializeDatabase();
|
||||
sub();
|
||||
|
||||
@@ -132,7 +132,7 @@ const Tabs = React.memo(_Tabs, () => true);
|
||||
|
||||
const _NavigationStack = () => {
|
||||
const clearSelection = useSelectionStore((state) => state.clearSelection);
|
||||
const loading = useNoteStore((state) => state.loading);
|
||||
const loading = useSettingStore((state) => state.isAppLoading);
|
||||
const onStateChange = React.useCallback(() => {
|
||||
if (useSelectionStore.getState().selectionMode) {
|
||||
clearSelection(true);
|
||||
|
||||
@@ -138,7 +138,7 @@ export const useEditorEvents = (
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
const fullscreen = useSettingStore((state) => state.fullscreen);
|
||||
const corsProxy = useSettingStore((state) => state.settings.corsProxy);
|
||||
const loading = useNoteStore((state) => state.loading);
|
||||
const loading = useSettingStore((state) => state.isAppLoading);
|
||||
const [dateFormat, timeFormat] = useSettingStore((state) => [
|
||||
state.dateFormat,
|
||||
state.timeFormat
|
||||
@@ -405,7 +405,7 @@ export const useEditorEvents = (
|
||||
db.relations
|
||||
.unlink(editorMessage.value as ItemReference, editor.note.current)
|
||||
.then(async () => {
|
||||
useTagStore.getState().setTags();
|
||||
useTagStore.getState().refresh();
|
||||
useRelationStore.getState().update();
|
||||
await editor.commands.setTags(editor.note.current);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
|
||||
@@ -48,7 +48,7 @@ import Notifications from "../../../services/notifications";
|
||||
import SettingsService from "../../../services/settings";
|
||||
import { TipManager } from "../../../services/tip-manager";
|
||||
import { useEditorStore } from "../../../stores/use-editor-store";
|
||||
import { useNoteStore } from "../../../stores/use-notes-store";
|
||||
import { useSettingStore } from "../../../stores/use-setting-store";
|
||||
import { useTagStore } from "../../../stores/use-tag-store";
|
||||
import { eClearEditor, eOnLoadNote } from "../../../utils/events";
|
||||
import { tabBarRef } from "../../../utils/global-refs";
|
||||
@@ -90,7 +90,7 @@ export const useEditor = (
|
||||
const sessionHistoryId = useRef<number>();
|
||||
const state = useRef<Partial<EditorState>>(defaultState);
|
||||
const placeholderTip = useRef(TipManager.placeholderTip());
|
||||
const tags = useTagStore((state) => state.tags);
|
||||
const tags = useTagStore((state) => state.items);
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
const isDefaultEditor = editorId === "";
|
||||
const saveCount = useRef(0);
|
||||
@@ -585,9 +585,9 @@ export const useEditor = (
|
||||
tabBarRef.current?.goToPage(1, false);
|
||||
}
|
||||
if (appState.note) {
|
||||
if (useNoteStore.getState().loading) {
|
||||
const remove = useNoteStore.subscribe((state) => {
|
||||
if (!state.loading && appState.note) {
|
||||
if (useSettingStore.getState().isAppLoading) {
|
||||
const remove = useSettingStore.subscribe((state) => {
|
||||
if (!state.isAppLoading && appState.note) {
|
||||
loadNote({
|
||||
item: appState.note
|
||||
});
|
||||
|
||||
@@ -21,21 +21,18 @@ import React from "react";
|
||||
import DelayLayout from "../../components/delay-layout";
|
||||
import { Header } from "../../components/header";
|
||||
import List from "../../components/list";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import SettingsService from "../../services/settings";
|
||||
import { useFavoriteStore } from "../../stores/use-favorite-store";
|
||||
import { useFavorites } from "../../stores/use-favorite-store";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useNoteStore } from "../../stores/use-notes-store";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
|
||||
export const Favorites = ({
|
||||
navigation,
|
||||
route
|
||||
}: NavigationProps<"Favorites">) => {
|
||||
const favorites = useFavoriteStore((state) => state.favorites);
|
||||
const setFavorites = useFavoriteStore((state) => state.setFavorites);
|
||||
const loading = useNoteStore((state) => state.loading);
|
||||
const [favorites, loading, refresh] = useFavorites();
|
||||
const isFocused = useNavigationFocus(navigation, {
|
||||
onFocus: (prev) => {
|
||||
Navigation.routeNeedsUpdate(
|
||||
@@ -43,7 +40,7 @@ export const Favorites = ({
|
||||
Navigation.routeUpdateFunctions[route.name]
|
||||
);
|
||||
useNavigationStore.getState().setFocusedRouteId(route?.name);
|
||||
return !prev?.current;
|
||||
return false;
|
||||
},
|
||||
onBlur: () => false,
|
||||
delay: SettingsService.get().homepage === route.name ? 1 : -1
|
||||
@@ -75,10 +72,10 @@ export const Favorites = ({
|
||||
data={favorites}
|
||||
dataType="note"
|
||||
onRefresh={() => {
|
||||
setFavorites();
|
||||
refresh();
|
||||
}}
|
||||
renderedInRoute="Favorites"
|
||||
loading={loading || !isFocused}
|
||||
loading={loading}
|
||||
placeholder={{
|
||||
title: "Your favorites",
|
||||
paragraph: "You have not added any notes to favorites yet.",
|
||||
|
||||
@@ -22,17 +22,16 @@ import { FloatingButton } from "../../components/container/floating-button";
|
||||
import DelayLayout from "../../components/delay-layout";
|
||||
import { Header } from "../../components/header";
|
||||
import List from "../../components/list";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import SettingsService from "../../services/settings";
|
||||
import { useNoteStore } from "../../stores/use-notes-store";
|
||||
import { openEditor } from "../notes/common";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { useNotes } from "../../stores/use-notes-store";
|
||||
import { openEditor } from "../notes/common";
|
||||
|
||||
export const Home = ({ navigation, route }: NavigationProps<"Notes">) => {
|
||||
const notes = useNoteStore((state) => state.notes);
|
||||
const loading = useNoteStore((state) => state.loading);
|
||||
const [notes, loading] = useNotes();
|
||||
const isFocused = useNavigationFocus(navigation, {
|
||||
onFocus: (prev) => {
|
||||
Navigation.routeNeedsUpdate(
|
||||
|
||||
@@ -39,12 +39,12 @@ import { eUpdateNotebookRoute } from "../../utils/events";
|
||||
import { findRootNotebookId } from "../../utils/notebooks";
|
||||
import { openEditor, setOnFirstSave } from "../notes/common";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { resolveItems } from "../../components/list/list-item.wrapper";
|
||||
import Paragraph from "../../components/ui/typography/paragraph";
|
||||
import { View } from "react-native";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { IconButton } from "../../components/ui/icon-button";
|
||||
import { PressableButton } from "../../components/ui/pressable";
|
||||
import { resolveItems } from "../../stores/resolve-items";
|
||||
|
||||
const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
|
||||
const [notes, setNotes] = useState<VirtualizedGrouping<Note>>();
|
||||
|
||||
@@ -23,14 +23,14 @@ import { FloatingButton } from "../../components/container/floating-button";
|
||||
import DelayLayout from "../../components/delay-layout";
|
||||
import { Header } from "../../components/header";
|
||||
import List from "../../components/list";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { AddNotebookSheet } from "../../components/sheets/add-notebook";
|
||||
import { Walkthrough } from "../../components/walkthroughs";
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import SettingsService from "../../services/settings";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useNotebookStore } from "../../stores/use-notebook-store";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { useNotebooks } from "../../stores/use-notebook-store";
|
||||
|
||||
const onButtonPress = () => {
|
||||
AddNotebookSheet.present();
|
||||
@@ -40,7 +40,8 @@ export const Notebooks = ({
|
||||
navigation,
|
||||
route
|
||||
}: NavigationProps<"Notebooks">) => {
|
||||
const notebooks = useNotebookStore((state) => state.notebooks);
|
||||
const [notebooks, loading] = useNotebooks();
|
||||
|
||||
const isFocused = useNavigationFocus(navigation, {
|
||||
onFocus: (prev) => {
|
||||
Navigation.routeNeedsUpdate(
|
||||
@@ -48,7 +49,7 @@ export const Notebooks = ({
|
||||
Navigation.routeUpdateFunctions[route.name]
|
||||
);
|
||||
useNavigationStore.getState().setFocusedRouteId(route.name);
|
||||
return !prev?.current;
|
||||
return false;
|
||||
},
|
||||
onBlur: () => false,
|
||||
delay: SettingsService.get().homepage === route.name ? 1 : -1
|
||||
@@ -83,12 +84,11 @@ export const Notebooks = ({
|
||||
}}
|
||||
onPressDefaultRightButton={onButtonPress}
|
||||
/>
|
||||
<DelayLayout>
|
||||
<DelayLayout wait={loading}>
|
||||
<List
|
||||
data={notebooks}
|
||||
dataType="notebook"
|
||||
renderedInRoute="Notebooks"
|
||||
loading={!isFocused}
|
||||
placeholder={{
|
||||
title: "Your notebooks",
|
||||
paragraph: "You have not added any notebooks yet.",
|
||||
|
||||
@@ -107,7 +107,7 @@ export async function onNoteCreated(noteId: string, data: FirstSaveData) {
|
||||
}
|
||||
|
||||
editorState().onNoteCreated = null;
|
||||
useTagStore.getState().setTags();
|
||||
useTagStore.getState().refresh();
|
||||
useRelationStore.getState().update();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ import useNavigationStore, {
|
||||
} from "../../stores/use-navigation-store";
|
||||
import { useNoteStore } from "../../stores/use-notes-store";
|
||||
import { setOnFirstSave } from "./common";
|
||||
import { resolveItems } from "../../components/list/list-item.wrapper";
|
||||
import { resolveItems } from "../../stores/resolve-items";
|
||||
export const WARNING_DATA = {
|
||||
title: "Some notes in this topic are not synced"
|
||||
};
|
||||
@@ -75,7 +75,6 @@ const NotesPage = ({
|
||||
>) => {
|
||||
const params = useRef<NotesScreenParams>(route?.params);
|
||||
const [notes, setNotes] = useState<VirtualizedGrouping<Note>>();
|
||||
const loading = useNoteStore((state) => state.loading);
|
||||
const [loadingNotes, setLoadingNotes] = useState(true);
|
||||
const isMonograph = route.name === "Monographs";
|
||||
const title =
|
||||
@@ -140,7 +139,7 @@ const NotesPage = ({
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (loadingNotes && !loading) {
|
||||
if (loadingNotes) {
|
||||
get(params.current, true)
|
||||
.then(async (items) => {
|
||||
setNotes(items as VirtualizedGrouping<Note>);
|
||||
@@ -152,7 +151,7 @@ const NotesPage = ({
|
||||
setLoadingNotes(false);
|
||||
});
|
||||
}
|
||||
}, [loadingNotes, loading, get]);
|
||||
}, [loadingNotes, get]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(route.name, onRequestUpdate);
|
||||
@@ -186,12 +185,12 @@ const NotesPage = ({
|
||||
headerRightButtons={rightButtons?.(params?.current)}
|
||||
/>
|
||||
|
||||
<DelayLayout color={accentColor} wait={loading || loadingNotes}>
|
||||
<DelayLayout color={accentColor} wait={loadingNotes}>
|
||||
<List
|
||||
data={notes}
|
||||
dataType="note"
|
||||
onRefresh={onRequestUpdate}
|
||||
loading={loading || !isFocused}
|
||||
loading={!isFocused}
|
||||
renderedInRoute={route.name}
|
||||
id={params.current.item?.id}
|
||||
headerTitle={title}
|
||||
|
||||
@@ -22,19 +22,19 @@ import { FloatingButton } from "../../components/container/floating-button";
|
||||
import DelayLayout from "../../components/delay-layout";
|
||||
import { Header } from "../../components/header";
|
||||
import List from "../../components/list";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import ReminderSheet from "../../components/sheets/reminder";
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import SettingsService from "../../services/settings";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useReminderStore } from "../../stores/use-reminder-store";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { useReminders } from "../../stores/use-reminder-store";
|
||||
|
||||
export const Reminders = ({
|
||||
navigation,
|
||||
route
|
||||
}: NavigationProps<"Reminders">) => {
|
||||
const reminders = useReminderStore((state) => state.reminders);
|
||||
const [reminders, loading] = useReminders();
|
||||
const isFocused = useNavigationFocus(navigation, {
|
||||
onFocus: (prev) => {
|
||||
Navigation.routeNeedsUpdate(
|
||||
@@ -43,7 +43,7 @@ export const Reminders = ({
|
||||
);
|
||||
|
||||
useNavigationStore.getState().setFocusedRouteId(route.name);
|
||||
return !prev?.current;
|
||||
return false;
|
||||
},
|
||||
onBlur: () => false,
|
||||
delay: SettingsService.get().homepage === route.name ? 1 : -1
|
||||
@@ -72,13 +72,13 @@ export const Reminders = ({
|
||||
}}
|
||||
/>
|
||||
|
||||
<DelayLayout>
|
||||
<DelayLayout wait={loading}>
|
||||
<List
|
||||
data={reminders}
|
||||
dataType="reminder"
|
||||
headerTitle="Reminders"
|
||||
renderedInRoute="Reminders"
|
||||
loading={!isFocused}
|
||||
loading={loading}
|
||||
placeholder={{
|
||||
title: "Your reminders",
|
||||
paragraph: "You have not set any reminders yet.",
|
||||
|
||||
@@ -22,7 +22,6 @@ import create, { State } from "zustand";
|
||||
import { persist, StateStorage } from "zustand/middleware";
|
||||
import { db } from "../../../common/database";
|
||||
import { MMKV } from "../../../common/database/mmkv";
|
||||
import { useNoteStore } from "../../../stores/use-notes-store";
|
||||
import { useSettingStore } from "../../../stores/use-setting-store";
|
||||
import { presets } from "./toolbar-definition";
|
||||
export type ToolDefinition = string | string[];
|
||||
@@ -124,7 +123,7 @@ export const useDragState = create<DragState>(
|
||||
getStorage: () => MMKV as unknown as StateStorage,
|
||||
onRehydrateStorage: () => {
|
||||
return () => {
|
||||
if (!useNoteStore.getState().loading) {
|
||||
if (!useSettingStore.getState().isAppLoading) {
|
||||
useDragState.getState().init();
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -297,6 +297,7 @@ export const settingsGroups: SettingSection[] = [
|
||||
await BiometicService.resetCredentials();
|
||||
MMKV.clearStore();
|
||||
clearAllStores();
|
||||
Navigation.queueRoutesForUpdate();
|
||||
SettingsService.resetSettings();
|
||||
useUserStore.getState().setUser(null);
|
||||
useUserStore.getState().setSyncing(false);
|
||||
@@ -304,7 +305,7 @@ export const settingsGroups: SettingSection[] = [
|
||||
Navigation.popToTop();
|
||||
setTimeout(() => {
|
||||
eSendEvent("settings-loading", false);
|
||||
}, 2000);
|
||||
}, 3000);
|
||||
}, 300);
|
||||
} catch (e) {
|
||||
ToastManager.error(e as Error, "Error logging out");
|
||||
|
||||
@@ -21,16 +21,15 @@ import React from "react";
|
||||
import DelayLayout from "../../components/delay-layout";
|
||||
import { Header } from "../../components/header";
|
||||
import List from "../../components/list";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import SettingsService from "../../services/settings";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useTagStore } from "../../stores/use-tag-store";
|
||||
import { db } from "../../common/database";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { useTags } from "../../stores/use-tag-store";
|
||||
|
||||
export const Tags = ({ navigation, route }: NavigationProps<"Tags">) => {
|
||||
const tags = useTagStore((state) => state.tags);
|
||||
const [tags, loading] = useTags();
|
||||
const isFocused = useNavigationFocus(navigation, {
|
||||
onFocus: (prev) => {
|
||||
Navigation.routeNeedsUpdate(
|
||||
@@ -61,7 +60,7 @@ export const Tags = ({ navigation, route }: NavigationProps<"Tags">) => {
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<DelayLayout>
|
||||
<DelayLayout wait={loading}>
|
||||
<List
|
||||
data={tags}
|
||||
dataType="tag"
|
||||
|
||||
@@ -29,7 +29,7 @@ import { ToastManager } from "../../services/event-manager";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useSelectionStore } from "../../stores/use-selection-store";
|
||||
import { useTrashStore } from "../../stores/use-trash-store";
|
||||
import { useTrash, useTrashStore } from "../../stores/use-trash-store";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
|
||||
const onPressFloatingButton = () => {
|
||||
@@ -40,7 +40,7 @@ const onPressFloatingButton = () => {
|
||||
negativeText: "Cancel",
|
||||
positivePress: async () => {
|
||||
await db.trash?.clear();
|
||||
useTrashStore.getState().setTrash();
|
||||
useTrashStore.getState().refresh();
|
||||
useSelectionStore.getState().clearSelection();
|
||||
ToastManager.show({
|
||||
heading: "Trash cleared",
|
||||
@@ -67,7 +67,7 @@ const PLACEHOLDER_DATA = (trashCleanupInterval = 7) => ({
|
||||
});
|
||||
|
||||
export const Trash = ({ navigation, route }: NavigationProps<"Trash">) => {
|
||||
const trash = useTrashStore((state) => state.trash);
|
||||
const [trash, loading] = useTrash();
|
||||
const isFocused = useNavigationFocus(navigation, {
|
||||
onFocus: () => {
|
||||
Navigation.routeNeedsUpdate(
|
||||
@@ -75,12 +75,6 @@ export const Trash = ({ navigation, route }: NavigationProps<"Trash">) => {
|
||||
Navigation.routeUpdateFunctions[route.name]
|
||||
);
|
||||
useNavigationStore.getState().setFocusedRouteId(route.name);
|
||||
if (
|
||||
!useTrashStore.getState().trash ||
|
||||
useTrashStore.getState().trash?.ids?.length === 0
|
||||
) {
|
||||
useTrashStore.getState().setTrash();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onBlur: () => false
|
||||
@@ -103,7 +97,7 @@ export const Trash = ({ navigation, route }: NavigationProps<"Trash">) => {
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<DelayLayout>
|
||||
<DelayLayout wait={loading}>
|
||||
<List
|
||||
data={trash}
|
||||
dataType="trash"
|
||||
|
||||
@@ -73,18 +73,18 @@ export type NavigationProps<T extends RouteName> = NativeStackScreenProps<
|
||||
const routeUpdateFunctions: {
|
||||
[name: string]: (...params: GenericRouteParam[]) => void;
|
||||
} = {
|
||||
Notes: () => useNoteStore.getState().setNotes(),
|
||||
Notebooks: () => useNotebookStore.getState().setNotebooks(),
|
||||
Tags: () => useTagStore.getState().setTags(),
|
||||
Favorites: () => useFavoriteStore.getState().setFavorites(),
|
||||
Trash: () => useTrashStore.getState().setTrash(),
|
||||
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().setReminders(),
|
||||
Reminders: () => useReminderStore.getState().refresh(),
|
||||
Search: () => eSendEvent(eOnRefreshSearch)
|
||||
};
|
||||
|
||||
|
||||
@@ -17,38 +17,38 @@ 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 { Reminder } from "@notesnook/core/dist/types";
|
||||
import notifee, {
|
||||
AndroidStyle,
|
||||
AuthorizationStatus,
|
||||
DisplayedNotification,
|
||||
Event,
|
||||
EventType,
|
||||
RepeatFrequency,
|
||||
TimestampTrigger,
|
||||
Trigger,
|
||||
TriggerType,
|
||||
Event,
|
||||
TriggerNotification,
|
||||
TimestampTrigger
|
||||
TriggerType
|
||||
} from "@notifee/react-native";
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
import dayjs, { Dayjs } from "dayjs";
|
||||
import { encodeNonAsciiHTML } from "entities";
|
||||
import { Platform } from "react-native";
|
||||
import { db } from "../common/database";
|
||||
import { MMKV } from "../common/database/mmkv";
|
||||
import { presentDialog } from "../components/dialog/functions";
|
||||
import { editorState } from "../screens/editor/tiptap/utils";
|
||||
import { useNoteStore } from "../stores/use-notes-store";
|
||||
import { eOnLoadNote } from "../utils/events";
|
||||
import { tabBarRef } from "../utils/global-refs";
|
||||
import { DDS } from "./device-detection";
|
||||
import { eSendEvent } from "./event-manager";
|
||||
import SettingsService from "./settings";
|
||||
import { useSettingStore } from "../stores/use-setting-store";
|
||||
import { sleep } from "../utils/time";
|
||||
import { useRelationStore } from "../stores/use-relation-store";
|
||||
import { useReminderStore } from "../stores/use-reminder-store";
|
||||
import { presentDialog } from "../components/dialog/functions";
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
import { encodeNonAsciiHTML } from "entities";
|
||||
import { useSettingStore } from "../stores/use-setting-store";
|
||||
import { eOnLoadNote } from "../utils/events";
|
||||
import { tabBarRef } from "../utils/global-refs";
|
||||
import { convertNoteToText } from "../utils/note-to-text";
|
||||
import { Reminder } from "@notesnook/core/dist/types";
|
||||
import { sleep } from "../utils/time";
|
||||
import { DDS } from "./device-detection";
|
||||
import { eSendEvent } from "./event-manager";
|
||||
import Navigation from "./navigation";
|
||||
import SettingsService from "./settings";
|
||||
|
||||
let pinned: DisplayedNotification[] = [];
|
||||
|
||||
@@ -136,19 +136,7 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
}
|
||||
editorState().movedAway = false;
|
||||
const noteId = notification?.id;
|
||||
if (useNoteStore?.getState()?.loading === false) {
|
||||
loadNote(noteId as string, false);
|
||||
return;
|
||||
}
|
||||
const unsub = useNoteStore.subscribe(
|
||||
(loading) => {
|
||||
if (loading === false) {
|
||||
loadNote(noteId as string, true);
|
||||
}
|
||||
unsub();
|
||||
},
|
||||
(state) => state.loading
|
||||
);
|
||||
loadNote(noteId as string, true);
|
||||
}
|
||||
|
||||
if (type === EventType.ACTION_PRESS) {
|
||||
@@ -173,7 +161,7 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
await db.reminders?.reminder(reminder?.id)
|
||||
);
|
||||
useRelationStore.getState().update();
|
||||
useReminderStore.getState().setReminders();
|
||||
useReminderStore.getState().refresh();
|
||||
break;
|
||||
}
|
||||
case "REMINDER_DISABLE": {
|
||||
@@ -191,7 +179,7 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
await db.reminders?.reminder(reminder?.id)
|
||||
);
|
||||
useRelationStore.getState().update();
|
||||
useReminderStore.getState().setReminders();
|
||||
useReminderStore.getState().refresh();
|
||||
break;
|
||||
}
|
||||
case "UNPIN": {
|
||||
@@ -207,7 +195,7 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
disabled: true
|
||||
});
|
||||
useRelationStore.getState().update();
|
||||
useReminderStore.getState().setReminders();
|
||||
useReminderStore.getState().refresh();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -253,7 +241,7 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
console.log(e, (e as Error).stack);
|
||||
}
|
||||
}
|
||||
useNoteStore.getState().setNotes();
|
||||
Navigation.queueRoutesForUpdate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -422,14 +410,17 @@ async function loadNote(id: string, jump: boolean) {
|
||||
tabBarRef.current?.goToPage(1);
|
||||
}
|
||||
eSendEvent("loadingNote", note);
|
||||
setTimeout(() => {
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: note
|
||||
});
|
||||
if (!jump && !DDS.isTab) {
|
||||
tabBarRef.current?.goToPage(1);
|
||||
}
|
||||
}, 2000);
|
||||
setTimeout(
|
||||
() => {
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: note
|
||||
});
|
||||
if (!jump && !DDS.isTab) {
|
||||
tabBarRef.current?.goToPage(1);
|
||||
}
|
||||
},
|
||||
tabBarRef?.current ? 0 : 2000
|
||||
);
|
||||
}
|
||||
|
||||
async function getChannelId(id: "silent" | "vibrate" | "urgent" | "default") {
|
||||
|
||||
93
apps/mobile/app/stores/create-db-collection-store.ts
Normal file
93
apps/mobile/app/stores/create-db-collection-store.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
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 { Item, VirtualizedGrouping } from "@notesnook/core";
|
||||
import create, { State, StoreApi, UseBoundStore } from "zustand";
|
||||
import { resolveItems } from "./resolve-items";
|
||||
import { useSettingStore } from "./use-setting-store";
|
||||
|
||||
export interface DBCollectionStore<Type extends Item> extends State {
|
||||
items: VirtualizedGrouping<Type> | undefined;
|
||||
loading: boolean;
|
||||
refresh: () => Promise<void>;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
const ALL_STORES: UseBoundStore<
|
||||
DBCollectionStore<Item>,
|
||||
StoreApi<DBCollectionStore<Item>>
|
||||
>[] = [];
|
||||
|
||||
export function clearAllStores() {
|
||||
ALL_STORES.forEach((store) => {
|
||||
store?.getState().clear();
|
||||
});
|
||||
}
|
||||
|
||||
export function refreshAllStores() {
|
||||
ALL_STORES.forEach((store) => store?.getState().refresh());
|
||||
}
|
||||
|
||||
export default function createDBCollectionStore<Type extends Item>({
|
||||
getCollection,
|
||||
eagerlyFetchFirstBatch
|
||||
}: {
|
||||
getCollection: () => Promise<VirtualizedGrouping<Type>>;
|
||||
eagerlyFetchFirstBatch?: boolean;
|
||||
}) {
|
||||
const useDBCollectionStore = create<DBCollectionStore<Type>>((set, get) => ({
|
||||
items: undefined,
|
||||
loading: true,
|
||||
refresh: async () => {
|
||||
const items = await getCollection();
|
||||
if (get().loading && eagerlyFetchFirstBatch) {
|
||||
await items.item(0, resolveItems);
|
||||
}
|
||||
set({
|
||||
items,
|
||||
loading: false
|
||||
});
|
||||
},
|
||||
clear: () => set({ items: undefined, loading: true })
|
||||
}));
|
||||
|
||||
const useStoreHook = (): [
|
||||
VirtualizedGrouping<Type> | undefined,
|
||||
boolean,
|
||||
() => Promise<void>
|
||||
] => {
|
||||
const isAppLoading = useSettingStore((state) => state.isAppLoading);
|
||||
const [items, loading] = useDBCollectionStore((state) => [
|
||||
state.items,
|
||||
state.loading
|
||||
]);
|
||||
|
||||
if (!items && !isAppLoading) {
|
||||
useDBCollectionStore.getState().refresh();
|
||||
}
|
||||
|
||||
return [items, loading, useDBCollectionStore.getState().refresh];
|
||||
};
|
||||
|
||||
ALL_STORES.push(useDBCollectionStore as any);
|
||||
return {
|
||||
useStore: useDBCollectionStore,
|
||||
useCollection: useStoreHook
|
||||
};
|
||||
}
|
||||
@@ -17,7 +17,6 @@ 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 { db } from "../common/database";
|
||||
import Navigation from "../services/navigation";
|
||||
import Notifications from "../services/notifications";
|
||||
import { useFavoriteStore } from "./use-favorite-store";
|
||||
@@ -28,36 +27,26 @@ import { useRelationStore } from "./use-relation-store";
|
||||
import { useReminderStore } from "./use-reminder-store";
|
||||
import { useTagStore } from "./use-tag-store";
|
||||
import { useTrashStore } from "./use-trash-store";
|
||||
|
||||
export function initAfterSync() {
|
||||
useMenuStore.getState().setColorNotes();
|
||||
useMenuStore.getState().setMenuPins();
|
||||
Navigation.queueRoutesForUpdate();
|
||||
// Whenever sync completes, try to reschedule
|
||||
// any new/updated reminders.
|
||||
Notifications.setupReminders(true);
|
||||
useRelationStore.getState().update();
|
||||
}
|
||||
|
||||
export async function initialize() {
|
||||
if (!db) return;
|
||||
useMenuStore.getState().setColorNotes();
|
||||
useMenuStore.getState().setMenuPins();
|
||||
useNotebookStore.getState().setNotebooks();
|
||||
useTrashStore.getState().setTrash();
|
||||
useTagStore.getState().setTags();
|
||||
useFavoriteStore.getState().setFavorites();
|
||||
await useNoteStore.getState().setNotes();
|
||||
useReminderStore.getState().setReminders();
|
||||
Notifications.setupReminders();
|
||||
}
|
||||
|
||||
export async function initialize() {}
|
||||
|
||||
export function clearAllStores() {
|
||||
useNotebookStore.getState().clearNotebooks();
|
||||
useTagStore.getState().clearTags();
|
||||
useFavoriteStore.getState().clearFavorites();
|
||||
useNotebookStore.getState().clear();
|
||||
useTagStore.getState().clear();
|
||||
useFavoriteStore.getState().clear();
|
||||
useMenuStore.getState().clearAll();
|
||||
useNoteStore.getState().clearNotes();
|
||||
useNoteStore.getState().clear();
|
||||
useMenuStore.getState().clearAll();
|
||||
useTrashStore.getState().clearTrash();
|
||||
useReminderStore.getState().cleareReminders();
|
||||
useTrashStore.getState().clear();
|
||||
useReminderStore.getState().clear();
|
||||
}
|
||||
|
||||
158
apps/mobile/app/stores/resolve-items.ts
Normal file
158
apps/mobile/app/stores/resolve-items.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
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 { Color, Item, Notebook, Reminder, Tag } from "@notesnook/core";
|
||||
import { db } from "../common/database";
|
||||
|
||||
export type WithDateEdited<T> = { items: T[]; dateEdited: number };
|
||||
export type NotebooksWithDateEdited = WithDateEdited<Notebook>;
|
||||
export type TagsWithDateEdited = WithDateEdited<Tag>;
|
||||
|
||||
function withDateEdited<
|
||||
T extends { dateEdited: number } | { dateModified: number }
|
||||
>(items: T[]): WithDateEdited<T> {
|
||||
let latestDateEdited = 0;
|
||||
items.forEach((item) => {
|
||||
const date = "dateEdited" in item ? item.dateEdited : item.dateModified;
|
||||
if (latestDateEdited < date) latestDateEdited = date;
|
||||
});
|
||||
return { dateEdited: latestDateEdited, items };
|
||||
}
|
||||
|
||||
export async function resolveItems(ids: string[], items: Item[]) {
|
||||
if (!ids.length || !items.length) return [];
|
||||
|
||||
const { type } = items[0];
|
||||
if (type === "note") return resolveNotes(ids);
|
||||
else if (type === "notebook") {
|
||||
return Promise.all(ids.map((id) => db.notebooks.totalNotes(id)));
|
||||
} else if (type === "tag") {
|
||||
return Promise.all(
|
||||
ids.map((id) => db.relations.from({ id, type: "tag" }, "note").count())
|
||||
);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
type NoteResolvedData = {
|
||||
notebooks?: NotebooksWithDateEdited;
|
||||
reminder?: Reminder;
|
||||
color?: Color;
|
||||
tags?: TagsWithDateEdited;
|
||||
attachmentsCount?: number;
|
||||
};
|
||||
async function resolveNotes(ids: string[]) {
|
||||
console.time("relations");
|
||||
const relations = [
|
||||
...(await db.relations
|
||||
.to({ type: "note", ids }, ["notebook", "tag", "color"])
|
||||
.get()),
|
||||
...(await db.relations.from({ type: "note", ids }, "reminder").get())
|
||||
];
|
||||
console.timeEnd("relations");
|
||||
const relationIds: {
|
||||
notebooks: Set<string>;
|
||||
colors: Set<string>;
|
||||
tags: Set<string>;
|
||||
reminders: Set<string>;
|
||||
} = {
|
||||
colors: new Set(),
|
||||
notebooks: new Set(),
|
||||
tags: new Set(),
|
||||
reminders: new Set()
|
||||
};
|
||||
|
||||
const grouped: Record<
|
||||
string,
|
||||
{
|
||||
notebooks: string[];
|
||||
color?: string;
|
||||
tags: string[];
|
||||
reminder?: string;
|
||||
}
|
||||
> = {};
|
||||
for (const relation of relations) {
|
||||
const noteId =
|
||||
relation.toType === "reminder" ? relation.fromId : relation.toId;
|
||||
const data = grouped[noteId] || {
|
||||
notebooks: [],
|
||||
tags: []
|
||||
};
|
||||
|
||||
if (relation.toType === "reminder" && !data.reminder) {
|
||||
data.reminder = relation.toId;
|
||||
relationIds.reminders.add(relation.toId);
|
||||
} else if (relation.fromType === "notebook" && data.notebooks.length < 2) {
|
||||
data.notebooks.push(relation.fromId);
|
||||
relationIds.notebooks.add(relation.fromId);
|
||||
} else if (relation.fromType === "tag" && data.tags.length < 3) {
|
||||
data.tags.push(relation.fromId);
|
||||
relationIds.tags.add(relation.fromId);
|
||||
} else if (relation.fromType === "color" && !data.color) {
|
||||
data.color = relation.fromId;
|
||||
relationIds.colors.add(relation.fromId);
|
||||
}
|
||||
grouped[noteId] = data;
|
||||
}
|
||||
|
||||
console.time("resolve");
|
||||
const resolved = {
|
||||
notebooks: await db.notebooks.all.records(
|
||||
Array.from(relationIds.notebooks)
|
||||
),
|
||||
tags: await db.tags.all.records(Array.from(relationIds.tags)),
|
||||
colors: await db.colors.all.records(Array.from(relationIds.colors)),
|
||||
reminders: await db.reminders.all.records(Array.from(relationIds.reminders))
|
||||
};
|
||||
console.timeEnd("resolve");
|
||||
|
||||
const data: NoteResolvedData[] = [];
|
||||
for (const noteId of ids) {
|
||||
const group = grouped[noteId];
|
||||
if (!group) {
|
||||
data.push({});
|
||||
continue;
|
||||
}
|
||||
|
||||
data.push({
|
||||
color: group.color ? resolved.colors[group.color] : undefined,
|
||||
reminder: group.reminder ? resolved.reminders[group.reminder] : undefined,
|
||||
tags: withDateEdited(
|
||||
group.tags.map((id) => resolved.tags[id]).filter(Boolean)
|
||||
),
|
||||
notebooks: withDateEdited(
|
||||
group.notebooks.map((id) => resolved.notebooks[id]).filter(Boolean)
|
||||
),
|
||||
attachmentsCount:
|
||||
(await db.attachments?.ofNote(noteId, "all").ids())?.length || 0
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export function isNoteResolvedData(data: unknown): data is NoteResolvedData {
|
||||
return (
|
||||
typeof data === "object" &&
|
||||
!!data &&
|
||||
"notebooks" in data &&
|
||||
"reminder" in data &&
|
||||
"color" in data &&
|
||||
"tags" in data
|
||||
);
|
||||
}
|
||||
@@ -17,26 +17,14 @@ 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 create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import { Note, VirtualizedGrouping } from "@notesnook/core";
|
||||
import createDBCollectionStore from "./create-db-collection-store";
|
||||
|
||||
export interface FavoriteStore extends State {
|
||||
favorites: VirtualizedGrouping<Note> | undefined;
|
||||
setFavorites: (items?: Note[]) => void;
|
||||
clearFavorites: () => void;
|
||||
}
|
||||
const { useStore: useFavoriteStore, useCollection: useFavorites } =
|
||||
createDBCollectionStore({
|
||||
getCollection: () =>
|
||||
db.notes.favorites.grouped(db.settings.getGroupOptions("favorites")),
|
||||
eagerlyFetchFirstBatch: true
|
||||
});
|
||||
|
||||
export const useFavoriteStore = create<FavoriteStore>((set) => ({
|
||||
favorites: undefined,
|
||||
setFavorites: () => {
|
||||
db.notes.favorites
|
||||
.grouped(db.settings.getGroupOptions("favorites"))
|
||||
.then((notes) => {
|
||||
set({
|
||||
favorites: notes
|
||||
});
|
||||
});
|
||||
},
|
||||
clearFavorites: () => set({ favorites: undefined })
|
||||
}));
|
||||
export { useFavoriteStore, useFavorites };
|
||||
|
||||
@@ -27,20 +27,25 @@ export interface MenuStore extends State {
|
||||
setMenuPins: () => void;
|
||||
setColorNotes: () => void;
|
||||
clearAll: () => void;
|
||||
loadingShortcuts: boolean;
|
||||
loadingColors: boolean;
|
||||
}
|
||||
|
||||
export const useMenuStore = create<MenuStore>((set) => ({
|
||||
menuPins: [],
|
||||
colorNotes: [],
|
||||
loadingShortcuts: true,
|
||||
loadingColors: true,
|
||||
setMenuPins: () => {
|
||||
db.shortcuts.resolved().then((shortcuts) => {
|
||||
set({ menuPins: [...(shortcuts as [])] });
|
||||
set({ menuPins: [...(shortcuts as [])], loadingShortcuts: false });
|
||||
});
|
||||
},
|
||||
setColorNotes: () => {
|
||||
db.colors?.all.items().then((colors) => {
|
||||
set({
|
||||
colorNotes: colors
|
||||
colorNotes: colors,
|
||||
loadingColors: false
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@@ -17,26 +17,14 @@ 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 create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import { VirtualizedGrouping, Notebook } from "@notesnook/core";
|
||||
import createDBCollectionStore from "./create-db-collection-store";
|
||||
|
||||
export interface NotebookStore extends State {
|
||||
notebooks: VirtualizedGrouping<Notebook> | undefined;
|
||||
setNotebooks: (items?: Notebook[]) => void;
|
||||
clearNotebooks: () => void;
|
||||
}
|
||||
const { useStore: useNotebookStore, useCollection: useNotebooks } =
|
||||
createDBCollectionStore({
|
||||
getCollection: () =>
|
||||
db.notebooks.roots.grouped(db.settings.getGroupOptions("notebooks")),
|
||||
eagerlyFetchFirstBatch: true
|
||||
});
|
||||
|
||||
export const useNotebookStore = create<NotebookStore>((set) => ({
|
||||
notebooks: undefined,
|
||||
setNotebooks: () => {
|
||||
db.notebooks.roots
|
||||
.grouped(db.settings.getGroupOptions("notebooks"))
|
||||
.then((notebooks) => {
|
||||
set({
|
||||
notebooks: notebooks
|
||||
});
|
||||
});
|
||||
},
|
||||
clearNotebooks: () => set({ notebooks: undefined })
|
||||
}));
|
||||
export { useNotebookStore, useNotebooks };
|
||||
|
||||
@@ -17,30 +17,14 @@ 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 { Note, VirtualizedGrouping } from "@notesnook/core";
|
||||
import create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import createDBCollectionStore from "./create-db-collection-store";
|
||||
|
||||
export interface NoteStore extends State {
|
||||
notes: VirtualizedGrouping<Note> | undefined;
|
||||
loading: boolean;
|
||||
setLoading: (loading: boolean) => void;
|
||||
setNotes: () => void;
|
||||
clearNotes: () => void;
|
||||
}
|
||||
const { useStore: useNoteStore, useCollection: useNotes } =
|
||||
createDBCollectionStore({
|
||||
getCollection: () =>
|
||||
db.notes.all.grouped(db.settings.getGroupOptions("home")),
|
||||
eagerlyFetchFirstBatch: true
|
||||
});
|
||||
|
||||
export const useNoteStore = create<NoteStore>((set) => ({
|
||||
notes: undefined,
|
||||
loading: true,
|
||||
setLoading: (loading) => set({ loading: loading }),
|
||||
setNotes: async () => {
|
||||
const notes = await db.notes.all.grouped(
|
||||
db.settings.getGroupOptions("home")
|
||||
);
|
||||
await notes.item(0);
|
||||
set({
|
||||
notes: notes
|
||||
});
|
||||
},
|
||||
clearNotes: () => set({ notes: undefined })
|
||||
}));
|
||||
export { useNoteStore, useNotes };
|
||||
|
||||
@@ -17,26 +17,14 @@ 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 create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import { Reminder, VirtualizedGrouping } from "@notesnook/core";
|
||||
import createDBCollectionStore from "./create-db-collection-store";
|
||||
|
||||
export interface ReminderStore extends State {
|
||||
reminders: VirtualizedGrouping<Reminder> | undefined;
|
||||
setReminders: (items?: Reminder[]) => void;
|
||||
cleareReminders: () => void;
|
||||
}
|
||||
const { useStore: useReminderStore, useCollection: useReminders } =
|
||||
createDBCollectionStore({
|
||||
getCollection: () =>
|
||||
db.reminders.all.grouped(db.settings.getGroupOptions("reminders")),
|
||||
eagerlyFetchFirstBatch: true
|
||||
});
|
||||
|
||||
export const useReminderStore = create<ReminderStore>((set) => ({
|
||||
reminders: undefined,
|
||||
setReminders: () => {
|
||||
db.reminders.all
|
||||
.grouped(db.settings.getGroupOptions("reminders"))
|
||||
.then((reminders) => {
|
||||
set({
|
||||
reminders: reminders
|
||||
});
|
||||
});
|
||||
},
|
||||
cleareReminders: () => set({ reminders: undefined })
|
||||
}));
|
||||
export { useReminderStore, useReminders };
|
||||
|
||||
@@ -98,8 +98,8 @@ export interface SettingStore extends State {
|
||||
setFullscreen: (fullscreen: boolean) => void;
|
||||
setDeviceMode: (mode: string) => void;
|
||||
setDimensions: (dimensions: DimensionsType) => void;
|
||||
appLoading: boolean;
|
||||
setAppLoading: (appLoading: boolean) => void;
|
||||
isAppLoading: boolean;
|
||||
setAppLoading: (isAppLoading: boolean) => void;
|
||||
setSheetKeyboardHandler: (sheetKeyboardHandler: boolean) => void;
|
||||
sheetKeyboardHandler: boolean;
|
||||
requestBiometrics: boolean;
|
||||
@@ -165,12 +165,12 @@ export const useSettingStore = create<SettingStore>((set, get) => ({
|
||||
fullscreen: false,
|
||||
deviceMode: null,
|
||||
dimensions: { width, height },
|
||||
appLoading: true,
|
||||
isAppLoading: true,
|
||||
setSettings: (settings) => set({ settings }),
|
||||
setFullscreen: (fullscreen) => set({ fullscreen }),
|
||||
setDeviceMode: (mode) => set({ deviceMode: mode }),
|
||||
setDimensions: (dimensions) => set({ dimensions: dimensions }),
|
||||
setAppLoading: (appLoading) => set({ appLoading }),
|
||||
setAppLoading: (isAppLoading) => set({ isAppLoading }),
|
||||
setSheetKeyboardHandler: (sheetKeyboardHandler) =>
|
||||
set({ sheetKeyboardHandler }),
|
||||
requestBiometrics: false,
|
||||
|
||||
@@ -17,24 +17,14 @@ 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 create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import { Tag, VirtualizedGrouping } from "@notesnook/core";
|
||||
import createDBCollectionStore from "./create-db-collection-store";
|
||||
|
||||
export interface TagStore extends State {
|
||||
tags: VirtualizedGrouping<Tag> | undefined;
|
||||
setTags: (items?: Tag[]) => void;
|
||||
clearTags: () => void;
|
||||
}
|
||||
const { useStore: useTagStore, useCollection: useTags } =
|
||||
createDBCollectionStore({
|
||||
getCollection: () =>
|
||||
db.tags.all.grouped(db.settings.getGroupOptions("tags")),
|
||||
eagerlyFetchFirstBatch: true
|
||||
});
|
||||
|
||||
export const useTagStore = create<TagStore>((set) => ({
|
||||
tags: undefined,
|
||||
setTags: () => {
|
||||
db.tags.all.grouped(db.settings.getGroupOptions("tags")).then((tags) => {
|
||||
set({
|
||||
tags: tags
|
||||
});
|
||||
});
|
||||
},
|
||||
clearTags: () => set({ tags: undefined })
|
||||
}));
|
||||
export { useTagStore, useTags };
|
||||
|
||||
@@ -17,25 +17,13 @@ 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 create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import { GroupedItems, TrashItem } from "@notesnook/core/dist/types";
|
||||
import { VirtualizedGrouping } from "@notesnook/core";
|
||||
import createDBCollectionStore from "./create-db-collection-store";
|
||||
|
||||
export interface TrashStore extends State {
|
||||
trash: VirtualizedGrouping<TrashItem> | undefined;
|
||||
setTrash: (items?: GroupedItems<TrashItem>) => void;
|
||||
clearTrash: () => void;
|
||||
}
|
||||
const { useStore: useTrashStore, useCollection: useTrash } =
|
||||
createDBCollectionStore({
|
||||
getCollection: () => db.trash.grouped(db.settings.getGroupOptions("trash")),
|
||||
eagerlyFetchFirstBatch: true
|
||||
});
|
||||
|
||||
export const useTrashStore = create<TrashStore>((set, get) => ({
|
||||
trash: undefined,
|
||||
setTrash: () => {
|
||||
db.trash.grouped(db.settings.getGroupOptions("trash")).then((trash) => {
|
||||
set({
|
||||
trash: trash
|
||||
});
|
||||
});
|
||||
},
|
||||
clearTrash: () => set({ trash: undefined })
|
||||
}));
|
||||
export { useTrashStore, useTrash };
|
||||
|
||||
867
apps/mobile/package-lock.json
generated
867
apps/mobile/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,7 @@
|
||||
"kysely": "^0.26.3",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.72.0",
|
||||
"react-native-quick-sqlite": "^8.0.6"
|
||||
"react-native-quick-sqlite": "^8.0.6",
|
||||
"tinycolor2": "1.6.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user