diff --git a/apps/mobile/app/components/attachments/index.js b/apps/mobile/app/components/attachments/index.js
index ce3e9cce5..877e1c7f0 100644
--- a/apps/mobile/app/components/attachments/index.js
+++ b/apps/mobile/app/components/attachments/index.js
@@ -17,70 +17,34 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-import React, { useEffect, useRef, useState } from "react";
+import React, { useRef, useState } from "react";
import { View } from "react-native";
import { FlatList } from "react-native-gesture-handler";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../common/database";
import filesystem from "../../common/filesystem";
-import {
- eSubscribeEvent,
- eUnSubscribeEvent
-} from "../../services/event-manager";
+import { presentSheet } from "../../services/event-manager";
import { useThemeStore } from "../../stores/use-theme-store";
-import {
- eCloseAttachmentDialog,
- eOpenAttachmentsDialog
-} from "../../utils/events";
import { SIZE } from "../../utils/size";
import DialogHeader from "../dialog/dialog-header";
-import { Toast } from "../toast";
import Input from "../ui/input";
import Seperator from "../ui/seperator";
-import SheetWrapper from "../ui/sheet";
import Paragraph from "../ui/typography/paragraph";
import { AttachmentItem } from "./attachment-item";
-export const AttachmentDialog = () => {
+
+export const AttachmentDialog = ({ data }) => {
const colors = useThemeStore((state) => state.colors);
- const [visible, setVisible] = useState(false);
- const [note, setNote] = useState(null);
+ const [note, setNote] = useState(data);
const actionSheetRef = useRef();
- const [attachments, setAttachments] = useState([]);
+ const [attachments, setAttachments] = useState(
+ data
+ ? db.attachments.ofNote(data.id, "all")
+ : [...(db.attachments.all || [])]
+ );
const attachmentSearchValue = useRef();
const searchTimer = useRef();
const [loading, setLoading] = useState(false);
- useEffect(() => {
- eSubscribeEvent(eOpenAttachmentsDialog, open);
- eSubscribeEvent(eCloseAttachmentDialog, close);
- return () => {
- eUnSubscribeEvent(eOpenAttachmentsDialog, open);
- eUnSubscribeEvent(eCloseAttachmentDialog, close);
- };
- }, [visible]);
-
- const open = (data) => {
- if (data?.id) {
- setNote(data);
- let _attachments = db.attachments.ofNote(data.id, "all");
- setAttachments(_attachments);
- } else {
- setAttachments([...db.attachments.all]);
- }
- setVisible(true);
- };
-
- useEffect(() => {
- if (visible) {
- actionSheetRef.current?.show();
- }
- }, [visible]);
-
- const close = () => {
- actionSheetRef.current?.hide();
- setVisible(false);
- };
-
const onChangeText = (text) => {
attachmentSearchValue.current = text;
if (
@@ -104,107 +68,104 @@ export const AttachmentDialog = () => {
);
- return !visible ? null : (
- {
- setVisible(false);
+ return (
+
-
-
- {
- setLoading(true);
- for (let attachment of attachments) {
- let result = await filesystem.checkAttachment(
- attachment.metadata.hash
+ {
+ setLoading(true);
+ for (let attachment of attachments) {
+ let result = await filesystem.checkAttachment(
+ attachment.metadata.hash
+ );
+ if (result.failed) {
+ db.attachments.markAsFailed(
+ attachment.metadata.hash,
+ result.failed
);
- if (result.failed) {
- db.attachments.markAsFailed(
- attachment.metadata.hash,
- result.failed
- );
- } else {
- db.attachments.markAsFailed(attachment.id, null);
- }
- setAttachments([...db.attachments.all]);
+ } else {
+ db.attachments.markAsFailed(attachment.id, null);
}
- setLoading(false);
+ setAttachments([...db.attachments.all]);
}
+ setLoading(false);
+ }
+ }}
+ />
+
+ {!note ? (
+ {
+ onChangeText(attachmentSearchValue.current);
}}
/>
-
- {!note ? (
- {
- onChangeText(attachmentSearchValue.current);
+ ) : null}
+
+ {
+ actionSheetRef.current?.handleChildScrollEnd();
+ }}
+ ListEmptyComponent={
+
+
+
+ {note ? "No attachments on this note" : "No attachments"}
+
+
+ }
+ ListFooterComponent={
+
- ) : null}
+ }
+ data={attachments}
+ keyExtractor={(item) => item.id}
+ renderItem={renderItem}
+ />
- {
- actionSheetRef.current?.handleChildScrollEnd();
- }}
- ListEmptyComponent={
-
-
-
- {note ? "No attachments on this note" : "No attachments"}
-
-
- }
- ListFooterComponent={
-
- }
- data={attachments}
- keyExtractor={(item) => item.id}
- renderItem={renderItem}
- />
-
-
-
- {" "}All attachments are end-to-end encrypted.
-
-
-
+
+
+ {" "}All attachments are end-to-end encrypted.
+
+
);
};
+
+AttachmentDialog.present = (note) => {
+ presentSheet({
+ component: () =>
+ });
+};
diff --git a/apps/mobile/app/components/dialog-provider/index.js b/apps/mobile/app/components/dialog-provider/index.js
index 1baea8141..97dc049b6 100644
--- a/apps/mobile/app/components/dialog-provider/index.js
+++ b/apps/mobile/app/components/dialog-provider/index.js
@@ -21,7 +21,6 @@ import React from "react";
import { useNoteStore } from "../../stores/use-notes-store";
import { useThemeStore } from "../../stores/use-theme-store";
import { AnnouncementDialog } from "../announcements";
-import { AttachmentDialog } from "../attachments";
import AuthModal from "../auth/auth-modal";
import { SessionExpired } from "../auth/session-expired";
import { Dialog } from "../dialog";
@@ -34,10 +33,6 @@ import MergeConflicts from "../merge-conflicts";
import PremiumDialog from "../premium";
import { Expiring } from "../premium/expiring";
import SheetProvider from "../sheet-provider";
-import { AddNotebookSheet } from "../sheets/add-notebook";
-import AddToNotebookSheet from "../sheets/add-to";
-import ManageTagsSheet from "../sheets/manage-tags";
-import PublishNoteSheet from "../sheets/publish-note";
import RateAppSheet from "../sheets/rate-app";
import RecoveryKeySheet from "../sheets/recovery-key";
import RestoreDataSheet from "../sheets/restore-data";
@@ -51,7 +46,6 @@ const DialogProvider = () => {
-
@@ -61,12 +55,8 @@ const DialogProvider = () => {
-
-
-
-
{loading ? null : }
diff --git a/apps/mobile/app/components/dialogs/add-topic/index.js b/apps/mobile/app/components/dialogs/add-topic/index.js
index 0986f9d74..777e21d0e 100644
--- a/apps/mobile/app/components/dialogs/add-topic/index.js
+++ b/apps/mobile/app/components/dialogs/add-topic/index.js
@@ -59,14 +59,12 @@ export class AddTopicDialog extends React.Component {
addNewTopic = async () => {
try {
- this.setState({ loading: true });
if (!this.title || this.title?.trim() === "") {
ToastEvent.show({
heading: "Topic title is required",
type: "error",
context: "local"
});
- this.setState({ loading: false });
return;
}
@@ -78,10 +76,11 @@ export class AddTopicDialog extends React.Component {
await db.notebooks.notebook(topic.notebookId).topics.add(topic);
}
- this.setState({ loading: false });
this.close();
- Navigation.queueRoutesForUpdate("Notebooks", "Notebook", "TopicNotes");
- useMenuStore.getState().setMenuPins();
+ setTimeout(() => {
+ Navigation.queueRoutesForUpdate("Notebooks", "Notebook", "TopicNotes");
+ useMenuStore.getState().setMenuPins();
+ });
} catch (e) {
console.error(e);
}
@@ -177,7 +176,6 @@ export class AddTopicDialog extends React.Component {
positiveTitle={this.toEdit ? "Save" : "Add"}
onPressNegative={() => this.close()}
onPressPositive={() => this.addNewTopic()}
- loading={this.state.loading}
/>
diff --git a/apps/mobile/app/components/header/title.js b/apps/mobile/app/components/header/title.js
index df0898677..f1c6f235b 100644
--- a/apps/mobile/app/components/header/title.js
+++ b/apps/mobile/app/components/header/title.js
@@ -30,7 +30,6 @@ import { useThemeStore } from "../../stores/use-theme-store";
import { eScrollEvent } from "../../utils/events";
import { SIZE } from "../../utils/size";
import Heading from "../ui/typography/heading";
-import Paragraph from "../ui/typography/paragraph";
import { useCallback } from "react";
import Tag from "../ui/tag";
@@ -120,12 +119,6 @@ export const Title = () => {
}}
color={currentScreen.color || colors.heading}
>
- {isTopic ? (
-
- {notebook?.title}
- {"\n"}
-
- ) : null}
{isTag ? (
{
- TopicNotes.navigate(topic, true);
-};
-
function navigateToTag(item) {
const tag = db.tags.tag(item.id);
if (!tag) return;
@@ -55,24 +52,29 @@ const showActionSheet = (item) => {
function getNotebook(item) {
const isTrash = item.type === "trash";
- if (isTrash || !item.notebooks || item.notebooks.length < 1) return [];
+ if (isTrash) return [];
+ const items = [];
+ const notebooks = db.relations.to(item, "notebook") || [];
- return item.notebooks.reduce(function (prev, curr) {
- if (prev && prev.length > 0) return prev;
- const topicId = curr.topics[0];
- const notebook = db.notebooks?.notebook(curr.id)?.data;
- if (!notebook) return [];
- const topic = notebook.topics.find((t) => t.id === topicId);
- if (!topic) return [];
+ for (let notebook of notebooks) {
+ if (items.length > 1) break;
+ items.push(notebook);
+ }
- return [
- {
- title: `${notebook?.title} › ${topic?.title}`,
- notebook: notebook,
- topic: topic
+ if (item.notebooks) {
+ for (let nb of item.notebooks) {
+ if (items.length > 1) break;
+ const notebook = db.notebooks?.notebook(nb.id)?.data;
+ if (!notebook) continue;
+ for (let topicId of nb.topics) {
+ if (items.length > 1) break;
+ const topic = notebook.topics.find((t) => t.id === topicId);
+ if (!topic) continue;
+ items.push(topic);
}
- ];
- }, []);
+ }
+ }
+ return items;
}
const NoteItem = ({
@@ -88,10 +90,11 @@ const NoteItem = ({
);
const compactMode = notesListMode === "compact";
const attachmentCount = db.attachments?.ofNote(item.id, "all")?.length || 0;
- const notebooks = React.useMemo(() => getNotebook(item), [item]);
+ const _update = useRelationStore((state) => state.updater);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ const notebooks = React.useMemo(() => getNotebook(item), [item, _update]);
const reminders = db.relations.from(item, "reminder");
const reminder = getUpcomingReminder(reminders);
- const _update = useRelationStore((state) => state.updater);
const noteColor = COLORS_NOTE[item.color?.toLowerCase()];
return (
<>
@@ -112,12 +115,12 @@ const NoteItem = ({
flexWrap: "wrap"
}}
>
- {notebooks?.map((_item) => (
+ {notebooks?.map((item) => (
+
+ {publishUrl}
+
+ {
+ try {
+ await openLinkInBrowser(publishUrl, colors.accent);
+ } catch (e) {
+ console.error(e);
+ }
+ }}
+ size={SIZE.xs}
style={{
- width: "100%",
- flexShrink: 1
+ marginTop: 5,
+ color: colors.pri
}}
>
- Published at:
-
- {publishUrl}
-
- {
- try {
- await openLinkInBrowser(publishUrl, colors.accent);
- } catch (e) {
- console.error(e);
- }
- }}
- size={SIZE.xs}
- style={{
- marginTop: 5,
- color: colors.pri
- }}
- >
- Open in
- browser
-
-
-
- {
- Clipboard.setString(publishUrl);
- ToastEvent.show({
- heading: "Note publish url copied",
- type: "success",
- context: "local"
- });
- }}
- color={colors.accent}
- size={SIZE.lg}
- name="content-copy"
- />
+ Open in
+ browser
+
- )}
-
- {
+ Clipboard.setString(publishUrl);
+ ToastEvent.show({
+ heading: "Note publish url copied",
+ type: "success",
+ context: "local"
+ });
+ }}
+ color={colors.accent}
+ size={SIZE.lg}
+ name="content-copy"
+ />
+
+ )}
+
+
+ {
+ if (publishing) return;
+ setIsLocked(!isLocked);
+ }}
+ activeOpacity={0.9}
+ style={{
+ flexDirection: "row",
+ alignItems: "center",
+ marginBottom: 10
+ }}
+ >
+ {
if (publishing) return;
setIsLocked(!isLocked);
}}
- activeOpacity={0.9}
- style={{
- flexDirection: "row",
- alignItems: "center",
- marginBottom: 10
- }}
- >
- {
- if (publishing) return;
- setIsLocked(!isLocked);
- }}
- color={isLocked ? colors.accent : colors.icon}
- size={SIZE.lg}
- name={
- isLocked
- ? "check-circle-outline"
- : "checkbox-blank-circle-outline"
- }
- />
-
-
- Password protection
-
- Published note can only be viewed by someone with the
- password.
-
-
-
-
- {
- setSelfDestruct(!selfDestruct);
- }}
- activeOpacity={0.9}
- style={{
- flexDirection: "row",
- alignItems: "center"
- }}
- >
- {
- setSelfDestruct(!selfDestruct);
- }}
- color={selfDestruct ? colors.accent : colors.icon}
- size={SIZE.lg}
- name={
- selfDestruct
- ? "check-circle-outline"
- : "checkbox-blank-circle-outline"
- }
- />
-
-
- Self destruct
-
- Published note link will be automatically deleted once it is
- viewed by someone.
-
-
-
+ color={isLocked ? colors.accent : colors.icon}
+ size={SIZE.lg}
+ name={
+ isLocked
+ ? "check-circle-outline"
+ : "checkbox-blank-circle-outline"
+ }
+ />
- {isLocked ? (
- <>
- (passwordValue = value)}
- blurOnSubmit
- secureTextEntry
- defaultValue={passwordValue}
- placeholder="Enter Password"
- />
-
- >
- ) : null}
-
-
-
- {isPublished && (
- <>
-
-
- >
- )}
+ Password protection
+
+ Published note can only be viewed by someone with the password.
+
- >
- )}
+
- {
- try {
- await openLinkInBrowser(
- "https://docs.notesnook.com/monographs/",
- colors.accent
- );
- } catch (e) {
- console.error(e);
- }
- }}
- >
- Learn more about Notesnook Monograph
-
-
-
+ {
+ setSelfDestruct(!selfDestruct);
+ }}
+ activeOpacity={0.9}
+ style={{
+ flexDirection: "row",
+ alignItems: "center"
+ }}
+ >
+ {
+ setSelfDestruct(!selfDestruct);
+ }}
+ color={selfDestruct ? colors.accent : colors.icon}
+ size={SIZE.lg}
+ name={
+ selfDestruct
+ ? "check-circle-outline"
+ : "checkbox-blank-circle-outline"
+ }
+ />
+
+
+ Self destruct
+
+ Published note link will be automatically deleted once it is
+ viewed by someone.
+
+
+
+
+
+ {isLocked ? (
+ <>
+ (passwordValue.current = value)}
+ blurOnSubmit
+ secureTextEntry
+ defaultValue={passwordValue.current}
+ placeholder="Enter Password"
+ />
+
+ >
+ ) : null}
+
+
+
+ {isPublished && (
+ <>
+
+
+ >
+ )}
+
+ >
+ )}
+
+ {
+ try {
+ await openLinkInBrowser(
+ "https://docs.notesnook.com/monographs/",
+ colors.accent
+ );
+ } catch (e) {
+ console.error(e);
+ }
+ }}
+ >
+ Learn more about Notesnook Monograph
+
+
);
};
+PublishNoteSheet.present = (note) => {
+ presentSheet({
+ component: (ref, close, update) => (
+
+ )
+ });
+};
+
export default PublishNoteSheet;
diff --git a/apps/mobile/app/components/sheets/relations-list/index.tsx b/apps/mobile/app/components/sheets/relations-list/index.tsx
index 176484808..697a5bc24 100644
--- a/apps/mobile/app/components/sheets/relations-list/index.tsx
+++ b/apps/mobile/app/components/sheets/relations-list/index.tsx
@@ -18,12 +18,13 @@ along with this program. If not, see .
*/
import React, { RefObject, useEffect, useState } from "react";
import { View } from "react-native";
-import ActionSheet from "react-native-actions-sheet";
+import { ActionSheetRef } from "react-native-actions-sheet";
+import { FlashList } from "react-native-actions-sheet/dist/src/views/FlashList";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../../common/database";
import {
- PresentSheetOptions,
- presentSheet
+ presentSheet,
+ PresentSheetOptions
} from "../../../services/event-manager";
import { Reminder } from "../../../services/notifications";
import { useRelationStore } from "../../../stores/use-relation-store";
@@ -37,7 +38,7 @@ import { PressableButtonProps } from "../../ui/pressable";
import Paragraph from "../../ui/typography/paragraph";
type RelationsListProps = {
- actionSheetRef: RefObject;
+ actionSheetRef: RefObject;
close?: () => void;
update?: (options: PresentSheetOptions) => void;
item: { id: string; type: string };
@@ -62,8 +63,6 @@ const IconsByType = {
export const RelationsList = ({
actionSheetRef,
- close,
- update,
item,
referenceType,
relationType,
@@ -75,7 +74,6 @@ export const RelationsList = ({
const [items, setItems] = useState([]);
const colors = useThemeStore((state) => state.colors);
const hasNoRelations = !items || items.length === 0;
-
useEffect(() => {
setItems(
db.relations?.[relationType]?.(
@@ -123,6 +121,7 @@ export const RelationsList = ({
) : (
.
*/
import dayjs from "dayjs";
import React, { RefObject } from "react";
-import { ScrollView, View } from "react-native";
-import ActionSheet from "react-native-actions-sheet";
+import { View } from "react-native";
+import { ActionSheetRef, ScrollView } from "react-native-actions-sheet";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../../common/database";
import {
@@ -36,7 +36,7 @@ import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
type ReminderSheetProps = {
- actionSheetRef: RefObject;
+ actionSheetRef: RefObject;
close?: () => void;
update?: (options: PresentSheetOptions) => void;
reminder?: Reminder;
diff --git a/apps/mobile/app/components/sheets/reminder/index.tsx b/apps/mobile/app/components/sheets/reminder/index.tsx
index 408298ec2..ff29647dc 100644
--- a/apps/mobile/app/components/sheets/reminder/index.tsx
+++ b/apps/mobile/app/components/sheets/reminder/index.tsx
@@ -17,14 +17,8 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
import React, { RefObject, useRef, useState } from "react";
-import {
- Platform,
- ScrollView,
- TextInput,
- useWindowDimensions,
- View
-} from "react-native";
-import ActionSheet from "react-native-actions-sheet";
+import { Platform, TextInput, View } from "react-native";
+import { ActionSheetRef, ScrollView } from "react-native-actions-sheet";
import DateTimePickerModal from "react-native-modal-datetime-picker";
import {
presentSheet,
@@ -44,13 +38,13 @@ import Notifications, { Reminder } from "../../../services/notifications";
import PremiumService from "../../../services/premium";
import SettingsService from "../../../services/settings";
import { useRelationStore } from "../../../stores/use-relation-store";
-import { ReminderTime } from "../../ui/reminder-time";
-import Paragraph from "../../ui/typography/paragraph";
import { NoteType } from "../../../utils/types";
import { Dialog } from "../../dialog";
+import { ReminderTime } from "../../ui/reminder-time";
+import Paragraph from "../../ui/typography/paragraph";
type ReminderSheetProps = {
- actionSheetRef: RefObject;
+ actionSheetRef: RefObject;
close?: (ctx?: string) => void;
update?: (options: PresentSheetOptions) => void;
reminder?: Reminder;
@@ -117,13 +111,15 @@ export default function ReminderSheet({
>(reminder?.priority || SettingsService.get().reminderNotificationMode);
const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
const [repeatFrequency, setRepeatFrequency] = useState(1);
- const title = useRef(reminder?.title);
- const details = useRef(reminder?.description);
- const titleRef = useRef(null);
- const { height } = useWindowDimensions();
const referencedItem = reference
? (db.notes?.note(reference.id)?.data as NoteType)
: null;
+ const title = useRef(
+ reminder?.title || referencedItem?.title
+ );
+ const details = useRef(reminder?.description);
+ const titleRef = useRef(null);
+ const timer = useRef();
const showDatePicker = () => {
setDatePickerVisibility(true);
@@ -134,9 +130,10 @@ export default function ReminderSheet({
};
const handleConfirm = (date: Date) => {
- hideDatePicker();
- setDate(date);
- console.log(date);
+ timer.current = setTimeout(() => {
+ hideDatePicker();
+ setDate(date);
+ }, 50);
};
function nth(n: number) {
return (
@@ -233,13 +230,8 @@ export default function ReminderSheet({
paddingHorizontal: 12
}}
>
-
- actionSheetRef.current?.handleChildScrollEnd()}
- style={{
- maxHeight: height * 0.85
- }}
- >
+
+
(details.current = text)}
containerStyle={{
@@ -440,6 +434,12 @@ export default function ReminderSheet({
+
-
);
}
@@ -582,6 +582,7 @@ ReminderSheet.present = (
) => {
presentSheet({
context: isSheet ? "local" : undefined,
+ enableGesturesInScrollView: true,
component: (ref, close, update) => (
.
*/
import { EVENTS } from "@notesnook/core/common";
-import React, { createRef, useCallback, useEffect, useState } from "react";
+import React, { useCallback, useEffect, useRef, useState } from "react";
import { ActivityIndicator, Platform, View } from "react-native";
+import { FlatList } from "react-native-actions-sheet";
import DocumentPicker from "react-native-document-picker";
-import { FlatList } from "react-native-gesture-handler";
import * as ScopedStorage from "react-native-scoped-storage";
import { db } from "../../../common/database";
import storage from "../../../common/database/storage";
@@ -35,7 +35,7 @@ import { initialize } from "../../../stores";
import { useThemeStore } from "../../../stores/use-theme-store";
import { eCloseRestoreDialog, eOpenRestoreDialog } from "../../../utils/events";
import { SIZE } from "../../../utils/size";
-import { sleep, timeConverter } from "../../../utils/time";
+import { timeConverter } from "../../../utils/time";
import { Dialog } from "../../dialog";
import DialogHeader from "../../dialog/dialog-header";
import { presentDialog } from "../../dialog/functions";
@@ -44,12 +44,18 @@ import { Button } from "../../ui/button";
import Seperator from "../../ui/seperator";
import SheetWrapper from "../../ui/sheet";
import Paragraph from "../../ui/typography/paragraph";
-const actionSheetRef = createRef();
let RNFetchBlob;
const RestoreDataSheet = () => {
const [visible, setVisible] = useState(false);
const [restoring, setRestoring] = useState(false);
+ const sheet = useRef();
useEffect(() => {
+ const open = async () => {
+ setVisible(true);
+ setTimeout(() => {
+ sheet.current?.show();
+ }, 1);
+ };
eSubscribeEvent(eOpenRestoreDialog, open);
eSubscribeEvent(eCloseRestoreDialog, close);
return () => {
@@ -58,21 +64,15 @@ const RestoreDataSheet = () => {
};
}, [close]);
- const open = async () => {
- setVisible(true);
- await sleep(30);
- actionSheetRef.current?.setModalVisible(true);
- };
-
const close = useCallback(() => {
if (restoring) {
showIsWorking();
return;
}
- actionSheetRef.current?.setModalVisible(false);
+ sheet.current?.hide();
setTimeout(() => {
setVisible(false);
- }, 300);
+ }, 150);
}, [restoring]);
const showIsWorking = () => {
@@ -86,15 +86,19 @@ const RestoreDataSheet = () => {
return !visible ? null : (
{
+ setVisible(false);
+ close();
+ }}
>
@@ -109,7 +113,6 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
const [loading, setLoading] = useState(true);
const [backupDirectoryAndroid, setBackupDirectoryAndroid] = useState(false);
const [progress, setProgress] = useState();
-
useEffect(() => {
const subscription = db.eventManager.subscribe(
EVENTS.migrationProgress,
@@ -123,7 +126,9 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
}, []);
useEffect(() => {
- checkBackups();
+ setTimeout(() => {
+ checkBackups();
+ }, 300);
}, []);
const restore = async (item) => {
@@ -362,10 +367,6 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
{
- actionSheetRef.current?.handleChildScrollEnd();
- }}
ListEmptyComponent={
!restoring ? (
loading ? (
diff --git a/apps/mobile/app/components/sheets/topic-sheet/index.tsx b/apps/mobile/app/components/sheets/topic-sheet/index.tsx
new file mode 100644
index 000000000..74cfc2c86
--- /dev/null
+++ b/apps/mobile/app/components/sheets/topic-sheet/index.tsx
@@ -0,0 +1,423 @@
+/*
+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 .
+*/
+import qclone from "qclone";
+import React, {
+ createContext,
+ useContext,
+ useEffect,
+ useRef,
+ useState
+} from "react";
+import { Animated, Dimensions, View, RefreshControl } from "react-native";
+import ActionSheet, {
+ ActionSheetRef,
+ FlatList
+} from "react-native-actions-sheet";
+import { db } from "../../../common/database";
+import { IconButton } from "../../../components/ui/icon-button";
+import { PressableButton } from "../../../components/ui/pressable";
+import Paragraph from "../../../components/ui/typography/paragraph";
+import { TopicNotes } from "../../../screens/notes/topic-notes";
+import {
+ eSendEvent,
+ eSubscribeEvent,
+ eUnSubscribeEvent
+} from "../../../services/event-manager";
+import useNavigationStore, {
+ NotebookScreenParams
+} from "../../../stores/use-navigation-store";
+import { useThemeStore } from "../../../stores/use-theme-store";
+import { eOnNewTopicAdded, eOpenAddTopicDialog } from "../../../utils/events";
+import { normalize, SIZE } from "../../../utils/size";
+import { NotebookType, TopicType } from "../../../utils/types";
+
+import Icon from "react-native-vector-icons/MaterialCommunityIcons";
+import { openEditor } from "../../../screens/notes/common";
+import { getTotalNotes, history } from "../../../utils";
+import { Properties } from "../../properties";
+import { deleteItems } from "../../../utils/functions";
+import { presentDialog } from "../../dialog/functions";
+export const TopicsSheet = () => {
+ const currentScreen = useNavigationStore((state) => state.currentScreen);
+ const canShow =
+ currentScreen.name === "Notebook" || currentScreen.name === "TopicNotes";
+ const [notebook, setNotebook] = useState(
+ canShow
+ ? db.notebooks?.notebook(
+ currentScreen?.notebookId || currentScreen?.id || ""
+ )?.data
+ : null
+ );
+ const [selection, setSelection] = useState([]);
+ const [enabled, setEnabled] = useState(false);
+ const colors = useThemeStore((state) => state.colors);
+ const ref = useRef(null);
+ const [topics, setTopics] = useState(notebook ? qclone(notebook.topics) : []);
+ const [animations] = useState({
+ translate: new Animated.Value(0),
+ display: new Animated.Value(-5000),
+ opacity: new Animated.Value(0)
+ });
+ const onRequestUpdate = React.useCallback(
+ (data?: NotebookScreenParams) => {
+ if (!canShow) return;
+ if (!data) data = { item: notebook } as NotebookScreenParams;
+ const _notebook = db.notebooks?.notebook(data.item?.id)
+ ?.data as NotebookType;
+ if (_notebook) {
+ setNotebook(_notebook);
+ setTopics(qclone(_notebook.topics));
+ }
+ },
+ [notebook, canShow]
+ );
+
+ useEffect(() => {
+ eSubscribeEvent(eOnNewTopicAdded, onRequestUpdate);
+ return () => {
+ eUnSubscribeEvent(eOnNewTopicAdded, onRequestUpdate);
+ };
+ }, [onRequestUpdate]);
+
+ const PLACEHOLDER_DATA = {
+ heading: "Topics",
+ paragraph: "You have not added any topics yet.",
+ button: "Add first topic",
+ action: () => {
+ eSendEvent(eOpenAddTopicDialog, { notebookId: notebook.id });
+ },
+ loading: "Loading notebook topics"
+ };
+
+ const renderTopic = ({ item, index }: { item: TopicType; index: number }) => (
+
+ );
+
+ const selectionContext = {
+ selection: selection,
+ enabled,
+ setEnabled,
+ toggleSelection: (item: TopicType) => {
+ setSelection((state) => {
+ const selection = [...state];
+ const index = selection.findIndex(
+ (selected) => selected.id === item.id
+ );
+ if (index > -1) {
+ selection.splice(index, 1);
+ if (selection.length === 0) {
+ setEnabled(false);
+ }
+ return selection;
+ }
+ selection.push(item);
+ return selection;
+ });
+ }
+ };
+
+ useEffect(() => {
+ if (canShow) {
+ const isTopic = currentScreen.name === "TopicNotes";
+ const id = isTopic ? currentScreen?.notebookId : currentScreen?.id;
+ if (!ref.current?.isOpen()) {
+ animations.display.setValue(5000);
+ animations.opacity.setValue(0);
+ }
+ if (id) {
+ onRequestUpdate({
+ item: db.notebooks?.notebook(id).data
+ } as any);
+ }
+ ref.current?.show();
+ } else {
+ ref.current?.hide();
+ }
+ }, [
+ animations.display,
+ animations.opacity,
+ canShow,
+ currentScreen?.id,
+ currentScreen.name,
+ currentScreen?.notebookId,
+ onRequestUpdate
+ ]);
+
+ return (
+ {
+ animations.translate.setValue(position);
+ const h = Dimensions.get("window").height;
+ const minPos = h - height;
+ if (position - 100 < minPos || !canShow) {
+ animations.display.setValue(5000);
+ animations.opacity.setValue(0);
+ } else {
+ animations.display.setValue(0);
+ setTimeout(() => {
+ animations.opacity.setValue(1);
+ }, 300);
+ }
+ }}
+ gestureEnabled
+ ExtraOverlayComponent={
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+ TOPICS
+
+
+ {enabled ? (
+ {
+ //@ts-ignore
+ history.selectedItemsList = selection;
+ presentDialog({
+ title: `Delete ${
+ selection.length > 1 ? "topics" : "topics"
+ }`,
+ paragraph: `Are you sure you want to delete ${
+ selection.length > 1 ? "these topicss?" : "this topics?"
+ }`,
+ positiveText: "Delete",
+ negativeText: "Cancel",
+ positivePress: async () => {
+ await deleteItems();
+ history.selectedItemsList = [];
+ setEnabled(false);
+ setSelection([]);
+ },
+ positiveType: "errorShade"
+ });
+ return;
+ }}
+ color={colors.pri}
+ tooltipText="Move to trash"
+ tooltipPosition={1}
+ name="delete"
+ size={22}
+ />
+ ) : (
+
+ )}
+
+
+
+ {
+ onRequestUpdate();
+ }}
+ />
+ }
+ keyExtractor={(item) => item.id}
+ renderItem={renderTopic}
+ ListFooterComponent={}
+ />
+
+
+
+ );
+};
+
+const SelectionContext = createContext<{
+ selection: TopicType[];
+ enabled: boolean;
+ setEnabled: (value: boolean) => void;
+ toggleSelection: (item: TopicType) => void;
+}>({
+ selection: [],
+ enabled: false,
+ setEnabled: (value: boolean) => {},
+ toggleSelection: (item: TopicType) => {}
+});
+const useSelection = () => useContext(SelectionContext);
+
+const TopicItem = ({ item }: { item: TopicType; index: number }) => {
+ const screen = useNavigationStore((state) => state.currentScreen);
+ const colors = useThemeStore((state) => state.colors);
+ const selection = useSelection();
+ const isSelected =
+ selection.selection.findIndex((selected) => selected.id === item.id) > -1;
+ const isFocused = screen.id === item.id;
+ const notesCount = getTotalNotes(item);
+
+ return (
+ {
+ if (selection.enabled) return;
+ selection.setEnabled(true);
+ selection.toggleSelection(item);
+ }}
+ onPress={() => {
+ if (selection.enabled) {
+ selection.toggleSelection(item);
+ return;
+ }
+ TopicNotes.navigate(item, true);
+ }}
+ customStyle={{
+ justifyContent: "space-between",
+ width: "100%",
+ alignItems: "center",
+ flexDirection: "row",
+ paddingHorizontal: 12,
+ borderRadius: 0
+ }}
+ >
+
+ {selection.enabled ? (
+
+ ) : null}
+
+ {item.title}{" "}
+ {notesCount ? (
+
+ {notesCount}
+
+ ) : null}
+
+
+ {
+ Properties.present(item);
+ }}
+ left={0}
+ right={0}
+ bottom={0}
+ top={0}
+ color={colors.pri}
+ size={SIZE.xl}
+ />
+
+ );
+};
diff --git a/apps/mobile/app/components/sheets/update/index.js b/apps/mobile/app/components/sheets/update/index.js
index c67bbddf1..4f94e2770 100644
--- a/apps/mobile/app/components/sheets/update/index.js
+++ b/apps/mobile/app/components/sheets/update/index.js
@@ -19,10 +19,10 @@ along with this program. If not, see .
import React, { useEffect, useState } from "react";
import { Linking, View } from "react-native";
+import { ScrollView } from "react-native-actions-sheet";
import { checkVersion } from "react-native-check-version";
import Config from "react-native-config";
import deviceInfoModule from "react-native-device-info";
-import { ScrollView } from "react-native-gesture-handler";
import { useThemeStore } from "../../../stores/use-theme-store";
import { STORE_LINK } from "../../../utils/constants";
import { SIZE } from "../../../utils/size";
@@ -148,9 +148,6 @@ export const Update = ({ version: appVersion, fwdRef }) => {
{
- fwdRef?.current?.handleChildScrollEnd();
- }}
style={{
width: "100%"
}}
diff --git a/apps/mobile/app/components/ui/sheet/index.js b/apps/mobile/app/components/ui/sheet/index.js
index 1027029b6..d8c66a641 100644
--- a/apps/mobile/app/components/ui/sheet/index.js
+++ b/apps/mobile/app/components/ui/sheet/index.js
@@ -37,7 +37,8 @@ const SheetWrapper = ({
onHasReachedTop,
keyboardMode,
overlay,
- overlayOpacity = 0.3
+ overlayOpacity = 0.3,
+ enableGesturesInScrollView = false
}) => {
const colors = useThemeStore((state) => state.colors);
const deviceMode = useSettingStore((state) => state.deviceMode);
@@ -59,8 +60,8 @@ const SheetWrapper = ({
zIndex: 10,
paddingTop: 5,
paddingBottom: 0,
- borderTopRightRadius: 20,
- borderTopLeftRadius: 20,
+ borderTopRightRadius: 15,
+ borderTopLeftRadius: 15,
alignSelf: "center",
borderBottomRightRadius: 0,
borderBottomLeftRadius: 0
@@ -84,7 +85,8 @@ const SheetWrapper = ({
backdrop: "sheet-backdrop"
}}
indicatorStyle={{
- width: 100
+ width: 100,
+ backgroundColor: colors.nav
}}
drawUnderStatusBar={false}
containerStyle={style}
@@ -98,8 +100,9 @@ const SheetWrapper = ({
indicatorColor={colors.nav}
onOpen={_onOpen}
keyboardDismissMode="none"
+ enableGesturesInScrollView={enableGesturesInScrollView}
defaultOverlayOpacity={overlayOpacity}
- overlayColor={pitchBlack ? "#585858" : "#000000"}
+ overlayColor={pitchBlack ? "#585858" : "#2b2b2b"}
keyboardShouldPersistTaps="always"
ExtraOverlayComponent={
<>
diff --git a/apps/mobile/app/hooks/use-actions.js b/apps/mobile/app/hooks/use-actions.js
index 1781d8d05..9c25df246 100644
--- a/apps/mobile/app/hooks/use-actions.js
+++ b/apps/mobile/app/hooks/use-actions.js
@@ -22,10 +22,15 @@ import React, { useCallback, useEffect, useState } from "react";
import { Platform } from "react-native";
import Share from "react-native-share";
import { db } from "../common/database";
+import { AttachmentDialog } from "../components/attachments";
import { presentDialog } from "../components/dialog/functions";
import NoteHistory from "../components/note-history";
+import { AddNotebookSheet } from "../components/sheets/add-notebook";
+import MoveNoteSheet from "../components/sheets/add-to";
import ExportNotesSheet from "../components/sheets/export-notes";
import { MoveNotes } from "../components/sheets/move-notes/movenote";
+import PublishNoteSheet from "../components/sheets/publish-note";
+import { RelationsList } from "../components/sheets/relations-list/index";
import ReminderSheet from "../components/sheets/reminder";
import {
eSendEvent,
@@ -40,24 +45,16 @@ import Notifications from "../services/notifications";
import { useEditorStore } from "../stores/use-editor-store";
import { useMenuStore } from "../stores/use-menu-store";
import useNavigationStore from "../stores/use-navigation-store";
+import { useRelationStore } from "../stores/use-relation-store";
import { useSelectionStore } from "../stores/use-selection-store";
import { useTagStore } from "../stores/use-tag-store";
import { useThemeStore } from "../stores/use-theme-store";
import { useUserStore } from "../stores/use-user-store";
import { toTXT } from "../utils";
import { toggleDarkMode } from "../utils/color-scheme/utils";
-import {
- eOpenAddNotebookDialog,
- eOpenAddTopicDialog,
- eOpenAttachmentsDialog,
- eOpenLoginDialog,
- eOpenMoveNoteDialog,
- eOpenPublishNoteDialog
-} from "../utils/events";
+import { eOpenAddTopicDialog, eOpenLoginDialog } from "../utils/events";
import { deleteItems } from "../utils/functions";
import { sleep } from "../utils/time";
-import { RelationsList } from "../components/sheets/relations-list/index";
-import { useRelationStore } from "../stores/use-relation-store";
export const useActions = ({ close = () => null, item }) => {
const colors = useThemeStore((state) => state.colors);
@@ -129,12 +126,9 @@ export const useActions = ({ close = () => null, item }) => {
}
function addTo() {
- close();
clearSelection(true);
setSelectedItem(item);
- setTimeout(() => {
- eSendEvent(eOpenMoveNoteDialog, item);
- }, 300);
+ MoveNoteSheet.present(item);
}
async function addToFavorites() {
@@ -270,9 +264,7 @@ export const useActions = ({ close = () => null, item }) => {
});
return;
}
- close();
- await sleep(300);
- eSendEvent(eOpenPublishNoteDialog, item);
+ PublishNoteSheet.present(item);
}
const checkNoteSynced = () => {
@@ -538,22 +530,16 @@ export const useActions = ({ close = () => null, item }) => {
}
async function openHistory() {
- close();
- await sleep(300);
presentSheet({
component: (ref) =>
});
}
async function showAttachments() {
- close();
- await sleep(300);
- eSendEvent(eOpenAttachmentsDialog, item);
+ AttachmentDialog.present();
}
async function exportNote() {
- close();
- await sleep(300);
ExportNotesSheet.present([item]);
}
@@ -647,8 +633,6 @@ export const useActions = ({ close = () => null, item }) => {
title: "Add notes",
icon: "plus",
func: async () => {
- close();
- await sleep(500);
MoveNotes.present(db.notebooks.notebook(item.notebookId).data, item);
}
},
@@ -689,9 +673,7 @@ export const useActions = ({ close = () => null, item }) => {
title: "Edit notebook",
icon: "square-edit-outline",
func: async () => {
- close();
- await sleep(300);
- eSendEvent(eOpenAddNotebookDialog, item);
+ AddNotebookSheet.present(item);
}
},
{
@@ -777,8 +759,6 @@ export const useActions = ({ close = () => null, item }) => {
title: "Edit reminder",
icon: "pencil",
func: async () => {
- close();
- await sleep(300);
ReminderSheet.present(item);
},
close: false
@@ -789,7 +769,6 @@ export const useActions = ({ close = () => null, item }) => {
title: "Reminders",
icon: "clock-outline",
func: async () => {
- close();
RelationsList.present({
reference: item,
referenceType: "reminder",
diff --git a/apps/mobile/app/navigation/navigation-stack.js b/apps/mobile/app/navigation/navigation-stack.js
index 8441ce743..360dfa77b 100644
--- a/apps/mobile/app/navigation/navigation-stack.js
+++ b/apps/mobile/app/navigation/navigation-stack.js
@@ -24,6 +24,7 @@ import { SafeAreaView } from "react-native";
import Container from "../components/container";
import DelayLayout from "../components/delay-layout";
import Intro from "../components/intro";
+import { TopicsSheet } from "../components/sheets/topic-sheet";
import useGlobalSafeAreaInsets from "../hooks/use-global-safe-area-insets";
import { hideAllTooltips } from "../hooks/use-tooltip";
import Favorites from "../screens/favorites";
@@ -198,6 +199,7 @@ const _NavigationStack = () => {
+
);
};
diff --git a/apps/mobile/app/package.json b/apps/mobile/app/package.json
index 629f3459d..ea3fb7829 100644
--- a/apps/mobile/app/package.json
+++ b/apps/mobile/app/package.json
@@ -4,6 +4,8 @@
"main": "./App.js",
"license": "GPL-3.0-or-later",
"dependencies": {
+ "react": "18.0.0",
+ "react-native": "0.69.7",
"@flyerhq/react-native-link-preview": "^1.6.0",
"@mdi/js": "^6.7.96",
"absolutify": "^0.1.0",
@@ -13,7 +15,7 @@
"html-to-text": "8.1.0",
"phone": "^3.1.14",
"qclone": "^1.2.0",
- "react-native-actions-sheet": "^0.7.2",
+ "react-native-actions-sheet": "^0.9.0-alpha.6",
"react-native-check-version": "https://github.com/flexible-agency/react-native-check-version",
"react-native-drax": "^0.10.2",
"react-native-image-zoom-viewer": "^3.0.1",
@@ -28,7 +30,6 @@
"zustand": "^3.6.0",
"fflate": "^0.7.3",
"timeago.js": "4.0.2"
-
},
"sideEffects": false
}
diff --git a/apps/mobile/app/screens/editor/loading.js b/apps/mobile/app/screens/editor/loading.js
index 7a0d81742..2a420af77 100644
--- a/apps/mobile/app/screens/editor/loading.js
+++ b/apps/mobile/app/screens/editor/loading.js
@@ -78,7 +78,7 @@ const EditorOverlay = ({ editorId = "", editor }) => {
setTimeout(() => {
translateValue.value = 6000;
}, 500);
- }, 100);
+ }, 0);
}
},
[opacity, translateValue]
diff --git a/apps/mobile/app/screens/editor/tiptap/use-editor-events.ts b/apps/mobile/app/screens/editor/tiptap/use-editor-events.ts
index 7be714a60..976e6f38e 100644
--- a/apps/mobile/app/screens/editor/tiptap/use-editor-events.ts
+++ b/apps/mobile/app/screens/editor/tiptap/use-editor-events.ts
@@ -29,7 +29,7 @@ import {
} from "react-native";
import { WebViewMessageEvent } from "react-native-webview";
import { db } from "../../../common/database";
-import ImagePreview from "../../../components/image-preview";
+import ManageTagsSheet from "../../../components/sheets/manage-tags";
import { RelationsList } from "../../../components/sheets/relations-list";
import ReminderSheet from "../../../components/sheets/reminder";
import useKeyboard from "../../../hooks/use-keyboard";
@@ -52,8 +52,7 @@ import {
eOpenFullscreenEditor,
eOpenLoginDialog,
eOpenPremiumDialog,
- eOpenPublishNoteDialog,
- eOpenTagsDialog
+ eOpenPublishNoteDialog
} from "../../../utils/events";
import { openLinkInBrowser } from "../../../utils/functions";
import { tabBarRef } from "../../../utils/global-refs";
@@ -327,7 +326,7 @@ export const useEditorEvents = (
});
return;
}
- eSendEvent(eOpenTagsDialog, editor.note.current);
+ ManageTagsSheet.present(editor.note.current);
break;
case EventTypes.tag:
if (editorMessage.value) {
diff --git a/apps/mobile/app/screens/editor/tiptap/use-editor.ts b/apps/mobile/app/screens/editor/tiptap/use-editor.ts
index 733fa20f2..620fd2ea6 100644
--- a/apps/mobile/app/screens/editor/tiptap/use-editor.ts
+++ b/apps/mobile/app/screens/editor/tiptap/use-editor.ts
@@ -230,6 +230,7 @@ export const useEditor = (
id = await db.notes?.add(noteData);
if (!note && id) {
currentNote.current = db.notes?.note(id).data as NoteType;
+ console.log("on Note Created", state.current?.onNoteCreated);
state.current?.onNoteCreated && state.current.onNoteCreated(id);
if (!noteData.title) {
postMessage(
diff --git a/apps/mobile/app/screens/home/index.tsx b/apps/mobile/app/screens/home/index.tsx
index 1e5ff7b8e..7e164031f 100755
--- a/apps/mobile/app/screens/home/index.tsx
+++ b/apps/mobile/app/screens/home/index.tsx
@@ -65,7 +65,6 @@ export const Home = ({ navigation, route }: NavigationProps<"Notes">) => {
onBlur: () => false,
delay: SettingsService.get().homepage === route.name ? 1 : -1
});
-
return (
.
*/
-
import { groupArray } from "@notesnook/core/utils/grouping";
-import qclone from "qclone";
import React, { useEffect, useRef, useState } from "react";
import { db } from "../../common/database";
-import { FloatingButton } from "../../components/container/floating-button";
import DelayLayout from "../../components/delay-layout";
import List from "../../components/list";
import { NotebookHeader } from "../../components/list-items/headers/notebook-header";
@@ -36,28 +33,29 @@ import SearchService from "../../services/search";
import useNavigationStore, {
NotebookScreenParams
} from "../../stores/use-navigation-store";
-import {
- eOnNewTopicAdded,
- eOpenAddNotebookDialog,
- eOpenAddTopicDialog
-} from "../../utils/events";
+import { eOnNewTopicAdded, eOpenAddNotebookDialog } from "../../utils/events";
import { NotebookType } from "../../utils/types";
+import { openEditor, setOnFirstSave } from "../notes/common";
const Notebook = ({ route, navigation }: NavigationProps<"Notebook">) => {
- const [topics, setTopics] = useState(
+ const [notes, setNotes] = useState(
groupArray(
- qclone(route?.params.item?.topics) || [],
- db.settings?.getGroupOptions("topics")
+ db.relations?.from(route.params.item, "note") || [],
+ db.settings?.getGroupOptions("notes")
)
);
const params = useRef(route?.params);
+
useNavigationFocus(navigation, {
onFocus: () => {
Navigation.routeNeedsUpdate(route.name, onRequestUpdate);
syncWithNavigation();
- useNavigationStore.getState().setButtonAction(onPressFloatingButton);
+ useNavigationStore.getState().setButtonAction(openEditor);
return false;
},
- onBlur: () => false
+ onBlur: () => {
+ setOnFirstSave(null);
+ return false;
+ }
});
const syncWithNavigation = React.useCallback(() => {
@@ -70,6 +68,10 @@ const Notebook = ({ route, navigation }: NavigationProps<"Notebook">) => {
},
params.current?.canGoBack
);
+ setOnFirstSave({
+ type: "notebook",
+ id: params.current.item.id
+ });
SearchService.prepareSearch = prepareSearch;
}, [route.name]);
@@ -82,11 +84,9 @@ const Notebook = ({ route, navigation }: NavigationProps<"Notebook">) => {
?.data as NotebookType;
if (notebook) {
params.current.item = notebook;
- setTopics(
- groupArray(
- qclone(notebook.topics),
- db.settings?.getGroupOptions("topics")
- )
+ const notes = db.relations?.from(notebook, "note");
+ setNotes(
+ groupArray(notes || [], db.settings?.getGroupOptions("notes"))
);
syncWithNavigation();
}
@@ -102,60 +102,61 @@ const Notebook = ({ route, navigation }: NavigationProps<"Notebook">) => {
return () => {
eUnSubscribeEvent(eOnNewTopicAdded, onRequestUpdate);
};
- }, [onRequestUpdate, topics]);
+ }, [onRequestUpdate]);
+
+ useEffect(() => {
+ return () => {
+ setOnFirstSave(null);
+ };
+ }, []);
const prepareSearch = () => {
SearchService.update({
placeholder: `Search in "${params.current.title}"`,
- type: "topics",
+ type: "notes",
title: params.current.title,
get: () => {
const notebook = db.notebooks?.notebook(params?.current?.item?.id)
?.data as NotebookType;
- return notebook?.topics;
+ return db.relations?.from(notebook, "note");
}
});
};
- const onPressFloatingButton = () => {
- const n = params.current.item;
- eSendEvent(eOpenAddTopicDialog, { notebookId: n.id });
- };
-
const PLACEHOLDER_DATA = {
heading: params.current.item?.title,
- paragraph: "You have not added any topics yet.",
- button: "Add first topic",
- action: onPressFloatingButton,
- loading: "Loading notebook topics"
+ paragraph: "You have not added any notes yet.",
+ button: "Add first note",
+ action: openEditor,
+ loading: "Loading notebook notes"
};
return (
-
- {
- onRequestUpdate();
- }}
- screen="Notebook"
- headerProps={{
- heading: params.current.title
- }}
- loading={false}
- ListHeader={
- {
- eSendEvent(eOpenAddNotebookDialog, params.current.item);
- }}
- notebook={params.current.item}
- />
- }
- placeholderData={PLACEHOLDER_DATA}
- />
-
-
-
+ <>
+
+ {
+ onRequestUpdate();
+ }}
+ screen="Notebook"
+ headerProps={{
+ heading: params.current.title
+ }}
+ loading={false}
+ ListHeader={
+ {
+ eSendEvent(eOpenAddNotebookDialog, params.current.item);
+ }}
+ notebook={params.current.item}
+ />
+ }
+ placeholderData={PLACEHOLDER_DATA}
+ />
+
+ >
);
};
diff --git a/apps/mobile/app/screens/notebooks/index.tsx b/apps/mobile/app/screens/notebooks/index.tsx
index b01ecc14b..95b59c4e5 100644
--- a/apps/mobile/app/screens/notebooks/index.tsx
+++ b/apps/mobile/app/screens/notebooks/index.tsx
@@ -18,11 +18,12 @@ along with this program. If not, see .
*/
import React from "react";
+import { Config } from "react-native-config";
import { db } from "../../common/database";
import { FloatingButton } from "../../components/container/floating-button";
import DelayLayout from "../../components/delay-layout";
-import { AddNotebookEvent } from "../../components/dialog-provider/recievers";
import List from "../../components/list";
+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";
@@ -30,10 +31,9 @@ import SearchService from "../../services/search";
import SettingsService from "../../services/settings";
import useNavigationStore from "../../stores/use-navigation-store";
import { useNotebookStore } from "../../stores/use-notebook-store";
-import { Config } from "react-native-config";
const onPressFloatingButton = () => {
- AddNotebookEvent();
+ AddNotebookSheet.present();
};
const prepareSearch = () => {
@@ -83,7 +83,7 @@ export const Notebooks = ({
});
return (
-
+
onNoteCreated(id, data);
+ setTimeout(() => {
+ editorState().onNoteCreated = (id) => onNoteCreated(id, data);
+ }, 0);
};
async function onNoteCreated(id: string, params: FirstSaveData) {
if (!params) return;
switch (params.type) {
+ case "notebook": {
+ await db.relations?.add(
+ { type: "notebook", id: params.id },
+ { type: "note", id: id }
+ );
+ Navigation.queueRoutesForUpdate(
+ "TaggedNotes",
+ "ColoredNotes",
+ "TopicNotes",
+ "Favorites",
+ "Notes",
+ "Notebook",
+ "Notebooks"
+ );
+ editorState().onNoteCreated = null;
+ break;
+ }
case "topic": {
if (!params.notebook) break;
await db.notes?.addToNotebook(
diff --git a/apps/mobile/app/screens/notes/index.tsx b/apps/mobile/app/screens/notes/index.tsx
index 1cce4bf20..2cbd12a0b 100644
--- a/apps/mobile/app/screens/notes/index.tsx
+++ b/apps/mobile/app/screens/notes/index.tsx
@@ -42,6 +42,13 @@ import {
setOnFirstSave,
toCamelCase
} from "./common";
+import { View } from "react-native";
+import { db } from "../../common/database";
+import Paragraph from "../../components/ui/typography/paragraph";
+import { IconButton } from "../../components/ui/icon-button";
+import { useThemeStore } from "../../stores/use-theme-store";
+import { SIZE } from "../../utils/size";
+import Notebook from "../notebook/index";
export const WARNING_DATA = {
title: "Some notes in this topic are not synced"
};
@@ -92,13 +99,18 @@ const NotesPage = ({
}: RouteProps<
"NotesPage" | "TaggedNotes" | "Monographs" | "ColoredNotes" | "TopicNotes"
>) => {
+ const colors = useThemeStore((state) => state.colors);
const params = useRef(route?.params);
const [notes, setNotes] = useState(get(route.params, true));
const loading = useNoteStore((state) => state.loading);
const [loadingNotes, setLoadingNotes] = useState(false);
const alias = getAlias(params.current);
const isMonograph = route.name === "Monographs";
-
+ const notebook =
+ route.name === "TopicNotes" && (params.current.item as TopicType).notebookId
+ ? db.notebooks?.notebook((params.current.item as TopicType).notebookId)
+ ?.data
+ : null;
const isFocused = useNavigationFocus(navigation, {
onFocus: (prev) => {
Navigation.routeNeedsUpdate(route.name, onRequestUpdate);
@@ -176,6 +188,7 @@ const NotesPage = ({
) {
return Navigation.goBack();
}
+ if (notes.length === 0) setLoadingNotes(false);
setNotes(notes);
syncWithNavigation();
} catch (e) {
@@ -187,7 +200,7 @@ const NotesPage = ({
useEffect(() => {
if (loadingNotes) {
- setTimeout(() => setLoadingNotes(false), 300);
+ setTimeout(() => setLoadingNotes(false), 50);
}
}, [loadingNotes, notes]);
@@ -208,6 +221,45 @@ const NotesPage = ({
}
wait={loading || loadingNotes}
>
+ {route.name === "TopicNotes" ? (
+
+ {
+ Navigation.navigate(
+ {
+ name: "Notebooks"
+ },
+ {}
+ );
+ }}
+ size={SIZE.xs}
+ >
+ Notebooks
+
+
+ {
+ Notebook.navigate(notebook, true);
+ }}
+ size={SIZE.xs}
+ >
+ {notebook.title}
+
+
+ ) : null}
) => {
return (
-
+ <>
+
+ >
);
};
diff --git a/apps/mobile/app/services/event-manager.ts b/apps/mobile/app/services/event-manager.ts
index de3e5fcf0..c769fde2e 100644
--- a/apps/mobile/app/services/event-manager.ts
+++ b/apps/mobile/app/services/event-manager.ts
@@ -17,10 +17,10 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-import Clipboard from "@react-native-clipboard/clipboard";
import EventManager from "@notesnook/core/utils/event-manager";
+import Clipboard from "@react-native-clipboard/clipboard";
import { RefObject } from "react";
-import ActionSheet from "react-native-actions-sheet";
+import { ActionSheetRef } from "react-native-actions-sheet";
import Config from "react-native-config";
import {
eCloseSheet,
@@ -97,7 +97,7 @@ export type PresentSheetOptions = {
component:
| JSX.Element
| ((
- ref: RefObject,
+ ref: RefObject,
close?: (ctx?: string) => void,
update?: (props: PresentSheetOptions) => void
) => JSX.Element);
@@ -114,6 +114,7 @@ export type PresentSheetOptions = {
actionsArray: SheetAction[];
learnMore: string;
learnMorePress: () => void;
+ enableGesturesInScrollView: boolean;
};
export function presentSheet(data: Partial) {
diff --git a/apps/mobile/package-lock.json b/apps/mobile/package-lock.json
index e07e510ce..ad903a49f 100644
--- a/apps/mobile/package-lock.json
+++ b/apps/mobile/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@notesnook/mobile",
- "version": "2.4.5",
+ "version": "2.4.6",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@notesnook/mobile",
- "version": "2.4.5",
+ "version": "2.4.6",
"license": "GPL-3.0-or-later",
"workspaces": [
"native/",
@@ -40,7 +40,9 @@
"html-to-text": "8.1.0",
"phone": "^3.1.14",
"qclone": "^1.2.0",
- "react-native-actions-sheet": "^0.7.2",
+ "react": "18.0.0",
+ "react-native": "0.69.7",
+ "react-native-actions-sheet": "^0.9.0-alpha.6",
"react-native-check-version": "https://github.com/flexible-agency/react-native-check-version",
"react-native-drax": "^0.10.2",
"react-native-image-zoom-viewer": "^3.0.1",
@@ -17955,10 +17957,28 @@
}
},
"node_modules/react-native-actions-sheet": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.7.2.tgz",
- "integrity": "sha512-au9QkDnSC+lhiTMHYA2cNdOhrKW/6v/vdeOTNigRFuvYoVVS2+vJOJpt2Z3mumRjmD02UocV0WmHu4anSsqqpA==",
+ "version": "0.9.0-alpha.6",
+ "resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.9.0-alpha.6.tgz",
+ "integrity": "sha512-CtSttiXk+pTmuzrtfDlX5cwYEBsS2DuvZSE17iEYzbTDaYQ2ahRn7+34h4kuDmqLvp9Sdksb7C8s5pFJj+S9sA==",
+ "dependencies": {
+ "@shopify/flash-list": "^1.4.1"
+ },
"peerDependencies": {
+ "react-native": "*",
+ "react-native-gesture-handler": "*"
+ }
+ },
+ "node_modules/react-native-actions-sheet/node_modules/@shopify/flash-list": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.4.1.tgz",
+ "integrity": "sha512-yM5dlhqolO/R8FKomqCrSYz0Cc82vJDikxhbu1CXXGp3rPvo/ceP9jJyKueW96SXHsn/87fcSq2BjztWjlp74Q==",
+ "dependencies": {
+ "recyclerlistview": "4.2.0",
+ "tslib": "2.4.0"
+ },
+ "peerDependencies": {
+ "@babel/runtime": "*",
+ "react": "*",
"react-native": "*"
}
},
@@ -24307,7 +24327,9 @@
"html-to-text": "8.1.0",
"phone": "^3.1.14",
"qclone": "^1.2.0",
- "react-native-actions-sheet": "^0.7.2",
+ "react": "18.0.0",
+ "react-native": "0.69.7",
+ "react-native-actions-sheet": "^0.9.0-alpha.6",
"react-native-check-version": "https://github.com/flexible-agency/react-native-check-version",
"react-native-drax": "^0.10.2",
"react-native-image-zoom-viewer": "^3.0.1",
@@ -34851,9 +34873,23 @@
}
},
"react-native-actions-sheet": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.7.2.tgz",
- "integrity": "sha512-au9QkDnSC+lhiTMHYA2cNdOhrKW/6v/vdeOTNigRFuvYoVVS2+vJOJpt2Z3mumRjmD02UocV0WmHu4anSsqqpA=="
+ "version": "0.9.0-alpha.6",
+ "resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.9.0-alpha.6.tgz",
+ "integrity": "sha512-CtSttiXk+pTmuzrtfDlX5cwYEBsS2DuvZSE17iEYzbTDaYQ2ahRn7+34h4kuDmqLvp9Sdksb7C8s5pFJj+S9sA==",
+ "requires": {
+ "@shopify/flash-list": "^1.4.1"
+ },
+ "dependencies": {
+ "@shopify/flash-list": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.4.1.tgz",
+ "integrity": "sha512-yM5dlhqolO/R8FKomqCrSYz0Cc82vJDikxhbu1CXXGp3rPvo/ceP9jJyKueW96SXHsn/87fcSq2BjztWjlp74Q==",
+ "requires": {
+ "recyclerlistview": "4.2.0",
+ "tslib": "2.4.0"
+ }
+ }
+ }
},
"react-native-actions-shortcuts": {
"version": "1.0.1",
diff --git a/packages/clipper/src/images.ts b/packages/clipper/src/images.ts
index 10a8f590a..897aa01e5 100644
--- a/packages/clipper/src/images.ts
+++ b/packages/clipper/src/images.ts
@@ -54,7 +54,7 @@ async function inlineImage(element: HTMLImageElement, options?: FetchOptions) {
return element;
}
- return new Promise(function (resolve, reject) {
+ return new Promise(function(resolve, reject) {
if (element.parentElement?.tagName === "PICTURE") {
element.parentElement?.replaceWith(element);
}
diff --git a/packages/editor/src/toolbar/tools/image.tsx b/packages/editor/src/toolbar/tools/image.tsx
index 7a3e83d44..99d8e19d6 100644
--- a/packages/editor/src/toolbar/tools/image.tsx
+++ b/packages/editor/src/toolbar/tools/image.tsx
@@ -43,8 +43,14 @@ export function ImageSettings(props: ToolProps) {
popupId="imageSettings"
tools={
findSelectedNode(editor, "image")?.attrs?.float
- ? ["imageAlignLeft", "imageAlignRight", "imageProperties"]
+ ? [
+ "downloadAttachment",
+ "imageAlignLeft",
+ "imageAlignRight",
+ "imageProperties"
+ ]
: [
+ "downloadAttachment",
"imageAlignLeft",
"imageAlignCenter",
"imageAlignRight",