mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
mobile: refactor
This commit is contained in:
committed by
Abdullah Atta
parent
c881e74aae
commit
fb616a246e
@@ -16,8 +16,7 @@ GNU General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
import { database } from "@notesnook/common";
|
||||||
import Database from "@notesnook/core/api/index";
|
|
||||||
import { initalize, logger as dbLogger } from "@notesnook/core/logger";
|
import { initalize, logger as dbLogger } from "@notesnook/core/logger";
|
||||||
import { Platform } from "react-native";
|
import { Platform } from "react-native";
|
||||||
import { MMKVLoader } from "react-native-mmkv-storage";
|
import { MMKVLoader } from "react-native-mmkv-storage";
|
||||||
@@ -30,13 +29,8 @@ import * as Gzip from "react-native-gzip";
|
|||||||
const LoggerStorage = new MMKVLoader()
|
const LoggerStorage = new MMKVLoader()
|
||||||
.withInstanceID("notesnook_logs")
|
.withInstanceID("notesnook_logs")
|
||||||
.initialize();
|
.initialize();
|
||||||
initalize(new KV(LoggerStorage), true);
|
|
||||||
export const DatabaseLogger = dbLogger;
|
|
||||||
|
|
||||||
/**
|
database.setup(
|
||||||
* @type {import("@notesnook/core/api/index").default}
|
|
||||||
*/
|
|
||||||
export var db = new Database(
|
|
||||||
Storage,
|
Storage,
|
||||||
Platform.OS === "ios" ? EventSource : AndroidEventSource,
|
Platform.OS === "ios" ? EventSource : AndroidEventSource,
|
||||||
filesystem,
|
filesystem,
|
||||||
@@ -46,7 +40,7 @@ export var db = new Database(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
db.host(
|
database.host(
|
||||||
__DEV__
|
__DEV__
|
||||||
? {
|
? {
|
||||||
API_HOST: "https://api.notesnook.com",
|
API_HOST: "https://api.notesnook.com",
|
||||||
@@ -68,3 +62,8 @@ db.host(
|
|||||||
ISSUES_HOST: "https://issues.streetwriters.co"
|
ISSUES_HOST: "https://issues.streetwriters.co"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
initalize(new KV(LoggerStorage), true);
|
||||||
|
|
||||||
|
export const db = database;
|
||||||
|
export const DatabaseLogger = dbLogger;
|
||||||
|
|||||||
0
apps/mobile/app/common/filesystem/attach-file.ts
Normal file
0
apps/mobile/app/common/filesystem/attach-file.ts
Normal file
@@ -34,7 +34,6 @@ import {
|
|||||||
import PremiumService from "../../services/premium";
|
import PremiumService from "../../services/premium";
|
||||||
import { useAttachmentStore } from "../../stores/use-attachment-store";
|
import { useAttachmentStore } from "../../stores/use-attachment-store";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { formatBytes } from "../../utils";
|
|
||||||
import { eCloseAttachmentDialog, eCloseSheet } from "../../utils/events";
|
import { eCloseAttachmentDialog, eCloseSheet } from "../../utils/events";
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
import { sleep } from "../../utils/time";
|
import { sleep } from "../../utils/time";
|
||||||
@@ -47,6 +46,7 @@ import { Notice } from "../ui/notice";
|
|||||||
import { PressableButton } from "../ui/pressable";
|
import { PressableButton } from "../ui/pressable";
|
||||||
import Heading from "../ui/typography/heading";
|
import Heading from "../ui/typography/heading";
|
||||||
import Paragraph from "../ui/typography/paragraph";
|
import Paragraph from "../ui/typography/paragraph";
|
||||||
|
import { formatBytes } from "@notesnook/common";
|
||||||
|
|
||||||
const Actions = ({ attachment, setAttachments, fwdRef }) => {
|
const Actions = ({ attachment, setAttachments, fwdRef }) => {
|
||||||
const colors = useThemeStore((state) => state.colors);
|
const colors = useThemeStore((state) => state.colors);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
|||||||
import { db } from "../../common/database";
|
import { db } from "../../common/database";
|
||||||
import { useAttachmentProgress } from "../../hooks/use-attachment-progress";
|
import { useAttachmentProgress } from "../../hooks/use-attachment-progress";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { formatBytes } from "../../utils";
|
import { formatBytes } from "@notesnook/common";
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
import SheetProvider from "../sheet-provider";
|
import SheetProvider from "../sheet-provider";
|
||||||
import { IconButton } from "../ui/icon-button";
|
import { IconButton } from "../ui/icon-button";
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useEffect } from "react";
|
import React, { useCallback, useEffect } from "react";
|
||||||
import { Keyboard, Platform, View } from "react-native";
|
import { Keyboard, Platform, View } from "react-native";
|
||||||
import Animated, {
|
import Animated, {
|
||||||
Easing,
|
Easing,
|
||||||
@@ -30,10 +30,10 @@ import { notesnook } from "../../../e2e/test.ids";
|
|||||||
import { editorState } from "../../screens/editor/tiptap/utils";
|
import { editorState } from "../../screens/editor/tiptap/utils";
|
||||||
import { useSelectionStore } from "../../stores/use-selection-store";
|
import { useSelectionStore } from "../../stores/use-selection-store";
|
||||||
import { useSettingStore } from "../../stores/use-setting-store";
|
import { useSettingStore } from "../../stores/use-setting-store";
|
||||||
import { getElevation, showTooltip, TOOLTIP_POSITIONS } from "../../utils";
|
import { getElevationStyle } from "../../utils/elevation";
|
||||||
import { normalize, SIZE } from "../../utils/size";
|
import { SIZE, normalize } from "../../utils/size";
|
||||||
|
import NativeTooltip from "../../utils/tooltip";
|
||||||
import { PressableButton } from "../ui/pressable";
|
import { PressableButton } from "../ui/pressable";
|
||||||
import { useCallback } from "react";
|
|
||||||
|
|
||||||
export const FloatingButton = ({
|
export const FloatingButton = ({
|
||||||
title,
|
title,
|
||||||
@@ -116,11 +116,11 @@ export const FloatingButton = ({
|
|||||||
accentColor={color || "accent"}
|
accentColor={color || "accent"}
|
||||||
accentText="light"
|
accentText="light"
|
||||||
customStyle={{
|
customStyle={{
|
||||||
...getElevation(5),
|
...getElevationStyle(5),
|
||||||
borderRadius: 100
|
borderRadius: 100
|
||||||
}}
|
}}
|
||||||
onLongPress={(event) => {
|
onLongPress={(event) => {
|
||||||
showTooltip(event, title, TOOLTIP_POSITIONS.LEFT);
|
NativeTooltip.show(event, title, NativeTooltip.POSITIONS.LEFT);
|
||||||
}}
|
}}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import React from "react";
|
|||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import { DDS } from "../../services/device-detection";
|
import { DDS } from "../../services/device-detection";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { getElevation } from "../../utils";
|
import { getElevationStyle } from "../../utils/elevation";
|
||||||
|
|
||||||
const DialogContainer = ({ width, height, ...restProps }) => {
|
const DialogContainer = ({ width, height, ...restProps }) => {
|
||||||
const colors = useThemeStore((state) => state.colors);
|
const colors = useThemeStore((state) => state.colors);
|
||||||
@@ -30,7 +30,7 @@ const DialogContainer = ({ width, height, ...restProps }) => {
|
|||||||
<View
|
<View
|
||||||
{...restProps}
|
{...restProps}
|
||||||
style={{
|
style={{
|
||||||
...getElevation(5),
|
...getElevationStyle(5),
|
||||||
width: width || DDS.isTab ? 500 : "85%",
|
width: width || DDS.isTab ? 500 : "85%",
|
||||||
maxHeight: height || 450,
|
maxHeight: height || 450,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import {
|
|||||||
eUnSubscribeEvent
|
eUnSubscribeEvent
|
||||||
} from "../../services/event-manager";
|
} from "../../services/event-manager";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { getElevation } from "../../utils";
|
import { getElevationStyle } from "../../utils/elevation";
|
||||||
import { eCloseSimpleDialog, eOpenSimpleDialog } from "../../utils/events";
|
import { eCloseSimpleDialog, eOpenSimpleDialog } from "../../utils/events";
|
||||||
import { sleep } from "../../utils/time";
|
import { sleep } from "../../utils/time";
|
||||||
import { Toast } from "../toast";
|
import { Toast } from "../toast";
|
||||||
@@ -111,7 +111,7 @@ export const Dialog = ({ context = "global" }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
...getElevation(5),
|
...getElevationStyle(5),
|
||||||
width: DDS.isTab ? 400 : "85%",
|
width: DDS.isTab ? 400 : "85%",
|
||||||
maxHeight: 450,
|
maxHeight: 450,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
} from "../../../services/event-manager";
|
} from "../../../services/event-manager";
|
||||||
import { useMessageStore } from "../../../stores/use-message-store";
|
import { useMessageStore } from "../../../stores/use-message-store";
|
||||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { getElevation } from "../../../utils";
|
import { getElevationStyle } from "../../../utils/elevation";
|
||||||
import {
|
import {
|
||||||
eCloseJumpToDialog,
|
eCloseJumpToDialog,
|
||||||
eOpenJumpToDialog,
|
eOpenJumpToDialog,
|
||||||
@@ -124,7 +124,7 @@ const JumpToSectionDialog = ({ scrollRef, data, type }) => {
|
|||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
...getElevation(5),
|
...getElevationStyle(5),
|
||||||
width: DDS.isTab ? 500 : "85%",
|
width: DDS.isTab ? 500 : "85%",
|
||||||
backgroundColor: colors.bg,
|
backgroundColor: colors.bg,
|
||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import {
|
|||||||
eUnSubscribeEvent
|
eUnSubscribeEvent
|
||||||
} from "../../../services/event-manager";
|
} from "../../../services/event-manager";
|
||||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { getElevation } from "../../../utils";
|
import { getElevationStyle } from "../../../utils/elevation";
|
||||||
import { eCloseResultDialog, eOpenResultDialog } from "../../../utils/events";
|
import { eCloseResultDialog, eOpenResultDialog } from "../../../utils/events";
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
import BaseDialog from "../../dialog/base-dialog";
|
import BaseDialog from "../../dialog/base-dialog";
|
||||||
@@ -68,7 +68,7 @@ const ResultDialog = () => {
|
|||||||
<BaseDialog visible={true} onRequestClose={close}>
|
<BaseDialog visible={true} onRequestClose={close}>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
...getElevation(5),
|
...getElevationStyle(5),
|
||||||
width: DDS.isTab ? 350 : "85%",
|
width: DDS.isTab ? 350 : "85%",
|
||||||
maxHeight: 500,
|
maxHeight: 500,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ import {
|
|||||||
} from "../../../services/event-manager";
|
} from "../../../services/event-manager";
|
||||||
import Navigation from "../../../services/navigation";
|
import Navigation from "../../../services/navigation";
|
||||||
import SearchService from "../../../services/search";
|
import SearchService from "../../../services/search";
|
||||||
import { getElevation, toTXT } from "../../../utils";
|
import { convertNoteToText } from "../../../utils/note-to-text";
|
||||||
|
import { getElevationStyle } from "../../../utils/elevation";
|
||||||
import {
|
import {
|
||||||
eClearEditor,
|
eClearEditor,
|
||||||
eCloseActionSheet,
|
eCloseActionSheet,
|
||||||
@@ -564,7 +565,7 @@ export class VaultDialog extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _copyNote(note) {
|
async _copyNote(note) {
|
||||||
Clipboard.setString(await toTXT(note));
|
Clipboard.setString(await convertNoteToText(note));
|
||||||
ToastEvent.show({
|
ToastEvent.show({
|
||||||
heading: "Note copied",
|
heading: "Note copied",
|
||||||
type: "success",
|
type: "success",
|
||||||
@@ -580,7 +581,7 @@ export class VaultDialog extends Component {
|
|||||||
await Share.open({
|
await Share.open({
|
||||||
heading: "Share note",
|
heading: "Share note",
|
||||||
failOnCancel: false,
|
failOnCancel: false,
|
||||||
message: await toTXT(note)
|
message: await convertNoteToText(note)
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@@ -678,7 +679,7 @@ export class VaultDialog extends Component {
|
|||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
...getElevation(5),
|
...getElevationStyle(5),
|
||||||
width: DDS.isTab ? 350 : "85%",
|
width: DDS.isTab ? 350 : "85%",
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
backgroundColor: colors.bg,
|
backgroundColor: colors.bg,
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export const RightMenus = () => {
|
|||||||
onRequestClose={() => {
|
onRequestClose={() => {
|
||||||
menuRef.current?.hide();
|
menuRef.current?.hide();
|
||||||
}}
|
}}
|
||||||
anchor={
|
button={
|
||||||
<IconButton
|
<IconButton
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
menuRef.current?.show();
|
menuRef.current?.show();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
|||||||
import SettingsService from "../../services/settings";
|
import SettingsService from "../../services/settings";
|
||||||
import { useSettingStore } from "../../stores/use-setting-store";
|
import { useSettingStore } from "../../stores/use-setting-store";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { getElevation } from "../../utils";
|
import { getElevationStyle } from "../../utils/elevation";
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import Heading from "../ui/typography/heading";
|
import Heading from "../ui/typography/heading";
|
||||||
@@ -198,7 +198,7 @@ const Intro = ({ navigation }) => {
|
|||||||
style={{
|
style={{
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: 24,
|
||||||
alignSelf: "center",
|
alignSelf: "center",
|
||||||
...getElevation(5),
|
...getElevationStyle(5),
|
||||||
borderRadius: 100
|
borderRadius: 100
|
||||||
}}
|
}}
|
||||||
fontSize={SIZE.md}
|
fontSize={SIZE.md}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { eSendEvent } from "../../services/event-manager";
|
|||||||
import Navigation from "../../services/navigation";
|
import Navigation from "../../services/navigation";
|
||||||
import SettingsService from "../../services/settings";
|
import SettingsService from "../../services/settings";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { getElevation } from "../../utils";
|
import { getElevationStyle } from "../../utils/elevation";
|
||||||
import {
|
import {
|
||||||
eCloseLoading,
|
eCloseLoading,
|
||||||
eOpenLoading,
|
eOpenLoading,
|
||||||
@@ -91,7 +91,7 @@ export const WelcomeNotice = () => {
|
|||||||
paddingHorizontal: 24,
|
paddingHorizontal: 24,
|
||||||
alignSelf: "center",
|
alignSelf: "center",
|
||||||
borderRadius: 100,
|
borderRadius: 100,
|
||||||
...getElevation(5),
|
...getElevationStyle(5),
|
||||||
marginTop: 30
|
marginTop: 30
|
||||||
}}
|
}}
|
||||||
type="accent"
|
type="accent"
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ import { useNoteStore } from "../../stores/use-notes-store";
|
|||||||
import { useSettingStore } from "../../stores/use-setting-store";
|
import { useSettingStore } from "../../stores/use-setting-store";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { useUserStore } from "../../stores/use-user-store";
|
import { useUserStore } from "../../stores/use-user-store";
|
||||||
import { AndroidModule } from "../../utils";
|
|
||||||
import { eOpenAnnouncementDialog } from "../../utils/events";
|
import { eOpenAnnouncementDialog } from "../../utils/events";
|
||||||
import { getGithubVersion } from "../../utils/github-version";
|
import { getGithubVersion } from "../../utils/github-version";
|
||||||
|
import { NotesnookModule } from "../../utils/notesnook-module";
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
import { sleep } from "../../utils/time";
|
import { sleep } from "../../utils/time";
|
||||||
import Migrate from "../sheets/migrate";
|
import Migrate from "../sheets/migrate";
|
||||||
@@ -175,7 +175,7 @@ const Launcher = React.memo(
|
|||||||
const onUnlockBiometrics = useCallback(async () => {
|
const onUnlockBiometrics = useCallback(async () => {
|
||||||
if (!(await BiometricService.isBiometryAvailable())) return;
|
if (!(await BiometricService.isBiometryAvailable())) return;
|
||||||
if (Platform.OS === "android") {
|
if (Platform.OS === "android") {
|
||||||
const activityName = await AndroidModule.getActivityName();
|
const activityName = await NotesnookModule.getActivityName();
|
||||||
if (activityName !== "MainActivity") return;
|
if (activityName !== "MainActivity") return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { View } from "react-native";
|
|||||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { useMenuStore } from "../../../stores/use-menu-store";
|
import { useMenuStore } from "../../../stores/use-menu-store";
|
||||||
import { ToastEvent } from "../../../services/event-manager";
|
import { ToastEvent } from "../../../services/event-manager";
|
||||||
import { getTotalNotes } from "../../../utils";
|
import { getTotalNotes } from "@notesnook/common";
|
||||||
import { db } from "../../../common/database";
|
import { db } from "../../../common/database";
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
import { IconButton } from "../../ui/icon-button";
|
import { IconButton } from "../../ui/icon-button";
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import {
|
|||||||
} from "../../../services/event-manager";
|
} from "../../../services/event-manager";
|
||||||
import { useEditorStore } from "../../../stores/use-editor-store";
|
import { useEditorStore } from "../../../stores/use-editor-store";
|
||||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||||
import { history } from "../../../utils";
|
|
||||||
import { eOnLoadNote, eShowMergeDialog } from "../../../utils/events";
|
import { eOnLoadNote, eShowMergeDialog } from "../../../utils/events";
|
||||||
import { tabBarRef } from "../../../utils/global-refs";
|
import { tabBarRef } from "../../../utils/global-refs";
|
||||||
import { presentDialog } from "../../dialog/functions";
|
import { presentDialog } from "../../dialog/functions";
|
||||||
@@ -59,12 +58,14 @@ export const openNote = async (item, isTrash, setSelectedItem, isSheet) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const { selectedItemsList, selectionMode, clearSelection } =
|
||||||
|
useSelectionStore.getState();
|
||||||
|
|
||||||
if (history.selectedItemsList.length > 0 && history.selectionMode) {
|
if (selectedItemsList.length > 0 && selectionMode) {
|
||||||
setSelectedItem && setSelectedItem(_note);
|
setSelectedItem && setSelectedItem(_note);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
history.selectedItemsList = [];
|
clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_note.conflicted) {
|
if (_note.conflicted) {
|
||||||
|
|||||||
@@ -22,23 +22,23 @@ import { View } from "react-native";
|
|||||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||||
import { notesnook } from "../../../../e2e/test.ids";
|
import { notesnook } from "../../../../e2e/test.ids";
|
||||||
import { TopicNotes } from "../../../screens/notes/topic-notes";
|
import { TopicNotes } from "../../../screens/notes/topic-notes";
|
||||||
|
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||||
import { useSettingStore } from "../../../stores/use-setting-store";
|
import { useSettingStore } from "../../../stores/use-setting-store";
|
||||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { history } from "../../../utils";
|
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
import { Properties } from "../../properties";
|
import { Properties } from "../../properties";
|
||||||
import { Button } from "../../ui/button";
|
import { Button } from "../../ui/button";
|
||||||
import { IconButton } from "../../ui/icon-button";
|
import { IconButton } from "../../ui/icon-button";
|
||||||
import Heading from "../../ui/typography/heading";
|
import Heading from "../../ui/typography/heading";
|
||||||
import Paragraph from "../../ui/typography/paragraph";
|
import Paragraph from "../../ui/typography/paragraph";
|
||||||
import { getFormattedDate } from "../../../utils/time";
|
import { getFormattedDate } from "@notesnook/common";
|
||||||
|
|
||||||
const showActionSheet = (item) => {
|
const showActionSheet = (item) => {
|
||||||
Properties.present(item);
|
Properties.present(item);
|
||||||
};
|
};
|
||||||
|
|
||||||
const navigateToTopic = (topic) => {
|
const navigateToTopic = (topic) => {
|
||||||
if (history.selectedItemsList.length > 0) return;
|
if (useSelectionStore.getState().selectedItemsList.length > 0) return;
|
||||||
TopicNotes.navigate(topic, true);
|
TopicNotes.navigate(topic, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import { ToastEvent } from "../../../services/event-manager";
|
|||||||
import Navigation from "../../../services/navigation";
|
import Navigation from "../../../services/navigation";
|
||||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||||
import { useTrashStore } from "../../../stores/use-trash-store";
|
import { useTrashStore } from "../../../stores/use-trash-store";
|
||||||
import { history } from "../../../utils";
|
|
||||||
import { db } from "../../../common/database";
|
import { db } from "../../../common/database";
|
||||||
import { presentDialog } from "../../dialog/functions";
|
import { presentDialog } from "../../dialog/functions";
|
||||||
import SelectionWrapper from "../selection-wrapper";
|
import SelectionWrapper from "../selection-wrapper";
|
||||||
@@ -49,11 +48,13 @@ const navigateToNotebook = (item, canGoBack) => {
|
|||||||
|
|
||||||
export const openNotebookTopic = (item) => {
|
export const openNotebookTopic = (item) => {
|
||||||
const isTrash = item.type === "trash";
|
const isTrash = item.type === "trash";
|
||||||
if (history.selectedItemsList.length > 0 && history.selectionMode) {
|
const { selectedItemsList, setSelectedItem, selectionMode, clearSelection } =
|
||||||
useSelectionStore.getState().setSelectedItem(item);
|
useSelectionStore.getState();
|
||||||
|
if (selectedItemsList.length > 0 && selectionMode) {
|
||||||
|
setSelectedItem(item);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
history.selectedItemsList = [];
|
clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTrash) {
|
if (isTrash) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import { NoteWrapper } from "../list-items/note/wrapper";
|
|||||||
import { NotebookWrapper } from "../list-items/notebook/wrapper";
|
import { NotebookWrapper } from "../list-items/notebook/wrapper";
|
||||||
import TagItem from "../list-items/tag";
|
import TagItem from "../list-items/tag";
|
||||||
import { Empty } from "./empty";
|
import { Empty } from "./empty";
|
||||||
import { getTotalNotes } from "../../utils";
|
import { getTotalNotes } from "@notesnook/common";
|
||||||
import { useSettingStore } from "../../stores/use-setting-store";
|
import { useSettingStore } from "../../stores/use-setting-store";
|
||||||
import ReminderItem from "../list-items/reminder";
|
import ReminderItem from "../list-items/reminder";
|
||||||
|
|
||||||
|
|||||||
@@ -34,10 +34,9 @@ import {
|
|||||||
import Navigation from "../../services/navigation";
|
import Navigation from "../../services/navigation";
|
||||||
import Sync from "../../services/sync";
|
import Sync from "../../services/sync";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { dHeight } from "../../utils";
|
|
||||||
import { eOnLoadNote, eShowMergeDialog } from "../../utils/events";
|
import { eOnLoadNote, eShowMergeDialog } from "../../utils/events";
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
import { getFormattedDate, sleep } from "../../utils/time";
|
import { sleep } from "../../utils/time";
|
||||||
import BaseDialog from "../dialog/base-dialog";
|
import BaseDialog from "../dialog/base-dialog";
|
||||||
import DialogButtons from "../dialog/dialog-buttons";
|
import DialogButtons from "../dialog/dialog-buttons";
|
||||||
import DialogContainer from "../dialog/dialog-container";
|
import DialogContainer from "../dialog/dialog-container";
|
||||||
@@ -46,6 +45,8 @@ import { Button } from "../ui/button";
|
|||||||
import { IconButton } from "../ui/icon-button";
|
import { IconButton } from "../ui/icon-button";
|
||||||
import Seperator from "../ui/seperator";
|
import Seperator from "../ui/seperator";
|
||||||
import Paragraph from "../ui/typography/paragraph";
|
import Paragraph from "../ui/typography/paragraph";
|
||||||
|
import { useSettingStore } from "../../stores/use-setting-store";
|
||||||
|
import { getFormattedDate } from "@notesnook/common";
|
||||||
|
|
||||||
const MergeConflicts = () => {
|
const MergeConflicts = () => {
|
||||||
const colors = useThemeStore((state) => state.colors);
|
const colors = useThemeStore((state) => state.colors);
|
||||||
@@ -57,6 +58,7 @@ const MergeConflicts = () => {
|
|||||||
const content = useRef(null);
|
const content = useRef(null);
|
||||||
const isKeepingConflicted = !keep?.conflicted;
|
const isKeepingConflicted = !keep?.conflicted;
|
||||||
const isKeeping = !!keep;
|
const isKeeping = !!keep;
|
||||||
|
const { height } = useSettingStore((state) => state.dimensions);
|
||||||
|
|
||||||
const applyChanges = async () => {
|
const applyChanges = async () => {
|
||||||
let _content = keep;
|
let _content = keep;
|
||||||
@@ -296,7 +298,7 @@ const MergeConflicts = () => {
|
|||||||
|
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={{
|
style={{
|
||||||
height: dHeight / 2 - (50 + insets.top / 2),
|
height: height / 2 - (50 + insets.top / 2),
|
||||||
backgroundColor: colors.bg,
|
backgroundColor: colors.bg,
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomColor: colors.nav
|
borderBottomColor: colors.nav
|
||||||
@@ -332,7 +334,7 @@ const MergeConflicts = () => {
|
|||||||
|
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={{
|
style={{
|
||||||
height: dHeight / 2 - (50 + insets.top / 2),
|
height: height / 2 - (50 + insets.top / 2),
|
||||||
backgroundColor: colors.bg,
|
backgroundColor: colors.bg,
|
||||||
borderRadius: 10
|
borderRadius: 10
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ import { presentSheet } from "../../services/event-manager";
|
|||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { openLinkInBrowser } from "../../utils/functions";
|
import { openLinkInBrowser } from "../../utils/functions";
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
import { getFormattedDate, timeSince } from "../../utils/time";
|
|
||||||
import DialogHeader from "../dialog/dialog-header";
|
import DialogHeader from "../dialog/dialog-header";
|
||||||
import SheetProvider from "../sheet-provider";
|
import SheetProvider from "../sheet-provider";
|
||||||
import { PressableButton } from "../ui/pressable";
|
import { PressableButton } from "../ui/pressable";
|
||||||
import Seperator from "../ui/seperator";
|
import Seperator from "../ui/seperator";
|
||||||
import Paragraph from "../ui/typography/paragraph";
|
import Paragraph from "../ui/typography/paragraph";
|
||||||
import NotePreview from "./preview";
|
import NotePreview from "./preview";
|
||||||
|
import { getFormattedDate, getTimeAgo } from "@notesnook/common";
|
||||||
|
|
||||||
export default function NoteHistory({ note, fwdRef }) {
|
export default function NoteHistory({ note, fwdRef }) {
|
||||||
const [history, setHistory] = useState([]);
|
const [history, setHistory] = useState([]);
|
||||||
@@ -90,7 +90,7 @@ export default function NoteHistory({ note, fwdRef }) {
|
|||||||
>
|
>
|
||||||
<Paragraph>{getDate(item.dateCreated, item.dateModified)}</Paragraph>
|
<Paragraph>{getDate(item.dateCreated, item.dateModified)}</Paragraph>
|
||||||
<Paragraph color={colors.icon} size={SIZE.xs}>
|
<Paragraph color={colors.icon} size={SIZE.xs}>
|
||||||
{timeSince(item.dateModified)}
|
{getTimeAgo(item.dateModified)}
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</PressableButton>
|
</PressableButton>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { DDS } from "../../services/device-detection";
|
|||||||
import { eSendEvent, presentSheet } from "../../services/event-manager";
|
import { eSendEvent, presentSheet } from "../../services/event-manager";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { useUserStore } from "../../stores/use-user-store";
|
import { useUserStore } from "../../stores/use-user-store";
|
||||||
import { getElevation } from "../../utils";
|
import { getElevationStyle } from "../../utils/elevation";
|
||||||
import {
|
import {
|
||||||
eClosePremiumDialog,
|
eClosePremiumDialog,
|
||||||
eCloseSheet,
|
eCloseSheet,
|
||||||
@@ -271,7 +271,7 @@ export const Component = ({ close, promo }) => {
|
|||||||
position: "absolute",
|
position: "absolute",
|
||||||
borderRadius: 100,
|
borderRadius: 100,
|
||||||
bottom: 30,
|
bottom: 30,
|
||||||
...getElevation(10)
|
...getElevationStyle(10)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
eUnSubscribeEvent
|
eUnSubscribeEvent
|
||||||
} from "../../services/event-manager";
|
} from "../../services/event-manager";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { getElevation } from "../../utils";
|
import { getElevationStyle } from "../../utils/elevation";
|
||||||
import {
|
import {
|
||||||
eCloseActionSheet,
|
eCloseActionSheet,
|
||||||
eCloseSheet,
|
eCloseSheet,
|
||||||
@@ -94,7 +94,7 @@ export const PremiumToast = ({ context = "global", offset = 0 }) => {
|
|||||||
position: "absolute",
|
position: "absolute",
|
||||||
backgroundColor: colors.nav,
|
backgroundColor: colors.nav,
|
||||||
zIndex: 999,
|
zIndex: 999,
|
||||||
...getElevation(20),
|
...getElevationStyle(20),
|
||||||
padding: 12,
|
padding: 12,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import React from "react";
|
|||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
import { getFormattedDate } from "../../utils/time";
|
|
||||||
import Paragraph from "../ui/typography/paragraph";
|
import Paragraph from "../ui/typography/paragraph";
|
||||||
|
import { getFormattedDate } from "@notesnook/common";
|
||||||
export const DateMeta = ({ item }) => {
|
export const DateMeta = ({ item }) => {
|
||||||
const colors = useThemeStore((state) => state.colors);
|
const colors = useThemeStore((state) => state.colors);
|
||||||
|
|
||||||
|
|||||||
@@ -41,11 +41,7 @@ enum EmailChangeSteps {
|
|||||||
changeEmail
|
changeEmail
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChangeEmail = ({
|
export const ChangeEmail = ({ close }: ChangeEmailProps) => {
|
||||||
actionSheetRef,
|
|
||||||
close,
|
|
||||||
update
|
|
||||||
}: ChangeEmailProps) => {
|
|
||||||
const [step, setStep] = useState(EmailChangeSteps.verify);
|
const [step, setStep] = useState(EmailChangeSteps.verify);
|
||||||
const emailChangeData = useRef<{
|
const emailChangeData = useRef<{
|
||||||
email?: string;
|
email?: string;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import Exporter from "../../../services/exporter";
|
|||||||
import PremiumService from "../../../services/premium";
|
import PremiumService from "../../../services/premium";
|
||||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { useUserStore } from "../../../stores/use-user-store";
|
import { useUserStore } from "../../../stores/use-user-store";
|
||||||
import { getElevation } from "../../../utils";
|
import { getElevationStyle } from "../../../utils/elevation";
|
||||||
import { ph, pv, SIZE } from "../../../utils/size";
|
import { ph, pv, SIZE } from "../../../utils/size";
|
||||||
import { sleep } from "../../../utils/time";
|
import { sleep } from "../../../utils/time";
|
||||||
import DialogHeader from "../../dialog/dialog-header";
|
import DialogHeader from "../../dialog/dialog-header";
|
||||||
@@ -340,7 +340,7 @@ ExportNotesSheet.present = (notes, allNotes) => {
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
...getElevation(5),
|
...getElevationStyle(5),
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
paddingVertical: pv
|
paddingVertical: pv
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import SettingsService from "../../../services/settings";
|
|||||||
import { db } from "../../../common/database";
|
import { db } from "../../../common/database";
|
||||||
import Storage from "../../../common/database/storage";
|
import Storage from "../../../common/database/storage";
|
||||||
import { eOpenRecoveryKeyDialog } from "../../../utils/events";
|
import { eOpenRecoveryKeyDialog } from "../../../utils/events";
|
||||||
import { sanitizeFilename } from "../../../utils/sanitizer";
|
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
import { sleep } from "../../../utils/time";
|
import { sleep } from "../../../utils/time";
|
||||||
import DialogHeader from "../../dialog/dialog-header";
|
import DialogHeader from "../../dialog/dialog-header";
|
||||||
@@ -44,6 +43,7 @@ import SheetWrapper from "../../ui/sheet";
|
|||||||
import { QRCode } from "../../ui/svg/lazy";
|
import { QRCode } from "../../ui/svg/lazy";
|
||||||
import Paragraph from "../../ui/typography/paragraph";
|
import Paragraph from "../../ui/typography/paragraph";
|
||||||
import RNFetchBlob from "react-native-blob-util";
|
import RNFetchBlob from "react-native-blob-util";
|
||||||
|
import { sanitizeFilename } from "@notesnook/common";
|
||||||
|
|
||||||
class RecoveryKeySheet extends React.Component {
|
class RecoveryKeySheet extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import { initialize } from "../../../stores";
|
|||||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { eCloseRestoreDialog, eOpenRestoreDialog } from "../../../utils/events";
|
import { eCloseRestoreDialog, eOpenRestoreDialog } from "../../../utils/events";
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
import { getFormattedDate } from "../../../utils/time";
|
|
||||||
import { Dialog } from "../../dialog";
|
import { Dialog } from "../../dialog";
|
||||||
import DialogHeader from "../../dialog/dialog-header";
|
import DialogHeader from "../../dialog/dialog-header";
|
||||||
import { presentDialog } from "../../dialog/functions";
|
import { presentDialog } from "../../dialog/functions";
|
||||||
@@ -45,6 +44,7 @@ import { Button } from "../../ui/button";
|
|||||||
import Seperator from "../../ui/seperator";
|
import Seperator from "../../ui/seperator";
|
||||||
import SheetWrapper from "../../ui/sheet";
|
import SheetWrapper from "../../ui/sheet";
|
||||||
import Paragraph from "../../ui/typography/paragraph";
|
import Paragraph from "../../ui/typography/paragraph";
|
||||||
|
import { getFormattedDate } from "@notesnook/common";
|
||||||
|
|
||||||
const RestoreDataSheet = () => {
|
const RestoreDataSheet = () => {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
|
|||||||
@@ -60,11 +60,12 @@ import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
|||||||
import { notesnook } from "../../../../e2e/test.ids";
|
import { notesnook } from "../../../../e2e/test.ids";
|
||||||
import { MMKV } from "../../../common/database/mmkv";
|
import { MMKV } from "../../../common/database/mmkv";
|
||||||
import { openEditor } from "../../../screens/notes/common";
|
import { openEditor } from "../../../screens/notes/common";
|
||||||
import { getTotalNotes, history } from "../../../utils";
|
import { getTotalNotes } from "@notesnook/common";
|
||||||
import { deleteItems } from "../../../utils/functions";
|
import { deleteItems } from "../../../utils/functions";
|
||||||
import { presentDialog } from "../../dialog/functions";
|
import { presentDialog } from "../../dialog/functions";
|
||||||
import { Properties } from "../../properties";
|
import { Properties } from "../../properties";
|
||||||
import Sort from "../sort";
|
import Sort from "../sort";
|
||||||
|
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||||
|
|
||||||
type ConfigItem = { id: string; type: string };
|
type ConfigItem = { id: string; type: string };
|
||||||
class TopicSheetConfig {
|
class TopicSheetConfig {
|
||||||
@@ -333,7 +334,9 @@ export const TopicsSheet = () => {
|
|||||||
}}
|
}}
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
history.selectedItemsList = selection;
|
useSelectionStore.setState({
|
||||||
|
selectedItemsList: selection
|
||||||
|
});
|
||||||
presentDialog({
|
presentDialog({
|
||||||
title: `Delete ${
|
title: `Delete ${
|
||||||
selection.length > 1 ? "topics" : "topics"
|
selection.length > 1 ? "topics" : "topics"
|
||||||
@@ -345,7 +348,7 @@ export const TopicsSheet = () => {
|
|||||||
negativeText: "Cancel",
|
negativeText: "Cancel",
|
||||||
positivePress: async () => {
|
positivePress: async () => {
|
||||||
await deleteItems();
|
await deleteItems();
|
||||||
history.selectedItemsList = [];
|
useSelectionStore.getState().clearSelection();
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
setSelection([]);
|
setSelection([]);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
eUnSubscribeEvent
|
eUnSubscribeEvent
|
||||||
} from "../../services/event-manager";
|
} from "../../services/event-manager";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { getElevation } from "../../utils";
|
import { getElevationStyle } from "../../utils/elevation";
|
||||||
import { eHideToast, eShowToast } from "../../utils/events";
|
import { eHideToast, eShowToast } from "../../utils/events";
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
@@ -136,7 +136,7 @@ export const Toast = ({ context = "global" }) => {
|
|||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
...getElevation(5),
|
...getElevationStyle(5),
|
||||||
maxWidth: "95%",
|
maxWidth: "95%",
|
||||||
backgroundColor: colors.nav,
|
backgroundColor: colors.nav,
|
||||||
minWidth: data?.func ? "95%" : "50%",
|
minWidth: data?.func ? "95%" : "50%",
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ import Animated, {
|
|||||||
} from "react-native-reanimated";
|
} from "react-native-reanimated";
|
||||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||||
import { ColorKey, useThemeStore } from "../../../stores/use-theme-store";
|
import { ColorKey, useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { showTooltip, TOOLTIP_POSITIONS } from "../../../utils";
|
|
||||||
import { BUTTON_TYPES } from "../../../utils/constants";
|
import { BUTTON_TYPES } from "../../../utils/constants";
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
|
import NativeTooltip from "../../../utils/tooltip";
|
||||||
import { ButtonProps } from "../button";
|
import { ButtonProps } from "../button";
|
||||||
import { PressableButton } from "../pressable";
|
import { PressableButton } from "../pressable";
|
||||||
import Heading from "../typography/heading";
|
import Heading from "../typography/heading";
|
||||||
@@ -86,7 +86,7 @@ export const AnimatedButton = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (tooltipText) {
|
if (tooltipText) {
|
||||||
showTooltip(event, tooltipText, TOOLTIP_POSITIONS.TOP);
|
NativeTooltip.show(event, tooltipText, NativeTooltip.POSITIONS.TOP);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
|
|||||||
@@ -22,15 +22,15 @@ import {
|
|||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
ColorValue,
|
ColorValue,
|
||||||
TextStyle,
|
TextStyle,
|
||||||
ViewStyle,
|
View,
|
||||||
View
|
ViewStyle
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||||
import { ColorKey, useThemeStore } from "../../../stores/use-theme-store";
|
import { ColorKey, useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { useUserStore } from "../../../stores/use-user-store";
|
import { useUserStore } from "../../../stores/use-user-store";
|
||||||
import { showTooltip, TOOLTIP_POSITIONS } from "../../../utils";
|
|
||||||
import { BUTTON_TYPES } from "../../../utils/constants";
|
import { BUTTON_TYPES } from "../../../utils/constants";
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
|
import NativeTooltip from "../../../utils/tooltip";
|
||||||
import { ProTag } from "../../premium/pro-tag";
|
import { ProTag } from "../../premium/pro-tag";
|
||||||
import { PressableButton, PressableButtonProps } from "../pressable";
|
import { PressableButton, PressableButtonProps } from "../pressable";
|
||||||
import Heading from "../typography/heading";
|
import Heading from "../typography/heading";
|
||||||
@@ -105,7 +105,7 @@ export const Button = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (tooltipText) {
|
if (tooltipText) {
|
||||||
showTooltip(event, tooltipText, TOOLTIP_POSITIONS.TOP);
|
NativeTooltip.show(event, tooltipText, NativeTooltip.POSITIONS.TOP);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ import { ColorValue, GestureResponderEvent, ViewStyle } from "react-native";
|
|||||||
import Animated, { Layout } from "react-native-reanimated";
|
import Animated, { Layout } from "react-native-reanimated";
|
||||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||||
import { ColorKey, useThemeStore } from "../../../stores/use-theme-store";
|
import { ColorKey, useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { showTooltip, TOOLTIP_POSITIONS } from "../../../utils";
|
|
||||||
import { hexToRGBA, RGB_Linear_Shade } from "../../../utils/color-scheme/utils";
|
import { hexToRGBA, RGB_Linear_Shade } from "../../../utils/color-scheme/utils";
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
import { PressableButton, PressableButtonProps } from "../pressable";
|
import { PressableButton, PressableButtonProps } from "../pressable";
|
||||||
|
import NativeTooltip from "../../../utils/tooltip";
|
||||||
interface IconButtonProps extends PressableButtonProps {
|
interface IconButtonProps extends PressableButtonProps {
|
||||||
name: string;
|
name: string;
|
||||||
color?: ColorValue;
|
color?: ColorValue;
|
||||||
@@ -56,7 +56,7 @@ export const IconButton = ({
|
|||||||
tooltipText,
|
tooltipText,
|
||||||
type = "gray",
|
type = "gray",
|
||||||
fwdRef,
|
fwdRef,
|
||||||
tooltipPosition = TOOLTIP_POSITIONS.TOP,
|
tooltipPosition = NativeTooltip.POSITIONS.TOP,
|
||||||
...restProps
|
...restProps
|
||||||
}: IconButtonProps) => {
|
}: IconButtonProps) => {
|
||||||
const colors = useThemeStore((state) => state.colors);
|
const colors = useThemeStore((state) => state.colors);
|
||||||
@@ -67,7 +67,7 @@ export const IconButton = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (tooltipText) {
|
if (tooltipText) {
|
||||||
showTooltip(event, tooltipText, tooltipPosition);
|
NativeTooltip.show(event, tooltipText, tooltipPosition);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import {
|
|||||||
validateUsername
|
validateUsername
|
||||||
} from "../../../services/validation";
|
} from "../../../services/validation";
|
||||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { getElevation } from "../../../utils";
|
import { getElevationStyle } from "../../../utils/elevation";
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
import { IconButton } from "../icon-button";
|
import { IconButton } from "../icon-button";
|
||||||
import Paragraph from "../typography/paragraph";
|
import Paragraph from "../typography/paragraph";
|
||||||
@@ -344,7 +344,7 @@ const Input = ({
|
|||||||
paddingVertical: 3,
|
paddingVertical: 3,
|
||||||
paddingHorizontal: 5,
|
paddingHorizontal: 5,
|
||||||
borderRadius: 2.5,
|
borderRadius: 2.5,
|
||||||
...getElevation(2),
|
...getElevationStyle(2),
|
||||||
top: 0
|
top: 0
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ import { ViewStyle } from "react-native";
|
|||||||
import { Reminder } from "../../../services/notifications";
|
import { Reminder } from "../../../services/notifications";
|
||||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
import { getFormattedReminderTime } from "../../../utils/time";
|
|
||||||
import { Button, ButtonProps } from "../button";
|
import { Button, ButtonProps } from "../button";
|
||||||
|
import { getFormattedReminderTime } from "@notesnook/common";
|
||||||
|
|
||||||
export const ReminderTime = ({
|
export const ReminderTime = ({
|
||||||
checkIsActive = true,
|
checkIsActive = true,
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import { useTimeAgo } from "@notesnook/common";
|
||||||
|
import React from "react";
|
||||||
import { TextProps } from "react-native";
|
import { TextProps } from "react-native";
|
||||||
import { timeSince } from "../../../utils/time";
|
|
||||||
import Heading from "../typography/heading";
|
import Heading from "../typography/heading";
|
||||||
import Paragraph from "../typography/paragraph";
|
import Paragraph from "../typography/paragraph";
|
||||||
interface TimeSinceProps extends TextProps {
|
interface TimeSinceProps extends TextProps {
|
||||||
@@ -34,20 +34,10 @@ export const TimeSince = ({
|
|||||||
updateFrequency = 30000,
|
updateFrequency = 30000,
|
||||||
bold
|
bold
|
||||||
}: TimeSinceProps) => {
|
}: TimeSinceProps) => {
|
||||||
const [timeAgo, setTimeAgo] = useState<string | null>(null);
|
const timeAgo = useTimeAgo(time, {
|
||||||
const interval = useRef<NodeJS.Timer>();
|
interval: updateFrequency,
|
||||||
|
locale: "short"
|
||||||
useEffect(() => {
|
});
|
||||||
let t = timeSince(time || Date.now());
|
|
||||||
setTimeAgo(t);
|
|
||||||
interval.current = setInterval(() => {
|
|
||||||
t = timeSince(time);
|
|
||||||
setTimeAgo(t);
|
|
||||||
}, updateFrequency);
|
|
||||||
return () => {
|
|
||||||
interval.current && clearInterval(interval.current);
|
|
||||||
};
|
|
||||||
}, [time, updateFrequency]);
|
|
||||||
|
|
||||||
return bold ? (
|
return bold ? (
|
||||||
<Heading style={style}>{timeAgo}</Heading>
|
<Heading style={style}>{timeAgo}</Heading>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
} from "../../assets/images/assets";
|
} from "../../assets/images/assets";
|
||||||
import { ThemeStore, useThemeStore } from "../../stores/use-theme-store";
|
import { ThemeStore, useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { eSendEvent } from "../../services/event-manager";
|
import { eSendEvent } from "../../services/event-manager";
|
||||||
import { getElevation } from "../../utils";
|
import { getElevationStyle } from "../../utils/elevation";
|
||||||
import { eOpenAddNotebookDialog } from "../../utils/events";
|
import { eOpenAddNotebookDialog } from "../../utils/events";
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
import useRotator from "../../hooks/use-rotator";
|
import useRotator from "../../hooks/use-rotator";
|
||||||
@@ -89,7 +89,7 @@ const NotebookWelcome = () => {
|
|||||||
padding: 12,
|
padding: 12,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
backgroundColor: colors.bg,
|
backgroundColor: colors.bg,
|
||||||
...getElevation(3),
|
...getElevationStyle(3),
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
marginVertical: 12
|
marginVertical: 12
|
||||||
}}
|
}}
|
||||||
@@ -142,7 +142,7 @@ const notebooks: { id: string; steps: TStep[] } = {
|
|||||||
padding: 12,
|
padding: 12,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
backgroundColor: colors.bg,
|
backgroundColor: colors.bg,
|
||||||
...getElevation(3),
|
...getElevationStyle(3),
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
marginVertical: 12
|
marginVertical: 12
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import { useSelectionStore } from "../stores/use-selection-store";
|
|||||||
import { useTagStore } from "../stores/use-tag-store";
|
import { useTagStore } from "../stores/use-tag-store";
|
||||||
import { useThemeStore } from "../stores/use-theme-store";
|
import { useThemeStore } from "../stores/use-theme-store";
|
||||||
import { useUserStore } from "../stores/use-user-store";
|
import { useUserStore } from "../stores/use-user-store";
|
||||||
import { toTXT } from "../utils";
|
import { convertNoteToText } from "../utils/note-to-text";
|
||||||
import { toggleDarkMode } from "../utils/color-scheme/utils";
|
import { toggleDarkMode } from "../utils/color-scheme/utils";
|
||||||
import {
|
import {
|
||||||
eOnTopicSheetUpdate,
|
eOnTopicSheetUpdate,
|
||||||
@@ -182,7 +182,7 @@ export const useActions = ({ close = () => null, item }) => {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let text = await toTXT(item, false);
|
let text = await convertNoteToText(item, false);
|
||||||
let html = text.replace(/\n/g, "<br />");
|
let html = text.replace(/\n/g, "<br />");
|
||||||
Notifications.displayNotification({
|
Notifications.displayNotification({
|
||||||
title: item.title,
|
title: item.title,
|
||||||
@@ -227,7 +227,7 @@ export const useActions = ({ close = () => null, item }) => {
|
|||||||
description: "Unlock note to copy to clipboard."
|
description: "Unlock note to copy to clipboard."
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Clipboard.setString(await toTXT(item));
|
Clipboard.setString(await convertNoteToText(item));
|
||||||
ToastEvent.show({
|
ToastEvent.show({
|
||||||
heading: "Note copied to clipboard",
|
heading: "Note copied to clipboard",
|
||||||
type: "success",
|
type: "success",
|
||||||
@@ -415,7 +415,7 @@ export const useActions = ({ close = () => null, item }) => {
|
|||||||
Share.open({
|
Share.open({
|
||||||
title: "Share note to",
|
title: "Share note to",
|
||||||
failOnCancel: false,
|
failOnCancel: false,
|
||||||
message: await toTXT(item)
|
message: await convertNoteToText(item)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ import { useNoteStore } from "../stores/use-notes-store";
|
|||||||
import { useSelectionStore } from "../stores/use-selection-store";
|
import { useSelectionStore } from "../stores/use-selection-store";
|
||||||
import { useSettingStore } from "../stores/use-setting-store";
|
import { useSettingStore } from "../stores/use-setting-store";
|
||||||
import { useThemeStore } from "../stores/use-theme-store";
|
import { useThemeStore } from "../stores/use-theme-store";
|
||||||
import { history } from "../utils";
|
|
||||||
import { rootNavigatorRef } from "../utils/global-refs";
|
import { rootNavigatorRef } from "../utils/global-refs";
|
||||||
import Auth from "../components/auth";
|
import Auth from "../components/auth";
|
||||||
const NativeStack = createNativeStackNavigator();
|
const NativeStack = createNativeStackNavigator();
|
||||||
@@ -191,7 +190,7 @@ const _NavigationStack = () => {
|
|||||||
const clearSelection = useSelectionStore((state) => state.clearSelection);
|
const clearSelection = useSelectionStore((state) => state.clearSelection);
|
||||||
|
|
||||||
const onStateChange = React.useCallback(() => {
|
const onStateChange = React.useCallback(() => {
|
||||||
if (history.selectionMode) {
|
if (useSelectionStore.getState().selectionMode) {
|
||||||
clearSelection(true);
|
clearSelection(true);
|
||||||
}
|
}
|
||||||
hideAllTooltips();
|
hideAllTooltips();
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ import {
|
|||||||
import { useEditorStore } from "../stores/use-editor-store";
|
import { useEditorStore } from "../stores/use-editor-store";
|
||||||
import { useSettingStore } from "../stores/use-setting-store";
|
import { useSettingStore } from "../stores/use-setting-store";
|
||||||
import { useThemeStore } from "../stores/use-theme-store";
|
import { useThemeStore } from "../stores/use-theme-store";
|
||||||
import { setWidthHeight } from "../utils";
|
|
||||||
import {
|
import {
|
||||||
eClearEditor,
|
eClearEditor,
|
||||||
eCloseFullscreenEditor,
|
eCloseFullscreenEditor,
|
||||||
@@ -221,7 +220,6 @@ const _TabsHolder = () => {
|
|||||||
width: size.width,
|
width: size.width,
|
||||||
height: size.height
|
height: size.height
|
||||||
});
|
});
|
||||||
setWidthHeight(size);
|
|
||||||
DDS.setSize(size, orientation);
|
DDS.setSize(size, orientation);
|
||||||
const nextDeviceMode = DDS.isLargeTablet()
|
const nextDeviceMode = DDS.isLargeTablet()
|
||||||
? "tablet"
|
? "tablet"
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import {
|
|||||||
eUnSubscribeEvent
|
eUnSubscribeEvent
|
||||||
} from "../../services/event-manager";
|
} from "../../services/event-manager";
|
||||||
import { useEditorStore } from "../../stores/use-editor-store";
|
import { useEditorStore } from "../../stores/use-editor-store";
|
||||||
import { getElevation } from "../../utils";
|
import { getElevationStyle } from "../../utils/elevation";
|
||||||
import { openLinkInBrowser } from "../../utils/functions";
|
import { openLinkInBrowser } from "../../utils/functions";
|
||||||
import { NoteType } from "../../utils/types";
|
import { NoteType } from "../../utils/types";
|
||||||
import { EDITOR_URI } from "./source";
|
import { EDITOR_URI } from "./source";
|
||||||
@@ -256,7 +256,7 @@ const ReadonlyButton = ({ editor }: { editor: useEditorType }) => {
|
|||||||
width: 60,
|
width: 60,
|
||||||
height: 60,
|
height: 60,
|
||||||
right: 12,
|
right: 12,
|
||||||
...getElevation(5)
|
...getElevationStyle(5)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ import { useTagStore } from "../../../stores/use-tag-store";
|
|||||||
import { ThemeStore, useThemeStore } from "../../../stores/use-theme-store";
|
import { ThemeStore, useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { eClearEditor, eOnLoadNote } from "../../../utils/events";
|
import { eClearEditor, eOnLoadNote } from "../../../utils/events";
|
||||||
import { tabBarRef } from "../../../utils/global-refs";
|
import { tabBarRef } from "../../../utils/global-refs";
|
||||||
import { getFormattedDate } from "../../../utils/time";
|
|
||||||
import { NoteType } from "../../../utils/types";
|
import { NoteType } from "../../../utils/types";
|
||||||
import { onNoteCreated } from "../../notes/common";
|
import { onNoteCreated } from "../../notes/common";
|
||||||
import Commands from "./commands";
|
import Commands from "./commands";
|
||||||
@@ -53,6 +52,7 @@ import {
|
|||||||
makeSessionId,
|
makeSessionId,
|
||||||
post
|
post
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
|
import { getFormattedDate } from "@notesnook/common";
|
||||||
|
|
||||||
export const useEditor = (
|
export const useEditor = (
|
||||||
editorId = "",
|
editorId = "",
|
||||||
@@ -139,7 +139,7 @@ export const useEditor = (
|
|||||||
|
|
||||||
const reset = useCallback(
|
const reset = useCallback(
|
||||||
async (resetState = true, resetContent = true) => {
|
async (resetState = true, resetContent = true) => {
|
||||||
currentNote.current?.id && db.fs.cancel(currentNote.current.id);
|
currentNote.current?.id && db.fs?.cancel(currentNote.current.id);
|
||||||
currentNote.current = null;
|
currentNote.current = null;
|
||||||
loadedImages.current = {};
|
loadedImages.current = {};
|
||||||
currentContent.current = null;
|
currentContent.current = null;
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ import {
|
|||||||
import { ThemeStore, useThemeStore } from "../../stores/use-theme-store";
|
import { ThemeStore, useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { useUserStore } from "../../stores/use-user-store";
|
import { useUserStore } from "../../stores/use-user-store";
|
||||||
import { eCloseSheet } from "../../utils/events";
|
import { eCloseSheet } from "../../utils/events";
|
||||||
import { sanitizeFilename } from "../../utils/sanitizer";
|
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
import { sleep } from "../../utils/time";
|
import { sleep } from "../../utils/time";
|
||||||
|
import { sanitizeFilename } from "@notesnook/common";
|
||||||
const mfaMethods: MFAMethod[] = [
|
const mfaMethods: MFAMethod[] = [
|
||||||
{
|
{
|
||||||
id: "app",
|
id: "app",
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import SettingsService from "../../services/settings";
|
|||||||
import { useSettingStore } from "../../stores/use-setting-store";
|
import { useSettingStore } from "../../stores/use-setting-store";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { useUserStore } from "../../stores/use-user-store";
|
import { useUserStore } from "../../stores/use-user-store";
|
||||||
import { getElevation } from "../../utils";
|
import { getElevationStyle } from "../../utils/elevation";
|
||||||
import { eOpenLoginDialog } from "../../utils/events";
|
import { eOpenLoginDialog } from "../../utils/events";
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
const AppLock = ({ route }) => {
|
const AppLock = ({ route }) => {
|
||||||
@@ -274,7 +274,7 @@ const AppLock = ({ route }) => {
|
|||||||
style={{
|
style={{
|
||||||
paddingHorizontal: 24,
|
paddingHorizontal: 24,
|
||||||
alignSelf: "center",
|
alignSelf: "center",
|
||||||
...getElevation(5),
|
...getElevationStyle(5),
|
||||||
marginTop: 30,
|
marginTop: 30,
|
||||||
borderRadius: 100
|
borderRadius: 100
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -17,107 +17,20 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useRef, useState } from "react";
|
import React from "react";
|
||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import Menu, { MenuItem } from "react-native-reanimated-material-menu";
|
|
||||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||||
import { PressableButton } from "../../components/ui/pressable";
|
import { PressableButton } from "../../components/ui/pressable";
|
||||||
import Paragraph from "../../components/ui/typography/paragraph";
|
|
||||||
import { DDS } from "../../services/device-detection";
|
import { DDS } from "../../services/device-detection";
|
||||||
import { ToastEvent } from "../../services/event-manager";
|
|
||||||
import PremiumService from "../../services/premium";
|
import PremiumService from "../../services/premium";
|
||||||
import SettingsService from "../../services/settings";
|
import SettingsService from "../../services/settings";
|
||||||
import { useSettingStore } from "../../stores/use-setting-store";
|
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import {
|
import {
|
||||||
hexToRGBA,
|
|
||||||
RGB_Linear_Shade,
|
RGB_Linear_Shade,
|
||||||
|
hexToRGBA,
|
||||||
switchAccentColor
|
switchAccentColor
|
||||||
} from "../../utils/color-scheme/utils";
|
} from "../../utils/color-scheme/utils";
|
||||||
import { MenuItemsList } from "../../utils/constants";
|
|
||||||
import { SIZE } from "../../utils/size";
|
import { SIZE } from "../../utils/size";
|
||||||
export const HomagePageSelector = () => {
|
|
||||||
const colors = useThemeStore((state) => state.colors);
|
|
||||||
const settings = useSettingStore((state) => state.settings);
|
|
||||||
const menuRef = useRef();
|
|
||||||
const [width, setWidth] = useState(0);
|
|
||||||
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 () => {
|
|
||||||
await PremiumService.verify(menuRef.current?.show);
|
|
||||||
}}
|
|
||||||
type="grayBg"
|
|
||||||
customStyle={{
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
marginTop: 10,
|
|
||||||
width: "100%",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
padding: 12
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Paragraph>{settings.homepage}</Paragraph>
|
|
||||||
<Icon color={colors.icon} name="menu-down" size={SIZE.md} />
|
|
||||||
</PressableButton>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{MenuItemsList.slice(0, MenuItemsList.length - 1).map(
|
|
||||||
(item) =>
|
|
||||||
item.name !== "Monographs" && (
|
|
||||||
<MenuItem
|
|
||||||
key={item.name}
|
|
||||||
onPress={async () => {
|
|
||||||
menuRef.current?.hide();
|
|
||||||
await SettingsService.set({ homepage: item.name });
|
|
||||||
ToastEvent.show({
|
|
||||||
heading: "Homepage set to " + item.name,
|
|
||||||
message: "Restart the app for changes to take effect.",
|
|
||||||
type: "success"
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
backgroundColor:
|
|
||||||
settings.homepage === item.name
|
|
||||||
? colors.nav
|
|
||||||
: "transparent",
|
|
||||||
width: "100%",
|
|
||||||
maxWidth: width
|
|
||||||
}}
|
|
||||||
textStyle={{
|
|
||||||
fontSize: SIZE.md,
|
|
||||||
color:
|
|
||||||
settings.homepage === item.name ? colors.accent : colors.pri
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.name}
|
|
||||||
</MenuItem>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</Menu>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AccentColorPicker = () => {
|
export const AccentColorPicker = () => {
|
||||||
const colors = useThemeStore((state) => state.colors);
|
const colors = useThemeStore((state) => state.colors);
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
/*
|
|
||||||
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 React from "react";
|
|
||||||
import { Platform, TouchableOpacity, View } from "react-native";
|
|
||||||
import Paragraph from "../../components/ui/typography/paragraph";
|
|
||||||
import Backup from "../../services/backup";
|
|
||||||
import PremiumService from "../../services/premium";
|
|
||||||
import SettingsService from "../../services/settings";
|
|
||||||
import { useSettingStore } from "../../stores/use-setting-store";
|
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
|
||||||
import { SIZE } from "../../utils/size";
|
|
||||||
export const AutomaticBackupsSelector = () => {
|
|
||||||
const colors = useThemeStore((state) => state.colors);
|
|
||||||
const settings = useSettingStore((state) => state.settings);
|
|
||||||
const updateAskForBackup = async () => {
|
|
||||||
SettingsService.set({
|
|
||||||
nextBackupRequestTime: Date.now() + 86400000 * 3
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flexDirection: "row",
|
|
||||||
borderRadius: 5,
|
|
||||||
overflow: "hidden",
|
|
||||||
flexShrink: 1,
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{[
|
|
||||||
{
|
|
||||||
title: "Never",
|
|
||||||
value: "useroff"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Daily",
|
|
||||||
value: "daily"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Weekly",
|
|
||||||
value: "weekly"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Monthly",
|
|
||||||
value: "monthly"
|
|
||||||
}
|
|
||||||
].map((item, index) => (
|
|
||||||
<TouchableOpacity
|
|
||||||
activeOpacity={0.9}
|
|
||||||
onPress={async () => {
|
|
||||||
if (item.value === "useroff") {
|
|
||||||
await SettingsService.set({ reminder: item.value });
|
|
||||||
} else {
|
|
||||||
await PremiumService.verify(async () => {
|
|
||||||
if (Platform.OS === "android") {
|
|
||||||
let granted = await Backup.checkBackupDirExists();
|
|
||||||
if (!granted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await SettingsService.set({ reminder: item.value });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
updateAskForBackup();
|
|
||||||
}}
|
|
||||||
key={item.value}
|
|
||||||
style={{
|
|
||||||
backgroundColor:
|
|
||||||
settings.reminder === item.value ? colors.accent : colors.nav,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
width: "25%",
|
|
||||||
height: 35,
|
|
||||||
borderRightWidth: index !== 3 ? 1 : 0,
|
|
||||||
borderRightColor: colors.border
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Paragraph
|
|
||||||
color={settings.reminder === item.value ? "white" : colors.icon}
|
|
||||||
size={SIZE.sm - 1}
|
|
||||||
>
|
|
||||||
{item.title}
|
|
||||||
</Paragraph>
|
|
||||||
</TouchableOpacity>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -18,29 +18,34 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { ReactElement } from "react";
|
import React, { ReactElement } from "react";
|
||||||
import { AccentColorPicker, HomagePageSelector } from "./appearance";
|
import { AccentColorPicker } from "./appearance";
|
||||||
import { AutomaticBackupsSelector } from "./backup-restore";
|
|
||||||
import DebugLogs from "./debug";
|
import DebugLogs from "./debug";
|
||||||
import { ConfigureToolbar } from "./editor/configure-toolbar";
|
import { ConfigureToolbar } from "./editor/configure-toolbar";
|
||||||
import { Licenses } from "./licenses";
|
import { Licenses } from "./licenses";
|
||||||
import SoundPicker from "./sound-picker";
|
import SoundPicker from "./sound-picker";
|
||||||
import { Subscription } from "./subscription";
|
import { Subscription } from "./subscription";
|
||||||
import { TrashIntervalSelector } from "./trash-interval-selector";
|
|
||||||
import { FontSelector } from "./font-selector";
|
|
||||||
import { TitleFormat } from "./title-format";
|
import { TitleFormat } from "./title-format";
|
||||||
import { DateFormatSelector, TimeFormatSelector } from "./date-format";
|
import {
|
||||||
|
HomePicker,
|
||||||
|
DateFormatPicker,
|
||||||
|
FontPicker,
|
||||||
|
TimeFormatPicker,
|
||||||
|
TrashIntervalPicker,
|
||||||
|
BackupReminderPicker
|
||||||
|
} from "./picker/pickers";
|
||||||
|
|
||||||
export const components: { [name: string]: ReactElement } = {
|
export const components: { [name: string]: ReactElement } = {
|
||||||
colorpicker: <AccentColorPicker />,
|
colorpicker: <AccentColorPicker />,
|
||||||
homeselector: <HomagePageSelector />,
|
homeselector: <HomePicker />,
|
||||||
autobackups: <AutomaticBackupsSelector />,
|
autobackups: <BackupReminderPicker />,
|
||||||
subscription: <Subscription />,
|
subscription: <Subscription />,
|
||||||
configuretoolbar: <ConfigureToolbar />,
|
configuretoolbar: <ConfigureToolbar />,
|
||||||
"debug-logs": <DebugLogs />,
|
"debug-logs": <DebugLogs />,
|
||||||
"sound-picker": <SoundPicker />,
|
"sound-picker": <SoundPicker />,
|
||||||
licenses: <Licenses />,
|
licenses: <Licenses />,
|
||||||
"trash-interval-selector": <TrashIntervalSelector />,
|
"trash-interval-selector": <TrashIntervalPicker />,
|
||||||
"font-selector": <FontSelector />,
|
"font-selector": <FontPicker />,
|
||||||
"title-format": <TitleFormat />,
|
"title-format": <TitleFormat />,
|
||||||
"date-format-selector": <DateFormatSelector />,
|
"date-format-selector": <DateFormatPicker />,
|
||||||
"time-format-selector": <TimeFormatSelector />
|
"time-format-selector": <TimeFormatPicker />
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,198 +0,0 @@
|
|||||||
/*
|
|
||||||
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";
|
|
||||||
import { useSettingStore } from "../../stores/use-setting-store";
|
|
||||||
|
|
||||||
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);
|
|
||||||
useSettingStore.setState({
|
|
||||||
dateFormat: 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);
|
|
||||||
useSettingStore.setState({
|
|
||||||
timeFormat: 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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -33,7 +33,8 @@ import useTimer from "../../hooks/use-timer";
|
|||||||
import { ToastEvent } from "../../services/event-manager";
|
import { ToastEvent } from "../../services/event-manager";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { hexToRGBA } from "../../utils/color-scheme/utils";
|
import { hexToRGBA } from "../../utils/color-scheme/utils";
|
||||||
import { sanitizeFilename } from "../../utils/sanitizer";
|
import { sanitizeFilename } from "@notesnook/common";
|
||||||
|
|
||||||
// function getLevelString(level: number) {
|
// function getLevelString(level: number) {
|
||||||
// switch (level) {
|
// switch (level) {
|
||||||
// case LogLevel.Debug:
|
// case LogLevel.Debug:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import { presentDialog } from "../../../components/dialog/functions";
|
|||||||
import { IconButton } from "../../../components/ui/icon-button";
|
import { IconButton } from "../../../components/ui/icon-button";
|
||||||
import Paragraph from "../../../components/ui/typography/paragraph";
|
import Paragraph from "../../../components/ui/typography/paragraph";
|
||||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { getElevation } from "../../../utils";
|
import { getElevationStyle } from "../../../utils/elevation";
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
import { renderTool } from "./common";
|
import { renderTool } from "./common";
|
||||||
import { DraggableItem, useDragState } from "./state";
|
import { DraggableItem, useDragState } from "./state";
|
||||||
@@ -174,7 +174,7 @@ export const Group = ({
|
|||||||
width: isDragged ? dimensions.current?.width : "100%",
|
width: isDragged ? dimensions.current?.width : "100%",
|
||||||
backgroundColor: colors.bg,
|
backgroundColor: colors.bg,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
...getElevation(hover ? 5 : 0),
|
...getElevationStyle(hover ? 5 : 0),
|
||||||
marginTop: isSubgroup ? 0 : 10
|
marginTop: isSubgroup ? 0 : 10
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { IconButton } from "../../../components/ui/icon-button";
|
|||||||
import { SvgView } from "../../../components/ui/svg";
|
import { SvgView } from "../../../components/ui/svg";
|
||||||
import Paragraph from "../../../components/ui/typography/paragraph";
|
import Paragraph from "../../../components/ui/typography/paragraph";
|
||||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import { getElevation } from "../../../utils";
|
import { getElevationStyle } from "../../../utils/elevation";
|
||||||
import { SIZE } from "../../../utils/size";
|
import { SIZE } from "../../../utils/size";
|
||||||
import { renderGroup } from "./common";
|
import { renderGroup } from "./common";
|
||||||
import { DraggableItem, useDragState } from "./state";
|
import { DraggableItem, useDragState } from "./state";
|
||||||
@@ -186,7 +186,7 @@ export const Tool = ({
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
paddingLeft: isSubgroup ? 30 : 12,
|
paddingLeft: isSubgroup ? 30 : 12,
|
||||||
...getElevation(hover ? 3 : 0)
|
...getElevationStyle(hover ? 3 : 0)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
|
|||||||
@@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
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 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 { PressableButton } from "../../components/ui/pressable";
|
|
||||||
import Paragraph from "../../components/ui/typography/paragraph";
|
|
||||||
import SettingsService from "../../services/settings";
|
|
||||||
import { useSettingStore } from "../../stores/use-setting-store";
|
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
|
||||||
import { SIZE } from "../../utils/size";
|
|
||||||
import { getFontById, getFonts } from "@notesnook/editor/dist/utils/font";
|
|
||||||
|
|
||||||
export const FontSelector = () => {
|
|
||||||
const colors = useThemeStore((state) => state.colors);
|
|
||||||
const defaultFontFamily = useSettingStore(
|
|
||||||
(state) => state.settings.defaultFontFamily
|
|
||||||
);
|
|
||||||
const menuRef = useRef();
|
|
||||||
const [width, setWidth] = useState(0);
|
|
||||||
|
|
||||||
const onChange = (item) => {
|
|
||||||
menuRef.current?.hide();
|
|
||||||
SettingsService.set({
|
|
||||||
defaultFontFamily: 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>{getFontById(defaultFontFamily).title}</Paragraph>
|
|
||||||
<Icon color={colors.icon} name="menu-down" size={SIZE.md} />
|
|
||||||
</PressableButton>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{getFonts().map((item) => (
|
|
||||||
<MenuItem
|
|
||||||
key={item.id}
|
|
||||||
onPress={async () => {
|
|
||||||
onChange(item.id);
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
backgroundColor:
|
|
||||||
defaultFontFamily === item.id ? colors.nav : "transparent",
|
|
||||||
width: "100%",
|
|
||||||
maxWidth: width
|
|
||||||
}}
|
|
||||||
textStyle={{
|
|
||||||
fontSize: SIZE.md,
|
|
||||||
color: defaultFontFamily === item.id ? colors.accent : colors.pri
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.title}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Menu>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -21,25 +21,51 @@ import React, { useRef, useState } from "react";
|
|||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import Menu, { MenuItem } from "react-native-reanimated-material-menu";
|
import Menu, { MenuItem } from "react-native-reanimated-material-menu";
|
||||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||||
import { db } from "../../common/database";
|
import { PressableButton } from "../../../components/ui/pressable";
|
||||||
import { PressableButton } from "../../components/ui/pressable";
|
import Paragraph from "../../../components/ui/typography/paragraph";
|
||||||
import Paragraph from "../../components/ui/typography/paragraph";
|
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||||
import PremiumService from "../../services/premium";
|
import { SIZE } from "../../../utils/size";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import PremiumService from "../../../services/premium";
|
||||||
import { SIZE } from "../../utils/size";
|
|
||||||
|
|
||||||
export const TrashIntervalSelector = () => {
|
interface PickerOptions<T> {
|
||||||
|
getValue: () => T;
|
||||||
|
updateValue: (item: T) => Promise<void>;
|
||||||
|
formatValue: (item: T) => any;
|
||||||
|
compareValue: (current: T, item: T) => boolean;
|
||||||
|
getItemKey: (item: T) => string;
|
||||||
|
options: T[];
|
||||||
|
premium?: boolean;
|
||||||
|
onCheckOptionIsPremium?: (item: T) => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingsPicker<T>({
|
||||||
|
getValue,
|
||||||
|
updateValue,
|
||||||
|
formatValue,
|
||||||
|
compareValue,
|
||||||
|
options,
|
||||||
|
getItemKey,
|
||||||
|
premium,
|
||||||
|
onCheckOptionIsPremium = () => true
|
||||||
|
}: PickerOptions<T>) {
|
||||||
const colors = useThemeStore((state) => state.colors);
|
const colors = useThemeStore((state) => state.colors);
|
||||||
const [trashInterval, setTrashInterval] = useState(
|
const menuRef = useRef<any>();
|
||||||
db.settings.getTrashCleanupInterval()
|
|
||||||
);
|
|
||||||
const menuRef = useRef();
|
|
||||||
const [width, setWidth] = useState(0);
|
const [width, setWidth] = useState(0);
|
||||||
|
const [currentValue, setCurrentValue] = useState(getValue());
|
||||||
|
|
||||||
|
const onChange = async (item: T) => {
|
||||||
|
if (premium && onCheckOptionIsPremium?.(item)) {
|
||||||
|
await PremiumService.verify(async () => {
|
||||||
|
menuRef.current?.hide();
|
||||||
|
await updateValue(item);
|
||||||
|
setCurrentValue(item);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const onChange = (item) => {
|
|
||||||
menuRef.current?.hide();
|
menuRef.current?.hide();
|
||||||
setTrashInterval(item);
|
await updateValue(item);
|
||||||
db.settings.setTrashCleanupInterval(item);
|
setCurrentValue(item);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -78,40 +104,42 @@ export const TrashIntervalSelector = () => {
|
|||||||
padding: 12
|
padding: 12
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Paragraph>
|
<Paragraph>{formatValue(currentValue)}</Paragraph>
|
||||||
{trashInterval === -1 ? "Never" : trashInterval + " days"}
|
|
||||||
</Paragraph>
|
|
||||||
<Icon color={colors.icon} name="menu-down" size={SIZE.md} />
|
<Icon color={colors.icon} name="menu-down" size={SIZE.md} />
|
||||||
</PressableButton>
|
</PressableButton>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{[-1, 7, 30, 365].map((item) => (
|
{options.map((item) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={item.toString()}
|
key={getItemKey(item)}
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
if (item === -1) {
|
|
||||||
await PremiumService.verify(() => {
|
|
||||||
onChange(item);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
onChange(item);
|
onChange(item);
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor:
|
backgroundColor: compareValue(currentValue, item)
|
||||||
trashInterval === item ? colors.nav : "transparent",
|
? colors.nav
|
||||||
|
: "transparent",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
maxWidth: width
|
maxWidth: width
|
||||||
}}
|
}}
|
||||||
textStyle={{
|
textStyle={{
|
||||||
fontSize: SIZE.md,
|
fontSize: SIZE.md,
|
||||||
color: trashInterval === item ? colors.accent : colors.pri
|
color: compareValue(currentValue, item)
|
||||||
|
? colors.accent
|
||||||
|
: colors.pri
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item === -1 ? "Never" : item + " days"}
|
{formatValue(item)}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
export function createSettingsPicker<T>(props: PickerOptions<T>) {
|
||||||
|
const Selector = () => {
|
||||||
|
return <SettingsPicker {...props} />;
|
||||||
|
};
|
||||||
|
return Selector;
|
||||||
|
}
|
||||||
130
apps/mobile/app/screens/settings/picker/pickers.jsx
Normal file
130
apps/mobile/app/screens/settings/picker/pickers.jsx
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
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 { db } from "../../../common/database";
|
||||||
|
import { ToastEvent } from "../../../services/event-manager";
|
||||||
|
import SettingsService from "../../../services/settings";
|
||||||
|
import { useSettingStore } from "../../../stores/use-setting-store";
|
||||||
|
import { MenuItemsList } from "../../../utils/constants";
|
||||||
|
import { createSettingsPicker } from ".";
|
||||||
|
import { getFontById, getFonts } from "@notesnook/editor/dist/utils/font";
|
||||||
|
import { DATE_FORMATS, TIME_FORMATS } from "@notesnook/core/common";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
export const FontPicker = createSettingsPicker({
|
||||||
|
getValue: () => useSettingStore.getState().settings.defaultFontFamily,
|
||||||
|
updateValue: (item) => {
|
||||||
|
SettingsService.set({
|
||||||
|
defaultFontFamily: item
|
||||||
|
});
|
||||||
|
},
|
||||||
|
formatValue: (item) => {
|
||||||
|
return getFontById(typeof item === "object" ? item.id : item).title;
|
||||||
|
},
|
||||||
|
getItemKey: (item) => item.id,
|
||||||
|
options: getFonts(),
|
||||||
|
compareValue: (current, item) => current === item.id
|
||||||
|
});
|
||||||
|
|
||||||
|
export const HomePicker = createSettingsPicker({
|
||||||
|
getValue: () => useSettingStore.getState().settings.homepage,
|
||||||
|
updateValue: (item) => {
|
||||||
|
SettingsService.set({ homepage: item.name });
|
||||||
|
ToastEvent.show({
|
||||||
|
heading: "Homepage set to " + item.name,
|
||||||
|
message: "Restart the app for changes to take effect.",
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
formatValue: (item) => {
|
||||||
|
return typeof item === "object" ? item.name : item;
|
||||||
|
},
|
||||||
|
getItemKey: (item) => item.name,
|
||||||
|
options: MenuItemsList.slice(0, MenuItemsList.length - 1),
|
||||||
|
compareValue: (current, item) => current === item.name,
|
||||||
|
premium: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export const TrashIntervalPicker = createSettingsPicker({
|
||||||
|
getValue: () => db.settings.getTrashCleanupInterval(),
|
||||||
|
updateValue: (item) => {
|
||||||
|
db.settings.setTrashCleanupInterval(item);
|
||||||
|
},
|
||||||
|
formatValue: (item) => {
|
||||||
|
return item === -1 ? "Never" : item + " days";
|
||||||
|
},
|
||||||
|
getItemKey: (item) => item.toString(),
|
||||||
|
options: [-1, 7, 30, 365],
|
||||||
|
compareValue: (current, item) => current === item,
|
||||||
|
premium: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export const DateFormatPicker = createSettingsPicker({
|
||||||
|
getValue: () => db.settings.getDateFormat(),
|
||||||
|
updateValue: (item) => {
|
||||||
|
db.settings.setDateFormat(item);
|
||||||
|
useSettingStore.setState({
|
||||||
|
dateFormat: item
|
||||||
|
});
|
||||||
|
},
|
||||||
|
formatValue: (item) => {
|
||||||
|
return `${item} (${dayjs().format(item)})`;
|
||||||
|
},
|
||||||
|
getItemKey: (item) => item,
|
||||||
|
options: DATE_FORMATS,
|
||||||
|
compareValue: (current, item) => current === item
|
||||||
|
});
|
||||||
|
|
||||||
|
const TimeFormats = {
|
||||||
|
"12-hour": "hh:mm A",
|
||||||
|
"24-hour": "HH:mm"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TimeFormatPicker = createSettingsPicker({
|
||||||
|
getValue: () => db.settings.getTimeFormat(),
|
||||||
|
updateValue: (item) => {
|
||||||
|
db.settings.setTimeFormat(item);
|
||||||
|
useSettingStore.setState({
|
||||||
|
timeFormat: item
|
||||||
|
});
|
||||||
|
},
|
||||||
|
formatValue: (item) => {
|
||||||
|
return `${item} (${dayjs().format(TimeFormats[item])})`;
|
||||||
|
},
|
||||||
|
getItemKey: (item) => item,
|
||||||
|
options: TIME_FORMATS,
|
||||||
|
compareValue: (current, item) => current === item
|
||||||
|
});
|
||||||
|
|
||||||
|
export const BackupReminderPicker = createSettingsPicker({
|
||||||
|
getValue: () => useSettingStore.getState().settings.reminder,
|
||||||
|
updateValue: (item) => {
|
||||||
|
SettingsService.set({ reminder: item });
|
||||||
|
},
|
||||||
|
formatValue: (item) => {
|
||||||
|
return item === "useroff"
|
||||||
|
? "Never"
|
||||||
|
: item.slice(0, 1).toUpperCase() + item.slice(1);
|
||||||
|
},
|
||||||
|
getItemKey: (item) => item,
|
||||||
|
options: ["useroff", "daily", "weekly", "monthly"],
|
||||||
|
compareValue: (current, item) => current === item,
|
||||||
|
premium: true,
|
||||||
|
onCheckOptionIsPremium: (item) => item !== "useroff"
|
||||||
|
});
|
||||||
@@ -35,14 +35,14 @@ import ExportNotesSheet from "../../components/sheets/export-notes";
|
|||||||
import { Issue } from "../../components/sheets/github/issue";
|
import { Issue } from "../../components/sheets/github/issue";
|
||||||
import { Progress } from "../../components/sheets/progress";
|
import { Progress } from "../../components/sheets/progress";
|
||||||
import { Update } from "../../components/sheets/update";
|
import { Update } from "../../components/sheets/update";
|
||||||
import { useVaultStatus, VaultStatusType } from "../../hooks/use-vault-status";
|
import { VaultStatusType, useVaultStatus } from "../../hooks/use-vault-status";
|
||||||
import BackupService from "../../services/backup";
|
import BackupService from "../../services/backup";
|
||||||
import BiometicService from "../../services/biometrics";
|
import BiometicService from "../../services/biometrics";
|
||||||
import {
|
import {
|
||||||
|
ToastEvent,
|
||||||
eSendEvent,
|
eSendEvent,
|
||||||
openVault,
|
openVault,
|
||||||
presentSheet,
|
presentSheet
|
||||||
ToastEvent
|
|
||||||
} from "../../services/event-manager";
|
} from "../../services/event-manager";
|
||||||
import { setLoginMessage } from "../../services/message";
|
import { setLoginMessage } from "../../services/message";
|
||||||
import Navigation from "../../services/navigation";
|
import Navigation from "../../services/navigation";
|
||||||
@@ -53,7 +53,6 @@ import Sync from "../../services/sync";
|
|||||||
import { clearAllStores } from "../../stores";
|
import { clearAllStores } from "../../stores";
|
||||||
import { useSettingStore } from "../../stores/use-setting-store";
|
import { useSettingStore } from "../../stores/use-setting-store";
|
||||||
import { useUserStore } from "../../stores/use-user-store";
|
import { useUserStore } from "../../stores/use-user-store";
|
||||||
import { AndroidModule } from "../../utils";
|
|
||||||
import { getColorScheme, toggleDarkMode } from "../../utils/color-scheme/utils";
|
import { getColorScheme, toggleDarkMode } from "../../utils/color-scheme/utils";
|
||||||
import { SUBSCRIPTION_STATUS } from "../../utils/constants";
|
import { SUBSCRIPTION_STATUS } from "../../utils/constants";
|
||||||
import {
|
import {
|
||||||
@@ -63,6 +62,7 @@ import {
|
|||||||
eOpenRecoveryKeyDialog,
|
eOpenRecoveryKeyDialog,
|
||||||
eOpenRestoreDialog
|
eOpenRestoreDialog
|
||||||
} from "../../utils/events";
|
} from "../../utils/events";
|
||||||
|
import { NotesnookModule } from "../../utils/notesnook-module";
|
||||||
import { sleep } from "../../utils/time";
|
import { sleep } from "../../utils/time";
|
||||||
import { MFARecoveryCodes, MFASheet } from "./2fa";
|
import { MFARecoveryCodes, MFASheet } from "./2fa";
|
||||||
import AppLock from "./app-lock";
|
import AppLock from "./app-lock";
|
||||||
@@ -762,7 +762,7 @@ export const settingsGroups: SettingSection[] = [
|
|||||||
modifer: () => {
|
modifer: () => {
|
||||||
const settings = SettingsService.get();
|
const settings = SettingsService.get();
|
||||||
Platform.OS === "android"
|
Platform.OS === "android"
|
||||||
? AndroidModule.setSecureMode(!settings.privacyScreen)
|
? NotesnookModule.setSecureMode(!settings.privacyScreen)
|
||||||
: enabled(true);
|
: enabled(true);
|
||||||
|
|
||||||
SettingsService.set({ privacyScreen: !settings.privacyScreen });
|
SettingsService.set({ privacyScreen: !settings.privacyScreen });
|
||||||
|
|||||||
@@ -16,6 +16,34 @@ GNU General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
import { Platform } from "react-native";
|
||||||
|
import {
|
||||||
|
beginBackgroundTask,
|
||||||
|
endBackgroundTask
|
||||||
|
} from "react-native-begin-background-task";
|
||||||
|
|
||||||
|
async function doInBackground(callback: () => Promise<void>) {
|
||||||
|
if (Platform.OS === "ios") {
|
||||||
|
try {
|
||||||
|
const bgTaskId = await beginBackgroundTask();
|
||||||
|
const result = await callback();
|
||||||
|
await endBackgroundTask(bgTaskId);
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
return (e as Error).message;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// eslint-disable-next-line no-async-promise-executor
|
||||||
|
return new Promise(async (resolve) => {
|
||||||
|
try {
|
||||||
|
const result = await callback();
|
||||||
|
resolve(result);
|
||||||
|
} catch (e) {
|
||||||
|
resolve((e as Error).message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// import BackgroundFetch from "react-native-background-fetch";
|
// import BackgroundFetch from "react-native-background-fetch";
|
||||||
// import { DatabaseLogger, db } from "../common/database";
|
// import { DatabaseLogger, db } from "../common/database";
|
||||||
@@ -120,4 +148,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
// start,
|
// start,
|
||||||
// registerHeadlessTask
|
// registerHeadlessTask
|
||||||
// };
|
// };
|
||||||
export {};
|
export default { doInBackground };
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ import { presentDialog } from "../components/dialog/functions";
|
|||||||
import { DatabaseLogger, db } from "../common/database";
|
import { DatabaseLogger, db } from "../common/database";
|
||||||
import storage from "../common/database/storage";
|
import storage from "../common/database/storage";
|
||||||
import { eCloseSheet } from "../utils/events";
|
import { eCloseSheet } from "../utils/events";
|
||||||
import { sanitizeFilename } from "../utils/sanitizer";
|
|
||||||
import { sleep } from "../utils/time";
|
import { sleep } from "../utils/time";
|
||||||
import { eSendEvent, presentSheet, ToastEvent } from "./event-manager";
|
import { eSendEvent, presentSheet, ToastEvent } from "./event-manager";
|
||||||
import SettingsService from "./settings";
|
import SettingsService from "./settings";
|
||||||
import PremiumService from "./premium";
|
import PremiumService from "./premium";
|
||||||
|
import { sanitizeFilename } from "@notesnook/common";
|
||||||
|
|
||||||
const MS_DAY = 86400000;
|
const MS_DAY = 86400000;
|
||||||
const MS_WEEK = MS_DAY * 7;
|
const MS_WEEK = MS_DAY * 7;
|
||||||
|
|||||||
@@ -25,9 +25,10 @@ import * as ScopedStorage from "react-native-scoped-storage";
|
|||||||
import RNFetchBlob from "react-native-blob-util";
|
import RNFetchBlob from "react-native-blob-util";
|
||||||
import { DatabaseLogger, db } from "../common/database/index";
|
import { DatabaseLogger, db } from "../common/database/index";
|
||||||
import Storage from "../common/database/storage";
|
import Storage from "../common/database/storage";
|
||||||
import { toTXT } from "../utils";
|
import { convertNoteToText } from "../utils/note-to-text";
|
||||||
import { sanitizeFilename } from "../utils/sanitizer";
|
|
||||||
import { sleep } from "../utils/time";
|
import { sleep } from "../utils/time";
|
||||||
|
import { sanitizeFilename } from "@notesnook/common";
|
||||||
|
|
||||||
const MIMETypes = {
|
const MIMETypes = {
|
||||||
txt: "text/plain",
|
txt: "text/plain",
|
||||||
@@ -149,7 +150,7 @@ async function exportAs(type, note, bulk) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "txt":
|
case "txt":
|
||||||
data = await toTXT(note);
|
data = await convertNoteToText(note);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import Orientation from "react-native-orientation";
|
|||||||
import { enabled } from "react-native-privacy-snapshot";
|
import { enabled } from "react-native-privacy-snapshot";
|
||||||
import { MMKV } from "../common/database/mmkv";
|
import { MMKV } from "../common/database/mmkv";
|
||||||
import { SettingStore, useSettingStore } from "../stores/use-setting-store";
|
import { SettingStore, useSettingStore } from "../stores/use-setting-store";
|
||||||
import { AndroidModule } from "../utils";
|
|
||||||
import { getColorScheme } from "../utils/color-scheme/utils";
|
import { getColorScheme } from "../utils/color-scheme/utils";
|
||||||
|
import { NotesnookModule } from "../utils/notesnook-module";
|
||||||
import { scale, updateSize } from "../utils/size";
|
import { scale, updateSize } from "../utils/size";
|
||||||
import { DDS } from "./device-detection";
|
import { DDS } from "./device-detection";
|
||||||
import { setAutobackOffMessage } from "./message";
|
import { setAutobackOffMessage } from "./message";
|
||||||
@@ -63,13 +63,13 @@ function init() {
|
|||||||
function setPrivacyScreen(settings: SettingStore["settings"]) {
|
function setPrivacyScreen(settings: SettingStore["settings"]) {
|
||||||
if (settings.privacyScreen || settings.appLockMode === "background") {
|
if (settings.privacyScreen || settings.appLockMode === "background") {
|
||||||
if (Platform.OS === "android") {
|
if (Platform.OS === "android") {
|
||||||
AndroidModule.setSecureMode(true);
|
NotesnookModule.setSecureMode(true);
|
||||||
} else {
|
} else {
|
||||||
enabled(true);
|
enabled(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Platform.OS === "android") {
|
if (Platform.OS === "android") {
|
||||||
AndroidModule.setSecureMode(false);
|
NotesnookModule.setSecureMode(false);
|
||||||
} else {
|
} else {
|
||||||
enabled(false);
|
enabled(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,15 +17,15 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import NetInfo from "@react-native-community/netinfo";
|
|
||||||
import { EVENTS } from "@notesnook/core/common";
|
import { EVENTS } from "@notesnook/core/common";
|
||||||
import { initAfterSync } from "../stores/index";
|
import NetInfo from "@react-native-community/netinfo";
|
||||||
import { SyncStatus, useUserStore } from "../stores/use-user-store";
|
|
||||||
import { doInBackground } from "../utils";
|
|
||||||
import { db } from "../common/database";
|
import { db } from "../common/database";
|
||||||
import { DatabaseLogger } from "../common/database/index";
|
import { DatabaseLogger } from "../common/database/index";
|
||||||
|
import { initAfterSync } from "../stores/index";
|
||||||
|
import { SyncStatus, useUserStore } from "../stores/use-user-store";
|
||||||
import { ToastEvent } from "./event-manager";
|
import { ToastEvent } from "./event-manager";
|
||||||
import SettingsService from "./settings";
|
import SettingsService from "./settings";
|
||||||
|
import BackgroundSync from "./background-sync";
|
||||||
|
|
||||||
export const ignoredMessages = [
|
export const ignoredMessages = [
|
||||||
"Sync already running",
|
"Sync already running",
|
||||||
@@ -61,7 +61,7 @@ const run = async (
|
|||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let res = await doInBackground(async () => {
|
let res = await BackgroundSync.doInBackground(async () => {
|
||||||
try {
|
try {
|
||||||
await db.sync(full, forced);
|
await db.sync(full, forced);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import create, { State } from "zustand";
|
import create, { State } from "zustand";
|
||||||
import { history } from "../utils";
|
|
||||||
|
|
||||||
type Item = {
|
type Item = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -30,23 +29,16 @@ export interface SelectionStore extends State {
|
|||||||
setAll: (all: Array<unknown>) => void;
|
setAll: (all: Array<unknown>) => void;
|
||||||
setSelectionMode: (mode: boolean) => void;
|
setSelectionMode: (mode: boolean) => void;
|
||||||
setSelectedItem: (item: Item) => void;
|
setSelectedItem: (item: Item) => void;
|
||||||
clearSelection: (noanimation: boolean) => void;
|
clearSelection: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useSelectionStore = create<SelectionStore>((set, get) => ({
|
export const useSelectionStore = create<SelectionStore>((set, get) => ({
|
||||||
selectedItemsList: [],
|
selectedItemsList: [],
|
||||||
selectionMode: false,
|
selectionMode: false,
|
||||||
setAll: (all) => {
|
setAll: (all) => {
|
||||||
history.selectedItemsList = all as never[];
|
|
||||||
set({ selectedItemsList: all });
|
set({ selectedItemsList: all });
|
||||||
},
|
},
|
||||||
setSelectionMode: (mode) => {
|
setSelectionMode: (mode) => {
|
||||||
if (!mode) {
|
|
||||||
history.selectedItemsList = [];
|
|
||||||
history.selectionMode = false;
|
|
||||||
} else {
|
|
||||||
history.selectionMode = true;
|
|
||||||
}
|
|
||||||
set({
|
set({
|
||||||
selectionMode: mode,
|
selectionMode: mode,
|
||||||
selectedItemsList: mode ? get().selectedItemsList : []
|
selectedItemsList: mode ? get().selectedItemsList : []
|
||||||
@@ -61,17 +53,13 @@ export const useSelectionStore = create<SelectionStore>((set, get) => ({
|
|||||||
selectedItems.push(item);
|
selectedItems.push(item);
|
||||||
}
|
}
|
||||||
selectedItems = [...new Set(selectedItems)];
|
selectedItems = [...new Set(selectedItems)];
|
||||||
history.selectedItemsList = selectedItems as never[];
|
|
||||||
history.selectionMode =
|
|
||||||
selectedItems.length > 0 ? get().selectionMode : false;
|
|
||||||
set({
|
set({
|
||||||
selectedItemsList: selectedItems,
|
selectedItemsList: selectedItems,
|
||||||
selectionMode: history.selectionMode
|
selectionMode: get().selectionMode
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
clearSelection: () => {
|
clearSelection: () => {
|
||||||
history.selectedItemsList = [];
|
|
||||||
history.selectionMode = false;
|
|
||||||
set({ selectionMode: false, selectedItemsList: [] });
|
set({ selectionMode: false, selectedItemsList: [] });
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Platform, StatusBar } from "react-native";
|
import { Platform, StatusBar } from "react-native";
|
||||||
import { AndroidModule } from "..";
|
|
||||||
import { eSendEvent } from "../../services/event-manager";
|
import { eSendEvent } from "../../services/event-manager";
|
||||||
import { useThemeStore } from "../../stores/use-theme-store";
|
import { useThemeStore } from "../../stores/use-theme-store";
|
||||||
import { eThemeUpdated } from "../events";
|
import { eThemeUpdated } from "../events";
|
||||||
|
import { NotesnookModule } from "../notesnook-module";
|
||||||
|
|
||||||
export const ACCENT = {
|
export const ACCENT = {
|
||||||
color: "#008837",
|
color: "#008837",
|
||||||
@@ -137,7 +137,7 @@ export function setColorScheme(colors = COLOR_SCHEME, accent = ACCENT) {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
if (Platform.OS === "android") {
|
if (Platform.OS === "android") {
|
||||||
AndroidModule.setBackgroundColor(COLOR_SCHEME.bg);
|
NotesnookModule.setBackgroundColor(COLOR_SCHEME.bg);
|
||||||
StatusBar.setBackgroundColor("transparent", false);
|
StatusBar.setBackgroundColor("transparent", false);
|
||||||
StatusBar.setTranslucent(true, false);
|
StatusBar.setTranslucent(true, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,16 +100,6 @@ export const SUBSCRIPTION_PROVIDER = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WeekDayNames = {
|
|
||||||
0: "Sunday",
|
|
||||||
1: "Monday",
|
|
||||||
2: "Tuesday",
|
|
||||||
3: "Wednesday",
|
|
||||||
4: "Thursday",
|
|
||||||
5: "Friday",
|
|
||||||
6: "Saturday"
|
|
||||||
};
|
|
||||||
|
|
||||||
export const MenuItemsList = [
|
export const MenuItemsList = [
|
||||||
{
|
{
|
||||||
name: "Notes",
|
name: "Notes",
|
||||||
@@ -214,15 +204,3 @@ export const BUTTON_TYPES = {
|
|||||||
opacity: 0.12
|
opacity: 0.12
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const bgTaskOptions = {
|
|
||||||
taskName: "notesnookSync",
|
|
||||||
taskTitle: "Notesnook Sync",
|
|
||||||
taskDesc: "Syncing your notes.",
|
|
||||||
taskIcon: {
|
|
||||||
name: "ic_stat_name",
|
|
||||||
type: "drawable"
|
|
||||||
},
|
|
||||||
color: "#ffffff",
|
|
||||||
linkingURI: "com.streetwriters.notesnook://launch"
|
|
||||||
};
|
|
||||||
|
|||||||
28
apps/mobile/app/utils/elevation.ts
Normal file
28
apps/mobile/app/utils/elevation.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function getElevationStyle(elevation: number) {
|
||||||
|
return {
|
||||||
|
elevation,
|
||||||
|
shadowColor: "black",
|
||||||
|
shadowOffset: { width: 0.3 * elevation, height: 0.5 * elevation },
|
||||||
|
shadowOpacity: 0.2,
|
||||||
|
shadowRadius: 0.7 * elevation
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -18,18 +18,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Linking } from "react-native";
|
import { Linking } from "react-native";
|
||||||
import { history } from ".";
|
import { db } from "../common/database";
|
||||||
|
import { presentDialog } from "../components/dialog/functions";
|
||||||
import { eSendEvent, ToastEvent } from "../services/event-manager";
|
import { eSendEvent, ToastEvent } from "../services/event-manager";
|
||||||
import Navigation from "../services/navigation";
|
import Navigation from "../services/navigation";
|
||||||
import SearchService from "../services/search";
|
import SearchService from "../services/search";
|
||||||
import { useSelectionStore } from "../stores/use-selection-store";
|
|
||||||
import { useMenuStore } from "../stores/use-menu-store";
|
import { useMenuStore } from "../stores/use-menu-store";
|
||||||
import { db } from "../common/database";
|
|
||||||
import { eClearEditor, eOnTopicSheetUpdate } from "./events";
|
|
||||||
import { useRelationStore } from "../stores/use-relation-store";
|
import { useRelationStore } from "../stores/use-relation-store";
|
||||||
import { presentDialog } from "../components/dialog/functions";
|
import { useSelectionStore } from "../stores/use-selection-store";
|
||||||
|
import { eClearEditor, eOnTopicSheetUpdate } from "./events";
|
||||||
|
|
||||||
function deleteConfirmDialog(items, type, context) {
|
function confirmDeleteAllNotes(items, type, context) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
presentDialog({
|
presentDialog({
|
||||||
title: `Delete ${
|
title: `Delete ${
|
||||||
@@ -68,33 +67,25 @@ export const deleteItems = async (item, context) => {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (item && item.id && history.selectedItemsList.length === 0) {
|
if (
|
||||||
history.selectedItemsList = [];
|
item &&
|
||||||
history.selectedItemsList.push(item);
|
item.id &&
|
||||||
|
useSelectionStore.getState().selectedItemsList.length === 0
|
||||||
|
) {
|
||||||
|
useSelectionStore.getState().setSelectedItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
let notes = history.selectedItemsList.filter((i) => i.type === "note");
|
const { selectedItemsList } = useSelectionStore.getState();
|
||||||
let notebooks = history.selectedItemsList.filter(
|
|
||||||
(i) => i.type === "notebook"
|
|
||||||
);
|
|
||||||
let topics = history.selectedItemsList.filter((i) => i.type === "topic");
|
|
||||||
let reminders = history.selectedItemsList.filter(
|
|
||||||
(i) => i.type === "reminder"
|
|
||||||
);
|
|
||||||
|
|
||||||
let routesForUpdate = [
|
let notes = selectedItemsList.filter((i) => i.type === "note");
|
||||||
"TaggedNotes",
|
let notebooks = selectedItemsList.filter((i) => i.type === "notebook");
|
||||||
"ColoredNotes",
|
let topics = selectedItemsList.filter((i) => i.type === "topic");
|
||||||
"TopicNotes",
|
let reminders = selectedItemsList.filter((i) => i.type === "reminder");
|
||||||
"Favorites",
|
|
||||||
"Notes"
|
|
||||||
];
|
|
||||||
|
|
||||||
if (reminders.length > 0) {
|
if (reminders.length > 0) {
|
||||||
for (let reminder of reminders) {
|
for (let reminder of reminders) {
|
||||||
await db.reminders.remove(reminder.id);
|
await db.reminders.remove(reminder.id);
|
||||||
}
|
}
|
||||||
routesForUpdate.push("Reminders");
|
|
||||||
useRelationStore.getState().update();
|
useRelationStore.getState().update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,12 +102,11 @@ export const deleteItems = async (item, context) => {
|
|||||||
}
|
}
|
||||||
await db.notes.delete(note.id);
|
await db.notes.delete(note.id);
|
||||||
}
|
}
|
||||||
routesForUpdate.push("Trash");
|
|
||||||
eSendEvent(eClearEditor);
|
eSendEvent(eClearEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topics?.length > 0) {
|
if (topics?.length > 0) {
|
||||||
const result = await deleteConfirmDialog(topics, "topic", context);
|
const result = await confirmDeleteAllNotes(topics, "topic", context);
|
||||||
if (result.delete) {
|
if (result.delete) {
|
||||||
for (const topic of topics) {
|
for (const topic of topics) {
|
||||||
if (result.deleteNotes) {
|
if (result.deleteNotes) {
|
||||||
@@ -127,7 +117,6 @@ export const deleteItems = async (item, context) => {
|
|||||||
}
|
}
|
||||||
await db.notebooks.notebook(topic.notebookId).topics.delete(topic.id);
|
await db.notebooks.notebook(topic.notebookId).topics.delete(topic.id);
|
||||||
}
|
}
|
||||||
routesForUpdate.push("Notebook", "Notebooks");
|
|
||||||
useMenuStore.getState().setMenuPins();
|
useMenuStore.getState().setMenuPins();
|
||||||
ToastEvent.show({
|
ToastEvent.show({
|
||||||
heading: `${topics.length > 1 ? "Topics" : "Topic"} deleted`,
|
heading: `${topics.length > 1 ? "Topics" : "Topic"} deleted`,
|
||||||
@@ -137,7 +126,7 @@ export const deleteItems = async (item, context) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (notebooks?.length > 0) {
|
if (notebooks?.length > 0) {
|
||||||
const result = await deleteConfirmDialog(notebooks, "notebook", context);
|
const result = await confirmDeleteAllNotes(notebooks, "notebook", context);
|
||||||
|
|
||||||
if (result.delete) {
|
if (result.delete) {
|
||||||
let ids = notebooks.map((i) => i.id);
|
let ids = notebooks.map((i) => i.id);
|
||||||
@@ -156,17 +145,17 @@ export const deleteItems = async (item, context) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
await db.notebooks.delete(...ids);
|
await db.notebooks.delete(...ids);
|
||||||
routesForUpdate.push("Notebook", "Notebooks");
|
|
||||||
useMenuStore.getState().setMenuPins();
|
useMenuStore.getState().setMenuPins();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Navigation.queueRoutesForUpdate();
|
Navigation.queueRoutesForUpdate();
|
||||||
|
|
||||||
let msgPart = history.selectedItemsList.length === 1 ? " item" : " items";
|
let message = `${selectedItemsList.length} ${
|
||||||
let message = history.selectedItemsList.length + msgPart + " moved to trash.";
|
selectedItemsList.length === 1 ? "item" : "items"
|
||||||
|
} moved to trash.`;
|
||||||
|
|
||||||
let itemsCopy = [...history.selectedItemsList];
|
let deletedItems = [...selectedItemsList];
|
||||||
if (
|
if (
|
||||||
topics.length === 0 &&
|
topics.length === 0 &&
|
||||||
reminders.length === 0 &&
|
reminders.length === 0 &&
|
||||||
@@ -178,13 +167,12 @@ export const deleteItems = async (item, context) => {
|
|||||||
func: async () => {
|
func: async () => {
|
||||||
let trash = db.trash.all;
|
let trash = db.trash.all;
|
||||||
let ids = [];
|
let ids = [];
|
||||||
for (var i = 0; i < itemsCopy.length; i++) {
|
for (var i = 0; i < deletedItems.length; i++) {
|
||||||
let it = itemsCopy[i];
|
let it = deletedItems[i];
|
||||||
let trashItem = trash.find((item) => item.id === it.id);
|
let trashItem = trash.find((item) => item.id === it.id);
|
||||||
ids.push(trashItem.id);
|
ids.push(trashItem.id);
|
||||||
}
|
}
|
||||||
await db.trash.restore(...ids);
|
await db.trash.restore(...ids);
|
||||||
|
|
||||||
Navigation.queueRoutesForUpdate();
|
Navigation.queueRoutesForUpdate();
|
||||||
useMenuStore.getState().setMenuPins();
|
useMenuStore.getState().setMenuPins();
|
||||||
useMenuStore.getState().setColorNotes();
|
useMenuStore.getState().setColorNotes();
|
||||||
@@ -193,9 +181,8 @@ export const deleteItems = async (item, context) => {
|
|||||||
actionText: "Undo"
|
actionText: "Undo"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
history.selectedItemsList = [];
|
|
||||||
Navigation.queueRoutesForUpdate();
|
Navigation.queueRoutesForUpdate();
|
||||||
useSelectionStore.getState().clearSelection(true);
|
useSelectionStore.getState().clearSelection();
|
||||||
useMenuStore.getState().setMenuPins();
|
useMenuStore.getState().setMenuPins();
|
||||||
useMenuStore.getState().setColorNotes();
|
useMenuStore.getState().setColorNotes();
|
||||||
SearchService.updateAndSearch();
|
SearchService.updateAndSearch();
|
||||||
@@ -204,8 +191,7 @@ export const deleteItems = async (item, context) => {
|
|||||||
|
|
||||||
export const openLinkInBrowser = async (link) => {
|
export const openLinkInBrowser = async (link) => {
|
||||||
try {
|
try {
|
||||||
const url = link;
|
Linking.openURL(link);
|
||||||
Linking.openURL(url);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error.message);
|
console.log(error.message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,177 +0,0 @@
|
|||||||
/*
|
|
||||||
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 { Dimensions, NativeModules, Platform } from "react-native";
|
|
||||||
import {
|
|
||||||
beginBackgroundTask,
|
|
||||||
endBackgroundTask
|
|
||||||
} from "react-native-begin-background-task";
|
|
||||||
import RNTooltips from "react-native-tooltips";
|
|
||||||
import { db } from "../common/database";
|
|
||||||
import { tabBarRef } from "./global-refs";
|
|
||||||
|
|
||||||
let prevTarget = null;
|
|
||||||
|
|
||||||
export const TOOLTIP_POSITIONS = {
|
|
||||||
LEFT: 1,
|
|
||||||
RIGHT: 2,
|
|
||||||
TOP: 3,
|
|
||||||
BOTTOM: 4
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sortSettings = {
|
|
||||||
sort: "default",
|
|
||||||
/**
|
|
||||||
* @type {"desc" | "asc"}
|
|
||||||
*/
|
|
||||||
sortOrder: "desc"
|
|
||||||
};
|
|
||||||
|
|
||||||
export const editing = {
|
|
||||||
currentlyEditing: false,
|
|
||||||
isFullscreen: false,
|
|
||||||
actionAfterFirstSave: {
|
|
||||||
type: null
|
|
||||||
},
|
|
||||||
isFocused: false,
|
|
||||||
focusType: null,
|
|
||||||
movedAway: true,
|
|
||||||
tooltip: false,
|
|
||||||
isRestoringState: false
|
|
||||||
};
|
|
||||||
export const selection = {
|
|
||||||
data: [],
|
|
||||||
type: null,
|
|
||||||
selectedItems: []
|
|
||||||
};
|
|
||||||
|
|
||||||
export const history = {
|
|
||||||
selectedItemsList: [],
|
|
||||||
selectionMode: false
|
|
||||||
};
|
|
||||||
|
|
||||||
export function formatBytes(bytes, decimals = 2) {
|
|
||||||
if (bytes === 0) return "0 Bytes";
|
|
||||||
|
|
||||||
const k = 1024;
|
|
||||||
const dm = decimals < 0 ? 0 : decimals;
|
|
||||||
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
||||||
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
||||||
|
|
||||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const AndroidModule = NativeModules.NNativeModule;
|
|
||||||
|
|
||||||
export let dWidth = Dimensions.get("window").width;
|
|
||||||
export let dHeight = Dimensions.get("window").height;
|
|
||||||
|
|
||||||
export const InteractionManager = {
|
|
||||||
runAfterInteractions: (func, time = 300) => setTimeout(func, time)
|
|
||||||
};
|
|
||||||
|
|
||||||
export function getElevation(elevation) {
|
|
||||||
return {
|
|
||||||
elevation,
|
|
||||||
shadowColor: "black",
|
|
||||||
shadowOffset: { width: 0.3 * elevation, height: 0.5 * elevation },
|
|
||||||
shadowOpacity: 0.2,
|
|
||||||
shadowRadius: 0.7 * elevation
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function doInBackground(cb) {
|
|
||||||
if (Platform.OS === "ios") {
|
|
||||||
let bgTaskId;
|
|
||||||
try {
|
|
||||||
bgTaskId = await beginBackgroundTask();
|
|
||||||
let res = await cb();
|
|
||||||
await endBackgroundTask(bgTaskId);
|
|
||||||
return res;
|
|
||||||
} catch (e) {
|
|
||||||
return e.message;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// eslint-disable-next-line no-async-promise-executor
|
|
||||||
return new Promise(async (res) => {
|
|
||||||
try {
|
|
||||||
let result = await cb();
|
|
||||||
res(result);
|
|
||||||
} catch (e) {
|
|
||||||
res(e.message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function nth(n) {
|
|
||||||
return (
|
|
||||||
["st", "nd", "rd"][(((((n < 0 ? -n : n) + 90) % 100) - 10) % 10) - 1] ||
|
|
||||||
"th"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setWidthHeight(size) {
|
|
||||||
dWidth = size.width;
|
|
||||||
dHeight = size.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getTotalNotes(item) {
|
|
||||||
if (!item || (item.type !== "notebook" && item.type !== "topic")) return 0;
|
|
||||||
if (item.type === "topic") {
|
|
||||||
return (
|
|
||||||
db.notebooks.notebook(item.notebookId)?.topics.topic(item.id)
|
|
||||||
?.totalNotes || 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return db.notebooks.notebook(item.id)?.totalNotes || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function toTXT(note, template = true) {
|
|
||||||
let text;
|
|
||||||
if (note.locked) {
|
|
||||||
text = await db.notes.note(note.id).export("txt", note.content, template);
|
|
||||||
} else {
|
|
||||||
text = await db.notes.note(note.id).export("txt", undefined, template);
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showTooltip(event, text, position = 2) {
|
|
||||||
if (!event._targetInst?.ref?.current) return;
|
|
||||||
prevTarget && RNTooltips.Dismiss(prevTarget);
|
|
||||||
prevTarget = null;
|
|
||||||
prevTarget = event._targetInst.ref.current;
|
|
||||||
RNTooltips.Show(prevTarget, tabBarRef.current?.node?.current, {
|
|
||||||
text: text,
|
|
||||||
tintColor: "#000000",
|
|
||||||
corner: Platform.OS === "ios" ? 5 : 40,
|
|
||||||
textSize: 14,
|
|
||||||
position: position,
|
|
||||||
duration: 1000,
|
|
||||||
autoHide: true,
|
|
||||||
clickToHide: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toTitleCase(value) {
|
|
||||||
if (!value) return;
|
|
||||||
return value.slice(0, 1).toUpperCase() + value.slice(1);
|
|
||||||
}
|
|
||||||
32
apps/mobile/app/utils/note-to-text.ts
Normal file
32
apps/mobile/app/utils/note-to-text.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
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 { db } from "../common/database";
|
||||||
|
import { NoteType } from "./types";
|
||||||
|
|
||||||
|
export async function convertNoteToText(note: NoteType, template = true) {
|
||||||
|
let text;
|
||||||
|
if (note.locked) {
|
||||||
|
text = await db.notes
|
||||||
|
?.note(note.id)
|
||||||
|
.export("txt", note.content as unknown as string, template);
|
||||||
|
} else {
|
||||||
|
text = await db.notes?.note(note.id).export("txt", undefined, template);
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
35
apps/mobile/app/utils/notesnook-module.ts
Normal file
35
apps/mobile/app/utils/notesnook-module.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
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 { NativeModules, Platform } from "react-native";
|
||||||
|
|
||||||
|
interface NotesnookModuleInterface {
|
||||||
|
getActivityName: () => Promise<string>;
|
||||||
|
setBackgroundColor: (color: string) => void;
|
||||||
|
setSecureMode: (enabled: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NotesnookModule: NotesnookModuleInterface = Platform.select({
|
||||||
|
ios: {
|
||||||
|
getActivityName: () => {},
|
||||||
|
setBackgroundColor: () => {},
|
||||||
|
setSecureMode: () => {}
|
||||||
|
},
|
||||||
|
android: NativeModules.NNativeModule
|
||||||
|
});
|
||||||
@@ -17,115 +17,5 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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) =>
|
export const sleep = (duration: number) =>
|
||||||
new Promise((resolve) => setTimeout(() => resolve(true), duration));
|
new Promise((resolve) => setTimeout(() => resolve(true), duration));
|
||||||
|
|
||||||
export function timeSince(date: number) {
|
|
||||||
const seconds = Math.floor((Date.now() - date) / 1000);
|
|
||||||
let interval = Math.floor(seconds / 31536000);
|
|
||||||
|
|
||||||
if (interval > 0.9) {
|
|
||||||
return interval < 2 ? interval + "yr ago" : interval + "yr ago";
|
|
||||||
}
|
|
||||||
interval = Math.floor(seconds / 2592000);
|
|
||||||
if (interval > 0.9) {
|
|
||||||
return interval < 2 ? interval + "mo ago" : interval + "mo ago";
|
|
||||||
}
|
|
||||||
|
|
||||||
interval = Math.floor(seconds / (86400 * 7));
|
|
||||||
if (interval > 0.9) {
|
|
||||||
if (interval === 4) return "1mo ago";
|
|
||||||
return interval < 2 ? interval + "w ago" : interval + "w ago";
|
|
||||||
}
|
|
||||||
|
|
||||||
interval = Math.floor(seconds / 86400);
|
|
||||||
if (interval > 0.9) {
|
|
||||||
return interval < 2 ? interval + "d ago" : interval + "d ago";
|
|
||||||
}
|
|
||||||
interval = Math.floor(seconds / 3600);
|
|
||||||
if (interval > 0.9) {
|
|
||||||
return interval < 2 ? interval + "h ago" : interval + "h ago";
|
|
||||||
}
|
|
||||||
interval = Math.floor(seconds / 60);
|
|
||||||
if (interval > 0.9) {
|
|
||||||
return interval < 2 ? interval + "m ago" : interval + "m ago";
|
|
||||||
}
|
|
||||||
return Math.floor(seconds) < 0 ? "0s ago" : Math.floor(seconds) + "s ago";
|
|
||||||
}
|
|
||||||
|
|
||||||
export const timeConverter = (timestamp: number | undefined | null) => {
|
|
||||||
if (!timestamp) return;
|
|
||||||
const d = new Date(timestamp); // Convert the passed timestamp to milliseconds
|
|
||||||
const yyyy = d.getFullYear();
|
|
||||||
const dd = ("0" + d.getDate()).slice(-2); // Add leading 0.
|
|
||||||
const currentDay = d.getDay();
|
|
||||||
const hh = d.getHours();
|
|
||||||
let h = hh;
|
|
||||||
const min = ("0" + d.getMinutes()).slice(-2); // Add leading 0.
|
|
||||||
let ampm = "AM";
|
|
||||||
const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
||||||
const months = [
|
|
||||||
"Jan",
|
|
||||||
"Feb",
|
|
||||||
"Mar",
|
|
||||||
"Apr",
|
|
||||||
"May",
|
|
||||||
"Jun",
|
|
||||||
"Jul",
|
|
||||||
"Aug",
|
|
||||||
"Sep",
|
|
||||||
"Oct",
|
|
||||||
"Nov",
|
|
||||||
"Dec"
|
|
||||||
];
|
|
||||||
|
|
||||||
if (hh > 12) {
|
|
||||||
h = hh - 12;
|
|
||||||
ampm = "PM";
|
|
||||||
} else if (hh === 12) {
|
|
||||||
h = 12;
|
|
||||||
ampm = "PM";
|
|
||||||
} else if (hh === 0) {
|
|
||||||
h = 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ie: 2013-02-18, 8:35 AM
|
|
||||||
const time =
|
|
||||||
days[currentDay] +
|
|
||||||
" " +
|
|
||||||
dd +
|
|
||||||
" " +
|
|
||||||
months[d.getMonth()] +
|
|
||||||
", " +
|
|
||||||
yyyy +
|
|
||||||
", " +
|
|
||||||
h +
|
|
||||||
":" +
|
|
||||||
min +
|
|
||||||
" " +
|
|
||||||
ampm;
|
|
||||||
|
|
||||||
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
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
53
apps/mobile/app/utils/tooltip.ts
Normal file
53
apps/mobile/app/utils/tooltip.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
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 RNTooltips from "react-native-tooltips";
|
||||||
|
import { tabBarRef } from "./global-refs";
|
||||||
|
import { Platform } from "react-native";
|
||||||
|
|
||||||
|
export const POSITIONS = {
|
||||||
|
LEFT: 1,
|
||||||
|
RIGHT: 2,
|
||||||
|
TOP: 3,
|
||||||
|
BOTTOM: 4
|
||||||
|
};
|
||||||
|
|
||||||
|
let prevTarget: any = null;
|
||||||
|
function show(event: any, text: string, position = 2) {
|
||||||
|
if (!event._targetInst?.ref?.current) return;
|
||||||
|
prevTarget && RNTooltips.Dismiss(prevTarget);
|
||||||
|
prevTarget = null;
|
||||||
|
prevTarget = event._targetInst.ref.current;
|
||||||
|
RNTooltips.Show(prevTarget, tabBarRef.current?.node?.current, {
|
||||||
|
text: text,
|
||||||
|
tintColor: "#000000",
|
||||||
|
corner: Platform.OS === "ios" ? 5 : 40,
|
||||||
|
textSize: 14,
|
||||||
|
position: position,
|
||||||
|
duration: 1000,
|
||||||
|
autoHide: true,
|
||||||
|
clickToHide: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const NativeTooltip = {
|
||||||
|
show,
|
||||||
|
POSITIONS
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NativeTooltip;
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
"@notesnook/editor": "*",
|
"@notesnook/editor": "*",
|
||||||
"@notesnook/editor-mobile": "*",
|
"@notesnook/editor-mobile": "*",
|
||||||
"react-native-swiper-flatlist": "3.2.2",
|
"react-native-swiper-flatlist": "3.2.2",
|
||||||
"@notesnook/logger": "*"
|
"@notesnook/logger": "*",
|
||||||
|
"@notesnook/common": "*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -274,10 +274,10 @@ index 69065f0..0000000
|
|||||||
-export default forwardRef(Menu);
|
-export default forwardRef(Menu);
|
||||||
diff --git a/node_modules/react-native-reanimated-material-menu/src/Menu.tsx b/node_modules/react-native-reanimated-material-menu/src/Menu.tsx
|
diff --git a/node_modules/react-native-reanimated-material-menu/src/Menu.tsx b/node_modules/react-native-reanimated-material-menu/src/Menu.tsx
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000..20469ee
|
index 0000000..c3bc1c9
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/node_modules/react-native-reanimated-material-menu/src/Menu.tsx
|
+++ b/node_modules/react-native-reanimated-material-menu/src/Menu.tsx
|
||||||
@@ -0,0 +1,289 @@
|
@@ -0,0 +1,303 @@
|
||||||
+import React from 'react';
|
+import React from 'react';
|
||||||
+
|
+
|
||||||
+import {
|
+import {
|
||||||
@@ -288,6 +288,7 @@ index 0000000..20469ee
|
|||||||
+ LayoutChangeEvent,
|
+ LayoutChangeEvent,
|
||||||
+ Modal,
|
+ Modal,
|
||||||
+ Platform,
|
+ Platform,
|
||||||
|
+ ScrollView,
|
||||||
+ StatusBar,
|
+ StatusBar,
|
||||||
+ StyleSheet,
|
+ StyleSheet,
|
||||||
+ TouchableWithoutFeedback,
|
+ TouchableWithoutFeedback,
|
||||||
@@ -325,6 +326,7 @@ index 0000000..20469ee
|
|||||||
+
|
+
|
||||||
+const EASING = Easing.bezier(0.4, 0, 0.2, 1);
|
+const EASING = Easing.bezier(0.4, 0, 0.2, 1);
|
||||||
+const SCREEN_INDENT = 8;
|
+const SCREEN_INDENT = 8;
|
||||||
|
+const SCREEN_INDENT_VERTICAL = 80;
|
||||||
+
|
+
|
||||||
+class Menu extends React.Component<MenuProps, State> {
|
+class Menu extends React.Component<MenuProps, State> {
|
||||||
+ _container: View | null = null;
|
+ _container: View | null = null;
|
||||||
@@ -384,7 +386,7 @@ index 0000000..20469ee
|
|||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ const { width, height } = e.nativeEvent.layout;
|
+ const { width, height } = e.nativeEvent.layout;
|
||||||
+
|
+ let timeout:any = 0;
|
||||||
+ this.setState(
|
+ this.setState(
|
||||||
+ {
|
+ {
|
||||||
+ menuState: States.Animating,
|
+ menuState: States.Animating,
|
||||||
@@ -405,7 +407,17 @@ index 0000000..20469ee
|
|||||||
+ easing: EASING,
|
+ easing: EASING,
|
||||||
+ useNativeDriver: false,
|
+ useNativeDriver: false,
|
||||||
+ }),
|
+ }),
|
||||||
+ ]).start();
|
+ ]).start(({finished}) => {
|
||||||
|
+ if (finished) {
|
||||||
|
+ clearTimeout(timeout);
|
||||||
|
+ timeout = setTimeout(() => {
|
||||||
|
+ this.setState({
|
||||||
|
+ menuState: States.Shown
|
||||||
|
+ })
|
||||||
|
+ },20)
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+ });
|
||||||
+ },
|
+ },
|
||||||
+ );
|
+ );
|
||||||
+ };
|
+ };
|
||||||
@@ -464,7 +476,7 @@ index 0000000..20469ee
|
|||||||
+
|
+
|
||||||
+ // Adjust position of menu
|
+ // Adjust position of menu
|
||||||
+ let { left, top } = this.state;
|
+ let { left, top } = this.state;
|
||||||
+ const transforms = [];
|
+ const transforms:any[] = [];
|
||||||
+
|
+
|
||||||
+ if (
|
+ if (
|
||||||
+ (isRTL && left + buttonWidth - menuWidth > SCREEN_INDENT) ||
|
+ (isRTL && left + buttonWidth - menuWidth > SCREEN_INDENT) ||
|
||||||
@@ -472,7 +484,7 @@ index 0000000..20469ee
|
|||||||
+ ) {
|
+ ) {
|
||||||
+ transforms.push({
|
+ transforms.push({
|
||||||
+ translateX: Animated.multiply(menuSizeAnimation.x, -1),
|
+ translateX: Animated.multiply(menuSizeAnimation.x, -1),
|
||||||
+ });
|
+ } as never);
|
||||||
+
|
+
|
||||||
+ left = Math.min(windowWidth - SCREEN_INDENT, left + buttonWidth);
|
+ left = Math.min(windowWidth - SCREEN_INDENT, left + buttonWidth);
|
||||||
+ } else if (left < SCREEN_INDENT) {
|
+ } else if (left < SCREEN_INDENT) {
|
||||||
@@ -480,26 +492,26 @@ index 0000000..20469ee
|
|||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ // Flip by Y axis if menu hits bottom screen border
|
+ // Flip by Y axis if menu hits bottom screen border
|
||||||
+ if (top > windowHeight - menuHeight - SCREEN_INDENT) {
|
+ if (top > windowHeight - menuHeight - SCREEN_INDENT_VERTICAL) {
|
||||||
+ transforms.push({
|
+ transforms.push({
|
||||||
+ translateY: Animated.multiply(menuSizeAnimation.y, -1),
|
+ translateY: Animated.multiply(menuSizeAnimation.y, -1),
|
||||||
+ });
|
+ } as never);
|
||||||
+
|
+
|
||||||
+ top = windowHeight - SCREEN_INDENT;
|
+ top = windowHeight - SCREEN_INDENT_VERTICAL;
|
||||||
+ top = Math.min(windowHeight - SCREEN_INDENT, top + buttonHeight);
|
+ top = Math.min(windowHeight - SCREEN_INDENT_VERTICAL, top + buttonHeight);
|
||||||
+ } else if (top < SCREEN_INDENT) {
|
+ } else if (top < SCREEN_INDENT_VERTICAL) {
|
||||||
+ top = SCREEN_INDENT;
|
+ top = SCREEN_INDENT_VERTICAL;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ const shadowMenuContainerStyle = {
|
+ const shadowMenuContainerStyle = {
|
||||||
+ opacity: opacityAnimation,
|
+ opacity: opacityAnimation,
|
||||||
+ transform: transforms,
|
+ transform: transforms,
|
||||||
|
+ maxHeight: 500,
|
||||||
+ top,
|
+ top,
|
||||||
+
|
+
|
||||||
+ // Switch left to right for rtl devices
|
+ // Switch left to right for rtl devices
|
||||||
+ ...(isRTL ? { right: left } : { left }),
|
+ ...(isRTL ? { right: left } : { left }),
|
||||||
+ };
|
+ };
|
||||||
+
|
|
||||||
+ const { menuState } = this.state;
|
+ const { menuState } = this.state;
|
||||||
+ const animationStarted = menuState === States.Animating;
|
+ const animationStarted = menuState === States.Animating;
|
||||||
+ const modalVisible = menuState === States.Shown || animationStarted;
|
+ const modalVisible = menuState === States.Shown || animationStarted;
|
||||||
@@ -529,7 +541,9 @@ index 0000000..20469ee
|
|||||||
+ style={[styles.shadowMenuContainer, shadowMenuContainerStyle, style]}
|
+ style={[styles.shadowMenuContainer, shadowMenuContainerStyle, style]}
|
||||||
+ >
|
+ >
|
||||||
+ <Animated.View style={[styles.menuContainer, animationStarted && menuSize]}>
|
+ <Animated.View style={[styles.menuContainer, animationStarted && menuSize]}>
|
||||||
+ {children}
|
+ <ScrollView showsVerticalScrollIndicator={menuState !== States.Animating} >
|
||||||
|
+ {children}
|
||||||
|
+ </ScrollView>
|
||||||
+ </Animated.View>
|
+ </Animated.View>
|
||||||
+ </Animated.View>
|
+ </Animated.View>
|
||||||
+ </View>
|
+ </View>
|
||||||
@@ -568,3 +582,19 @@ index 0000000..20469ee
|
|||||||
+
|
+
|
||||||
+export default Menu
|
+export default Menu
|
||||||
\ No newline at end of file
|
\ No newline at end of file
|
||||||
|
diff --git a/node_modules/react-native-reanimated-material-menu/src/MenuItem.js b/node_modules/react-native-reanimated-material-menu/src/MenuItem.js
|
||||||
|
index 120a870..d6459c0 100644
|
||||||
|
--- a/node_modules/react-native-reanimated-material-menu/src/MenuItem.js
|
||||||
|
+++ b/node_modules/react-native-reanimated-material-menu/src/MenuItem.js
|
||||||
|
@@ -14,6 +14,11 @@ const Touchable =
|
||||||
|
? TouchableNativeFeedback
|
||||||
|
: TouchableHighlight;
|
||||||
|
|
||||||
|
+/**
|
||||||
|
+ *
|
||||||
|
+ * @param {any} param0
|
||||||
|
+ * @returns
|
||||||
|
+ */
|
||||||
|
function MenuItem({
|
||||||
|
children,
|
||||||
|
disabled,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||||
import { db } from "../app/common/database";
|
import { db } from "../app/common/database";
|
||||||
import { getElevation } from "../app/utils";
|
import { getElevationStyle } from "../app/utils/elevation";
|
||||||
import { initDatabase, useShareStore } from "./store";
|
import { initDatabase, useShareStore } from "./store";
|
||||||
|
|
||||||
const ListItem = ({ item, mode, close }) => {
|
const ListItem = ({ item, mode, close }) => {
|
||||||
@@ -262,7 +262,7 @@ export const Search = ({ close, getKeyboardHeight, quicknote, mode }) => {
|
|||||||
alignSelf: "center",
|
alignSelf: "center",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
zIndex: 999,
|
zIndex: 999,
|
||||||
...getElevation(quicknote ? 1 : 5),
|
...getElevationStyle(quicknote ? 1 : 5),
|
||||||
...extra
|
...extra
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ import { db } from "../app/common/database";
|
|||||||
import { MMKV } from "../app/common/database/mmkv";
|
import { MMKV } from "../app/common/database/mmkv";
|
||||||
import Storage from "../app/common/database/storage";
|
import Storage from "../app/common/database/storage";
|
||||||
import { eSendEvent } from "../app/services/event-manager";
|
import { eSendEvent } from "../app/services/event-manager";
|
||||||
import { formatBytes, getElevation } from "../app/utils";
|
import { getElevationStyle } from "../app/utils/elevation";
|
||||||
|
import { formatBytes } from "@notesnook/common";
|
||||||
import { eOnLoadNote } from "../app/utils/events";
|
import { eOnLoadNote } from "../app/utils/events";
|
||||||
import { Editor } from "./editor";
|
import { Editor } from "./editor";
|
||||||
import { Search } from "./search";
|
import { Search } from "./search";
|
||||||
@@ -459,7 +460,7 @@ const ShareView = ({ quicknote = false }) => {
|
|||||||
backgroundColor: colors.bg,
|
backgroundColor: colors.bg,
|
||||||
height: 50 + insets.top,
|
height: 50 + insets.top,
|
||||||
paddingTop: insets.top,
|
paddingTop: insets.top,
|
||||||
...getElevation(1),
|
...getElevationStyle(1),
|
||||||
marginTop: -insets.top,
|
marginTop: -insets.top,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
"@notesnook/logger": "*",
|
"@notesnook/logger": "*",
|
||||||
"@notesnook/streamable-fs": "*",
|
"@notesnook/streamable-fs": "*",
|
||||||
"@notesnook/theme": "*",
|
"@notesnook/theme": "*",
|
||||||
|
"@notesnook/common": "*",
|
||||||
"@notesnook/web-clipper": "*",
|
"@notesnook/web-clipper": "*",
|
||||||
"@react-pdf-viewer/core": "^3.12.0",
|
"@react-pdf-viewer/core": "^3.12.0",
|
||||||
"@react-pdf-viewer/toolbar": "^3.12.0",
|
"@react-pdf-viewer/toolbar": "^3.12.0",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { db } from "./db";
|
|||||||
async function download(hash: string) {
|
async function download(hash: string) {
|
||||||
const attachment = db.attachments?.attachment(hash);
|
const attachment = db.attachments?.attachment(hash);
|
||||||
if (!attachment) return;
|
if (!attachment) return;
|
||||||
const downloadResult = await db.fs.downloadFile(
|
const downloadResult = await db.fs?.downloadFile(
|
||||||
attachment.metadata.hash,
|
attachment.metadata.hash,
|
||||||
attachment.metadata.hash,
|
attachment.metadata.hash,
|
||||||
attachment.chunkSize,
|
attachment.chunkSize,
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ const AttachmentMenuItems: MenuItem[] = [
|
|||||||
onClick: async ({ attachment, status }) => {
|
onClick: async ({ attachment, status }) => {
|
||||||
const isDownloading = status?.type === "download";
|
const isDownloading = status?.type === "download";
|
||||||
if (isDownloading) {
|
if (isDownloading) {
|
||||||
await db.fs.cancel(attachment.metadata.hash, "download");
|
await db.fs?.cancel(attachment.metadata.hash, "download");
|
||||||
} else await saveAttachment(attachment.metadata.hash);
|
} else await saveAttachment(attachment.metadata.hash);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -311,7 +311,7 @@ const AttachmentMenuItems: MenuItem[] = [
|
|||||||
onClick: async ({ attachment, status }) => {
|
onClick: async ({ attachment, status }) => {
|
||||||
const isDownloading = status?.type === "upload";
|
const isDownloading = status?.type === "upload";
|
||||||
if (isDownloading) {
|
if (isDownloading) {
|
||||||
await db.fs.cancel(attachment.metadata.hash, "upload");
|
await db.fs?.cancel(attachment.metadata.hash, "upload");
|
||||||
} else
|
} else
|
||||||
await reuploadAttachment(
|
await reuploadAttachment(
|
||||||
attachment.metadata.type,
|
attachment.metadata.type,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export class AttachmentStream extends ReadableStream<ZipFile> {
|
|||||||
) {
|
) {
|
||||||
if (signal)
|
if (signal)
|
||||||
signal.onabort = async () => {
|
signal.onabort = async () => {
|
||||||
await db.fs.cancel(GROUP_ID, "download");
|
await db.fs?.cancel(GROUP_ID, "download");
|
||||||
};
|
};
|
||||||
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
@@ -46,7 +46,7 @@ export class AttachmentStream extends ReadableStream<ZipFile> {
|
|||||||
onProgress && onProgress(index);
|
onProgress && onProgress(index);
|
||||||
const attachment = attachments[index++];
|
const attachment = attachments[index++];
|
||||||
|
|
||||||
await db.fs.downloadFile(
|
await db.fs?.downloadFile(
|
||||||
GROUP_ID,
|
GROUP_ID,
|
||||||
attachment.metadata.hash,
|
attachment.metadata.hash,
|
||||||
attachment.chunkSize,
|
attachment.chunkSize,
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ function RecoveryKeyMethod(props: BaseRecoveryComponentProps<"method:key">) {
|
|||||||
|
|
||||||
const user = await db.user?.getUser();
|
const user = await db.user?.getUser();
|
||||||
if (!user) throw new Error("User not authenticated");
|
if (!user) throw new Error("User not authenticated");
|
||||||
await db.storage.write(`_uk_@${user.email}@_k`, form.recoveryKey);
|
await db.storage?.write(`_uk_@${user.email}@_k`, form.recoveryKey);
|
||||||
await db.sync(true, true);
|
await db.sync(true, true);
|
||||||
navigate("backup");
|
navigate("backup");
|
||||||
}}
|
}}
|
||||||
|
|||||||
32
packages/common/.gitignore
vendored
Normal file
32
packages/common/.gitignore
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
.now
|
||||||
|
|
||||||
|
__diff_output__
|
||||||
|
|
||||||
|
dist
|
||||||
|
public/workbox
|
||||||
|
scripts/secrets
|
||||||
|
test-results
|
||||||
3
packages/common/.npmignore
Normal file
3
packages/common/.npmignore
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
*
|
||||||
|
!dist/**/*
|
||||||
|
!package.json
|
||||||
0
packages/common/README.md
Normal file
0
packages/common/README.md
Normal file
169
packages/common/package-lock.json
generated
Normal file
169
packages/common/package-lock.json
generated
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
{
|
||||||
|
"name": "@notesnook/common",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "@notesnook/common",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "GPL-3.0-or-later",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "18.2.9",
|
||||||
|
"react": "18.2.0",
|
||||||
|
"timeago.js": "4.0.2",
|
||||||
|
"typescript": "^4.8.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@notesnook/core": "*",
|
||||||
|
"react": "*",
|
||||||
|
"timeago.js": "4.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/prop-types": {
|
||||||
|
"version": "15.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||||
|
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/@types/react": {
|
||||||
|
"version": "18.2.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.9.tgz",
|
||||||
|
"integrity": "sha512-pL3JAesUkF7PEQGxh5XOwdXGV907te6m1/Qe1ERJLgomojS6Ne790QiA7GUl434JEkFA2aAaB6qJ5z4e1zJn/w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/prop-types": "*",
|
||||||
|
"@types/scheduler": "*",
|
||||||
|
"csstype": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/scheduler": {
|
||||||
|
"version": "0.16.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||||
|
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/csstype": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/js-tokens": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"loose-envify": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react": {
|
||||||
|
"version": "18.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||||
|
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/timeago.js": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/timeago.js/-/timeago.js-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "4.9.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||||
|
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/prop-types": {
|
||||||
|
"version": "15.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||||
|
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@types/react": {
|
||||||
|
"version": "18.2.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.9.tgz",
|
||||||
|
"integrity": "sha512-pL3JAesUkF7PEQGxh5XOwdXGV907te6m1/Qe1ERJLgomojS6Ne790QiA7GUl434JEkFA2aAaB6qJ5z4e1zJn/w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/prop-types": "*",
|
||||||
|
"@types/scheduler": "*",
|
||||||
|
"csstype": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/scheduler": {
|
||||||
|
"version": "0.16.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||||
|
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"csstype": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"js-tokens": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react": {
|
||||||
|
"version": "18.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||||
|
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"loose-envify": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timeago.js": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/timeago.js/-/timeago.js-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"typescript": {
|
||||||
|
"version": "4.9.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||||
|
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
packages/common/package.json
Normal file
43
packages/common/package.json
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "@notesnook/common",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A set of common utilities shared across multiple Notesnook clients and services.",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"pub": "tsc && np",
|
||||||
|
"build": "tsc"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/streetwriters/notesnook.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"logger"
|
||||||
|
],
|
||||||
|
"license": "GPL-3.0-or-later",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/streetwriters/notesnook/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/streetwriters/notesnook#readme",
|
||||||
|
"np": {
|
||||||
|
"tests": false,
|
||||||
|
"releaseDraft": false,
|
||||||
|
"message": "chore: bump version to %s"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://npm.pkg.github.com",
|
||||||
|
"access": "restricted"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^4.8.2",
|
||||||
|
"@notesnook/core": "*",
|
||||||
|
"timeago.js": "4.0.2",
|
||||||
|
"react": "18.2.0",
|
||||||
|
"@types/react": "18.2.9"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@notesnook/core": "*",
|
||||||
|
"timeago.js": "4.0.2",
|
||||||
|
"react": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
24
packages/common/src/database.ts
Normal file
24
packages/common/src/database.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
//@ts-ignore
|
||||||
|
import Database from "@notesnook/core/api/index";
|
||||||
|
|
||||||
|
export const database = new Database();
|
||||||
88
packages/common/src/hooks/use-time-ago.ts
Normal file
88
packages/common/src/hooks/use-time-ago.ts
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
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 { useEffect, useState } from "react";
|
||||||
|
import { TDate, format, register } from "timeago.js";
|
||||||
|
const shortLocale: [string, string][] = [
|
||||||
|
["now", "now"],
|
||||||
|
["%ss", "in %ss"],
|
||||||
|
["1m", "in 1m"],
|
||||||
|
["%sm", "in %sm"],
|
||||||
|
["1h", "in 1h"],
|
||||||
|
["%sh", "in %sh"],
|
||||||
|
["1d", "in 1d"],
|
||||||
|
["%sd", "in %sd"],
|
||||||
|
["1w", "in 1w"],
|
||||||
|
["%sw", "in %sw"],
|
||||||
|
["1mo", "in 1mo"],
|
||||||
|
["%smo", "in %smo"],
|
||||||
|
["1yr", "in 1yr"],
|
||||||
|
["%syr", "in %syr"]
|
||||||
|
];
|
||||||
|
|
||||||
|
const enShortLocale: [string, string][] = [
|
||||||
|
["now", "now"],
|
||||||
|
["%ss ago", "in %ss"],
|
||||||
|
["1m ago", "in 1m"],
|
||||||
|
["%sm ago", "in %sm"],
|
||||||
|
["1h ago", "in 1h"],
|
||||||
|
["%sh ago", "in %sh"],
|
||||||
|
["1d ago", "in 1d"],
|
||||||
|
["%sd ago", "in %sd"],
|
||||||
|
["1w ago", "in 1w"],
|
||||||
|
["%sw ago", "in %sw"],
|
||||||
|
["1mo ago", "in 1mo"],
|
||||||
|
["%smo ago", "in %smo"],
|
||||||
|
["1yr ago", "in 1yr"],
|
||||||
|
["%syr ago", "in %syr"]
|
||||||
|
];
|
||||||
|
register("short", (_n, index) => shortLocale[index]);
|
||||||
|
register("en_short", (_n, index) => enShortLocale[index]);
|
||||||
|
|
||||||
|
export function getTimeAgo(datetime: TDate, locale = "short") {
|
||||||
|
return format(datetime, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
type TimeAgoOptions = {
|
||||||
|
locale?: "short" | "en_short";
|
||||||
|
live?: boolean;
|
||||||
|
interval?: number;
|
||||||
|
onUpdate?: (timeAgo: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useTimeAgo(
|
||||||
|
datetime: TDate,
|
||||||
|
{ locale = "short", live = true, interval = 60000, onUpdate }: TimeAgoOptions
|
||||||
|
) {
|
||||||
|
const [timeAgo, setTimeAgo] = useState(getTimeAgo(datetime, locale));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!live) return;
|
||||||
|
const reset = setInterval(() => {
|
||||||
|
const value = getTimeAgo(datetime, locale);
|
||||||
|
onUpdate?.(value);
|
||||||
|
setTimeAgo(value);
|
||||||
|
}, interval);
|
||||||
|
return () => {
|
||||||
|
clearInterval(reset);
|
||||||
|
};
|
||||||
|
}, [datetime, interval, locale, live, onUpdate]);
|
||||||
|
|
||||||
|
return timeAgo;
|
||||||
|
}
|
||||||
27
packages/common/src/index.ts
Normal file
27
packages/common/src/index.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from "./database";
|
||||||
|
|
||||||
|
export * from "./utils/file";
|
||||||
|
export * from "./utils/number";
|
||||||
|
export * from "./utils/total-notes";
|
||||||
|
export * from "./utils/time";
|
||||||
|
|
||||||
|
export * from "./hooks/use-time-ago";
|
||||||
@@ -17,6 +17,17 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export function formatBytes(bytes: number, decimals = 2) {
|
||||||
|
if (bytes === 0) return "0 Bytes";
|
||||||
|
|
||||||
|
const k = 1024;
|
||||||
|
const dm = decimals < 0 ? 0 : decimals;
|
||||||
|
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||||
|
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
/*jshint node:true*/
|
/*jshint node:true*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,7 +80,7 @@ function sanitize(input: string, replacement: string) {
|
|||||||
|
|
||||||
export function sanitizeFilename(
|
export function sanitizeFilename(
|
||||||
input: string,
|
input: string,
|
||||||
options: { replacement: string }
|
options?: { replacement: string }
|
||||||
) {
|
) {
|
||||||
const replacement = (options && options.replacement) || "";
|
const replacement = (options && options.replacement) || "";
|
||||||
return sanitize(input, replacement);
|
return sanitize(input, replacement);
|
||||||
26
packages/common/src/utils/number.ts
Normal file
26
packages/common/src/utils/number.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function nth(number: number) {
|
||||||
|
return (
|
||||||
|
["st", "nd", "rd"][
|
||||||
|
(((((number < 0 ? -number : number) + 90) % 100) - 10) % 10) - 1
|
||||||
|
] || "th"
|
||||||
|
);
|
||||||
|
}
|
||||||
40
packages/common/src/utils/time.ts
Normal file
40
packages/common/src/utils/time.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
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 { formatDate } from "@notesnook/core/utils/date";
|
||||||
|
import { database } from "../database";
|
||||||
|
import { formatReminderTime } from "@notesnook/core/collections/reminders";
|
||||||
|
|
||||||
|
export function getFormattedDate(
|
||||||
|
date: string | number | Date,
|
||||||
|
type: "time" | "date-time" | "date" = "date-time"
|
||||||
|
) {
|
||||||
|
return formatDate(date, {
|
||||||
|
dateFormat: database.settings?.getDateFormat() as string,
|
||||||
|
timeFormat: database.settings?.getTimeFormat() as string,
|
||||||
|
type: type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFormattedReminderTime(reminder: any, short = false) {
|
||||||
|
return formatReminderTime(reminder, short, {
|
||||||
|
dateFormat: database.settings?.getDateFormat() as string,
|
||||||
|
timeFormat: database.settings?.getTimeFormat() as string
|
||||||
|
});
|
||||||
|
}
|
||||||
30
packages/common/src/utils/total-notes.ts
Normal file
30
packages/common/src/utils/total-notes.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
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 { database } from "../database";
|
||||||
|
|
||||||
|
export function getTotalNotes(item?: any) {
|
||||||
|
if (!item || (item.type !== "notebook" && item.type !== "topic")) return 0;
|
||||||
|
if (item.type === "topic") {
|
||||||
|
return (
|
||||||
|
database.notebooks?.notebook(item.notebookId)?.topics.topic(item.id)
|
||||||
|
?.totalNotes || 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return database.notebooks?.notebook(item.id)?.totalNotes || 0;
|
||||||
|
}
|
||||||
11
packages/common/tsconfig.json
Normal file
11
packages/common/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist",
|
||||||
|
"maxNodeModuleJsDepth": 10,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"jsx": "react-jsx"
|
||||||
|
},
|
||||||
|
"include": ["src/"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user