Compare commits

..

1 Commits

Author SHA1 Message Date
Ammar Ahmed
953a1142a3 mobile: prepare v3.4.5 for release 2026-07-06 13:42:23 +05:00
44 changed files with 445 additions and 672 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/desktop",
"version": "3.4.4",
"version": "3.4.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/desktop",
"version": "3.4.4",
"version": "3.4.2",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {

View File

@@ -2,7 +2,7 @@
"name": "@notesnook/desktop",
"productName": "Notesnook",
"description": "Your private note taking space",
"version": "3.4.4",
"version": "3.4.2",
"appAppleId": "1544027013",
"private": true,
"main": "./dist/cjs/index.js",

View File

@@ -140,7 +140,7 @@ android {
if (project.hasProperty("prBuildNumber")) {
versionCode Integer.parseInt(prBuildNumber())
} else {
versionCode 3113
versionCode 3111
}
versionName getNpmVersion()
testBuildType System.getProperty('testBuildType', 'debug')

View File

@@ -1,4 +1,3 @@
- Add option to clear note version history
- Minor bug fixes and improvements
Thank you for using Notesnook!

View File

@@ -72,7 +72,6 @@ const MergeConflicts = () => {
const insets = useGlobalSafeAreaInsets();
const content = useRef<UnencryptedContentItem>(null);
const { height } = useSettingStore((state) => state.dimensions);
const keepScreenOn = useSettingStore((state) => state.settings.keepScreenOn);
const applyChanges = async () => {
const contentToSave = selectedContent;
@@ -156,9 +155,9 @@ const MergeConflicts = () => {
...item.content,
conflicted: currentContent?.conflicted
? await db.vault.decryptContent(
currentContent?.conflicted as EncryptedContentItem,
password
)
currentContent?.conflicted as EncryptedContentItem,
password
)
: undefined
} as UnencryptedContentItem;
@@ -183,9 +182,9 @@ const MergeConflicts = () => {
...item.content,
conflicted: currentContent?.conflicted
? await db.vault.decryptContent(
currentContent?.conflicted as EncryptedContentItem,
password
)
currentContent?.conflicted as EncryptedContentItem,
password
)
: undefined
} as UnencryptedContentItem;
@@ -386,7 +385,7 @@ const MergeConflicts = () => {
paddingTop: insets.top
}}
>
{keepScreenOn && <KeepAwake />}
<KeepAwake />
{dialogVisible && (
<BaseDialog visible={true}>
<DialogContainer>

View File

@@ -29,7 +29,7 @@ import { ActionSheetRef, ScrollView } from "react-native-actions-sheet";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../common/database";
import { useDBItem } from "../../hooks/use-db-item";
import { presentSheet, ToastManager } from "../../services/event-manager";
import { presentSheet } from "../../services/event-manager";
import { openLinkInBrowser } from "../../utils/functions";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
@@ -39,19 +39,15 @@ import { Pressable } from "../ui/pressable";
import Seperator from "../ui/seperator";
import Paragraph from "../ui/typography/paragraph";
import NotePreview from "./preview";
import { presentDialog } from "../dialog/functions";
import { Dialog } from "../dialog";
const HistoryItem = ({
index,
items,
note,
refresh
note
}: {
index: number;
items?: VirtualizedGrouping<HistorySession>;
note: Note;
refresh: () => void;
}) => {
const [item] = useDBItem(index, "noteHistory", items);
const { colors } = useThemeColors();
@@ -79,13 +75,12 @@ const HistoryItem = ({
}}
content={content}
note={note}
update={refresh}
/>
),
context: "note_history"
});
},
[note, refresh]
[note]
);
return (
@@ -117,8 +112,7 @@ const HistoryItem = ({
};
export default function NoteHistory({
note,
fwdRef
note
}: {
note: Note;
fwdRef: RefObject<ActionSheetRef>;
@@ -127,7 +121,7 @@ export default function NoteHistory({
const [_loading, setLoading] = useState(true);
const { colors } = useThemeColors();
const refresh = useCallback(() => {
useEffect(() => {
db.noteHistory
.get(note.id)
.sorted({
@@ -143,56 +137,17 @@ export default function NoteHistory({
});
}, [note.id]);
useEffect(() => {
refresh();
}, [refresh]);
const renderItem = useCallback(
({ index }: { index: number }) => (
<HistoryItem
index={index}
items={history}
note={note}
refresh={refresh}
/>
<HistoryItem index={index} items={history} note={note} />
),
[history, note, refresh]
[history, note]
);
return (
<View>
<SheetProvider context="note_history" />
<Dialog context="local" />
<DialogHeader
title={strings.noteHistory()}
padding={12}
button={
history?.placeholders.length
? {
title: strings.clearHistory(),
type: "secondary",
onPress: () => {
presentDialog({
title: strings.clearHistory(),
paragraph: strings.clearHistoryConfirmation(),
positiveText: strings.clear(),
negativeText: strings.cancel(),
positiveType: "errorShade",
context: "local",
positivePress: async () => {
await db.noteHistory.clearSessions(note.id);
fwdRef.current?.hide();
ToastManager.show({
heading: strings.historyCleared(),
type: "success"
});
}
});
}
}
: undefined
}
/>
<DialogHeader title={strings.noteHistory()} padding={12} />
<Seperator />

View File

@@ -53,8 +53,7 @@ import {
export default function NotePreview({
session,
content,
note,
update
note
}: {
session?: HistorySession & { session: string };
content:
@@ -65,7 +64,6 @@ export default function NotePreview({
>
| undefined;
note: TrashOrItem<Note>;
update?: () => void;
}) {
const { colors } = useThemeColors();
const [locked, setLocked] = useState(false);
@@ -109,35 +107,24 @@ export default function NotePreview({
}, [note]);
const deleteNote = async () => {
const isSession = !!session;
presentDialog({
title: isSession ? strings.deleteVersion() : strings.deleteNote(),
paragraph: isSession
? strings.deleteVersionConfirmation()
: strings.deleteNoteConfirmation(),
title: strings.deleteNote(),
paragraph: strings.deleteNoteConfirmation(),
positiveText: strings.delete(),
negativeText: strings.cancel(),
context: "preview",
context: "local",
positivePress: async () => {
if (isSession) {
await db.noteHistory.remove(session.id);
update?.();
eSendEvent(eCloseSheet, "note_history");
Navigation.queueRoutesForUpdate();
} else if (note.type === "trash") {
if (note) {
await db.trash.delete(note.id);
useTrashStore.getState().refresh();
useSelectionStore.getState().setSelectionMode();
ToastManager.show({
heading: strings.noteDeleted(),
type: "success",
context: "local"
});
eSendEvent(eCloseSheet);
}
ToastManager.show({
heading: isSession ? strings.versionDeleted() : strings.noteDeleted(),
type: "success",
context: isSession ? "local" : "global"
});
return true;
},
positiveType: "error"
});
@@ -150,7 +137,7 @@ export default function NotePreview({
width: "100%"
}}
>
<Dialog context="preview" />
<Dialog context="local" />
<DialogHeader
padding={12}
title={content?.title || note.title || session?.session}

View File

@@ -112,8 +112,7 @@ const PayWall = (props: NavigationProps<"PayWall">) => {
}
setStep(Steps.buy);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [routeParams.state]);
}, [pricingPlans, routeParams.state]);
useEffect(() => {
let listener: NativeEventSubscription;

View File

@@ -170,147 +170,147 @@ export const SelectionHeader = React.memo(
{!selectedItemsList.length
? null
: (focusedRouteId === "Monographs"
? [
{
title: strings.unpublish(),
onPress: () => {
presentDialog({
title: strings.doActions.unpublish.note(
selectedItemsList.length
),
positiveText: strings.unpublish(),
negativeText: strings.cancel(),
positivePress: async () => {
for (const id of selectedItemsList) {
await db.monographs.unpublish(id);
}
? [
{
title: strings.unpublish(),
onPress: () => {
presentDialog({
title: strings.doActions.unpublish.note(
selectedItemsList.length
),
positiveText: strings.unpublish(),
negativeText: strings.cancel(),
positivePress: async () => {
for (const id of selectedItemsList) {
await db.monographs.unpublish(id);
}
Navigation.queueRoutesForUpdate();
clearSelection();
},
positiveType: "errorShade"
});
},
visible: true,
icon: "delete"
}
]
: [
{
title: strings.manageTags(),
onPress: async () => {
ManageTags.present(selectedItemsList);
},
visible: type === "note",
icon: "pound"
},
{
title: strings.export(),
onPress: async () => {
ExportNotesSheet.present(selectedItemsList);
},
visible: type === "note",
icon: "export"
},
{
title: strings.addToNotebook(),
onPress: async () => {
Navigation.navigate("LinkNotebooks", {
noteIds: selectedItemsList
});
},
visible: type === "note",
icon: "plus"
},
{
title: strings.unlinkNotebook(),
onPress: async () => {
if (!id) return;
await db.notes.removeFromNotebook(
id,
...selectedItemsList
);
updateNotebook(id);
Navigation.queueRoutesForUpdate();
clearSelection();
},
positiveType: "errorShade"
});
},
visible: true,
icon: "delete"
}
]
: [
{
title: strings.manageTags(),
onPress: async () => {
ManageTags.present(selectedItemsList);
},
visible: type === "note",
icon: "pound"
},
{
title: strings.export(),
onPress: async () => {
ExportNotesSheet.present(selectedItemsList);
},
visible: type === "note",
icon: "export"
},
{
title: strings.addToNotebook(),
onPress: async () => {
Navigation.navigate("LinkNotebooks", {
noteIds: selectedItemsList
});
},
visible: type === "note",
icon: "plus"
},
{
title: strings.unlinkNotebook(),
onPress: async () => {
if (!id) return;
await db.notes.removeFromNotebook(
id,
...selectedItemsList
);
updateNotebook(id);
Navigation.queueRoutesForUpdate();
clearSelection();
},
visible: renderedInRoute === "Notebook",
icon: "minus"
},
{
title: strings.unfavorite(),
onPress: addToFavorite,
visible: focusedRouteId === "Favorites",
icon: "star-off"
},
{
title: strings.moveToTrash(),
onPress: async () => {
const selection = useSelectionStore.getState();
if (!selection.selectionMode) return;
await deleteItems(
selection.selectionMode as ItemType,
selection.selectedItemsList
);
selection.clearSelection();
selection.setSelectionMode(undefined);
},
visible: type === "note" || type === "notebook",
icon: "delete"
},
{
title: strings.doActions.delete.unknown(
type!,
selectedItemsList.length
),
onPress: async () => {
const selection = useSelectionStore.getState();
if (!selection.selectionMode) return;
await deleteItems(
selection.selectionMode as ItemType,
selection.selectedItemsList
);
selection.clearSelection();
selection.setSelectionMode(undefined);
},
visible:
type !== "trash" &&
type !== "note" &&
type !== "notebook",
icon: "delete"
},
{
title: strings.restore(),
onPress: restoreItem,
visible: type === "trash",
icon: "delete-restore"
},
{
title: strings.delete(),
onPress: deleteItem,
visible: type === "trash",
icon: "delete"
}
]
).map((item) =>
!item.visible ? null : (
<IconButton
size={AppFontSize.lg}
type="plain"
tooltipText={item.title}
tooltipPosition={NativeTooltip.POSITIONS.TOP}
testID={`select-${item.icon}`}
name={item.icon}
key={item.title}
color={colors.primary.icon}
onPress={async () => {
//@ts-ignore
menuRef.current?.hide();
if (Platform.OS === "ios") await sleep(300);
item.onPress();
}}
/>
)
)}
visible: renderedInRoute === "Notebook",
icon: "minus"
},
{
title: strings.unfavorite(),
onPress: addToFavorite,
visible: focusedRouteId === "Favorites",
icon: "star-off"
},
{
title: strings.moveToTrash(),
onPress: async () => {
const selection = useSelectionStore.getState();
if (!selection.selectionMode) return;
await deleteItems(
selection.selectionMode as ItemType,
selection.selectedItemsList
);
selection.clearSelection();
selection.setSelectionMode(undefined);
},
visible: type === "note" || type === "notebook",
icon: "delete"
},
{
title: strings.doActions.delete.unknown(
type!,
selectedItemsList.length
),
onPress: async () => {
const selection = useSelectionStore.getState();
if (!selection.selectionMode) return;
await deleteItems(
selection.selectionMode as ItemType,
selection.selectedItemsList
);
selection.clearSelection();
selection.setSelectionMode(undefined);
},
visible:
type !== "trash" &&
type !== "note" &&
type !== "notebook",
icon: "delete"
},
{
title: strings.restore(),
onPress: restoreItem,
visible: type === "trash",
icon: "delete-restore"
},
{
title: strings.delete(),
onPress: deleteItem,
visible: type === "trash",
icon: "delete"
}
]
).map((item) =>
!item.visible ? null : (
<IconButton
size={AppFontSize.lg}
type="plain"
tooltipText={item.title}
tooltipPosition={NativeTooltip.POSITIONS.TOP}
testID={`select-${item.icon}`}
name={item.icon}
key={item.title}
color={colors.primary.icon}
onPress={async () => {
//@ts-ignore
menuRef.current?.hide();
if (Platform.OS === "ios") await sleep(300);
item.onPress();
}}
/>
)
)}
</View>
<IconButton

View File

@@ -28,7 +28,7 @@ import { NativeEvents } from "@notesnook/editor-mobile/src/utils/native-events";
import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useRef, useState } from "react";
import { ActivityIndicator, TextInput, View } from "react-native";
import { TextInput, View } from "react-native";
import { FlatList } from "react-native-actions-sheet";
import { db } from "../../../common/database";
import { useDBItem } from "../../../hooks/use-db-item";
@@ -40,8 +40,6 @@ import { Button } from "../../ui/button";
import Input from "../../ui/input";
import { Pressable } from "../../ui/pressable";
import Paragraph from "../../ui/typography/paragraph";
import Navigation from "../../../services/navigation";
import { useUserStore } from "../../../stores/use-user-store";
const ListNoteItem = ({
id,
@@ -120,8 +118,8 @@ const ListBlockItem = ({
{item?.content.length > 200
? item?.content.slice(0, 200) + "..."
: !item.content || item.content.trim() === ""
? strings.linkNoteEmptyBlock()
: item.content}
? strings.linkNoteEmptyBlock()
: item.content}
</Paragraph>
<View
@@ -160,7 +158,6 @@ export default function LinkNote(props: {
const [selectedNote, setSelectedNote] = useState<Note>();
const [selectedNodeId, setSelectedNodeId] = useState<string>();
const [blocksLoading, setBlocksLoading] = useState(false);
useEffect(() => {
db.notes.all.sorted(db.settings.getGroupOptions("notes")).then((notes) => {
@@ -209,12 +206,10 @@ export default function LinkNote(props: {
const onSelectNote = async (note: Note) => {
setSelectedNote(note);
setBlocksLoading(true);
inputRef.current?.clear();
setTimeout(async () => {
nodesRef.current = await db.notes.contentBlocks(note.id);
setNodes(nodesRef.current);
setBlocksLoading(false);
});
// Fetch and set note's nodes.
};
@@ -229,7 +224,6 @@ export default function LinkNote(props: {
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingBottom: DefaultAppStyles.GAP,
minHeight: "100%",
maxHeight: "100%"
}}
@@ -336,42 +330,28 @@ export default function LinkNote(props: {
windowSize={3}
keyExtractor={(item) => item.id}
ListEmptyComponent={
!blockLinking || blocksLoading ? (
<ActivityIndicator size={25} color={colors.primary.accent} />
) : !blockLinking.isAllowed ? (
<View
<View
style={{
gap: DefaultAppStyles.GAP_VERTICAL,
backgroundColor: colors.secondary.background,
padding: DefaultAppStyles.GAP,
borderRadius: defaultBorderRadius,
borderWidth: 0.5,
borderColor: colors.secondary.border,
alignItems: "center"
}}
>
<Paragraph color={colors.secondary.paragraph}>
{blockLinking?.error}
</Paragraph>
<Button
title={strings.upgradePlan()}
style={{
gap: DefaultAppStyles.GAP_VERTICAL,
backgroundColor: colors.secondary.background,
padding: DefaultAppStyles.GAP,
borderRadius: defaultBorderRadius,
borderWidth: 0.5,
borderColor: colors.secondary.border,
alignItems: "center"
width: "100%"
}}
>
<Paragraph color={colors.secondary.paragraph}>
{blockLinking?.error}
</Paragraph>
<Button
title={strings.upgradePlan()}
style={{
width: "100%"
}}
type="accent"
onPress={() => {
Navigation.navigate("PayWall", {
context: useUserStore.getState().user
? "logged-in"
: "logged-out",
canGoBack: true
});
props.close?.();
}}
/>
</View>
) : null
type="accent"
/>
</View>
}
data={blockLinking?.isAllowed ? nodes : []}
/>

View File

@@ -447,9 +447,7 @@ const onChangeTab = async (event: { i: number; from: number }) => {
if (event.i === 2) {
editorState().movedAway = false;
editorState().isFocused = true;
if (useSettingStore.getState().settings.keepScreenOn) {
activateKeepAwake();
}
activateKeepAwake();
eSendEvent(eOnEnterEditor);
if (

View File

@@ -163,20 +163,7 @@ const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
}, [noteIds]);
const onSave = async () => {
const selectionState = useNotebookSelectionStore.getState();
const changedNotebooks = { ...selectionState.selection };
if (!selectionState.multiSelect) {
for (const id in selectionState.initialState) {
if (
selectionState.initialState[id] === "selected" &&
changedNotebooks[id] !== "selected"
) {
changedNotebooks[id] = "deselected";
}
}
}
const changedNotebooks = useNotebookSelectionStore.getState().selection;
for (const id in changedNotebooks) {
const item = await db.notebooks.notebook(id);
if (!item) continue;
@@ -220,11 +207,11 @@ const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
rightButton={
hasSelection
? {
name: "restore",
onPress: () => {
updateInitialSelectionState(noteIds);
name: "restore",
onPress: () => {
updateInitialSelectionState(noteIds);
}
}
}
: undefined
}
/>

View File

@@ -210,7 +210,7 @@ export const settingsGroups: SettingSection[] = [
: status === SubscriptionStatus.ACTIVE
? strings.subRenewOn(expiryDate)
: status === SubscriptionStatus.CANCELED ||
status === SubscriptionStatus.PAUSED
status === SubscriptionStatus.PAUSED
? strings.subEndsOn(expiryDate)
: status === SubscriptionStatus.EXPIRED
? subscriptionDaysLeft.time < -3
@@ -965,14 +965,6 @@ export const settingsGroups: SettingSection[] = [
property: "checkForUpdates",
icon: "update"
},
{
id: "keep-screen-on",
type: "switch",
name: strings.keepScreenOn(),
description: strings.keepScreenOnDesc(),
property: "keepScreenOn",
icon: "cellphone-screenshot",
},
{
id: "image-compression",
type: "component",

View File

@@ -35,7 +35,7 @@ import notifee, {
import NetInfo from "@react-native-community/netinfo";
import dayjs, { Dayjs } from "dayjs";
import { encodeNonAsciiHTML } from "entities";
import { AppState, Platform } from "react-native";
import { Platform } from "react-native";
import { db, setupDatabase } from "../common/database";
import { MMKV } from "../common/database/mmkv";
import { presentDialog } from "../components/dialog/functions";
@@ -45,7 +45,7 @@ import { useRelationStore } from "../stores/use-relation-store";
import { useReminderStore } from "../stores/use-reminder-store";
import { useSettingStore } from "../stores/use-setting-store";
import { useUserStore } from "../stores/use-user-store";
import { eCloseSimpleDialog, eOnLoadNote } from "../utils/events";
import { eOnLoadNote } from "../utils/events";
import { fluidTabsRef } from "../utils/global-refs";
import { convertNoteToText } from "../utils/note-to-text";
import { NotesnookModule } from "../utils/notesnook-module";
@@ -577,7 +577,7 @@ async function displayNotification({
}
function openSettingsDialog(context: string) {
return new Promise<boolean>((resolve) => {
return new Promise((resolve) => {
presentDialog({
title: strings.notificationsDisabled(),
paragraph: strings.notificationsDisabledDesc(),
@@ -597,94 +597,49 @@ function openSettingsDialog(context: string) {
});
}
function waitForAppFocusAfterSettings(timeoutMs = 120000): Promise<void> {
return new Promise((resolve) => {
let didLeaveApp = AppState.currentState !== "active";
const timeout = setTimeout(() => {
subscription.remove();
resolve();
}, timeoutMs);
const subscription = AppState.addEventListener("change", (state) => {
if (state !== "active") {
didLeaveApp = true;
return;
}
if (didLeaveApp && state === "active") {
clearTimeout(timeout);
subscription.remove();
resolve();
}
});
});
}
async function checkAndRequestPermissions(
promptUser?: boolean
): Promise<boolean> {
let permissionStatus = await notifee.getNotificationSettings();
if (Platform.OS === "android") {
const hasNotificationPermission =
permissionStatus.authorizationStatus === AuthorizationStatus.AUTHORIZED;
const hasAlarmPermission = permissionStatus.android.alarm === 1;
if (hasNotificationPermission && hasAlarmPermission) {
if (
permissionStatus.authorizationStatus === AuthorizationStatus.AUTHORIZED &&
permissionStatus.android.alarm === 1
)
return true;
}
if (permissionStatus.authorizationStatus === AuthorizationStatus.DENIED) {
permissionStatus = await notifee.requestPermission();
}
// Wait for user to return from exact alarm settings
if (permissionStatus.android.alarm !== 1) {
const waitForAppFocus = waitForAppFocusAfterSettings();
await notifee.openAlarmPermissionSettings();
await waitForAppFocus;
}
permissionStatus = await notifee.getNotificationSettings();
const authorized =
if (
permissionStatus.authorizationStatus === AuthorizationStatus.AUTHORIZED &&
permissionStatus.android.alarm === 1;
if (authorized) {
permissionStatus.android.alarm === 1
)
return true;
}
if (promptUser) {
const openSettings = await openSettingsDialog("local");
if (openSettings) {
const waitForAppFocus = waitForAppFocusAfterSettings();
if (await openSettingsDialog("local")) {
await notifee.openNotificationSettings();
await waitForAppFocus;
permissionStatus = await notifee.getNotificationSettings();
const finalAuthorized =
permissionStatus.authorizationStatus ===
AuthorizationStatus.AUTHORIZED &&
permissionStatus.android.alarm === 1;
if (finalAuthorized) {
eSendEvent(eCloseSimpleDialog);
return true;
}
return false;
}
return false;
}
return false;
} else {
permissionStatus = await notifee.requestPermission();
if (permissionStatus.authorizationStatus === AuthorizationStatus.AUTHORIZED)
return true;
if (promptUser) {
await openSettingsDialog("local");
}
return false;
}
// iOS
permissionStatus = await notifee.requestPermission();
if (permissionStatus.authorizationStatus === AuthorizationStatus.AUTHORIZED) {
return true;
}
if (promptUser) {
await openSettingsDialog("local");
}
return false;
}
async function getTriggers(
reminder: Reminder
): Promise<(Trigger & { id: string })[] | undefined> {

View File

@@ -104,7 +104,6 @@ export type Settings = {
checkForUpdates?: boolean;
defaultLineHeight: number;
imageCompression: "ask-every-time" | "enabled" | "disabled";
keepScreenOn?: boolean;
};
type DimensionsType = {
@@ -214,8 +213,7 @@ export const defaultSettings: SettingStore["settings"] = {
lastFullBackupDate: 0,
checkForUpdates: true,
defaultLineHeight: EDITOR_LINE_HEIGHT.DEFAULT,
imageCompression: "ask-every-time",
keepScreenOn: true
imageCompression: "ask-every-time"
};
export const useSettingStore = create<SettingStore>((set, get) => ({

View File

@@ -1,6 +1,6 @@
// Production iOS build identifiers
IOS_CURRENT_PROJECT_VERSION = 2191
IOS_MARKETING_VERSION = 3.4.7
IOS_CURRENT_PROJECT_VERSION = 2189
IOS_MARKETING_VERSION = 3.4.5
IOS_MAIN_BUNDLE_ID = org.streetwriters.notesnook
IOS_WIDGET_BUNDLE_ID = org.streetwriters.notesnook.notewidget
IOS_SHARE_BUNDLE_ID = org.streetwriters.notesnook.share

View File

@@ -1,6 +1,6 @@
// Production iOS build identifiers
IOS_CURRENT_PROJECT_VERSION = 2191
IOS_MARKETING_VERSION = 3.4.7
IOS_CURRENT_PROJECT_VERSION = 2189
IOS_MARKETING_VERSION = 3.4.5
IOS_MAIN_BUNDLE_ID = org.streetwriters.notesnook
IOS_WIDGET_BUNDLE_ID = org.streetwriters.notesnook.notewidget
IOS_SHARE_BUNDLE_ID = org.streetwriters.notesnook.share

View File

@@ -1,6 +1,6 @@
// Staging iOS build identifiers
IOS_CURRENT_PROJECT_VERSION = 2191
IOS_MARKETING_VERSION = 3.4.7
IOS_CURRENT_PROJECT_VERSION = 2189
IOS_MARKETING_VERSION = 3.4.5
IOS_MAIN_BUNDLE_ID = org.streetwriters.notesnook
IOS_WIDGET_BUNDLE_ID = org.streetwriters.notesnook.notewidget
IOS_SHARE_BUNDLE_ID = org.streetwriters.notesnook.share

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/mobile",
"version": "3.4.5",
"version": "3.4.0-beta.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/mobile",
"version": "3.4.5",
"version": "3.4.0-beta.1",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
@@ -290,7 +290,7 @@
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook-importer/core": "^2.4.5",
"@notesnook-importer/core": "^2.2.5",
"@notesnook/common": "file:../common",
"@notesnook/intl": "file:../intl",
"@notesnook/theme": "file:../theme",

View File

@@ -1,6 +1,6 @@
{
"name": "@notesnook/mobile",
"version": "3.4.7",
"version": "3.4.5",
"private": true,
"license": "GPL-3.0-or-later",
"scripts": {

View File

@@ -1,6 +1,6 @@
{
"name": "@notesnook/vericrypt",
"version": "1.4.0",
"version": "1.3.0",
"private": true,
"devDependencies": {
"@types/platform": "^1.3.6",
@@ -43,4 +43,4 @@
"last 1 safari version"
]
}
}
}

View File

@@ -31,7 +31,7 @@ import { PasteEncryptedData, SyncRequestBody } from "./components/step-4";
import { StepSeperator } from "./components/step-seperator";
import { Footer } from "./components/footer";
import { useState } from "react";
import { NNCrypto, Cipher } from "@notesnook/crypto";
import { NNCrypto } from "@notesnook/crypto";
import { Code } from "./components/code";
import { Accordion } from "./components/accordion";
import { DecryptedResult } from "./components/decrypted-result";
@@ -41,7 +41,7 @@ const instructions = [
"Go to Notesnook",
"Open Settings",
<>
Click on <Code text="Save data recovery key" />
Click on <Code text="Backup data recovery key" />
</>,
"Enter your account password for verification",
"Confirm that your generated encryption key matches"
@@ -52,7 +52,6 @@ function App() {
const [salt, setSalt] = useState<string>();
const [key, setKey] = useState<string>();
const [data, setData] = useState<SyncRequestBody | undefined>();
const [accountDataKey, setAccountDataKey] = useState<Cipher<"base64"> | null | undefined>();
const theme = useTheme({ accent: getDefaultAccentColor(), theme: "light" });
return (
@@ -68,7 +67,7 @@ function App() {
>
<LoginToNotesnook />
<StepSeperator />
<GetAccountSalt onSaltSubmitted={setSalt} setAccountDataKey={setAccountDataKey} />
<GetAccountSalt onSaltSubmitted={setSalt} />
{salt && (
<>
@@ -92,7 +91,7 @@ function App() {
return true;
}}
popup={{
title: "Your master encryption key",
title: "Your data encryption key",
body: key ? (
<>
<Text
@@ -147,13 +146,11 @@ function App() {
password={password}
salt={salt}
data={data}
accountKey={accountDataKey}
onRestartProcess={() => {
setSalt(undefined);
setPassword(undefined);
setKey(undefined);
setData(undefined);
setAccountDataKey(undefined);
}}
/>
</>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { Flex, Button, Text, Link } from "@theme-ui/components";
import { StepContainer } from "./step-container";
import { SyncRequestBody } from "./step-4";
import { NNCrypto, Cipher } from "@notesnook/crypto";
import { NNCrypto } from "@notesnook/crypto";
import { useEffect, useState } from "react";
import { FcDataEncryption } from "react-icons/fc";
import { Code } from "./code";
@@ -32,7 +32,6 @@ type DecryptedResultProps = {
password: string;
salt: string;
data: SyncRequestBody;
accountKey: Cipher<"base64"> | null | undefined;
onRestartProcess: () => void;
};
@@ -52,19 +51,10 @@ export function DecryptedResult(props: DecryptedResultProps) {
};
const crypto = new NNCrypto();
const key = await crypto.exportKey(props.password, props.salt);
let encryptionKey = undefined;
if (props.accountKey != null){
// Need to decrypt the account key
props.accountKey.format = "base64"; // account keys don't have the format set, but they're base64.
const dataEncryptionKey = JSON.parse(await crypto.decrypt(key, props.accountKey, "text"))
encryptionKey = dataEncryptionKey;
} else {
encryptionKey = key;
}
for (const arrayKey in data) {
const array = data[arrayKey];
for (const encryptedItem of (props.data as any)[arrayKey]) {
const data = await crypto.decrypt(encryptionKey, encryptedItem, "text");
const data = await crypto.decrypt(key, encryptedItem, "text");
array.push(JSON.parse(data));
}
}
@@ -160,9 +150,19 @@ export function DecryptedResult(props: DecryptedResultProps) {
support@streetwriters.co
</Link>{" "}
or{" "}
<Link href="https://go.notesnook.com/discord">join our Discord community</Link>.
<Link href="https://discord.gg/">joining our Discord community</Link>.
We&apos;ll do our best to alleviate all your worries.
</Text>
<Text as="p" variant="body" sx={{ mx: 2, mt: 2, fontWeight: "bold" }}>
What about open sourcing Notesnook?
</Text>
<Text as="p" variant="body" sx={{ mx: 2, my: 2 }}>
Open sourcing is another part of garnering our users&apos; trust. We
have <Link href="https://notesnook.com/roadmap">plans</Link> to begin
open sourcing in May but open sourcing will not make this tool
obsolete. Verifying the integrity of encrypted data at any point in
time is very important even if the software is open source.
</Text>
</Accordion>
<Flex sx={{ alignSelf: "center", mt: 4 }}>
<Button

View File

@@ -38,6 +38,11 @@ export function LoginToNotesnook() {
>
<Text variant="title">Welcome to Vericrypt</Text>
<Text as="p" variant="body" sx={{ mt: 1 }}>
<del>
Trust is a huge problem in closed source end-to-end encrypted
applications. How can you be sure that the app is actually encrypting
your data?
</del>
</Text>
<Text as="p" variant="body" sx={{ mt: 1 }}>
The only way to earn a user&apos;s trust is by allowing them to see how
@@ -51,10 +56,9 @@ export function LoginToNotesnook() {
</Link>
</Text>
<Text as="p" variant="body" sx={{ mt: 1 }}>
Yes, that&apos;s right. Notesnook is 100% open source under the
GPLv3 license. That includes the app, the encryption library, and
everything else. We&apos;ve even open sourced the server, available under the
AGPLv3 license.
Yes, that&apos;s right. Notesnook is now 100% open source under the
GPLv3 license. That includes the app, the encryption library, the
backend server, and everything else.
</Text>
<Text as="p" variant="body" sx={{ mt: 1 }}>
However, even with an open source app, how can you be sure that the app
@@ -82,7 +86,7 @@ export function LoginToNotesnook() {
sx={{ alignSelf: "center", mt: 2 }}
onClick={() => window.open("https://app.notesnook.com/login", "_blank")}
>
Get Started by Logging in
Login to Notesnook
</Button>
</StepContainer>
);

View File

@@ -16,11 +16,11 @@ 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 { Flex, Text, Image, Textarea } from "@theme-ui/components";
import { Flex, Text, Image, Input } from "@theme-ui/components";
import { StepContainer } from "./step-container";
import DevtoolsCopyUsersChrome from "../assets/screenshots/devtools_copy_users.png";
import DevtoolsCopySaltChrome from "../assets/screenshots/devtools_copy_salt.png";
import DevtoolsCopyUsersFirefox from "../assets/screenshots/firefox/firefox_copy_users.png";
import DevtoolsCopySaltFirefox from "../assets/screenshots/firefox/firefox_copy_salt.png";
import { Accordion } from "./accordion";
import { getCombo } from "../utils/keycombos";
@@ -29,11 +29,9 @@ import { KeyCombo } from "./key-combo";
import { Code } from "./code";
import { useState } from "react";
import { getSourceUrl } from "../utils/links";
import { Cipher } from "@notesnook/crypto";
type GetAccountSaltProps = {
onSaltSubmitted: (salt: string) => void;
setAccountDataKey: (accountDataKey: Cipher<"base64"> | null) => void;
};
const steps = {
@@ -54,10 +52,10 @@ const steps = {
</Text>,
<Flex key="key-named-salt" sx={{ flexDirection: "column" }}>
<Text as="p">Follow the steps as shown in the image:</Text>
<Image src={DevtoolsCopyUsersChrome} width={"100%"} sx={{ mt: 1 }} />
<Image src={DevtoolsCopySaltChrome} width={"100%"} sx={{ mt: 1 }} />
</Flex>,
<Flex key="copy-salt" sx={{ flexDirection: "column" }}>
<Text as="p">Copy everything in the response and paste it below.</Text>
<Text as="p">Copy the salt and paste it below.</Text>
</Flex>
],
firefox: [
@@ -77,10 +75,10 @@ const steps = {
</Text>,
<Flex key="key-named-salt" sx={{ flexDirection: "column" }}>
<Text as="p">Follow the steps as shown in the image:</Text>
<Image src={DevtoolsCopyUsersFirefox} width={"100%"} sx={{ mt: 1 }} />
<Image src={DevtoolsCopySaltFirefox} width={"100%"} sx={{ mt: 1 }} />
</Flex>,
<Flex key="copy-salt" sx={{ flexDirection: "column" }}>
<Text as="p">Copy everything in the response and paste it below.</Text>
<Text as="p">Copy the salt and paste it below.</Text>
</Flex>
]
};
@@ -116,14 +114,14 @@ export function GetAccountSalt(props: GetAccountSaltProps) {
sx={{ flexDirection: "column" }}
>
<Flex sx={{ justifyContent: "space-between", alignItems: "center" }}>
<Text variant="title">Account Key Data</Text>
<Text variant="title">Account salt</Text>
<Code
text="src/components/step-2.tsx"
href={getSourceUrl("src/components/step-2.tsx")}
/>
</Flex>
<Accordion
title="How to get your key data?"
title="How to get your account salt?"
sx={{
border: "1px solid var(--border)",
mt: 2,
@@ -131,9 +129,9 @@ export function GetAccountSalt(props: GetAccountSaltProps) {
}}
>
<Text variant="body" sx={{ mx: 2 }}>
You&apos;ll be extracting your account&apos;s keys right from
We&apos;ll be extracting your account&apos;s salt right from
Notesnook&apos;s local database that lives in your web browser. So put
on your seat belt and let&apos;s retrieve those keys.
on your seat belt and let&apos;s get some salt!
</Text>
<Text as="ol" variant="body" sx={{ mb: 2 }}>
{instructions?.map((item, index) => (
@@ -143,11 +141,12 @@ export function GetAccountSalt(props: GetAccountSaltProps) {
))}
</Text>
</Accordion>
<Textarea
<Input
variant="forms.clean"
id="account-data"
name="account-data"
placeholder="Paste the response here"
id="salt"
name="salt"
type="text"
placeholder="Enter your account salt"
sx={{
mt: 2,
fontSize: "subheading",
@@ -163,21 +162,13 @@ export function GetAccountSalt(props: GetAccountSaltProps) {
spellCheck={false}
onChange={(e) => {
setIsSaltValid(undefined);
/*
If there is no dataEncryptionKey, try reading the legacyDataEncryptionKey.
If there is a legacyDataEncryptionKey, use this one.
If there is no legacyDataEncryptionKey, it is a legacy account (pre DEK update) that has not
changed passwords. (Use master key instead.)
*/
try {
const value = JSON.parse(e.target.value);
props.setAccountDataKey(value.dataEncryptionKey ?? value.legacyDataEncryptionKey ?? null);
const salt = value.salt;
const isValid = Buffer.from(salt, "base64").length === 16;
const value = e.target.value;
const isValid = Buffer.from(value, "base64").length === 16;
if (!isValid) setIsSaltValid(false);
else {
setIsSaltValid(true);
props.onSaltSubmitted(salt);
props.onSaltSubmitted(value);
}
} catch (e) {
console.error(e);

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/web",
"version": "3.4.4",
"version": "3.4.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/web",
"version": "3.4.4",
"version": "3.4.2",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {

View File

@@ -1,7 +1,7 @@
{
"name": "@notesnook/web",
"description": "Your private note taking space",
"version": "3.4.4",
"version": "3.4.2",
"private": true,
"main": "./src/app.js",
"homepage": "https://notesnook.com/",

View File

@@ -684,12 +684,6 @@ function TiptapWrapper(
}
}, [props.spellcheck]);
useEffect(() => {
if (editorContainerRef.current) {
editorContainerRef.current.style.fontSize = `${editorConfig.fontSize}px`;
}
}, [editorConfig.fontSize]);
return (
<Flex
ref={containerRef}

View File

@@ -97,7 +97,34 @@ const features: Record<FeatureKeys, Feature> = {
)
}
]
: [],
: [
{
icon: Inbox,
title: "Inbox API",
subtitle: "A new API to send data to Notesnook from other apps."
},
{
icon: LinkedTo,
title: "Deep links on Desktop",
subtitle: "Reference Notesnook notes from other apps."
},
{
icon: Plus,
title: "More features, bug fixes, and security improvments",
subtitle: (
<>
This release contains much much more.{" "}
<Link
href="https://blog.notesnook.com/notesnook-desktop-v3.4.0"
target="_blank"
title="Read the full release notes"
>
Read the full release notes
</Link>
</>
)
}
],
cta: {
title: strings.gotIt(),
icon: Checkmark,

View File

@@ -21,7 +21,7 @@ On all three platforms we use the same exact library for all cryptographic funct
> info Fun story
>
> When we first added encryption, we used AES-GCM-256 across platforms but the cross-platform compatibility was abyssmal. That is when I found out about the great libsodium. Written in C, wrappers available for all platforms...what more could I want?
> When we first added encryption, we used AES-GCM-256 across platforms but the cross-platform compatbility was abyssmal. That is when I found out about the great libsodium. Written in C, wrappers available for all platforms...what more could I want?
## Process
@@ -41,7 +41,13 @@ This process is repeated every time you sign in.
### 2. Key generation
When you first sign up for an account, your client generates two encryption keys. One is a unique data encryption key that encrypts all your notes and other data. The second is your master encryption key, this is derived by your password and predictable salt. This key protects all your encryption keys, like the aforementioned data encryption key. If you change your password, your client will re-encrypt your existing data encryption key with your new master key.
After you are signed in, the app requests your user data which includes, among other things, your salt.
> info Salt generation
>
> When you create an account, the server generates a cryptographically secure random salt for you. This salt is used for key generation.
You password & salt is then used to derive a strong irreversible key using Argon2 as the password key derivation function (PKDF).
### 3. Encryption key storage
@@ -49,7 +55,7 @@ When you first sign up for an account, your client generates two encryption keys
Instead of storing the key as plain text (and allowing anyone to copy/move it), we use browser's `IndexedDB` to store the key as a `CryptoKey`.
`CryptoKey` is stored securely by the browser and cannot be exported, viewed, or copied except by the app & browser.
`CryptoKey` is stored securely by the browser and cannot be exported, viewed, copied except by the app & browser.
# [Mobile](#/tab/mobile)
@@ -59,12 +65,12 @@ On iOS and Android, the encryption key is stored in the phone's keychain.
### 4. Data encryption
Encryption only takes place when you sync. Each item in the database is encrypted separately using XChaCha-Poly1305-IETF.
Encryption only takes place when you sync. Each item in the database is encrypted seperately using XChaCha-Poly1305-IETF.
#### How it works
1. The item is read from the database as JSON object and stringified (i.e. converted to a string).
2. The string is encrypted using the data encryption key generated earlier.
2. The string is encrypted using the encryption key generated earlier.
3. The result is a JSON object which contains:
1. A base64 encoded `cipher`
2. A 192-bit nonce (`iv`)
@@ -77,9 +83,3 @@ Encryption only takes place when you sync. Each item in the database is encrypte
> See the whole process in action [here.](https://vericrypt.notesnook.com/)
This object is then sent to the server for storage. The server performs no further operation on this data (because it can't).
## Faqs
### I am an old user of Notesnook, I don't have a data encryption key.
Your data encryption key will be created when you change your password.

View File

@@ -2,7 +2,7 @@
> error This feature is Android only.
A simple, quick and convenient way to take notes on your phone from notifications. This works the same way as a messaging/chat app allows you to reply to messages from notifications.
A simple, quick and convinient way to take notes on your phone from notifications. This works the same way as a messaging/chat app allows you to reply to messages from notifications.
![Notes in notifications](/static/mobile-integration/android-quick-note-notifications.png)

View File

@@ -2,7 +2,7 @@
Basic web clipping support is available on both Android & iOS apps via share extensions.
We are going to use browser app as an example to demonstrate how you can clip information from webpages and other apps on your iPhone.
We are going to use browser app as an example to demonstarte how you can clip information from webpages and other apps on your iPhone.
1. Select some text on a webpage then Tap on "Share" on the context menu.
@@ -40,7 +40,7 @@ We are going to use browser app as an example to demonstrate how you can clip in
> info
>
> Share extension will save the note you selected so in future web clips, it will be selected by default until you reset it.
> Share exenstion will save the note you selected so in future web clips, it will be selected by default until you reset it.
## Clipping full webpage content

View File

@@ -29,7 +29,7 @@ The first step to recovering your account consists of requesting an account reco
5. On the next page, your email should be prefilled. If it isn't, fill it out.
![](/static/account-recovery/step-2.png)
6. Click on `Send recovery email`
7. If everything goes well, you should receive an email from Notesnook in your inbox:
7. If everything goes well, you should recieve an email from Notesnook in your inbox:
![](/static/account-recovery/recovery_email.png)
> info What if I didn't receive an email?
>

View File

@@ -1,3 +0,0 @@
- Minor bug fixes and improvements
Thank you for using Notesnook!

View File

@@ -1,4 +0,0 @@
- Add option to clear note version history
- Minor bug fixes and improvements
Thank you for using Notesnook!

View File

@@ -437,7 +437,6 @@ export class Notes implements ICollection {
const duplicateId = await this.db.notes.add({
...clone(note),
id: undefined,
pinned: false,
isGeneratedTitle: false,
contentId: undefined,
title: note.title + " (Copy)",

View File

@@ -63,7 +63,7 @@
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook-importer/core": "^2.4.5",
"@notesnook-importer/core": "^2.2.5",
"@notesnook/common": "file:../common",
"@notesnook/intl": "file:../intl",
"@notesnook/theme": "file:../theme",

View File

@@ -138,7 +138,7 @@ msgstr "{count, plural, one {Are you sure you want to download all attachments o
msgid "{count, plural, one {Are you sure you want to move this notebook to {selectedNotebookTitle}?} other {Are you sure you want to move these # notebooks {selectedNotebookTitle}?}}"
msgstr "{count, plural, one {Are you sure you want to move this notebook to {selectedNotebookTitle}?} other {Are you sure you want to move these # notebooks {selectedNotebookTitle}?}}"
#: generated/action-confirmations.ts:82
#: generated/action-confirmations.ts:76
msgid "{count, plural, one {Are you sure you want to permanently delete this item?} other {Are you sure you to permanently delete these items?}}"
msgstr "{count, plural, one {Are you sure you want to permanently delete this item?} other {Are you sure you to permanently delete these items?}}"
@@ -150,10 +150,6 @@ msgstr "{count, plural, one {Are you sure you want to permanently delete this no
msgid "{count, plural, one {Are you sure you want to permanently delete this notebook?} other {Are you sure you to permanently delete these notebooks?}}"
msgstr "{count, plural, one {Are you sure you want to permanently delete this notebook?} other {Are you sure you to permanently delete these notebooks?}}"
#: generated/action-confirmations.ts:69
msgid "{count, plural, one {Are you sure you want to permanently delete this version?} other {Are you sure you to permanently delete these versions?}}"
msgstr "{count, plural, one {Are you sure you want to permanently delete this version?} other {Are you sure you to permanently delete these versions?}}"
#: src/strings.ts:135
msgid "{count, plural, one {Attach image} other {Attach # images}}"
msgstr "{count, plural, one {Attach image} other {Attach # images}}"
@@ -166,7 +162,7 @@ msgstr "{count, plural, one {Attachment deleted} other {# attachments deleted}}"
msgid "{count, plural, one {Attachment downloaded at {path}} other {#/{total} attachments downloaded as a zip file at {path}}}"
msgstr "{count, plural, one {Attachment downloaded at {path}} other {#/{total} attachments downloaded as a zip file at {path}}}"
#: generated/actions.ts:222
#: generated/actions.ts:216
msgid "{count, plural, one {Color renamed} other {# colors renamed}}"
msgstr "{count, plural, one {Color renamed} other {# colors renamed}}"
@@ -179,7 +175,7 @@ msgid "{count, plural, one {Delete color} other {Delete # colors}}"
msgstr "{count, plural, one {Delete color} other {Delete # colors}}"
#: generated/do-actions.ts:12
#: generated/do-actions.ts:59
#: generated/do-actions.ts:53
msgid "{count, plural, one {Delete item} other {Delete # items}}"
msgstr "{count, plural, one {Delete item} other {Delete # items}}"
@@ -199,10 +195,6 @@ msgstr "{count, plural, one {Delete reminder} other {Delete # reminders}}"
msgid "{count, plural, one {Delete tag} other {Delete # tags}}"
msgstr "{count, plural, one {Delete tag} other {Delete # tags}}"
#: generated/do-actions.ts:36
msgid "{count, plural, one {Delete version} other {Delete # versions}}"
msgstr "{count, plural, one {Delete version} other {Delete # versions}}"
#: generated/in-progress-actions.ts:16
msgid "{count, plural, one {Deleting attachment...} other {Deleting # attachments...}}"
msgstr "{count, plural, one {Deleting attachment...} other {Deleting # attachments...}}"
@@ -227,27 +219,27 @@ msgstr "{count, plural, one {Deleting reminder...} other {Deleting # reminders..
msgid "{count, plural, one {Deleting tag...} other {Deleting # tags...}}"
msgstr "{count, plural, one {Deleting tag...} other {Deleting # tags...}}"
#: generated/do-actions.ts:280
#: generated/do-actions.ts:274
msgid "{count, plural, one {Download attachment} other {Download # attachments}}"
msgstr "{count, plural, one {Download attachment} other {Download # attachments}}"
#: generated/do-actions.ts:289
#: generated/do-actions.ts:283
msgid "{count, plural, one {Download item} other {Download # items}}"
msgstr "{count, plural, one {Download item} other {Download # items}}"
#: generated/do-actions.ts:214
#: generated/do-actions.ts:208
msgid "{count, plural, one {Edit item} other {Edit # items}}"
msgstr "{count, plural, one {Edit item} other {Edit # items}}"
#: generated/do-actions.ts:197
#: generated/do-actions.ts:191
msgid "{count, plural, one {Edit notebook} other {Edit # notebooks}}"
msgstr "{count, plural, one {Edit notebook} other {Edit # notebooks}}"
#: generated/do-actions.ts:201
#: generated/do-actions.ts:195
msgid "{count, plural, one {Edit reminder} other {Edit # reminders}}"
msgstr "{count, plural, one {Edit reminder} other {Edit # reminders}}"
#: generated/do-actions.ts:193
#: generated/do-actions.ts:187
msgid "{count, plural, one {Edit tag} other {Edit # tags}}"
msgstr "{count, plural, one {Edit tag} other {Edit # tags}}"
@@ -263,41 +255,41 @@ msgstr "{count, plural, one {Item could not be published} other {# items could n
msgid "{count, plural, one {Item could not be unpublished} other {# items could not be unpublished}}"
msgstr "{count, plural, one {Item could not be unpublished} other {# items could not be unpublished}}"
#: generated/actions.ts:214
#: generated/actions.ts:208
msgid "{count, plural, one {Item created} other {# items created}}"
msgstr "{count, plural, one {Item created} other {# items created}}"
#: generated/actions.ts:47
#: generated/actions.ts:41
msgid "{count, plural, one {Item deleted} other {# items deleted}}"
msgstr "{count, plural, one {Item deleted} other {# items deleted}}"
#: generated/actions.ts:185
#: generated/actions.ts:179
msgid "{count, plural, one {Item edited} other {# items edited}}"
msgstr "{count, plural, one {Item edited} other {# items edited}}"
#: generated/actions.ts:70
#: generated/actions.ts:64
msgid "{count, plural, one {Item moved to trash} other {# items moved to trash}}"
msgstr "{count, plural, one {Item moved to trash} other {# items moved to trash}}"
#: generated/actions.ts:86
#: generated/actions.ts:99
#: generated/actions.ts:80
#: generated/actions.ts:93
msgid "{count, plural, one {Item permanently deleted} other {# items permanently deleted}}"
msgstr "{count, plural, one {Item permanently deleted} other {# items permanently deleted}}"
#: generated/actions.ts:116
#: generated/actions.ts:110
msgid "{count, plural, one {Item published} other {# items published}}"
msgstr "{count, plural, one {Item published} other {# items published}}"
#: generated/actions.ts:231
#: generated/actions.ts:225
msgid "{count, plural, one {Item renamed} other {# items renamed}}"
msgstr "{count, plural, one {Item renamed} other {# items renamed}}"
#: generated/actions.ts:149
#: generated/actions.ts:162
#: generated/actions.ts:143
#: generated/actions.ts:156
msgid "{count, plural, one {Item restored} other {# items restored}}"
msgstr "{count, plural, one {Item restored} other {# items restored}}"
#: generated/actions.ts:133
#: generated/actions.ts:127
msgid "{count, plural, one {Item unpublished} other {# items unpublished}}"
msgstr "{count, plural, one {Item unpublished} other {# items unpublished}}"
@@ -329,23 +321,23 @@ msgstr "{count, plural, one {Note deleted} other {# notes deleted}}"
msgid "{count, plural, one {Note exported} other {# notes exported}}"
msgstr "{count, plural, one {Note exported} other {# notes exported}}"
#: generated/actions.ts:55
#: generated/actions.ts:49
msgid "{count, plural, one {Note moved to trash} other {# notes moved to trash}}"
msgstr "{count, plural, one {Note moved to trash} other {# notes moved to trash}}"
#: generated/actions.ts:78
#: generated/actions.ts:72
msgid "{count, plural, one {Note permanently deleted} other {# notes permanently deleted}}"
msgstr "{count, plural, one {Note permanently deleted} other {# notes permanently deleted}}"
#: generated/actions.ts:107
#: generated/actions.ts:101
msgid "{count, plural, one {Note published} other {# notes published}}"
msgstr "{count, plural, one {Note published} other {# notes published}}"
#: generated/actions.ts:141
#: generated/actions.ts:135
msgid "{count, plural, one {Note restored} other {# notes restored}}"
msgstr "{count, plural, one {Note restored} other {# notes restored}}"
#: generated/actions.ts:124
#: generated/actions.ts:118
msgid "{count, plural, one {Note unpublished} other {# notes unpublished}}"
msgstr "{count, plural, one {Note unpublished} other {# notes unpublished}}"
@@ -353,7 +345,7 @@ msgstr "{count, plural, one {Note unpublished} other {# notes unpublished}}"
msgid "{count, plural, one {Note will be automatically deleted from all other devices & any future changes won't get synced. Are you sure you want to continue?} other {# notes will be automatically deleted from all other devices & any future changes won't get synced. Are you sure you want to continue?}}"
msgstr "{count, plural, one {Note will be automatically deleted from all other devices & any future changes won't get synced. Are you sure you want to continue?} other {# notes will be automatically deleted from all other devices & any future changes won't get synced. Are you sure you want to continue?}}"
#: generated/actions.ts:193
#: generated/actions.ts:187
msgid "{count, plural, one {Notebook created} other {# notebooks created}}"
msgstr "{count, plural, one {Notebook created} other {# notebooks created}}"
@@ -361,28 +353,28 @@ msgstr "{count, plural, one {Notebook created} other {# notebooks created}}"
msgid "{count, plural, one {Notebook deleted} other {# notebooks deleted}}"
msgstr "{count, plural, one {Notebook deleted} other {# notebooks deleted}}"
#: generated/actions.ts:174
#: generated/actions.ts:168
msgid "{count, plural, one {Notebook edited} other {# notebooks edited}}"
msgstr "{count, plural, one {Notebook edited} other {# notebooks edited}}"
#: generated/actions.ts:59
#: generated/actions.ts:53
msgid "{count, plural, one {Notebook moved to trash} other {# notebooks moved to trash}}"
msgstr "{count, plural, one {Notebook moved to trash} other {# notebooks moved to trash}}"
#: generated/actions.ts:82
#: generated/actions.ts:76
msgid "{count, plural, one {Notebook permanently deleted} other {# notebooks permanently deleted}}"
msgstr "{count, plural, one {Notebook permanently deleted} other {# notebooks permanently deleted}}"
#: generated/actions.ts:145
#: generated/actions.ts:139
msgid "{count, plural, one {Notebook restored} other {# notebooks restored}}"
msgstr "{count, plural, one {Notebook restored} other {# notebooks restored}}"
#: generated/do-actions.ts:147
#: generated/do-actions.ts:141
msgid "{count, plural, one {Permanently delete attachment} other {Permanently delete # attachments}}"
msgstr "{count, plural, one {Permanently delete attachment} other {Permanently delete # attachments}}"
#: generated/do-actions.ts:151
#: generated/do-actions.ts:162
#: generated/do-actions.ts:145
#: generated/do-actions.ts:156
msgid "{count, plural, one {Permanently delete item} other {Permanently delete # items}}"
msgstr "{count, plural, one {Permanently delete item} other {Permanently delete # items}}"
@@ -391,15 +383,15 @@ msgstr "{count, plural, one {Permanently delete item} other {Permanently delete
msgid "{count, plural, one {permanently deleting item...} other {permanently deleting # items...}}"
msgstr "{count, plural, one {permanently deleting item...} other {permanently deleting # items...}}"
#: generated/do-actions.ts:105
#: generated/do-actions.ts:99
msgid "{count, plural, one {Pin item} other {Pin # items}}"
msgstr "{count, plural, one {Pin item} other {Pin # items}}"
#: generated/do-actions.ts:90
#: generated/do-actions.ts:84
msgid "{count, plural, one {Pin note} other {Pin # notes}}"
msgstr "{count, plural, one {Pin note} other {Pin # notes}}"
#: generated/do-actions.ts:94
#: generated/do-actions.ts:88
msgid "{count, plural, one {Pin notebook} other {Pin # notebooks}}"
msgstr "{count, plural, one {Pin notebook} other {Pin # notebooks}}"
@@ -407,11 +399,11 @@ msgstr "{count, plural, one {Pin notebook} other {Pin # notebooks}}"
msgid "{count, plural, one {Prevent note from syncing} other {Prevent # notes from syncing}}"
msgstr "{count, plural, one {Prevent note from syncing} other {Prevent # notes from syncing}}"
#: generated/do-actions.ts:139
#: generated/do-actions.ts:133
msgid "{count, plural, one {Publish item} other {Publish # items}}"
msgstr "{count, plural, one {Publish item} other {Publish # items}}"
#: generated/do-actions.ts:130
#: generated/do-actions.ts:124
msgid "{count, plural, one {Publish note} other {Publish # notes}}"
msgstr "{count, plural, one {Publish note} other {Publish # notes}}"
@@ -419,47 +411,47 @@ msgstr "{count, plural, one {Publish note} other {Publish # notes}}"
msgid "{count, plural, one {Reminder deleted} other {# reminders deleted}}"
msgstr "{count, plural, one {Reminder deleted} other {# reminders deleted}}"
#: generated/do-actions.ts:259
#: generated/do-actions.ts:253
msgid "{count, plural, one {Remove attachment} other {Remove # attachments}}"
msgstr "{count, plural, one {Remove attachment} other {Remove # attachments}}"
#: generated/do-actions.ts:255
#: generated/do-actions.ts:249
msgid "{count, plural, one {Remove color} other {Remove # colors}}"
msgstr "{count, plural, one {Remove color} other {Remove # colors}}"
#: generated/do-actions.ts:272
#: generated/do-actions.ts:266
msgid "{count, plural, one {Remove item} other {Remove # items}}"
msgstr "{count, plural, one {Remove item} other {Remove # items}}"
#: generated/do-actions.ts:251
#: generated/do-actions.ts:245
msgid "{count, plural, one {Remove shortcut} other {Remove # shortcuts}}"
msgstr "{count, plural, one {Remove shortcut} other {Remove # shortcuts}}"
#: generated/do-actions.ts:222
#: generated/do-actions.ts:216
msgid "{count, plural, one {Rename attachment} other {Rename # attachments}}"
msgstr "{count, plural, one {Rename attachment} other {Rename # attachments}}"
#: generated/do-actions.ts:226
#: generated/do-actions.ts:220
msgid "{count, plural, one {Rename color} other {Rename # colors}}"
msgstr "{count, plural, one {Rename color} other {Rename # colors}}"
#: generated/do-actions.ts:243
#: generated/do-actions.ts:237
msgid "{count, plural, one {Rename item} other {Rename # items}}"
msgstr "{count, plural, one {Rename item} other {Rename # items}}"
#: generated/do-actions.ts:230
#: generated/do-actions.ts:224
msgid "{count, plural, one {Rename tag} other {Rename # tags}}"
msgstr "{count, plural, one {Rename tag} other {Rename # tags}}"
#: generated/do-actions.ts:185
#: generated/do-actions.ts:179
msgid "{count, plural, one {Restore item} other {Restore # items}}"
msgstr "{count, plural, one {Restore item} other {Restore # items}}"
#: generated/do-actions.ts:170
#: generated/do-actions.ts:164
msgid "{count, plural, one {Restore note} other {Restore # notes}}"
msgstr "{count, plural, one {Restore note} other {Restore # notes}}"
#: generated/do-actions.ts:174
#: generated/do-actions.ts:168
msgid "{count, plural, one {Restore notebook} other {Restore # notebooks}}"
msgstr "{count, plural, one {Restore notebook} other {Restore # notebooks}}"
@@ -468,11 +460,11 @@ msgstr "{count, plural, one {Restore notebook} other {Restore # notebooks}}"
msgid "{count, plural, one {Restoring item...} other {Restoring # items...}}"
msgstr "{count, plural, one {Restoring item...} other {Restoring # items...}}"
#: generated/actions.ts:201
#: generated/actions.ts:195
msgid "{count, plural, one {Shortcut created} other {# shortcuts created}}"
msgstr "{count, plural, one {Shortcut created} other {# shortcuts created}}"
#: generated/actions.ts:197
#: generated/actions.ts:191
msgid "{count, plural, one {Tag created} other {# tags created}}"
msgstr "{count, plural, one {Tag created} other {# tags created}}"
@@ -480,34 +472,30 @@ msgstr "{count, plural, one {Tag created} other {# tags created}}"
msgid "{count, plural, one {Tag deleted} other {# tags deleted}}"
msgstr "{count, plural, one {Tag deleted} other {# tags deleted}}"
#: generated/actions.ts:170
#: generated/actions.ts:164
msgid "{count, plural, one {Tag edited} other {# tags edited}}"
msgstr "{count, plural, one {Tag edited} other {# tags edited}}"
#: generated/do-actions.ts:82
#: generated/do-actions.ts:76
msgid "{count, plural, one {Unpin item} other {Unpin # items}}"
msgstr "{count, plural, one {Unpin item} other {Unpin # items}}"
#: generated/do-actions.ts:67
#: generated/do-actions.ts:61
msgid "{count, plural, one {Unpin note} other {Unpin # notes}}"
msgstr "{count, plural, one {Unpin note} other {Unpin # notes}}"
#: generated/do-actions.ts:71
#: generated/do-actions.ts:65
msgid "{count, plural, one {Unpin notebook} other {Unpin # notebooks}}"
msgstr "{count, plural, one {Unpin notebook} other {Unpin # notebooks}}"
#: generated/do-actions.ts:122
#: generated/do-actions.ts:116
msgid "{count, plural, one {Unpublish item} other {Unpublish # items}}"
msgstr "{count, plural, one {Unpublish item} other {Unpublish # items}}"
#: generated/do-actions.ts:113
#: generated/do-actions.ts:107
msgid "{count, plural, one {Unpublish note} other {Unpublish # notes}}"
msgstr "{count, plural, one {Unpublish note} other {Unpublish # notes}}"
#: generated/actions.ts:28
msgid "{count, plural, one {Version deleted} other {# versions deleted}}"
msgstr "{count, plural, one {Version deleted} other {# versions deleted}}"
#: src/strings.ts:2510
msgid "{count} characters"
msgstr "{count} characters"
@@ -1659,10 +1647,6 @@ msgstr "Clear data & reset account"
msgid "Clear default notebook"
msgstr "Clear default notebook"
#: src/strings.ts:2800
msgid "Clear history"
msgstr "Clear history"
#: src/strings.ts:1015
msgid "Clear logs"
msgstr "Clear logs"
@@ -2311,10 +2295,6 @@ msgstr "Delete account"
msgid "Delete all"
msgstr "Delete all"
#: src/strings.ts:2802
msgid "Delete all version history for this note?"
msgstr "Delete all version history for this note?"
#: src/strings.ts:2732
msgid "Delete attachment"
msgstr "Delete attachment"
@@ -3841,10 +3821,6 @@ msgstr "Keep"
msgid "Keep open"
msgstr "Keep open"
#: src/strings.ts:2800
msgid "Keep screen on"
msgstr "Keep screen on"
#: src/strings.ts:1361
msgid "Keep your data safe"
msgstr "Keep your data safe"
@@ -5215,10 +5191,6 @@ msgstr "Pressing \"X\" will hide the app in your system tray."
msgid "Prevent note title from appearing in tab/window title."
msgstr "Prevent note title from appearing in tab/window title."
#: src/strings.ts:2802
msgid "Prevent the screen from turning off while the editor is focused."
msgstr "Prevent the screen from turning off while the editor is focused."
#: src/strings.ts:2325
msgid "Preview attachment"
msgstr "Preview attachment"
@@ -7553,10 +7525,6 @@ msgstr "Verifying your email"
msgid "Version"
msgstr "Version"
#: src/strings.ts:2801
msgid "Version history cleared"
msgstr "Version history cleared"
#: src/strings.ts:50
msgid "Vibrate"
msgstr "Vibrate"

View File

@@ -138,7 +138,7 @@ msgstr ""
msgid "{count, plural, one {Are you sure you want to move this notebook to {selectedNotebookTitle}?} other {Are you sure you want to move these # notebooks {selectedNotebookTitle}?}}"
msgstr ""
#: generated/action-confirmations.ts:82
#: generated/action-confirmations.ts:76
msgid "{count, plural, one {Are you sure you want to permanently delete this item?} other {Are you sure you to permanently delete these items?}}"
msgstr ""
@@ -150,10 +150,6 @@ msgstr ""
msgid "{count, plural, one {Are you sure you want to permanently delete this notebook?} other {Are you sure you to permanently delete these notebooks?}}"
msgstr ""
#: generated/action-confirmations.ts:69
msgid "{count, plural, one {Are you sure you want to permanently delete this version?} other {Are you sure you to permanently delete these versions?}}"
msgstr ""
#: src/strings.ts:135
msgid "{count, plural, one {Attach image} other {Attach # images}}"
msgstr ""
@@ -166,7 +162,7 @@ msgstr ""
msgid "{count, plural, one {Attachment downloaded at {path}} other {#/{total} attachments downloaded as a zip file at {path}}}"
msgstr ""
#: generated/actions.ts:222
#: generated/actions.ts:216
msgid "{count, plural, one {Color renamed} other {# colors renamed}}"
msgstr ""
@@ -179,7 +175,7 @@ msgid "{count, plural, one {Delete color} other {Delete # colors}}"
msgstr ""
#: generated/do-actions.ts:12
#: generated/do-actions.ts:59
#: generated/do-actions.ts:53
msgid "{count, plural, one {Delete item} other {Delete # items}}"
msgstr ""
@@ -199,10 +195,6 @@ msgstr ""
msgid "{count, plural, one {Delete tag} other {Delete # tags}}"
msgstr ""
#: generated/do-actions.ts:36
msgid "{count, plural, one {Delete version} other {Delete # versions}}"
msgstr ""
#: generated/in-progress-actions.ts:16
msgid "{count, plural, one {Deleting attachment...} other {Deleting # attachments...}}"
msgstr ""
@@ -227,27 +219,27 @@ msgstr ""
msgid "{count, plural, one {Deleting tag...} other {Deleting # tags...}}"
msgstr ""
#: generated/do-actions.ts:280
#: generated/do-actions.ts:274
msgid "{count, plural, one {Download attachment} other {Download # attachments}}"
msgstr ""
#: generated/do-actions.ts:289
#: generated/do-actions.ts:283
msgid "{count, plural, one {Download item} other {Download # items}}"
msgstr ""
#: generated/do-actions.ts:214
#: generated/do-actions.ts:208
msgid "{count, plural, one {Edit item} other {Edit # items}}"
msgstr ""
#: generated/do-actions.ts:197
#: generated/do-actions.ts:191
msgid "{count, plural, one {Edit notebook} other {Edit # notebooks}}"
msgstr ""
#: generated/do-actions.ts:201
#: generated/do-actions.ts:195
msgid "{count, plural, one {Edit reminder} other {Edit # reminders}}"
msgstr ""
#: generated/do-actions.ts:193
#: generated/do-actions.ts:187
msgid "{count, plural, one {Edit tag} other {Edit # tags}}"
msgstr ""
@@ -263,41 +255,41 @@ msgstr ""
msgid "{count, plural, one {Item could not be unpublished} other {# items could not be unpublished}}"
msgstr ""
#: generated/actions.ts:214
#: generated/actions.ts:208
msgid "{count, plural, one {Item created} other {# items created}}"
msgstr ""
#: generated/actions.ts:47
#: generated/actions.ts:41
msgid "{count, plural, one {Item deleted} other {# items deleted}}"
msgstr ""
#: generated/actions.ts:185
#: generated/actions.ts:179
msgid "{count, plural, one {Item edited} other {# items edited}}"
msgstr ""
#: generated/actions.ts:70
#: generated/actions.ts:64
msgid "{count, plural, one {Item moved to trash} other {# items moved to trash}}"
msgstr ""
#: generated/actions.ts:86
#: generated/actions.ts:99
#: generated/actions.ts:80
#: generated/actions.ts:93
msgid "{count, plural, one {Item permanently deleted} other {# items permanently deleted}}"
msgstr ""
#: generated/actions.ts:116
#: generated/actions.ts:110
msgid "{count, plural, one {Item published} other {# items published}}"
msgstr ""
#: generated/actions.ts:231
#: generated/actions.ts:225
msgid "{count, plural, one {Item renamed} other {# items renamed}}"
msgstr ""
#: generated/actions.ts:149
#: generated/actions.ts:162
#: generated/actions.ts:143
#: generated/actions.ts:156
msgid "{count, plural, one {Item restored} other {# items restored}}"
msgstr ""
#: generated/actions.ts:133
#: generated/actions.ts:127
msgid "{count, plural, one {Item unpublished} other {# items unpublished}}"
msgstr ""
@@ -329,23 +321,23 @@ msgstr ""
msgid "{count, plural, one {Note exported} other {# notes exported}}"
msgstr ""
#: generated/actions.ts:55
#: generated/actions.ts:49
msgid "{count, plural, one {Note moved to trash} other {# notes moved to trash}}"
msgstr ""
#: generated/actions.ts:78
#: generated/actions.ts:72
msgid "{count, plural, one {Note permanently deleted} other {# notes permanently deleted}}"
msgstr ""
#: generated/actions.ts:107
#: generated/actions.ts:101
msgid "{count, plural, one {Note published} other {# notes published}}"
msgstr ""
#: generated/actions.ts:141
#: generated/actions.ts:135
msgid "{count, plural, one {Note restored} other {# notes restored}}"
msgstr ""
#: generated/actions.ts:124
#: generated/actions.ts:118
msgid "{count, plural, one {Note unpublished} other {# notes unpublished}}"
msgstr ""
@@ -353,7 +345,7 @@ msgstr ""
msgid "{count, plural, one {Note will be automatically deleted from all other devices & any future changes won't get synced. Are you sure you want to continue?} other {# notes will be automatically deleted from all other devices & any future changes won't get synced. Are you sure you want to continue?}}"
msgstr ""
#: generated/actions.ts:193
#: generated/actions.ts:187
msgid "{count, plural, one {Notebook created} other {# notebooks created}}"
msgstr ""
@@ -361,28 +353,28 @@ msgstr ""
msgid "{count, plural, one {Notebook deleted} other {# notebooks deleted}}"
msgstr ""
#: generated/actions.ts:174
#: generated/actions.ts:168
msgid "{count, plural, one {Notebook edited} other {# notebooks edited}}"
msgstr ""
#: generated/actions.ts:59
#: generated/actions.ts:53
msgid "{count, plural, one {Notebook moved to trash} other {# notebooks moved to trash}}"
msgstr ""
#: generated/actions.ts:82
#: generated/actions.ts:76
msgid "{count, plural, one {Notebook permanently deleted} other {# notebooks permanently deleted}}"
msgstr ""
#: generated/actions.ts:145
#: generated/actions.ts:139
msgid "{count, plural, one {Notebook restored} other {# notebooks restored}}"
msgstr ""
#: generated/do-actions.ts:147
#: generated/do-actions.ts:141
msgid "{count, plural, one {Permanently delete attachment} other {Permanently delete # attachments}}"
msgstr ""
#: generated/do-actions.ts:151
#: generated/do-actions.ts:162
#: generated/do-actions.ts:145
#: generated/do-actions.ts:156
msgid "{count, plural, one {Permanently delete item} other {Permanently delete # items}}"
msgstr ""
@@ -391,15 +383,15 @@ msgstr ""
msgid "{count, plural, one {permanently deleting item...} other {permanently deleting # items...}}"
msgstr ""
#: generated/do-actions.ts:105
#: generated/do-actions.ts:99
msgid "{count, plural, one {Pin item} other {Pin # items}}"
msgstr ""
#: generated/do-actions.ts:90
#: generated/do-actions.ts:84
msgid "{count, plural, one {Pin note} other {Pin # notes}}"
msgstr ""
#: generated/do-actions.ts:94
#: generated/do-actions.ts:88
msgid "{count, plural, one {Pin notebook} other {Pin # notebooks}}"
msgstr ""
@@ -407,11 +399,11 @@ msgstr ""
msgid "{count, plural, one {Prevent note from syncing} other {Prevent # notes from syncing}}"
msgstr ""
#: generated/do-actions.ts:139
#: generated/do-actions.ts:133
msgid "{count, plural, one {Publish item} other {Publish # items}}"
msgstr ""
#: generated/do-actions.ts:130
#: generated/do-actions.ts:124
msgid "{count, plural, one {Publish note} other {Publish # notes}}"
msgstr ""
@@ -419,47 +411,47 @@ msgstr ""
msgid "{count, plural, one {Reminder deleted} other {# reminders deleted}}"
msgstr ""
#: generated/do-actions.ts:259
#: generated/do-actions.ts:253
msgid "{count, plural, one {Remove attachment} other {Remove # attachments}}"
msgstr ""
#: generated/do-actions.ts:255
#: generated/do-actions.ts:249
msgid "{count, plural, one {Remove color} other {Remove # colors}}"
msgstr ""
#: generated/do-actions.ts:272
#: generated/do-actions.ts:266
msgid "{count, plural, one {Remove item} other {Remove # items}}"
msgstr ""
#: generated/do-actions.ts:251
#: generated/do-actions.ts:245
msgid "{count, plural, one {Remove shortcut} other {Remove # shortcuts}}"
msgstr ""
#: generated/do-actions.ts:222
#: generated/do-actions.ts:216
msgid "{count, plural, one {Rename attachment} other {Rename # attachments}}"
msgstr ""
#: generated/do-actions.ts:226
#: generated/do-actions.ts:220
msgid "{count, plural, one {Rename color} other {Rename # colors}}"
msgstr ""
#: generated/do-actions.ts:243
#: generated/do-actions.ts:237
msgid "{count, plural, one {Rename item} other {Rename # items}}"
msgstr ""
#: generated/do-actions.ts:230
#: generated/do-actions.ts:224
msgid "{count, plural, one {Rename tag} other {Rename # tags}}"
msgstr ""
#: generated/do-actions.ts:185
#: generated/do-actions.ts:179
msgid "{count, plural, one {Restore item} other {Restore # items}}"
msgstr ""
#: generated/do-actions.ts:170
#: generated/do-actions.ts:164
msgid "{count, plural, one {Restore note} other {Restore # notes}}"
msgstr ""
#: generated/do-actions.ts:174
#: generated/do-actions.ts:168
msgid "{count, plural, one {Restore notebook} other {Restore # notebooks}}"
msgstr ""
@@ -468,11 +460,11 @@ msgstr ""
msgid "{count, plural, one {Restoring item...} other {Restoring # items...}}"
msgstr ""
#: generated/actions.ts:201
#: generated/actions.ts:195
msgid "{count, plural, one {Shortcut created} other {# shortcuts created}}"
msgstr ""
#: generated/actions.ts:197
#: generated/actions.ts:191
msgid "{count, plural, one {Tag created} other {# tags created}}"
msgstr ""
@@ -480,34 +472,30 @@ msgstr ""
msgid "{count, plural, one {Tag deleted} other {# tags deleted}}"
msgstr ""
#: generated/actions.ts:170
#: generated/actions.ts:164
msgid "{count, plural, one {Tag edited} other {# tags edited}}"
msgstr ""
#: generated/do-actions.ts:82
#: generated/do-actions.ts:76
msgid "{count, plural, one {Unpin item} other {Unpin # items}}"
msgstr ""
#: generated/do-actions.ts:67
#: generated/do-actions.ts:61
msgid "{count, plural, one {Unpin note} other {Unpin # notes}}"
msgstr ""
#: generated/do-actions.ts:71
#: generated/do-actions.ts:65
msgid "{count, plural, one {Unpin notebook} other {Unpin # notebooks}}"
msgstr ""
#: generated/do-actions.ts:122
#: generated/do-actions.ts:116
msgid "{count, plural, one {Unpublish item} other {Unpublish # items}}"
msgstr ""
#: generated/do-actions.ts:113
#: generated/do-actions.ts:107
msgid "{count, plural, one {Unpublish note} other {Unpublish # notes}}"
msgstr ""
#: generated/actions.ts:28
msgid "{count, plural, one {Version deleted} other {# versions deleted}}"
msgstr ""
#: src/strings.ts:2510
msgid "{count} characters"
msgstr ""
@@ -1659,10 +1647,6 @@ msgstr ""
msgid "Clear default notebook"
msgstr ""
#: src/strings.ts:2800
msgid "Clear history"
msgstr ""
#: src/strings.ts:1015
msgid "Clear logs"
msgstr ""
@@ -2300,10 +2284,6 @@ msgstr ""
msgid "Delete all"
msgstr ""
#: src/strings.ts:2802
msgid "Delete all version history for this note?"
msgstr ""
#: src/strings.ts:2732
msgid "Delete attachment"
msgstr ""
@@ -3821,10 +3801,6 @@ msgstr ""
msgid "Keep open"
msgstr ""
#: src/strings.ts:2800
msgid "Keep screen on"
msgstr ""
#: src/strings.ts:1361
msgid "Keep your data safe"
msgstr ""
@@ -5189,10 +5165,6 @@ msgstr ""
msgid "Prevent note title from appearing in tab/window title."
msgstr ""
#: src/strings.ts:2802
msgid "Prevent the screen from turning off while the editor is focused."
msgstr ""
#: src/strings.ts:2325
msgid "Preview attachment"
msgstr ""
@@ -7503,10 +7475,6 @@ msgstr ""
msgid "Version"
msgstr ""
#: src/strings.ts:2801
msgid "Version history cleared"
msgstr ""
#: src/strings.ts:50
msgid "Vibrate"
msgstr ""

View File

@@ -30,8 +30,7 @@ const DO_ACTIONS = [
"notebook",
"tag",
"color",
"attachment",
"version"
"attachment"
]
},
{ action: "unpin", label: "Unpin", dataTypes: ["note", "notebook"] },
@@ -74,7 +73,7 @@ const ACTIONS = [
{
action: "deleted",
label: "deleted",
dataTypes: ["attachment", "reminder", "tag", "note", "notebook", "version"]
dataTypes: ["attachment", "reminder", "tag", "note", "notebook"]
},
{
action: "movedToTrash",
@@ -122,12 +121,12 @@ const ACTION_CONFIRMATIONS = [
"tag",
"color",
"attachment"
]
],
},
{
action: "permanentlyDelete",
label: "permanently delete",
dataTypes: ["note", "notebook", "version"]
dataTypes: ["note", "notebook"]
}
];
@@ -210,12 +209,6 @@ const DATA_TYPES = {
singularCamelCase: `Shortcut`,
plural: `shortcuts`,
pluralCamelCase: `Shortcuts`
},
version: {
singular: `version`,
singularCamelCase: `Version`,
plural: `versions`,
pluralCamelCase: `Versions`
}
};

View File

@@ -2796,15 +2796,5 @@ Continue without attachments?`,
t`Colornote password for ${filename}`,
colorNotPasswordForDesc: () =>
t`The password for decrypting the Colornote backup file.`,
deleteItem: () => t`Delete item`,
keepScreenOn: () => t`Keep screen on`,
keepScreenOnDesc: () =>
t`Prevent the screen from turning off while the editor is focused.`,
clearHistory: () => t`Clear history`,
historyCleared: () => t`Version history cleared`,
clearHistoryConfirmation: () => t`Delete all version history for this note?`,
deleteVersion: () => doActions.delete.version(1),
deleteVersionConfirmation: () =>
actionConfirmations.permanentlyDelete.version(1),
versionDeleted: () => actions.deleted.version(1)
deleteItem: () => t`Delete item`
};