mobile: add settings

This commit is contained in:
ammarahm-ed
2023-06-01 20:56:02 +05:00
committed by Abdullah Atta
parent 25bf4fee82
commit 58f7a206d9
20 changed files with 559 additions and 66 deletions

View File

@@ -31,6 +31,7 @@ import { Button } from "../../ui/button";
import { IconButton } from "../../ui/icon-button";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import { getFormattedDate } from "../../../utils/time";
const showActionSheet = (item) => {
Properties.present(item);
@@ -163,7 +164,7 @@ export const NotebookItem = ({
marginRight: 6
}}
>
{new Date(item[dateBy]).toDateString().substring(4)}
{getFormattedDate(item[dateBy], "date")}
</Paragraph>
)}
<Paragraph

View File

@@ -37,7 +37,7 @@ import { useThemeStore } from "../../stores/use-theme-store";
import { dHeight } from "../../utils";
import { eOnLoadNote, eShowMergeDialog } from "../../utils/events";
import { SIZE } from "../../utils/size";
import { sleep, timeConverter } from "../../utils/time";
import { getFormattedDate, sleep } from "../../utils/time";
import BaseDialog from "../dialog/base-dialog";
import DialogButtons from "../dialog/dialog-buttons";
import DialogContainer from "../dialog/dialog-container";
@@ -166,7 +166,7 @@ const MergeConflicts = () => {
{isCurrent ? "(This Device)" : "(Incoming)"}
</Text>
{"\n"}
{timeConverter(contentToKeep?.dateEdited)}
{getFormattedDate(contentToKeep?.dateEdited)}
</Paragraph>
</View>

View File

@@ -26,7 +26,7 @@ import { presentSheet } from "../../services/event-manager";
import { useThemeStore } from "../../stores/use-theme-store";
import { openLinkInBrowser } from "../../utils/functions";
import { SIZE } from "../../utils/size";
import { timeConverter, timeSince } from "../../utils/time";
import { getFormattedDate, timeSince } from "../../utils/time";
import DialogHeader from "../dialog/dialog-header";
import SheetProvider from "../sheet-provider";
import { PressableButton } from "../ui/pressable";
@@ -63,15 +63,15 @@ export default function NoteHistory({ note, fwdRef }) {
}, []);
const getDate = (start, end) => {
let _start = timeConverter(start);
let _end = timeConverter(end + 60000);
if (_start === _end) return _start;
let final = _end.lastIndexOf(",");
let part = _end.slice(0, final + 1);
if (_start.includes(part)) {
return _start + " —" + _end.replace(part, "");
}
return _start + " — " + _end;
let _start_date = getFormattedDate(start, "date");
let _end_date = getFormattedDate(end + 60000, "date");
let _start_time = getFormattedDate(start, "time");
let _end_time = getFormattedDate(end + 60000, "time");
return `${_start_date} ${_start_time} - ${
_end_date === _start_date ? " " : _end_date + " "
}${_end_time}`;
};
const renderItem = useCallback(

View File

@@ -21,7 +21,7 @@ import React from "react";
import { View } from "react-native";
import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
import { timeConverter } from "../../utils/time";
import { getFormattedDate } from "../../utils/time";
import Paragraph from "../ui/typography/paragraph";
export const DateMeta = ({ item }) => {
const colors = useThemeStore((state) => state.colors);
@@ -66,7 +66,7 @@ export const DateMeta = ({ item }) => {
{getNameFromKey(key)}
</Paragraph>
<Paragraph size={SIZE.xs} color={colors.icon}>
{timeConverter(item[key])}
{getFormattedDate(item[key], "date-time")}
</Paragraph>
</View>
);

View File

@@ -191,13 +191,25 @@ Properties.present = (item, buttons = [], isSheet) => {
break;
case "notebook":
props[0] = db.notebooks.notebook(item.id).data;
props.push(["edit-notebook", "pin", "add-shortcut", "trash"]);
props.push([
"edit-notebook",
"pin",
"add-shortcut",
"trash",
"default-notebook"
]);
break;
case "topic":
props[0] = db.notebooks
.notebook(item.notebookId)
.topics.topic(item.id)._topic;
props.push(["move-notes", "edit-topic", "add-shortcut", "trash"]);
props.push([
"move-notes",
"edit-topic",
"add-shortcut",
"trash",
"default-topic"
]);
break;
case "tag":
props[0] = db.tags.tag(item.id);

View File

@@ -21,21 +21,22 @@ import { EVENTS } from "@notesnook/core/common";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { ActivityIndicator, Platform, View } from "react-native";
import { FlatList } from "react-native-actions-sheet";
import RNFetchBlob from "react-native-blob-util";
import DocumentPicker from "react-native-document-picker";
import * as ScopedStorage from "react-native-scoped-storage";
import { db } from "../../../common/database";
import storage from "../../../common/database/storage";
import {
ToastEvent,
eSubscribeEvent,
eUnSubscribeEvent,
ToastEvent
eUnSubscribeEvent
} from "../../../services/event-manager";
import SettingsService from "../../../services/settings";
import { initialize } from "../../../stores";
import { useThemeStore } from "../../../stores/use-theme-store";
import { eCloseRestoreDialog, eOpenRestoreDialog } from "../../../utils/events";
import { SIZE } from "../../../utils/size";
import { timeConverter } from "../../../utils/time";
import { getFormattedDate } from "../../../utils/time";
import { Dialog } from "../../dialog";
import DialogHeader from "../../dialog/dialog-header";
import { presentDialog } from "../../dialog/functions";
@@ -44,7 +45,6 @@ import { Button } from "../../ui/button";
import Seperator from "../../ui/seperator";
import SheetWrapper from "../../ui/sheet";
import Paragraph from "../../ui/typography/paragraph";
import RNFetchBlob from "react-native-blob-util";
const RestoreDataSheet = () => {
const [visible, setVisible] = useState(false);
@@ -251,7 +251,7 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
}}
>
<Paragraph size={SIZE.sm} style={{ width: "100%", maxWidth: "100%" }}>
{timeConverter(item?.lastModified * 1)}
{getFormattedDate(item?.lastModified * 1)}
</Paragraph>
<Paragraph size={SIZE.xs}>
{(item.filename || item.name).replace(".nnbackup", "")}

View File

@@ -16,17 +16,15 @@ 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 { isReminderActive } from "@notesnook/core/collections/reminders";
import React from "react";
import {
formatReminderTime,
isReminderActive
} from "@notesnook/core/collections/reminders";
import { ViewStyle } from "react-native";
import { Reminder } from "../../../services/notifications";
import { Button, ButtonProps } from "../button";
import { useThemeStore } from "../../../stores/use-theme-store";
import { SIZE } from "../../../utils/size";
import { getFormattedReminderTime } from "../../../utils/time";
import { Button, ButtonProps } from "../button";
export const ReminderTime = ({
checkIsActive = true,
@@ -42,7 +40,7 @@ export const ReminderTime = ({
} & ButtonProps) => {
const colors = useThemeStore((state) => state.colors);
const reminder = props.reminder;
const time = !reminder ? undefined : formatReminderTime(reminder);
const time = !reminder ? undefined : getFormattedReminderTime(reminder);
const isTodayOrTomorrow =
(time?.includes("Today") || time?.includes("Tomorrow")) &&
!time?.includes("Last");

View File

@@ -71,6 +71,9 @@ export const useActions = ({ close = () => null, item }) => {
const user = useUserStore((state) => state.user);
const [notifPinned, setNotifPinned] = useState(null);
const alias = item.alias || item.title;
const [defaultNotebook, setDefaultNotebook] = useState(
db.settings.getDefaultNotebook()
);
const isPublished =
item.type === "note" && db.monographs.isPublished(item.id);
@@ -773,6 +776,44 @@ export const useActions = ({ close = () => null, item }) => {
func: openHistory
},
{
id: "default-notebook",
title:
defaultNotebook?.id === item.id
? "Remove as default notebook"
: "Set as default notebook",
hidden: item.type !== "notebook",
icon: "notebook",
func: async () => {
if (defaultNotebook?.id === item.id) {
await db.settings.setDefaultNotebook();
setDefaultNotebook();
} else {
await db.settings.setDefaultNotebook(item);
setDefaultNotebook(item);
}
},
on: defaultNotebook?.id === item.id
},
{
id: "default-topic",
title:
defaultNotebook?.id === item.id
? "Remove as default topic"
: "Set as default topic",
hidden: item.type !== "topic",
icon: "bookmark",
func: async () => {
if (defaultNotebook?.id === item.id) {
await db.settings.setDefaultNotebook();
setDefaultNotebook();
} else {
await db.settings.setDefaultNotebook(item);
setDefaultNotebook(item);
}
},
on: defaultNotebook?.id === item.id
},
{
id: "disable-reminder",
title: !item.disabled ? "Turn off reminder" : "Turn on reminder",

View File

@@ -38,8 +38,9 @@ import { useTagStore } from "../../../stores/use-tag-store";
import { ThemeStore, useThemeStore } from "../../../stores/use-theme-store";
import { eClearEditor, eOnLoadNote } from "../../../utils/events";
import { tabBarRef } from "../../../utils/global-refs";
import { timeConverter } from "../../../utils/time";
import { getFormattedDate } from "../../../utils/time";
import { NoteType } from "../../../utils/types";
import { onNoteCreated } from "../../notes/common";
import Commands from "./commands";
import { Content, EditorState, Note, SavePayload } from "./types";
import {
@@ -198,10 +199,7 @@ export const useEditor = (
sessionId: isContentInvalid(data) ? null : currentSessionHistoryId
};
if (title) {
noteData.title = title;
}
noteData.title = title;
if (data) {
noteData.content = {
data: data,
@@ -213,12 +211,19 @@ export const useEditor = (
id = await db.notes?.add(noteData);
if (!note && id) {
currentNote.current = db.notes?.note(id).data as NoteType;
state.current?.onNoteCreated && state.current.onNoteCreated(id);
const defaultNotebook = db.settings?.getDefaultNotebook();
if (!state.current.onNoteCreated && defaultNotebook) {
onNoteCreated(id, {
type: defaultNotebook.type,
id: defaultNotebook.id,
notebook: defaultNotebook.notebookId
});
} else {
state.current?.onNoteCreated && state.current.onNoteCreated(id);
}
if (!noteData.title) {
postMessage(
EditorEvents.titleplaceholder,
currentNote.current.title
);
postMessage(EditorEvents.title, currentNote.current.title);
}
}
@@ -243,7 +248,7 @@ export const useEditor = (
}
if (id && sessionIdRef.current === currentSessionId) {
note = db.notes?.note(id)?.data as Note;
await commands.setStatus(timeConverter(note.dateEdited), "Saved");
await commands.setStatus(getFormattedDate(note.dateEdited), "Saved");
lastContentChangeTime.current = note.dateEdited;
@@ -373,7 +378,7 @@ export const useEditor = (
commands.setSessionId(nextSessionId);
sessionIdRef.current = nextSessionId;
currentNote.current = item as NoteType;
await commands.setStatus(timeConverter(item.dateEdited), "Saved");
await commands.setStatus(getFormattedDate(item.dateEdited), "Saved");
await postMessage(EditorEvents.title, item.title);
await postMessage(
EditorEvents.html,
@@ -460,7 +465,7 @@ export const useEditor = (
if (note.tags !== currentNote.current.tags) {
await commands.setTags(note);
}
await commands.setStatus(timeConverter(note.dateEdited), "Saved");
await commands.setStatus(getFormattedDate(note.dateEdited), "Saved");
}
lock.current = false;

View File

@@ -86,7 +86,7 @@ export const setOnFirstSave = (
}, 0);
};
async function onNoteCreated(id: string, params: FirstSaveData) {
export async function onNoteCreated(id: string, params: FirstSaveData) {
if (!params) return;
switch (params.type) {
case "notebook": {

View File

@@ -27,6 +27,8 @@ import SoundPicker from "./sound-picker";
import { Subscription } from "./subscription";
import { TrashIntervalSelector } from "./trash-interval-selector";
import { FontSelector } from "./font-selector";
import { TitleFormat } from "./title-format";
import { DateFormatSelector, TimeFormatSelector } from "./date-format";
export const components: { [name: string]: ReactElement } = {
colorpicker: <AccentColorPicker />,
homeselector: <HomagePageSelector />,
@@ -37,5 +39,8 @@ export const components: { [name: string]: ReactElement } = {
"sound-picker": <SoundPicker />,
licenses: <Licenses />,
"trash-interval-selector": <TrashIntervalSelector />,
"font-selector": <FontSelector />
"font-selector": <FontSelector />,
"title-format": <TitleFormat />,
"date-format-selector": <DateFormatSelector />,
"time-format-selector": <TimeFormatSelector />
};

View File

@@ -0,0 +1,191 @@
/*
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 dayjs from "dayjs";
import React, { useRef, useState } from "react";
import { View } from "react-native";
import Menu, { MenuItem } from "react-native-reanimated-material-menu";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../common/database";
import { PressableButton } from "../../components/ui/pressable";
import Paragraph from "../../components/ui/typography/paragraph";
import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
import { DATE_FORMATS, TIME_FORMATS } from "@notesnook/core/common";
export const DateFormatSelector = () => {
const colors = useThemeStore((state) => state.colors);
const menuRef = useRef();
const [width, setWidth] = useState(0);
const [dateFormat, setDateFormat] = useState(db.settings.getDateFormat());
const onChange = (item) => {
menuRef.current?.hide();
db.settings.setDateFormat(item);
setDateFormat(item);
};
return (
<View
onLayout={(event) => {
setWidth(event.nativeEvent.layout.width);
}}
style={{
width: "100%"
}}
>
<Menu
ref={menuRef}
animationDuration={200}
style={{
borderRadius: 5,
backgroundColor: colors.bg,
width: width,
marginTop: 60
}}
onRequestClose={() => {
menuRef.current?.hide();
}}
anchor={
<PressableButton
onPress={async () => {
menuRef.current?.show();
}}
type="grayBg"
customStyle={{
flexDirection: "row",
alignItems: "center",
marginTop: 10,
width: "100%",
justifyContent: "space-between",
padding: 12
}}
>
<Paragraph>
{dateFormat} ({dayjs().format(dateFormat)})
</Paragraph>
<Icon color={colors.icon} name="menu-down" size={SIZE.md} />
</PressableButton>
}
>
{DATE_FORMATS.map((item) => (
<MenuItem
key={item.id}
onPress={async () => {
onChange(item);
}}
style={{
backgroundColor: dateFormat === item ? colors.nav : "transparent",
width: "100%",
maxWidth: width
}}
textStyle={{
fontSize: SIZE.md,
color: dateFormat === item ? colors.accent : colors.pri
}}
>
{item} ({dayjs().format(item)})
</MenuItem>
))}
</Menu>
</View>
);
};
export const TimeFormatSelector = () => {
const colors = useThemeStore((state) => state.colors);
const menuRef = useRef();
const [width, setWidth] = useState(0);
const [timeFormat, setTimeFormat] = useState(db.settings.getTimeFormat());
const onChange = (item) => {
menuRef.current?.hide();
db.settings.setTimeFormat(item);
setTimeFormat(item);
};
const TimeFormats = {
"12-hour": "hh:mm A",
"24-hour": "HH:mm"
};
return (
<View
onLayout={(event) => {
setWidth(event.nativeEvent.layout.width);
}}
style={{
width: "100%"
}}
>
<Menu
ref={menuRef}
animationDuration={200}
style={{
borderRadius: 5,
backgroundColor: colors.bg,
width: width,
marginTop: 60
}}
onRequestClose={() => {
menuRef.current?.hide();
}}
anchor={
<PressableButton
onPress={async () => {
menuRef.current?.show();
}}
type="grayBg"
customStyle={{
flexDirection: "row",
alignItems: "center",
marginTop: 10,
width: "100%",
justifyContent: "space-between",
padding: 12
}}
>
<Paragraph>
{timeFormat} ({dayjs().format(TimeFormats[timeFormat])})
</Paragraph>
<Icon color={colors.icon} name="menu-down" size={SIZE.md} />
</PressableButton>
}
>
{TIME_FORMATS.map((item) => (
<MenuItem
key={item.id}
onPress={async () => {
onChange(item);
}}
style={{
backgroundColor: timeFormat === item ? colors.nav : "transparent",
width: "100%",
maxWidth: width
}}
textStyle={{
fontSize: SIZE.md,
color: timeFormat === item ? colors.accent : colors.pri
}}
>
{item} ({dayjs().format(TimeFormats[item])})
</MenuItem>
))}
</Menu>
</View>
);
};

View File

@@ -524,6 +524,20 @@ export const settingsGroups: SettingSection[] = [
description: "Default screen to open on app startup",
component: "homeselector"
},
{
id: "date-format",
name: "Date format",
description: "Set the format for date used across the app",
type: "component",
component: "date-format-selector"
},
{
id: "time-format",
name: "Time format",
description: "Set the format for time used across the app",
type: "component",
component: "time-format-selector"
},
{
id: "clear-trash-interval",
type: "component",
@@ -531,6 +545,15 @@ export const settingsGroups: SettingSection[] = [
description:
"Select the duration after which trash items will be cleared",
component: "trash-interval-selector"
},
{
id: "default-notebook",
name: "Clear default notebook",
description: "Clear the default notebook for new notes",
modifer: () => {
db.settings?.setDefaultNotebook(undefined);
},
hidden: () => !db.settings?.getDefaultNotebook()
}
]
},
@@ -588,6 +611,13 @@ export const settingsGroups: SettingSection[] = [
icon: "format-font",
property: "defaultFontFamily",
component: "font-selector"
},
{
id: "title-format",
name: "Title format",
component: "title-format",
description: "Customize the formatting for new note title",
type: "component"
}
]
}

View File

@@ -0,0 +1,61 @@
/*
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 { useRef, useState } from "react";
import { db } from "../../common/database";
import Input from "../../components/ui/input";
import React from "react";
import { TextInput } from "react-native";
import Paragraph from "../../components/ui/typography/paragraph";
import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
export const TitleFormat = () => {
const [titleFormat] = useState(db.settings?.getTitleFormat());
const inputRef = useRef<TextInput>();
const colors = useThemeStore((state) => state.colors);
return (
<>
<Input
onSubmit={(e) => {
db.settings?.setTitleFormat(e.nativeEvent.text);
}}
onChangeText={(text) => {
db.settings?.setTitleFormat(text);
}}
containerStyle={{ marginTop: 6 }}
onLayout={() => {
inputRef?.current?.setNativeProps({
text: titleFormat
});
}}
defaultValue={titleFormat}
/>
<Paragraph style={{ marginTop: 2 }} color={colors.icon} size={SIZE.xs}>
Use the following key to format the title:{"\n"}
{"\n"}
$date$: Current date{"\n"}
$time$: Current time{"\n"}
$count$: Number of untitled notes + 1{"\n"}
$headline$: Use starting line of the note as title{"\n"}
</Paragraph>
</>
);
};

View File

@@ -17,6 +17,10 @@ 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 { formatDate } from "@notesnook/core/utils/date";
import { db } from "../../common/database";
import { formatReminderTime } from "@notesnook/core/collections/reminders";
export const sleep = (duration: number) =>
new Promise((resolve) => setTimeout(() => resolve(true), duration));
@@ -107,3 +111,21 @@ export const timeConverter = (timestamp: number | undefined | null) => {
return time;
};
export function getFormattedDate(
date: any,
type: "time" | "date-time" | "date" = "date-time"
) {
return formatDate(date, {
dateFormat: db.settings?.getDateFormat() as string,
timeFormat: db.settings?.getTimeFormat() as string,
type: type
});
}
export function getFormattedReminderTime(reminder: any, short = false) {
return formatReminderTime(reminder, short, {
dateFormat: db.settings?.getDateFormat() as string,
timeFormat: db.settings?.getTimeFormat() as string
});
}

View File

@@ -140,6 +140,66 @@ class Settings {
return this._settings.trashCleanupInterval || 7;
}
/**
*
* @param {{type: "notebook" | "topic", id: string, notebookId?: string} | undefined} item
*/
async setDefaultNotebook(item) {
this._settings.defaultNotebook = !item
? undefined
: {
id: item.id,
type: item.type,
notebookId: item.type === "topic" ? item.notebookId : undefined
};
await this._saveSettings();
}
/**
*
* @returns {Notebook | Topic | undefined}
*/
getDefaultNotebook() {
const notebook = this._settings.defaultNotebook;
if (!notebook) return;
if (notebook.type === "topic") {
return this._db.notebooks
.notebook(notebook.notebookId)
.topics.topic(notebook.id)._topic;
} else {
return this._db.notebooks.notebook(notebook.id).data;
}
}
async setTitleFormat(format) {
this._settings.titleFormat = format || "Note $date$ $time$";
await this._saveSettings();
}
getTitleFormat() {
return this._settings.titleFormat;
}
getDateFormat() {
return this._settings.dateFormat;
}
async setDateFormat(format) {
this._settings.dateFormat = format || "DD-MM-YYYY";
await this._saveSettings();
}
/**
*
* @returns {"12-hour" | "24-hour"}
*/
getTimeFormat() {
return this._settings.timeFormat;
}
async setTimeFormat(format) {
this._settings.timeFormat = format || "12-hour";
await this._saveSettings();
}
_initSettings(settings) {
this._settings = {
type: "settings",
@@ -150,6 +210,9 @@ class Settings {
dateModified: 0,
dateCreated: 0,
trashCleanupInterval: 7,
titleFormat: "Note $date$ $time$",
timeFormat: "12-hour",
dateFormat: "DD-MM-YYYY",
...(settings || {})
};
}

View File

@@ -23,6 +23,12 @@ import getId from "../utils/id";
import { getContentFromData } from "../content-types";
import qclone from "qclone";
import { deleteItem, findById } from "../utils/array";
import { formatDate } from "../utils/date";
const DATE_REGEX = /\$date\$/gm;
const COUNT_REGEX = /\$count\$/gm;
const TIME_REGEX = /\$time\$/gm;
const HEADLINE_REGEX = /\$headline\$/gm;
/**
* @typedef {{ id: string, topic?: string, rebuildCache?: boolean }} NotebookReference
@@ -112,7 +118,7 @@ export default class Notes extends Collection {
});
}
const noteTitle = getNoteTitle(note, oldNote);
const noteTitle = this._getNoteTitle(note, oldNote, note.headline);
if (oldNote && oldNote.title !== noteTitle) note.dateEdited = Date.now();
note = {
@@ -408,6 +414,41 @@ export default class Notes extends Collection {
await this._collection.updateItem(note);
}
}
formatTitle(title, headline) {
const date = formatDate(Date.now(), {
dateFormat: this._db.settings.getDateFormat(),
timeFormat: this._db.settings.getTimeFormat(),
type: "date"
});
const time = formatDate(Date.now(), {
dateFormat: this._db.settings.getDateFormat(),
timeFormat: this._db.settings.getTimeFormat(),
type: "time"
});
return title
.replace(NEWLINE_STRIP_REGEX, " ")
.replace(DATE_REGEX, date)
.replace(TIME_REGEX, time)
.replace(HEADLINE_REGEX, headline)
.replace(COUNT_REGEX, this.all.length);
}
_getNoteTitle(note, oldNote, headline) {
if (note.title && note.title.trim().length > 0) {
return note.title.replace(NEWLINE_STRIP_REGEX, " ");
} else if (
oldNote &&
oldNote.title &&
oldNote.title.trim().length > 0 &&
(note.title === undefined || note.title === null)
) {
return oldNote.title.replace(NEWLINE_STRIP_REGEX, " ");
}
return this.formatTitle(this._db.settings.getTitleFormat(), headline);
}
}
function getNoteHeadline(note, content) {
@@ -416,18 +457,6 @@ function getNoteHeadline(note, content) {
}
const NEWLINE_STRIP_REGEX = /[\r\n\t\v]+/gm;
function getNoteTitle(note, oldNote) {
if (note.title && note.title.trim().length > 0) {
return note.title.replace(NEWLINE_STRIP_REGEX, " ");
} else if (oldNote && oldNote.title && oldNote.title.trim().length > 0) {
return oldNote.title.replace(NEWLINE_STRIP_REGEX, " ");
}
return `Note ${new Date().toLocaleString(undefined, {
dateStyle: "short",
timeStyle: "short"
})}`;
}
class NoteIdCache {
/**

View File

@@ -124,7 +124,14 @@ export default class Reminders extends Collection {
/**
* @param {Reminder} reminder
*/
export function formatReminderTime(reminder, short = false) {
export function formatReminderTime(
reminder,
short = false,
options = {
timeFormat: "12-hour",
dateFormat: "DD-MM-YYYY"
}
) {
const { date } = reminder;
let time = date;
let tag = "";
@@ -133,7 +140,9 @@ export function formatReminderTime(reminder, short = false) {
if (reminder.mode === "permanent") return `Ongoing`;
if (reminder.snoozeUntil && reminder.snoozeUntil > Date.now()) {
return `Snoozed until ${dayjs(reminder.snoozeUntil).format("hh:mm A")}`;
return `Snoozed until ${dayjs(reminder.snoozeUntil).format(
options.timeFormat
)}`;
}
if (reminder.mode === "repeat") {
@@ -142,17 +151,17 @@ export function formatReminderTime(reminder, short = false) {
if (dayjs(time).isTomorrow()) {
tag = "Upcoming";
text = `Tomorrow, ${dayjs(time).format("hh:mm A")}`;
text = `Tomorrow, ${dayjs(time).format(options.timeFormat)}`;
} else if (dayjs(time).isYesterday()) {
tag = "Last";
text = `Yesterday, ${dayjs(time).format("hh:mm A")}`;
text = `Yesterday, ${dayjs(time).format(options.timeFormat)}`;
} else {
const isPast = dayjs(time).isSameOrBefore(dayjs());
tag = isPast ? "Last" : "Upcoming";
if (dayjs(time).isToday()) {
text = `Today, ${dayjs(time).format("hh:mm A")}`;
text = `Today, ${dayjs(time).format(options.timeFormat)}`;
} else {
text = dayjs(time).format(`ddd, YYYY-MM-DD hh:mm A`);
text = dayjs(time).format(options.dateFormat);
}
}

View File

@@ -106,4 +106,14 @@ export const EVENTS = {
systemTimeInvalid: "system:invalidTime"
};
export const DATE_FORMATS = [
"DD-MM-YYYY",
"YYYY-DD-MM",
"DD/MM/YYYY",
"YYYY/DD/MM",
"MMM D, YYYY"
];
export const TIME_FORMATS = ["12-hour", "24-hour"];
export const CURRENT_DATABASE_VERSION = 5.8;

View File

@@ -17,6 +17,8 @@ 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 dayjs from "dayjs";
export function getWeekGroupFromTimestamp(timestamp) {
const date = new Date(timestamp);
const { start, end } = getWeek(date);
@@ -64,17 +66,31 @@ function getWeek(date) {
/**
*
* @param {number} date
* @param {Intl.DateTimeFormatOptions} options
* @param {{dateFormat: string, timeFormat: string, type: "date-time" | "time" | "date"}} options
* @returns
*/
export function formatDate(
date,
options = {
dateStyle: "medium",
timeStyle: "short"
dateFormat: "DD-MM-YYYY",
timeFormat: "12-hour",
type: "date-time"
}
) {
return new Date(date).toLocaleString(undefined, options);
switch (options.type) {
case "date-time":
return dayjs(date).format(
`${options.dateFormat} ${
options.timeFormat === "12-hour" ? "h:mm A" : "HH:mm"
}`
);
case "time":
return dayjs(date).format(
`${options.timeFormat === "12-hour" ? "h:mm A" : "HH:mm"}`
);
case "date":
return dayjs(date).format(`${options.dateFormat}`);
}
}
export const MONTHS_FULL = [