From 26ec8551f97171ec4415459334e515d78fa61454 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Tue, 3 Jan 2023 10:23:48 +0500 Subject: [PATCH] mobile: add disable/snooze function --- .gitignore | 3 +- .../app/components/announcements/cta.js | 6 +- .../app/components/attachments/actions.js | 8 +- .../app/components/auth/change-password.js | 4 +- apps/mobile/app/components/auth/two-factor.js | 4 +- .../components/dialogs/result/pro-features.js | 4 +- .../app/components/list-items/note/index.js | 20 +- .../app/components/list-items/note/wrapper.js | 23 +- .../components/list-items/reminder/index.tsx | 76 ++++-- .../list-items/selection-wrapper/index.js | 4 +- apps/mobile/app/components/list/index.js | 10 +- .../app/components/note-history/preview.js | 10 +- .../app/components/premium/component.js | 4 +- .../app/components/premium/pricing-plans.js | 10 +- .../mobile/app/components/properties/index.js | 11 +- .../app/components/sheet-provider/index.js | 10 +- .../components/sheets/export-notes/index.js | 4 +- .../app/components/sheets/github/issue.js | 4 +- .../app/components/sheets/migrate/index.tsx | 4 +- .../components/sheets/move-notes/movenote.tsx | 4 +- .../components/sheets/new-feature/index.tsx | 4 +- .../sheets/relations-list/index.tsx | 12 +- .../sheets/reminder-notify/index.tsx | 186 +++++++++++++ .../app/components/sheets/reminder/index.tsx | 117 ++++---- apps/mobile/app/components/tip/index.tsx | 4 +- .../app/components/walkthroughs/index.tsx | 6 +- apps/mobile/app/hooks/use-actions.js | 58 +++- apps/mobile/app/hooks/use-app-events.js | 4 +- .../app/screens/editor/tiptap/picker.js | 8 +- apps/mobile/app/screens/settings/2fa.tsx | 6 +- .../app/screens/settings/settings-data.tsx | 10 +- apps/mobile/app/services/backup.js | 10 +- apps/mobile/app/services/event-manager.ts | 11 +- apps/mobile/app/services/notifications.ts | 253 ++++++++++++------ apps/mobile/app/utils/events.js | 4 +- apps/mobile/app/utils/time/index.ts | 112 -------- apps/mobile/native/ios/Podfile.lock | 15 ++ packages/core/collections/reminders.js | 9 + 38 files changed, 680 insertions(+), 372 deletions(-) create mode 100644 apps/mobile/app/components/sheets/reminder-notify/index.tsx diff --git a/.gitignore b/.gitignore index b411e32b6..d754c0236 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ node_modules dist .DS_STORE nx-cloud.env -.idea \ No newline at end of file +.idea +.eslintcache \ No newline at end of file diff --git a/apps/mobile/app/components/announcements/cta.js b/apps/mobile/app/components/announcements/cta.js index fdf2f3029..c0a95b541 100644 --- a/apps/mobile/app/components/announcements/cta.js +++ b/apps/mobile/app/components/announcements/cta.js @@ -25,7 +25,7 @@ import Sync from "../../services/sync"; import { useThemeStore } from "../../stores/use-theme-store"; import { eCloseAnnouncementDialog, - eCloseProgressDialog + eCloseSheet } from "../../utils/events"; import { SIZE } from "../../utils/size"; import { sleep } from "../../utils/time"; @@ -60,11 +60,11 @@ export const Cta = ({ actions, style = {}, color, inline }) => { ) }); } else if (item.type === "force-sync") { - eSendEvent(eCloseProgressDialog); + eSendEvent(eCloseSheet); await sleep(300); Progress.present(); Sync.run("global", true, true, () => { - eSendEvent(eCloseProgressDialog); + eSendEvent(eCloseSheet); }); } }; diff --git a/apps/mobile/app/components/attachments/actions.js b/apps/mobile/app/components/attachments/actions.js index 821fe244a..7b1151134 100644 --- a/apps/mobile/app/components/attachments/actions.js +++ b/apps/mobile/app/components/attachments/actions.js @@ -37,7 +37,7 @@ import { useThemeStore } from "../../stores/use-theme-store"; import { formatBytes } from "../../utils"; import { eCloseAttachmentDialog, - eCloseProgressDialog + eCloseSheet } from "../../utils/events"; import { SIZE } from "../../utils/size"; import { sleep } from "../../utils/time"; @@ -71,7 +71,7 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => { useAttachmentStore.getState().remove(attachment.metadata.hash); } downloadAttachment(attachment.metadata.hash, false); - eSendEvent(eCloseProgressDialog, contextId); + eSendEvent(eCloseSheet, contextId); }, icon: "download" }, @@ -150,7 +150,7 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => { onPress: async () => { await db.attachments.remove(attachment.metadata.hash, false); setAttachments([...db.attachments.all]); - eSendEvent(eCloseProgressDialog, contextId); + eSendEvent(eCloseSheet, contextId); }, icon: "delete-outline" } @@ -293,7 +293,7 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => { }); return; } - eSendEvent(eCloseProgressDialog, contextId); + eSendEvent(eCloseSheet, contextId); await sleep(150); eSendEvent(eCloseAttachmentDialog); await sleep(300); diff --git a/apps/mobile/app/components/auth/change-password.js b/apps/mobile/app/components/auth/change-password.js index 9699b9c4c..7ad1a11d5 100644 --- a/apps/mobile/app/components/auth/change-password.js +++ b/apps/mobile/app/components/auth/change-password.js @@ -26,7 +26,7 @@ import { ToastEvent } from "../../services/event-manager"; import { useUserStore } from "../../stores/use-user-store"; -import { eCloseProgressDialog } from "../../utils/events"; +import { eCloseSheet } from "../../utils/events"; import DialogHeader from "../dialog/dialog-header"; import { Button } from "../ui/button"; import Input from "../ui/input"; @@ -72,7 +72,7 @@ export const ChangePassword = () => { context: "global" }); setLoading(false); - eSendEvent(eCloseProgressDialog); + eSendEvent(eCloseSheet); } catch (e) { setLoading(false); ToastEvent.show({ diff --git a/apps/mobile/app/components/auth/two-factor.js b/apps/mobile/app/components/auth/two-factor.js index d051cb64e..16fc5e3d5 100644 --- a/apps/mobile/app/components/auth/two-factor.js +++ b/apps/mobile/app/components/auth/two-factor.js @@ -27,7 +27,7 @@ import { ToastEvent } from "../../services/event-manager"; import { useThemeStore } from "../../stores/use-theme-store"; -import { eCloseProgressDialog } from "../../utils/events"; +import { eCloseSheet } from "../../utils/events"; import { SIZE } from "../../utils/size"; import { Button } from "../ui/button"; import { IconButton } from "../ui/icon-button"; @@ -77,7 +77,7 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo }) => { }, (result) => { if (result) { - eSendEvent(eCloseProgressDialog, "two_factor_verify"); + eSendEvent(eCloseSheet, "two_factor_verify"); } setLoading(false); } diff --git a/apps/mobile/app/components/dialogs/result/pro-features.js b/apps/mobile/app/components/dialogs/result/pro-features.js index acdf5dd3e..3dd1caa8d 100644 --- a/apps/mobile/app/components/dialogs/result/pro-features.js +++ b/apps/mobile/app/components/dialogs/result/pro-features.js @@ -23,7 +23,7 @@ import Icon from "react-native-vector-icons/MaterialCommunityIcons"; import { eSendEvent } from "../../../services/event-manager"; import { useThemeStore } from "../../../stores/use-theme-store"; import { - eCloseProgressDialog, + eCloseSheet, eCloseResultDialog, eOpenPremiumDialog } from "../../../utils/events"; @@ -82,7 +82,7 @@ export const ProFeatures = ({ count = 6 }) => { { eSendEvent(eCloseResultDialog); - eSendEvent(eCloseProgressDialog); + eSendEvent(eCloseSheet); await sleep(300); eSendEvent(eOpenPremiumDialog); }} diff --git a/apps/mobile/app/components/list-items/note/index.js b/apps/mobile/app/components/list-items/note/index.js index 0d3de364c..2658af984 100644 --- a/apps/mobile/app/components/list-items/note/index.js +++ b/apps/mobile/app/components/list-items/note/index.js @@ -17,14 +17,19 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +import { + formatReminderTime, + getUpcomingReminder +} from "@notesnook/core/collections/reminders"; import { decode, EntityLevel } from "entities"; import React from "react"; -import { View } from "react-native"; +import { TouchableOpacity, View } from "react-native"; import Icon from "react-native-vector-icons/MaterialCommunityIcons"; import { notesnook } from "../../../../e2e/test.ids"; import { db } from "../../../common/database"; import { TaggedNotes } from "../../../screens/notes/tagged"; import { TopicNotes } from "../../../screens/notes/topic-notes"; +import { useRelationStore } from "../../../stores/use-relation-store"; import { useSettingStore } from "../../../stores/use-setting-store"; import { useThemeStore } from "../../../stores/use-theme-store"; import { COLORS_NOTE } from "../../../utils/color-scheme"; @@ -35,10 +40,6 @@ import { IconButton } from "../../ui/icon-button"; import { TimeSince } from "../../ui/time-since"; import Heading from "../../ui/typography/heading"; import Paragraph from "../../ui/typography/paragraph"; -import { getUpcomingReminder } from "../../../utils/time"; -import { formatReminderTime } from "../../../utils/time/index"; -import { TouchableOpacity } from "react-native"; -import ReminderSheet from "../../sheets/reminder"; const navigateToTopic = (topic) => { TopicNotes.navigate(topic, true); @@ -92,6 +93,7 @@ const NoteItem = ({ const notebooks = React.useMemo(() => getNotebook(item), [item]); const reminders = db.relations.from(item, "reminder"); const current = getUpcomingReminder(reminders); + useRelationStore((state) => state.updater); return ( <> @@ -160,13 +162,15 @@ const NoteItem = ({ ) : null} - {current && current.date ? ( + {current && + current.date && + (current.mode !== "once" || current.date > Date.now()) ? ( { - Properties.present(item); + Properties.present(current); }} - style={{ + style={{ backgroundColor: colors.nav, borderRadius: 5, flexDirection: "row", diff --git a/apps/mobile/app/components/list-items/note/wrapper.js b/apps/mobile/app/components/list-items/note/wrapper.js index 47759133b..ac0f5685b 100644 --- a/apps/mobile/app/components/list-items/note/wrapper.js +++ b/apps/mobile/app/components/list-items/note/wrapper.js @@ -20,24 +20,22 @@ along with this program. If not, see . import React from "react"; import NoteItem from "."; import { notesnook } from "../../../../e2e/test.ids"; -import { useSelectionStore } from "../../../stores/use-selection-store"; -import { useTrashStore } from "../../../stores/use-trash-store"; -import { useEditorStore } from "../../../stores/use-editor-store"; +import { db } from "../../../common/database"; import { DDS } from "../../../services/device-detection"; import { eSendEvent, + hideSheet, openVault, - presentSheet, - ToastEvent + presentSheet } from "../../../services/event-manager"; -import Navigation from "../../../services/navigation"; +import { useEditorStore } from "../../../stores/use-editor-store"; +import { useSelectionStore } from "../../../stores/use-selection-store"; import { history } from "../../../utils"; -import { db } from "../../../common/database"; import { eOnLoadNote, eShowMergeDialog } from "../../../utils/events"; import { tabBarRef } from "../../../utils/global-refs"; import { presentDialog } from "../../dialog/functions"; -import SelectionWrapper from "../selection-wrapper"; import NotePreview from "../../note-history/preview"; +import SelectionWrapper from "../selection-wrapper"; const present = () => presentDialog({ @@ -46,9 +44,9 @@ const present = () => paragraph: "Please sync again to open this note for editing" }); -export const openNote = async (item, isTrash, setSelectedItem) => { +export const openNote = async (item, isTrash, setSelectedItem, isSheet) => { let _note = item; - + if (isSheet) hideSheet(); if (!isTrash) { _note = db.notes.note(item.id).data; if (!db.notes.note(item.id)?.synced()) { @@ -102,7 +100,7 @@ export const openNote = async (item, isTrash, setSelectedItem) => { }; export const NoteWrapper = React.memo( - function NoteWrapper({ item, index, tags, dateBy }) { + function NoteWrapper({ item, index, tags, dateBy, isSheet }) { const isTrash = item.type === "trash"; const setSelectedItem = useSelectionStore((state) => state.setSelectedItem); @@ -111,7 +109,8 @@ export const NoteWrapper = React.memo( index={index} height={100} testID={notesnook.ids.note.get(index)} - onPress={() => openNote(item, isTrash, setSelectedItem)} + onPress={() => openNote(item, isTrash, setSelectedItem, isSheet)} + isSheet={isSheet} item={item} > diff --git a/apps/mobile/app/components/list-items/reminder/index.tsx b/apps/mobile/app/components/list-items/reminder/index.tsx index f283690f4..389c4fa31 100644 --- a/apps/mobile/app/components/list-items/reminder/index.tsx +++ b/apps/mobile/app/components/list-items/reminder/index.tsx @@ -29,7 +29,7 @@ import Paragraph from "../../ui/typography/paragraph"; import SelectionWrapper from "../selection-wrapper"; import Icon from "react-native-vector-icons/MaterialCommunityIcons"; import ReminderSheet from "../../sheets/reminder"; -import { formatReminderTime } from "../../../utils/time/index"; +import { formatReminderTime } from "@notesnook/core/collections/reminders"; const ReminderItem = React.memo( ({ @@ -54,7 +54,12 @@ const ReminderItem = React.memo( item={item} isSheet={isSheet} > - + - {item.mode === "repeat" ? ( + + {item.disabled ? ( + + + + Disabled + + + ) : null} + {item.mode === "repeat" && item.recurringMode ? ( ) : null} - - {item.date ? ( + {item.date ? ( + <> - ) : null} - + + ) : null} { ); }; +/** + * + * @param {any} param0 + * @returns + */ const List = ({ listData, type, @@ -97,7 +102,8 @@ const List = ({ screen, ListHeader, warning, - isSheet = false + isSheet = false, + onMomentumScrollEnd }) => { const colors = useThemeStore((state) => state.colors); const scrollRef = useRef(); @@ -168,8 +174,10 @@ const List = ({ data={listData} renderItem={renderItem} onScroll={_onScroll} + nestedScrollEnabled={true} onMomentumScrollEnd={() => { tabBarRef.current?.unlock(); + onMomentumScrollEnd?.(); }} getItemType={(item) => item.itemType || item.type} estimatedItemSize={isCompactModeEnabled ? 60 : 100} diff --git a/apps/mobile/app/components/note-history/preview.js b/apps/mobile/app/components/note-history/preview.js index bc6517aec..b5cc59dd3 100644 --- a/apps/mobile/app/components/note-history/preview.js +++ b/apps/mobile/app/components/note-history/preview.js @@ -29,7 +29,7 @@ import { useEditorStore } from "../../stores/use-editor-store"; import { useSelectionStore } from "../../stores/use-selection-store"; import { useThemeStore } from "../../stores/use-theme-store"; import { useTrashStore } from "../../stores/use-trash-store"; -import { eCloseProgressDialog, eOnLoadNote } from "../../utils/events"; +import { eCloseSheet, eOnLoadNote } from "../../utils/events"; import { sleep } from "../../utils/time"; import { Dialog } from "../dialog"; import DialogHeader from "../dialog/dialog-header"; @@ -59,7 +59,7 @@ export default function NotePreview({ session, content, note }) { heading: "Restore successful", type: "success" }); - eSendEvent(eCloseProgressDialog); + eSendEvent(eCloseSheet); return; } await db.noteHistory.restore(session.id); @@ -71,8 +71,8 @@ export default function NotePreview({ session, content, note }) { }); } } - eSendEvent(eCloseProgressDialog, "note_history"); - eSendEvent(eCloseProgressDialog); + eSendEvent(eCloseSheet, "note_history"); + eSendEvent(eCloseSheet); Navigation.queueRoutesForUpdate( "Notes", "Favorites", @@ -103,7 +103,7 @@ export default function NotePreview({ session, content, note }) { type: "success", context: "local" }); - eSendEvent(eCloseProgressDialog); + eSendEvent(eCloseSheet); }, positiveType:"error" }); diff --git a/apps/mobile/app/components/premium/component.js b/apps/mobile/app/components/premium/component.js index b6de5d399..bccb11bbf 100644 --- a/apps/mobile/app/components/premium/component.js +++ b/apps/mobile/app/components/premium/component.js @@ -30,7 +30,7 @@ import { useUserStore } from "../../stores/use-user-store"; import { getElevation } from "../../utils"; import { eClosePremiumDialog, - eCloseProgressDialog, + eCloseSheet, eOpenLoginDialog } from "../../utils/events"; import { SIZE } from "../../utils/size"; @@ -194,7 +194,7 @@ export const Component = ({ close, promo }) => { try { await db.user.activateTrial(); eSendEvent(eClosePremiumDialog); - eSendEvent(eCloseProgressDialog); + eSendEvent(eCloseSheet); await sleep(300); Walkthrough.present("trialstarted", false, true); } catch (e) { diff --git a/apps/mobile/app/components/premium/pricing-plans.js b/apps/mobile/app/components/premium/pricing-plans.js index 0d5705d31..279eec9be 100644 --- a/apps/mobile/app/components/premium/pricing-plans.js +++ b/apps/mobile/app/components/premium/pricing-plans.js @@ -33,7 +33,7 @@ import { useThemeStore } from "../../stores/use-theme-store"; import { useUserStore } from "../../stores/use-user-store"; import { eClosePremiumDialog, - eCloseProgressDialog, + eCloseSheet, eCloseSimpleDialog, eOpenLoginDialog } from "../../utils/events"; @@ -154,7 +154,7 @@ export const PricingPlans = ({ user.id ); setBuying(false); - eSendEvent(eCloseProgressDialog); + eSendEvent(eCloseSheet); eSendEvent(eClosePremiumDialog); await sleep(500); presentSheet({ @@ -162,7 +162,7 @@ export const PricingPlans = ({ paragraph: "Your Notesnook Pro subscription will be activated soon. If your account is not upgraded to Notesnook Pro, your money will be refunded to you. In case of any issues, please reach out to us at support@streetwriters.co", action: async () => { - eSendEvent(eCloseProgressDialog); + eSendEvent(eCloseSheet); }, icon: "check", actionText: "Continue" @@ -226,7 +226,7 @@ export const PricingPlans = ({ try { await db.user.activateTrial(); eSendEvent(eClosePremiumDialog); - eSendEvent(eCloseProgressDialog); + eSendEvent(eCloseSheet); await sleep(300); Walkthrough.present("trialstarted", false, true); } catch (e) { @@ -393,7 +393,7 @@ export const PricingPlans = ({