mobile: minor improvements

This commit is contained in:
ammarahm-ed
2022-12-16 22:28:30 +05:00
committed by Abdullah Atta
parent 7ac8b478ed
commit 32467c36af
14 changed files with 263 additions and 47 deletions

View File

@@ -35,6 +35,7 @@ type DialogHeaderProps = {
loading?: boolean;
title?: string;
type?: PressableButtonProps["type"];
icon?: string
};
paragraphColor?: string;
padding?: number;
@@ -96,6 +97,7 @@ const DialogHeader = ({
loading={button.loading}
fontSize={13}
title={button.title}
icon={button.icon}
type={button.type || "grayBg"}
height={25}
/>

View File

@@ -35,6 +35,10 @@ 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);
@@ -86,6 +90,8 @@ const NoteItem = ({
const compactMode = notesListMode === "compact";
const attachmentCount = db.attachments?.ofNote(item.id, "all")?.length || 0;
const notebooks = React.useMemo(() => getNotebook(item), [item]);
const reminders = db.relations.from(item, "reminder");
const current = getUpcomingReminder(reminders);
return (
<>
@@ -154,6 +160,37 @@ const NoteItem = ({
</Paragraph>
) : null}
{current && current.date ? (
<TouchableOpacity
activeOpacity={1}
onPress={() => {
Properties.present(item);
}}
style={{
backgroundColor: colors.nav,
borderRadius: 5,
flexDirection: "row",
paddingHorizontal: 5,
paddingVertical: 3,
alignItems: "center",
marginTop: 5,
justifyContent: "flex-start",
alignSelf: "flex-start"
}}
>
<>
<Icon name="clock-outline" size={SIZE.md} color={colors.accent} />
<Paragraph
size={SIZE.xs + 1}
color={colors.icon}
style={{ marginLeft: 5 }}
>
{formatReminderTime(current)}
</Paragraph>
</>
</TouchableOpacity>
) : null}
<View
style={{
flexDirection: "row",

View File

@@ -104,7 +104,8 @@ const SelectionWrapper = ({
overflow: "hidden",
paddingHorizontal: 12,
paddingVertical: compactMode ? 8 : 12,
borderRadius:isSheet ? 10 : 0
borderRadius: isSheet ? 10 : 0,
marginBottom: isSheet ? 12 : undefined
}}
>
{item.type === "note" ? (

View File

@@ -124,7 +124,8 @@ export const Properties = ({
alignItems: "center",
justifyContent: "flex-start",
alignSelf: "flex-start",
marginBottom: 5
marginBottom: 5,
marginTop: !item.description ? 5 : 0
}}
>
{item.date ? (
@@ -249,7 +250,7 @@ Properties.present = (item, buttons = [], isSheet) => {
}
if (!props[0]) return;
presentSheet({
context:isSheet ? "local" : undefined,
context: isSheet ? "local" : undefined,
component: (ref, close) => (
<Properties
close={() => {

View File

@@ -16,20 +16,25 @@ 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 React, { RefObject, useState } from "react";
import React, { RefObject, useEffect, useState } from "react";
import { View } from "react-native";
import ActionSheet from "react-native-actions-sheet";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../../common/database";
import {
presentSheet,
PresentSheetOptions
PresentSheetOptions,
presentSheet
} from "../../../services/event-manager";
import { Reminder } from "../../../services/notifications";
import { useRelationStore } from "../../../stores/use-relation-store";
import { useThemeStore } from "../../../stores/use-theme-store";
import { SIZE } from "../../../utils/size";
import DialogHeader from "../../dialog/dialog-header";
import List from "../../list";
import { useEffect } from "react";
import { Reminder } from "../../../services/notifications";
import { PressableButtonProps } from "../../ui/pressable";
import SheetProvider from "../../sheet-provider";
import { Button } from "../../ui/button";
import { PressableButtonProps } from "../../ui/pressable";
import Paragraph from "../../ui/typography/paragraph";
type RelationsListProps = {
actionSheetRef: RefObject<ActionSheet>;
@@ -40,6 +45,7 @@ type RelationsListProps = {
relationType: "to" | "from";
title: string;
button?: Button;
onAdd: () => void;
};
type Button = {
@@ -47,6 +53,11 @@ type Button = {
loading?: boolean | undefined;
title?: string | undefined;
type?: PressableButtonProps["type"];
icon?: string;
};
const IconsByType = {
reminder: "bell"
};
export const RelationsList = ({
@@ -57,27 +68,68 @@ export const RelationsList = ({
referenceType,
relationType,
title,
button
button,
onAdd
}: RelationsListProps) => {
const relations = useRelationStore();
const [items, setItems] = useState<Reminder[]>([]);
const colors = useThemeStore((state) => state.colors);
const hasNoReminders = !items || items.length === 0;
useEffect(() => {
db.relations?.[relationType]?.(
{ id: item?.id, type: item.type },
referenceType
).then((items) => setItems(items as any));
}, [item?.id, item?.type, referenceType, relationType]);
setItems(
db.relations?.[relationType]?.(
{ id: item?.id, type: item.type },
referenceType
) as any
);
}, [item?.id, item?.type, referenceType, relationType, relations.updater]);
console.log(items);
return (
<View style={{ paddingHorizontal: 12, height: "100%" }}>
<View
style={{ paddingHorizontal: 12, height: hasNoReminders ? 300 : "100%" }}
>
<SheetProvider context="local" />
<DialogHeader title={title} button={button} />
<List
listData={items}
loading={false}
type={referenceType}
headerProps={null}
isSheet={true}
<DialogHeader
title={title}
button={hasNoReminders ? undefined : button}
/>
{hasNoReminders ? (
<View
style={{
height: "85%",
justifyContent: "center",
alignItems: "center"
}}
>
<Icon
name={IconsByType[referenceType as keyof typeof IconsByType]}
size={60}
color={colors.icon}
/>
<Paragraph>
No {referenceType}s linked to this {item.type}.
</Paragraph>
<Button
onPress={() => {
onAdd?.();
}}
fontSize={SIZE.sm}
// width="100%"
type="inverted"
icon="plus"
title={`Add a ${referenceType}`}
/>
</View>
) : (
<List
listData={items}
loading={false}
type={referenceType}
headerProps={null}
isSheet={true}
/>
)}
</View>
);
};
@@ -87,13 +139,15 @@ RelationsList.present = ({
referenceType,
relationType,
title,
button
button,
onAdd
}: {
reference: { id: string; type: string };
referenceType: string;
relationType: "to" | "from";
title: string;
button: Button;
button?: Button;
onAdd: () => void;
}) => {
presentSheet({
component: (ref, close, update) => (
@@ -106,6 +160,7 @@ RelationsList.present = ({
relationType={relationType}
title={title}
button={button}
onAdd={onAdd}
/>
)
});

View File

@@ -21,23 +21,23 @@ import { Platform, ScrollView, View } from "react-native";
import ActionSheet from "react-native-actions-sheet";
import DateTimePickerModal from "react-native-modal-datetime-picker";
import {
presentSheet,
PresentSheetOptions,
ToastEvent
ToastEvent,
presentSheet
} from "../../../services/event-manager";
import { useThemeStore } from "../../../stores/use-theme-store";
import { SIZE } from "../../../utils/size";
import { Button } from "../../ui/button";
import Input from "../../ui/input";
import Notifications, { Reminder } from "../../../services/notifications";
import Paragraph from "../../ui/typography/paragraph";
import dayjs from "dayjs";
import { db } from "../../../common/database";
import Navigation from "../../../services/navigation";
import { formatReminderTime } from "../../../utils/time";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../../common/database";
import Notifications, { Reminder } from "../../../services/notifications";
import { useReminderStore } from "../../../stores/use-reminder-store";
import { formatReminderTime } from "../../../utils/time";
import Paragraph from "../../ui/typography/paragraph";
import DialogHeader from "../../dialog/dialog-header";
type ReminderSheetProps = {
actionSheetRef: RefObject<ActionSheet>;
close?: () => void;
@@ -62,7 +62,6 @@ const RecurringModes = {
Week: "week",
Month: "month"
};
const WeekDays = new Array(7).fill(true);
const MonthDays = new Array(31).fill(true);
const WeekDayNames = {
@@ -81,6 +80,9 @@ const ReminderNotificationModes = {
Urgent: "urgent"
};
export default function ReminderSheet({
actionSheetRef,
close,
@@ -431,7 +433,7 @@ export default function ReminderSheet({
<View
style={{
flexDirection: "row",
marginBottom: 12
marginBottom: 12,
}}
>
{Object.keys(ReminderNotificationModes).map((mode) => (

View File

@@ -57,7 +57,7 @@ import {
} from "../utils/events";
import { deleteItems } from "../utils/functions";
import { sleep } from "../utils/time";
import { RelationsList } from "../components/sheets/reminders-list/index";
import { RelationsList } from "../components/sheets/relations-list/index";
export const useActions = ({ close = () => null, item }) => {
const colors = useThemeStore((state) => state.colors);
@@ -820,15 +820,23 @@ export const useActions = ({ close = () => null, item }) => {
name: "Reminders",
title: "Reminders",
icon: "bell",
func: () => {
func: async () => {
close();
RelationsList.present({
reference: item,
referenceType: "reminder",
relationType: "from",
title: "Reminders"
title: "Reminders",
onAdd: () => ReminderSheet.present(null, item, true),
button: {
title: "Add",
type: "accent",
onPress: () => ReminderSheet.present(null, item, true),
icon:"plus"
}
});
},
close: true
close: false
}
];

View File

@@ -59,6 +59,8 @@ import { useDragState } from "../../settings/editor/state";
import { EditorMessage, EditorProps, useEditorType } from "./types";
import { EditorEvents, editorState } from "./utils";
import { openLinkInBrowser } from "../../../utils/functions";
import { RelationsList } from "../../../components/sheets/relations-list";
import ReminderSheet from "../../../components/sheets/reminder";
export const EventTypes = {
selection: "editor-event:selection",
@@ -77,7 +79,8 @@ export const EventTypes = {
properties: "editor-event:properties",
fullscreen: "editor-event:fullscreen",
link: "editor-event:link",
contentchange: "editor-event:content-change"
contentchange: "editor-event:content-change",
reminders: "editor-event:reminders"
};
const publishNote = async (editor: useEditorType) => {
@@ -315,8 +318,32 @@ export const useEditorEvents = (
title: editorMessage.value as string
});
break;
case EventTypes.reminders:
if (!editor.note.current) {
ToastEvent.show({
heading: "Create a note first to add a reminder",
type: "success"
});
return;
}
RelationsList.present({
reference: editor.note.current as any,
referenceType: "reminder",
relationType: "from",
title: "Reminders",
onAdd: () =>
ReminderSheet.present(undefined, editor.note.current as any, true)
});
break;
case EventTypes.newtag:
if (!editor.note.current) return;
if (!editor.note.current) {
ToastEvent.show({
heading: "Create a note first to add a tag",
type: "success"
});
return;
}
eSendEvent(eOpenTagsDialog, editor.note.current);
break;
case EventTypes.tag:

View File

@@ -60,19 +60,31 @@ let pinned: DisplayedNotification[] = [];
const onEvent = async ({ type, detail }: Event) => {
const { notification, pressAction, input } = detail;
if (type === EventType.PRESS) {
if (notification?.data?.type !== "pinnedNote") return;
if (notification?.data?.type === "quickNote") return;
editorState().movedAway = false;
MMKV.removeItem("appState");
let noteId = notification?.id;
if (notification?.data?.type === "reminder") {
const notes = db.relations?.to(
{ type: "reminder", id: notification.id?.split("_")[0] as string },
"note"
);
if (!notes || notes.length === 0) return;
if (notes && notes.length > 0) {
noteId = notes[0].id;
}
}
if (useNoteStore?.getState()?.loading === false) {
await db.init();
await db.notes?.init();
loadNote(notification?.id as string, false);
loadNote(noteId as string, false);
return;
}
const unsub = useNoteStore.subscribe(
(loading) => {
if (loading === false) {
loadNote(notification?.id as string, true);
loadNote(noteId as string, true);
}
unsub();
},
@@ -184,6 +196,7 @@ function loadNote(id: string, jump: boolean) {
}
}, 2000);
}
async function getChannelId(id: "silent" | "vibrate" | "urgent" | "default") {
switch (id) {
case "default":
@@ -323,7 +336,7 @@ function getTriggers(
];
case "permanent":
return undefined;
case "repeat" : {
case "repeat": {
switch (recurringMode) {
case "day":
return [

View File

@@ -0,0 +1,32 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2022 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 create, { State } from "zustand";
export interface RelationStore extends State {
updater: number;
update: () => void;
}
export const useRelationStore = create<RelationStore>((set, get) => ({
updater: 0,
update: () => {
set({ updater: get().updater + 1 });
}
}));

View File

@@ -120,6 +120,15 @@ export function formatReminderTime(reminder: Reminder) {
);
}
export function getUpcomingReminder(reminders: Reminder[]) {
const sorted = reminders.sort((a, b) => {
const d1 = a.mode === "repeat" ? getUpcomingReminderTime(a) : a.date;
const d2 = a.mode === "repeat" ? getUpcomingReminderTime(b) : b.date;
return !d1 || !d2 ? 0 : d1 - d2;
});
return sorted[0];
}
export const sleep = (duration: number) =>
new Promise((resolve) => setTimeout(() => resolve(true), duration));

View File

@@ -172,3 +172,5 @@ export interface GroupHeader
extends Omit<Entity<"header">, "id" | "dateCreated" | "dateModified"> {
title: string;
}
export type ItemReference = { id: string; type: string };

View File

@@ -25,6 +25,7 @@ import ArrowULeftTopIcon from "mdi-react/ArrowULeftTopIcon";
import ArrowURightTopIcon from "mdi-react/ArrowURightTopIcon";
import FullscreenIcon from "mdi-react/FullscreenIcon";
import MagnifyIcon from "mdi-react/MagnifyIcon";
import BellIcon from "mdi-react/BellIcon";
import React from "react";
import { useSafeArea } from "../hooks/useSafeArea";
import { EventTypes, Settings } from "../utils";
@@ -77,7 +78,6 @@ export default function Header({
position: "sticky",
width: "100vw"
}}
>
{noHeader ? null : (
<div
@@ -90,7 +90,7 @@ export default function Header({
height: 50,
alignItems: "center"
}}
id='header'
id="header"
>
{settings.deviceMode !== "mobile" && !settings.fullscreen ? (
<div />
@@ -211,6 +211,32 @@ export default function Header({
</Button>
)}
<Button
onPress={() => {
post(EventTypes.reminders);
}}
style={{
borderWidth: 0,
borderRadius: 100,
color: "var(--nn_icon)",
marginRight: 10,
width: 39,
height: 39,
display: "flex",
justifyContent: "center",
alignItems: "center",
position: "relative"
}}
>
<BellIcon
size={25}
style={{
position: "absolute"
}}
color="var(--nn_pri)"
/>
</Button>
<Button
onPress={() => {
editor?.commands.startSearch();

View File

@@ -143,7 +143,8 @@ export const EventTypes = {
properties: "editor-event:properties",
fullscreen: "editor-event:fullscreen",
link: "editor-event:link",
contentchange: "editor-event:content-change"
contentchange: "editor-event:content-change",
reminders: "editor-event:reminders"
} as const;
export function isReactNative(): boolean {