mobile: add inbox api settings

This commit is contained in:
Ammar Ahmed
2026-01-24 12:32:12 +05:00
parent 9a2ce9873b
commit f7d86420ea
17 changed files with 1284 additions and 49 deletions

View File

@@ -31,6 +31,7 @@ import {
generateCryptoKeyFallback
} from "./encryption";
import { MMKV } from "./mmkv";
import OpenPGP from "react-native-fast-openpgp";
export class KV {
storage: MMKVInstance;
@@ -136,11 +137,30 @@ export const Storage: IStorage = {
clear(): Promise<void> {
return DefaultStorage.clear();
},
generateCryptoKeyPair() {
throw new Error("Not implemented");
async generatePGPKeyPair() {
const keys = await OpenPGP.generate({
name: "NN",
email: "NN@NN.NN"
});
return { publicKey: keys.publicKey, privateKey: keys.privateKey };
},
decryptAsymmetric() {
throw new Error("Not implemented");
async validatePGPKeyPair(keys) {
try {
const dummyData = JSON.stringify({
favorite: true,
title: "Hello world"
});
const encrypted = await OpenPGP.encrypt(dummyData, keys.publicKey);
const decrypted = await OpenPGP.decrypt(encrypted, keys.privateKey, "");
return decrypted === dummyData;
} catch (e) {
console.error("PGP key pair validation error:", e);
return false;
}
},
async decryptPGPMessage(privateKeyArmored, encryptedMessage) {
return await OpenPGP.decrypt(encryptedMessage, privateKeyArmored, "");
},
getAllKeys(): Promise<string[]> {
return DefaultStorage.getAllKeys();

View File

@@ -0,0 +1,169 @@
/*
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, ScrollView } from "react-native";
import { strings } from "@notesnook/intl";
import { db } from "../../../common/database";
import { Button } from "../../ui/button";
import Input from "../../ui/input";
import Paragraph from "../../ui/typography/paragraph";
import Heading from "../../ui/typography/heading";
import { DefaultAppStyles } from "../../../utils/styles";
import { AppFontSize } from "../../../utils/size";
import { ToastManager, presentSheet } from "../../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { Pressable } from "../../ui/pressable";
const getExpiryOptions = () => [
{ label: strings.expiryOneDay(), value: 24 * 60 * 60 * 1000 },
{ label: strings.expiryOneWeek(), value: 7 * 24 * 60 * 60 * 1000 },
{ label: strings.expiryOneMonth(), value: 30 * 24 * 60 * 60 * 1000 },
{ label: strings.expiryOneYear(), value: 365 * 24 * 60 * 60 * 1000 },
{ label: strings.never(), value: -1 }
];
type AddApiKeySheetProps = {
close?: (ctx?: string | undefined) => void;
onAdd: () => void;
};
export default function AddApiKeySheet({ close, onAdd }: AddApiKeySheetProps) {
const { colors } = useThemeColors();
const keyNameRef = useRef<string>("");
const [selectedExpiry, setSelectedExpiry] = useState(
getExpiryOptions()[2].value
);
const [isCreating, setIsCreating] = useState(false);
const handleCreate = async () => {
try {
if (!keyNameRef.current || !keyNameRef.current.trim()) {
ToastManager.show({
message: strings.enterKeyName(),
type: "error"
});
return;
}
setIsCreating(true);
await db.inboxApiKeys.create(keyNameRef.current, selectedExpiry);
ToastManager.show({
message: strings.apiKeyCreatedSuccessfully(),
type: "success"
});
onAdd();
close?.();
} catch (error) {
const message = error instanceof Error ? error.message : "";
ToastManager.show({
message: strings.failedToCreateApiKey(message),
type: "error"
});
} finally {
setIsCreating(false);
}
};
return (
<ScrollView
contentContainerStyle={{
paddingHorizontal: DefaultAppStyles.GAP,
gap: DefaultAppStyles.GAP_VERTICAL,
paddingTop: DefaultAppStyles.GAP_VERTICAL,
paddingBottom: DefaultAppStyles.GAP_VERTICAL * 2
}}
>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center"
}}
>
<Heading size={AppFontSize.xl}>{strings.createApiKey()}</Heading>
</View>
<View style={{ gap: DefaultAppStyles.GAP_VERTICAL }}>
<Paragraph size={AppFontSize.sm}>{strings.keyName()}</Paragraph>
<Input
placeholder={strings.exampleKeyName()}
onChangeText={(text) => {
keyNameRef.current = text;
}}
/>
</View>
<View style={{ gap: DefaultAppStyles.GAP_VERTICAL }}>
<Paragraph size={AppFontSize.sm}>{strings.expiresIn()}</Paragraph>
<View
style={{
flexDirection: "row",
flexWrap: "wrap",
gap: DefaultAppStyles.GAP_SMALL
}}
>
{getExpiryOptions().map((option) => (
<Pressable
key={option.label}
onPress={() => setSelectedExpiry(option.value)}
type={
selectedExpiry === option.value ? "selected" : "transparent"
}
style={{
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
paddingHorizontal: DefaultAppStyles.GAP
}}
>
<Paragraph
size={AppFontSize.sm}
color={
selectedExpiry === option.value
? colors.selected.paragraph
: colors.primary.paragraph
}
>
{option.label}
</Paragraph>
</Pressable>
))}
</View>
</View>
<Button
title={isCreating ? strings.creating() : strings.create()}
type="accent"
width="100%"
loading={isCreating}
disabled={isCreating}
onPress={handleCreate}
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL
}}
/>
</ScrollView>
);
}
AddApiKeySheet.present = (onAdd: () => void) => {
presentSheet({
component: (ref, close, update) => (
<AddApiKeySheet close={close} onAdd={onAdd} />
)
});
};

View File

@@ -48,7 +48,6 @@ export const Notice = ({
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingLeft: 5,
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
flexDirection: "row",
backgroundColor: colors.secondary.background,
@@ -63,6 +62,9 @@ export const Notice = ({
size={isSmall ? AppFontSize.md + 2 : AppFontSize.xxl}
name={type}
color={type === "alert" ? colors.error.icon : colors.primary.accent}
style={{
marginTop: isSmall ? 3 : 5
}}
/>
<Paragraph
style={{

View File

@@ -155,14 +155,6 @@ const SheetWrapper = ({
onClose={_onClose}
>
{children}
{bottomPadding ? (
<View
style={{
height: bottomInsets
}}
/>
) : null}
</ActionSheet>
</ScopedThemeProvider>
);

View File

@@ -46,6 +46,7 @@ import SoundPicker from "./sound-picker";
import ThemeSelector from "./theme-selector";
import { TitleFormat } from "./title-format";
import { NotesnookCircle } from "./notesnook-circle";
import { ManageInboxKeys, InboxKeysList } from "./manage-inbox-keys";
export const components: { [name: string]: ReactElement } = {
homeselector: <HomePicker />,
@@ -75,5 +76,7 @@ export const components: { [name: string]: ReactElement } = {
"sidebar-tab-selector": <SidebarTabPicker />,
"change-password": <ChangePassword />,
"change-email": <ChangeEmail />,
"notesnook-circle": <NotesnookCircle />
"notesnook-circle": <NotesnookCircle />,
"manage-inbox-keys": <ManageInboxKeys />,
"inbox-keys": <InboxKeysList />
};

View File

@@ -0,0 +1,474 @@
import { usePromise } from "@notesnook/common";
import { db } from "../../common/database";
import { ActivityIndicator, ScrollView, View } from "react-native";
import { Button } from "../../components/ui/button";
import { strings } from "@notesnook/intl";
import Input from "../../components/ui/input";
import { useEffect, useRef, useState } from "react";
import { SerializedKeyPair } from "@notesnook/crypto";
import Paragraph from "../../components/ui/typography/paragraph";
import { DefaultAppStyles } from "../../utils/styles";
import { ToastManager } from "../../services/event-manager";
import Navigation from "../../services/navigation";
import { Storage } from "../../common/database/storage";
import { Notice } from "../../components/ui/notice";
import { presentDialog } from "../../components/dialog/functions";
import { useSettingStore } from "../../stores/use-setting-store";
import { InboxApiKey } from "@notesnook/core";
import { IconButton } from "../../components/ui/icon-button";
import Clipboard from "@react-native-clipboard/clipboard";
import { useThemeColors } from "@notesnook/theme";
import dayjs from "dayjs";
import Heading from "../../components/ui/typography/heading";
import { AppFontSize } from "../../utils/size";
import AddApiKeySheet from "../../components/sheets/add-api-key";
const ManageInboxKeys = () => {
const keys = usePromise(() => db.user.getInboxKeys());
const keysEdited = useRef<SerializedKeyPair>(undefined);
if (keys.status === "fulfilled" && keys.value && !keysEdited.current) {
keysEdited.current = keys.value;
}
return (
<ScrollView
contentContainerStyle={{
paddingHorizontal: DefaultAppStyles.GAP,
gap: DefaultAppStyles.GAP_VERTICAL,
marginTop: DefaultAppStyles.GAP_VERTICAL
}}
>
<Notice type="alert" text={strings.changingInboxPgpKeysNotice()} />
<Paragraph>{strings.publicKey()}</Paragraph>
<Input
defaultValue={keysEdited.current?.publicKey}
multiline
onChangeText={(value) => {
if (keysEdited.current) {
keysEdited.current.publicKey = value;
}
}}
style={{
height: 150
}}
wrapperStyle={{
height: 150
}}
/>
<Paragraph>{strings.privateKey()}</Paragraph>
<Input
defaultValue={keysEdited.current?.privateKey}
multiline
onChangeText={(value) => {
if (keysEdited.current) {
keysEdited.current.privateKey = value;
}
}}
style={{
height: 150
}}
wrapperStyle={{
height: 150
}}
/>
<Button
title={strings.save()}
type="accent"
width={"100%"}
onPress={async () => {
try {
if (keysEdited.current) {
const valid = await Storage.validatePGPKeyPair(
keysEdited.current
);
if (!valid) {
ToastManager.show({
message: strings.invalidPgpKeyPair(),
type: "error"
});
return;
}
presentDialog({
title: strings.areYouSure(),
paragraph: strings.changingInboxPgpKeysNotice(),
positiveText: strings.yes(),
negativeText: strings.no(),
positivePress: async () => {
db.user?.saveInboxKeys(keysEdited.current!);
ToastManager.show({
message: strings.inboxKeysSaved(),
type: "success"
});
Navigation.goBack();
return true;
}
});
}
} catch (e) {
ToastManager.error(e as Error);
}
}}
/>
</ScrollView>
);
};
const InboxKeysList = () => {
const inboxEnabled = useSettingStore((state) => state.inboxEnabled);
const apiKeysPromise = usePromise(
() => db.inboxApiKeys.get(),
[inboxEnabled]
);
const { colors } = useThemeColors();
if (apiKeysPromise.status === "pending") {
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP,
gap: DefaultAppStyles.GAP_VERTICAL,
width: "100%"
}}
>
<ActivityIndicator size="small" color={colors.primary.accent} />
<Paragraph color={colors.secondary.paragraph}>
{strings.loadingApiKeys()}
</Paragraph>
</View>
);
}
if (apiKeysPromise.status === "rejected") {
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP,
gap: DefaultAppStyles.GAP_VERTICAL,
width: "100%"
}}
>
<Paragraph color={colors.error.paragraph}>
{strings.failedToLoadApiKeys()}
</Paragraph>
<Button
title={strings.retry()}
type="accent"
onPress={() => apiKeysPromise.refresh()}
/>
</View>
);
}
const apiKeys = apiKeysPromise.value || [];
return (
<ScrollView
contentContainerStyle={{
gap: DefaultAppStyles.GAP_VERTICAL,
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
width: "100%",
paddingHorizontal: DefaultAppStyles.GAP,
paddingBottom: 50
}}
>
{apiKeys.length === 0 ? (
<View
style={{
padding: DefaultAppStyles.GAP * 2,
borderWidth: 1,
borderStyle: "dashed",
borderColor: colors.secondary.border,
borderRadius: 5,
backgroundColor: colors.secondary.background,
alignItems: "center"
}}
>
<Paragraph color={colors.secondary.paragraph}>
{strings.createFirstApiKey()}
</Paragraph>
</View>
) : (
<View style={{ gap: 0 }}>
{apiKeys.map((key, i) => (
<ApiKeyItem
key={key.key}
apiKey={key}
onRevoke={() => apiKeysPromise.refresh()}
isAtEnd={i === apiKeys.length - 1}
/>
))}
<Button
title={strings.createKey()}
type="accent"
style={{
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
width: "100%"
}}
onPress={() => {
if (apiKeys.length >= 10) {
presentDialog({
title: strings.apiKeysLimitReached(),
paragraph: strings.apiKeysLimitReachedMessage(),
positiveText: strings.ok()
});
} else {
AddApiKeySheet.present(() => apiKeysPromise.refresh());
}
}}
/>
</View>
)}
</ScrollView>
);
};
const VIEW_KEY_TIMEOUT = 15;
type ApiKeyItemProps = {
apiKey: InboxApiKey;
onRevoke: () => void;
isAtEnd: boolean;
};
function ApiKeyItem({ apiKey, onRevoke, isAtEnd }: ApiKeyItemProps) {
const { colors } = useThemeColors();
const [copied, setCopied] = useState(false);
const [viewing, setViewing] = useState(false);
const [isRevoking, setIsRevoking] = useState(false);
const [secondsLeft, setSecondsLeft] = useState(VIEW_KEY_TIMEOUT);
async function viewKey() {
presentDialog({
title: strings.authenticateToViewApiKey(),
paragraph: strings.enterPasswordToViewApiKey(),
positiveText: strings.authenticate(),
negativeText: strings.cancel(),
input: true,
secureTextEntry: true,
inputPlaceholder: strings.accountPassword(),
positivePress: async (value) => {
try {
const verified = await db.user.verifyPassword(value);
if (!verified) {
ToastManager.show({
message: strings.invalidPassword(),
type: "error"
});
return false;
}
setViewing(true);
return true;
} catch (error) {
ToastManager.error(error as Error);
return false;
}
}
});
}
async function copyToClipboard() {
if (!viewing) return;
try {
Clipboard.setString(apiKey.key);
setCopied(true);
ToastManager.show({
message: strings.apiKeyCopiedToClipboard(),
type: "success"
});
} catch (error) {
ToastManager.show({
message: strings.failedToCopyToClipboard(),
type: "error"
});
}
}
useEffect(() => {
if (copied) {
const timer = setTimeout(() => {
setCopied(false);
}, 1000);
return () => clearTimeout(timer);
}
}, [copied]);
useEffect(() => {
if (viewing) {
setSecondsLeft(VIEW_KEY_TIMEOUT);
const interval = setInterval(() => {
setSecondsLeft((prev) => {
if (prev <= 1) {
setViewing(false);
return VIEW_KEY_TIMEOUT;
}
return prev - 1;
});
}, 1000);
return () => clearInterval(interval);
}
}, [viewing]);
const isApiKeyExpired = Date.now() > apiKey.expiryDate;
return (
<View
style={{
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
borderBottomWidth: isAtEnd ? 0 : 1,
borderBottomColor: colors.secondary.border
}}
>
<View
style={{
flexDirection: "column",
gap: DefaultAppStyles.GAP_VERTICAL
}}
>
<View
style={{
flexDirection: "row",
alignItems: "center",
gap: DefaultAppStyles.GAP_SMALL
}}
>
<Heading size={AppFontSize.md}>{apiKey.name}</Heading>
{isApiKeyExpired && (
<View
style={{
paddingVertical: 4,
paddingHorizontal: 8,
backgroundColor: colors.error.background,
borderRadius: 5
}}
>
<Paragraph
color={colors.static.white}
size={AppFontSize.xxs}
style={{ fontWeight: "bold" }}
>
EXPIRED
</Paragraph>
</View>
)}
</View>
<View style={{ gap: 4 }}>
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
{apiKey.lastUsedAt
? `${strings.lastUsedOn()} ${dayjs(apiKey.lastUsedAt).format("MMM DD, YYYY")}`
: strings.neverUsed()}
</Paragraph>
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
{strings.createdOn()}{" "}
{dayjs(apiKey.dateCreated).format("MMM DD, YYYY")}
</Paragraph>
<Paragraph size={AppFontSize.xs} color={colors.secondary.paragraph}>
{apiKey.expiryDate === -1
? strings.neverExpires()
: `${isApiKeyExpired ? strings.expired() : strings.expiresOn()} ${dayjs(apiKey.expiryDate).format("MMM DD, YYYY")}`}
</Paragraph>
</View>
<View
style={{
flexDirection: "row",
alignItems: "center",
gap: DefaultAppStyles.GAP_SMALL
}}
>
<Input
editable={false}
value={
viewing
? apiKey.key
: `${apiKey.key.slice(0, 10)}${"*".repeat(
apiKey.key.length - 10
)}`
}
style={{
flex: 1,
fontFamily: "monospace",
fontSize: AppFontSize.xs
}}
wrapperStyle={{
flex: 1
}}
/>
{!viewing && (
<IconButton
name="eye-off-outline"
color={colors.primary.icon}
onPress={() => viewKey()}
/>
)}
{viewing && (
<>
<Paragraph
style={{
fontFamily: "monospace",
minWidth: 35,
textAlign: "center"
}}
color={colors.primary.accent}
>
{secondsLeft}s
</Paragraph>
<IconButton
name={copied ? "check" : "content-copy"}
color={colors.primary.icon}
onPress={() => copyToClipboard()}
/>
</>
)}
<IconButton
name="delete-outline"
color={colors.error.icon}
disabled={isRevoking}
onPress={async () => {
presentDialog({
title: strings.revokeInboxApiKey(apiKey.name),
paragraph: strings.revokeApiKeyConfirmation(apiKey.name),
positiveText: strings.revoke(),
negativeText: strings.cancel(),
positiveType: "error",
positivePress: async () => {
try {
setIsRevoking(true);
await db.inboxApiKeys.revoke(apiKey.key);
onRevoke();
ToastManager.show({
message: strings.apiKeyRevoked(),
type: "success"
});
return true;
} catch (error) {
ToastManager.show({
message: strings.failedToRevokeApiKey(),
type: "error"
});
return false;
} finally {
setIsRevoking(false);
}
}
});
}}
/>
</View>
</View>
</View>
);
}
export { ManageInboxKeys, InboxKeysList };

View File

@@ -203,21 +203,21 @@ const _SectionItem = ({ item }: { item: SettingSection }) => {
flexShrink: 1
}}
>
<View
style={{
width: 40,
height: 40,
justifyContent: "center",
alignItems: "center",
marginRight: 12,
backgroundColor:
item.component === "colorpicker"
? colors.primary.accent
: undefined,
borderRadius: 100
}}
>
{!!item.icon && (
{item.icon ? (
<View
style={{
width: 40,
height: 40,
justifyContent: "center",
alignItems: "center",
marginRight: 12,
backgroundColor:
item.component === "colorpicker"
? colors.primary.accent
: undefined,
borderRadius: 100
}}
>
<Icon
color={
item.type === "danger"
@@ -227,25 +227,28 @@ const _SectionItem = ({ item }: { item: SettingSection }) => {
name={item.icon}
size={30}
/>
)}
</View>
</View>
) : null}
<View
style={{
flexShrink: 1,
paddingRight: item.type === "switch" ? 10 : 0
paddingRight: item.type === "switch" ? 10 : 0,
flex: item.type === "component" ? 1 : 0
}}
>
<Heading
color={
item.type === "danger"
? colors.error.paragraph
: colors.primary.heading
}
size={AppFontSize.sm}
>
{typeof item.name === "function" ? item.name(current) : item.name}
</Heading>
{item.name ? (
<Heading
color={
item.type === "danger"
? colors.error.paragraph
: colors.primary.heading
}
size={AppFontSize.sm}
>
{typeof item.name === "function" ? item.name(current) : item.name}
</Heading>
) : null}
{!!item.description && (
<Paragraph

View File

@@ -72,6 +72,7 @@ import { logoutUser } from "./logout";
import { SettingSection } from "./types";
import { getTimeLeft } from "./user-section";
import { EDITOR_LINE_HEIGHT } from "../../utils/constants";
import { useSettingStore } from "../../stores/use-setting-store";
export const settingsGroups: SettingSection[] = [
{
@@ -646,6 +647,63 @@ export const settingsGroups: SettingSection[] = [
type: "screen",
description: strings.notesnookCircleDesc(),
component: "notesnook-circle"
},
{
id: "inbox-api",
name: strings.inboxAPI(),
icon: "inbox",
type: "screen",
description: strings.inboxAPIDesc(),
sections: [
{
id: "toggle-inbox-api",
name: strings.enableInboxAPI(),
description: strings.enableInboxAPIDesc(),
type: "switch",
useHook: () => useSettingStore((state) => state.inboxEnabled),
getter: (current) => current,
modifer: async (current) => {
if (current) {
presentDialog({
title: strings.disableInboxAPI(),
paragraph: strings.disableInboxAPIDesc(),
positiveText: strings.disable(),
positivePress: async () => {
await db.user.discardInboxKeys();
useSettingStore.setState({
inboxEnabled: false
});
return true;
}
});
return;
}
try {
await db.user.getInboxKeys();
useSettingStore.setState({
inboxEnabled: true
});
} catch (e) {
console.log(e);
}
}
},
{
id: "manage-inbox-keys",
name: strings.manageInboxKeys(),
description: strings.manageInboxKeysDesc(),
type: "screen",
component: "manage-inbox-keys"
},
{
id: "inbox-keys",
name: strings.viewAPIKeys(),
description: strings.viewAPIKeysDesc(),
type: "screen",
component: "inbox-keys"
}
]
}
]
},

View File

@@ -143,6 +143,7 @@ export interface SettingStore {
isOldAppLock: () => boolean;
initialUrl: string | null;
refresh: () => void;
inboxEnabled: boolean;
}
const { width, height } = Dimensions.get("window");
@@ -248,12 +249,14 @@ export const useSettingStore = create<SettingStore>((set, get) => ({
? initialWindowMetrics.insets
: { top: 0, right: 0, left: 0, bottom: 0 },
initialUrl: null,
refresh: () => {
refresh: async () => {
set({
dayFormat: db.settings.getDayFormat(),
timeFormat: db.settings.getTimeFormat(),
dateFormat: db.settings?.getTimeFormat(),
weekFormat: db.settings.getWeekFormat()
weekFormat: db.settings.getWeekFormat(),
inboxEnabled: await db.user.hasInboxKeys()
});
}
},
inboxEnabled: false
}));

View File

@@ -9,6 +9,9 @@ import "./app/common/logger/index";
import { setI18nGlobal } from "@notesnook/intl";
import { i18n } from "@lingui/core";
import Config from "react-native-config";
import OpenPGP from "react-native-fast-openpgp";
OpenPGP.useJSI = false;
let domParser;
Object.defineProperty(global, "DOMParser", {

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/mobile",
"version": "3.3.13-beta.0",
"version": "3.3.13-beta.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/mobile",
"version": "3.3.13-beta.0",
"version": "3.3.13-beta.1",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
@@ -84,6 +84,7 @@
"react-native-device-info": "^14.1.1",
"react-native-drax": "^0.10.2",
"react-native-exit-app": "github:ammarahm-ed/react-native-exit-app",
"react-native-fast-openpgp": "^2.9.3",
"react-native-file-viewer": "^2.1.1",
"react-native-format-currency": "0.0.5",
"react-native-gesture-handler": "2.28.0",
@@ -10883,6 +10884,12 @@
"node": ">=16"
}
},
"node_modules/flatbuffers": {
"version": "24.3.25",
"resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-24.3.25.tgz",
"integrity": "sha512-3HDgPbgiwWMI9zVB7VYBHaMrbOO7Gm0v+yD2FV/sCKj+9NDeVL7BOBYUuhWAQGKWOzBo8S9WdMvV0eixO233XQ==",
"license": "Apache-2.0"
},
"node_modules/flatted": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
@@ -17532,6 +17539,26 @@
"resolved": "git+ssh://git@github.com/ammarahm-ed/react-native-exit-app.git#3087d4bce1320227384d24b34b354600457a817d",
"license": "MIT"
},
"node_modules/react-native-fast-openpgp": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/react-native-fast-openpgp/-/react-native-fast-openpgp-2.9.3.tgz",
"integrity": "sha512-JF+h0e45mi1kHSYfpXIDWnH5x3uFHU8DqGsuqZo7JWKfmE6MF7ppwvI4dyc5rUdGoZI752IdxI33F86UcR/fnQ==",
"license": "MIT",
"workspaces": [
"example"
],
"dependencies": {
"big-integer": "^1.6.51",
"flatbuffers": "24.3.25"
},
"engines": {
"node": ">= 18.0.0"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-file-viewer": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/react-native-file-viewer/-/react-native-file-viewer-2.1.5.tgz",

View File

@@ -100,6 +100,7 @@
"react-native-device-info": "^14.1.1",
"react-native-drax": "^0.10.2",
"react-native-exit-app": "github:ammarahm-ed/react-native-exit-app",
"react-native-fast-openpgp": "^2.9.3",
"react-native-file-viewer": "^2.1.1",
"react-native-format-currency": "0.0.5",
"react-native-gesture-handler": "2.28.0",

View File

@@ -121,7 +121,8 @@ const EXTRA_ICON_NAMES = [
"calendar-today",
"bomb",
"bomb-off",
"cancel"
"cancel",
"inbox"
];
const __filename = fileURLToPath(import.meta.url);

View File

@@ -607,6 +607,22 @@ msgstr "{words, plural, other {# selected}}"
msgid "#notesnook"
msgstr "#notesnook"
#: src/strings.ts:2659
msgid "1 day"
msgstr "1 day"
#: src/strings.ts:2661
msgid "1 month"
msgstr "1 month"
#: src/strings.ts:2660
msgid "1 week"
msgstr "1 week"
#: src/strings.ts:2662
msgid "1 year"
msgstr "1 year"
#: src/strings.ts:1583
msgid "12-hour"
msgstr "12-hour"
@@ -699,6 +715,10 @@ msgstr "Add a tag"
msgid "Add color"
msgstr "Add color"
#: src/strings.ts:2647
msgid "Add key"
msgstr "Add key"
#: src/strings.ts:895
msgid "Add notebook"
msgstr "Add notebook"
@@ -871,6 +891,26 @@ msgstr "and we will manually confirm your account."
msgid "ANNOUNCEMENT"
msgstr "ANNOUNCEMENT"
#: src/strings.ts:2677
msgid "API key copied to clipboard"
msgstr "API key copied to clipboard"
#: src/strings.ts:2655
msgid "API key created successfully"
msgstr "API key created successfully"
#: src/strings.ts:2682
msgid "API key revoked"
msgstr "API key revoked"
#: src/strings.ts:2648
msgid "API Keys"
msgstr "API Keys"
#: src/strings.ts:2669
msgid "API Keys Limit Reached"
msgstr "API Keys Limit Reached"
#: src/strings.ts:252
msgid "App data has been cleared. Kindly relaunch the app to login again."
msgstr "App data has been cleared. Kindly relaunch the app to login again."
@@ -950,6 +990,10 @@ msgstr "Are you sure you want to remove your name?"
msgid "Are you sure you want to remove your profile picture?"
msgstr "Are you sure you want to remove your profile picture?"
#: src/strings.ts:2681
msgid "Are you sure you want to revoke the key \"{name}\"? All inbox actions using this key will stop working immediately."
msgstr "Are you sure you want to revoke the key \"{name}\"? All inbox actions using this key will stop working immediately."
#: src/strings.ts:1323
msgid "Are you sure?"
msgstr "Are you sure?"
@@ -1028,6 +1072,14 @@ msgstr "Audios"
msgid "Auth server"
msgstr "Auth server"
#: src/strings.ts:2675
msgid "Authenticate"
msgstr "Authenticate"
#: src/strings.ts:2672
msgid "Authenticate to view API key"
msgstr "Authenticate to view API key"
#: src/strings.ts:1795
msgid "Authenticated as {email}"
msgstr "Authenticated as {email}"
@@ -1309,6 +1361,10 @@ msgstr "Cancel subscription"
msgid "Cancel upload"
msgstr "Cancel upload"
#: src/strings.ts:2671
msgid "Cannot create more than 10 api keys at a time. Please revoke some existing keys before creating new ones."
msgstr "Cannot create more than 10 api keys at a time. Please revoke some existing keys before creating new ones."
#: src/strings.ts:2301
msgid "Cell background color"
msgstr "Cell background color"
@@ -1410,6 +1466,10 @@ msgstr "Change your primary two-factor authentication method"
msgid "Changes from other devices won't be updated in the editor in real-time."
msgstr "Changes from other devices won't be updated in the editor in real-time."
#: src/strings.ts:2691
msgid "Changing Inbox PGP keys will delete all your unsynced inbox items."
msgstr "Changing Inbox PGP keys will delete all your unsynced inbox items."
#: src/strings.ts:734
msgid "Changing password is an irreversible process. You will be logged out from all your devices. Please make sure you do not close the app while your password is changing and have good internet connection."
msgstr "Changing password is an irreversible process. You will be logged out from all your devices. Please make sure you do not close the app while your password is changing and have good internet connection."
@@ -1886,6 +1946,14 @@ msgstr "Create a shortcut"
msgid "Create account"
msgstr "Create account"
#: src/strings.ts:2650
msgid "Create API Key"
msgstr "Create API Key"
#: src/strings.ts:2667
msgid "Create Key"
msgstr "Create Key"
#: src/strings.ts:581
msgid "Create link"
msgstr "Create link"
@@ -1914,15 +1982,27 @@ msgstr "Create vault"
msgid "Create your account"
msgstr "Create your account"
#: src/strings.ts:2666
msgid "Create your first api key to get started."
msgstr "Create your first api key to get started."
#: src/strings.ts:2229
msgid "Created at"
msgstr "Created at"
#: src/strings.ts:2686
msgid "Created on"
msgstr "Created on"
#. placeholder {0}: type === "full" ? " full" : ""
#: src/strings.ts:1344
msgid "Creating a{0} backup"
msgstr "Creating a{0} backup"
#: src/strings.ts:2658
msgid "Creating..."
msgstr "Creating..."
#: src/strings.ts:2049
msgid "Credentials"
msgstr "Credentials"
@@ -2197,6 +2277,10 @@ msgstr "Disable auto sync"
msgid "Disable editor margins"
msgstr "Disable editor margins"
#: src/strings.ts:2644
msgid "Disable Inbox API"
msgstr "Disable Inbox API"
#: src/strings.ts:1087
msgid "Disable realtime sync"
msgstr "Disable realtime sync"
@@ -2209,6 +2293,10 @@ msgstr "Disable sync"
msgid "Disabled"
msgstr "Disabled"
#: src/strings.ts:2646
msgid "Disabling will delete all your unsynced inbox items. Additionally, disabling will revoke all existing API keys, they will no longer work. Are you sure?"
msgstr "Disabling will delete all your unsynced inbox items. Additionally, disabling will revoke all existing API keys, they will no longer work. Are you sure?"
#: src/strings.ts:565
msgid "Discard"
msgstr "Discard"
@@ -2374,6 +2462,10 @@ msgstr "Due today"
msgid "Duplicate"
msgstr "Duplicate"
#: src/strings.ts:2652
msgid "e.g., Todo integration"
msgstr "e.g., Todo integration"
#: src/strings.ts:644
msgid "Earliest first"
msgstr "Earliest first"
@@ -2476,6 +2568,10 @@ msgstr "Enable app lock"
msgid "Enable editor margins"
msgstr "Enable editor margins"
#: src/strings.ts:2639
msgid "Enable Inbox API"
msgstr "Enable Inbox API"
#: src/strings.ts:2465
msgid "Enable ligatures for common symbols like →, ←, etc"
msgstr "Enable ligatures for common symbols like →, ←, etc"
@@ -2492,6 +2588,10 @@ msgstr "Enable spell checker"
msgid "Enable two-factor authentication to add an extra layer of security to your account."
msgstr "Enable two-factor authentication to add an extra layer of security to your account."
#: src/strings.ts:2640
msgid "Enable/Disable Inbox API"
msgstr "Enable/Disable Inbox API"
#: src/strings.ts:1234
msgid "Encrypt your backups for added security"
msgstr "Encrypt your backups for added security"
@@ -2700,6 +2800,18 @@ msgstr "Expand sidebar"
msgid "Experience the next level of private note taking\""
msgstr "Experience the next level of private note taking\""
#: src/strings.ts:2688
msgid "Expired"
msgstr "Expired"
#: src/strings.ts:2653
msgid "Expires in"
msgstr "Expires in"
#: src/strings.ts:2689
msgid "Expires on"
msgstr "Expires on"
#: src/strings.ts:2632
msgid "Expiry date"
msgstr "Expiry date"
@@ -2761,6 +2873,15 @@ msgstr "Failed"
msgid "Failed to copy note"
msgstr "Failed to copy note"
#: src/strings.ts:2678
msgid "Failed to copy to clipboard"
msgstr "Failed to copy to clipboard"
#. placeholder {0}: message ? `: ${message}` : ""
#: src/strings.ts:2657
msgid "Failed to create API key{0}"
msgstr "Failed to create API key{0}"
#: src/strings.ts:1560
msgid "Failed to decrypt backup"
msgstr "Failed to decrypt backup"
@@ -2781,6 +2902,10 @@ msgstr "Failed to download file"
msgid "Failed to install theme."
msgstr "Failed to install theme."
#: src/strings.ts:2664
msgid "Failed to load API keys. Please try again."
msgstr "Failed to load API keys. Please try again."
#: src/strings.ts:948
msgid "Failed to open"
msgstr "Failed to open"
@@ -2797,6 +2922,10 @@ msgstr "Failed to register task"
msgid "Failed to resolve download url"
msgstr "Failed to resolve download url"
#: src/strings.ts:2683
msgid "Failed to revoke API key"
msgstr "Failed to revoke API key"
#: src/strings.ts:773
msgid "Failed to send recovery email"
msgstr "Failed to send recovery email"
@@ -3352,6 +3481,18 @@ msgstr "Import CSV"
msgid "import guide"
msgstr "import guide"
#: src/strings.ts:2636
msgid "Inbox API"
msgstr "Inbox API"
#: src/strings.ts:2641
msgid "Inbox Keys"
msgstr "Inbox Keys"
#: src/strings.ts:2696
msgid "Inbox keys saved"
msgstr "Inbox keys saved"
#: src/strings.ts:174
msgid "Incoming"
msgstr "Incoming"
@@ -3432,6 +3573,14 @@ msgstr "Invalid CORS proxy url"
msgid "Invalid email"
msgstr "Invalid email"
#: src/strings.ts:2676
msgid "Invalid password"
msgstr "Invalid password"
#: src/strings.ts:2695
msgid "Invalid PGP key pair. Please check your keys and try again."
msgstr "Invalid PGP key pair. Please check your keys and try again."
#: src/strings.ts:224
msgid "Issue created"
msgstr "Issue created"
@@ -3514,6 +3663,10 @@ msgstr "Keep open"
msgid "Keep your data safe"
msgstr "Keep your data safe"
#: src/strings.ts:2651
msgid "Key name"
msgstr "Key name"
#: src/strings.ts:2128
msgid "Languages"
msgstr "Languages"
@@ -3522,6 +3675,10 @@ msgstr "Languages"
msgid "Last edited at"
msgstr "Last edited at"
#: src/strings.ts:2684
msgid "Last used on"
msgstr "Last used on"
#: src/strings.ts:590
msgid "Later"
msgstr "Later"
@@ -3647,6 +3804,10 @@ msgstr "Loading"
msgid "Loading {0}, please wait..."
msgstr "Loading {0}, please wait..."
#: src/strings.ts:2663
msgid "Loading API keys..."
msgstr "Loading API keys..."
#: src/strings.ts:1664
msgid "Loading editor. Please wait..."
msgstr "Loading editor. Please wait..."
@@ -4012,6 +4173,10 @@ msgstr "Never"
msgid "Never ask again"
msgstr "Never ask again"
#: src/strings.ts:2687
msgid "Never expires"
msgstr "Never expires"
#: src/strings.ts:1037
msgid "Never hesitate to choose privacy"
msgstr "Never hesitate to choose privacy"
@@ -4020,6 +4185,10 @@ msgstr "Never hesitate to choose privacy"
msgid "Never show again"
msgstr "Never show again"
#: src/strings.ts:2685
msgid "Never used"
msgstr "Never used"
#: src/strings.ts:642
msgid "New - old"
msgstr "New - old"
@@ -4357,6 +4526,10 @@ msgstr "Off"
msgid "Offline"
msgstr "Offline"
#: src/strings.ts:2668
msgid "OK"
msgstr "OK"
#: src/strings.ts:2227
msgid "Okay"
msgstr "Okay"
@@ -4628,6 +4801,10 @@ msgstr "Please download a backup of your data as your account will be cleared be
msgid "Please enable automatic backups to avoid losing important data."
msgstr "Please enable automatic backups to avoid losing important data."
#: src/strings.ts:2654
msgid "Please enter a key name"
msgstr "Please enter a key name"
#: src/strings.ts:1512
msgid "Please enter a valid email address"
msgstr "Please enter a valid email address"
@@ -4664,6 +4841,10 @@ msgstr "Please enter the password to unlock this note"
msgid "Please enter the password to view this version"
msgstr "Please enter the password to view this version"
#: src/strings.ts:2674
msgid "Please enter your account password to view this API key."
msgstr "Please enter your account password to view this API key."
#: src/strings.ts:1021
msgid "Please enter your app lock password to continue"
msgstr "Please enter your app lock password to continue"
@@ -4870,6 +5051,10 @@ msgstr "Privacy Policy. "
msgid "private analytics and bug reports."
msgstr "private analytics and bug reports."
#: src/strings.ts:2693
msgid "Private Key:"
msgstr "Private Key:"
#: src/strings.ts:821
msgid "Private."
msgstr "Private."
@@ -4918,6 +5103,10 @@ msgstr "Protect your notes"
msgid "Proxy"
msgstr "Proxy"
#: src/strings.ts:2692
msgid "Public Key:"
msgstr "Public Key:"
#: src/strings.ts:486
msgid "Publish"
msgstr "Publish"
@@ -5409,6 +5598,10 @@ msgstr "Resubscribe from Playstore"
msgid "Resubscribe to Pro"
msgstr "Resubscribe to Pro"
#: src/strings.ts:2665
msgid "Retry"
msgstr "Retry"
#: src/strings.ts:513
msgid "Reupload"
msgstr "Reupload"
@@ -5425,6 +5618,10 @@ msgstr "Revoke"
msgid "Revoke biometric unlocking"
msgstr "Revoke biometric unlocking"
#: src/strings.ts:2679
msgid "Revoke Inbox API Key - {name}"
msgstr "Revoke Inbox API Key - {name}"
#: src/strings.ts:450
msgid "Revoke vault fingerprint unlock"
msgstr "Revoke vault fingerprint unlock"
@@ -5976,6 +6173,10 @@ msgstr "Share note"
msgid "Share Notesnook with friends!"
msgstr "Share Notesnook with friends!"
#: src/strings.ts:2638
msgid "Share things to Notesbook from anywhere using the Inbox API"
msgstr "Share things to Notesbook from anywhere using the Inbox API"
#: src/strings.ts:594
msgid "Share to cloud"
msgstr "Share to cloud"
@@ -7092,6 +7293,14 @@ msgstr "Videos"
msgid "View all linked notebooks"
msgstr "View all linked notebooks"
#: src/strings.ts:2643
msgid "View and edit your inbox public/private key pair"
msgstr "View and edit your inbox public/private key pair"
#: src/strings.ts:2649
msgid "View and manage inbox API keys"
msgstr "View and manage inbox API keys"
#: src/strings.ts:1270
msgid "View and share debug logs"
msgstr "View and share debug logs"

View File

@@ -607,6 +607,22 @@ msgstr ""
msgid "#notesnook"
msgstr ""
#: src/strings.ts:2659
msgid "1 day"
msgstr ""
#: src/strings.ts:2661
msgid "1 month"
msgstr ""
#: src/strings.ts:2660
msgid "1 week"
msgstr ""
#: src/strings.ts:2662
msgid "1 year"
msgstr ""
#: src/strings.ts:1583
msgid "12-hour"
msgstr ""
@@ -699,6 +715,10 @@ msgstr ""
msgid "Add color"
msgstr ""
#: src/strings.ts:2647
msgid "Add key"
msgstr ""
#: src/strings.ts:895
msgid "Add notebook"
msgstr ""
@@ -871,6 +891,26 @@ msgstr ""
msgid "ANNOUNCEMENT"
msgstr ""
#: src/strings.ts:2677
msgid "API key copied to clipboard"
msgstr ""
#: src/strings.ts:2655
msgid "API key created successfully"
msgstr ""
#: src/strings.ts:2682
msgid "API key revoked"
msgstr ""
#: src/strings.ts:2648
msgid "API Keys"
msgstr ""
#: src/strings.ts:2669
msgid "API Keys Limit Reached"
msgstr ""
#: src/strings.ts:252
msgid "App data has been cleared. Kindly relaunch the app to login again."
msgstr ""
@@ -950,6 +990,10 @@ msgstr ""
msgid "Are you sure you want to remove your profile picture?"
msgstr ""
#: src/strings.ts:2681
msgid "Are you sure you want to revoke the key \"{name}\"? All inbox actions using this key will stop working immediately."
msgstr ""
#: src/strings.ts:1323
msgid "Are you sure?"
msgstr ""
@@ -1028,6 +1072,14 @@ msgstr ""
msgid "Auth server"
msgstr ""
#: src/strings.ts:2675
msgid "Authenticate"
msgstr ""
#: src/strings.ts:2672
msgid "Authenticate to view API key"
msgstr ""
#: src/strings.ts:1795
msgid "Authenticated as {email}"
msgstr ""
@@ -1309,6 +1361,10 @@ msgstr ""
msgid "Cancel upload"
msgstr ""
#: src/strings.ts:2671
msgid "Cannot create more than 10 api keys at a time. Please revoke some existing keys before creating new ones."
msgstr ""
#: src/strings.ts:2301
msgid "Cell background color"
msgstr ""
@@ -1410,6 +1466,10 @@ msgstr ""
msgid "Changes from other devices won't be updated in the editor in real-time."
msgstr ""
#: src/strings.ts:2691
msgid "Changing Inbox PGP keys will delete all your unsynced inbox items."
msgstr ""
#: src/strings.ts:734
msgid "Changing password is an irreversible process. You will be logged out from all your devices. Please make sure you do not close the app while your password is changing and have good internet connection."
msgstr ""
@@ -1875,6 +1935,14 @@ msgstr ""
msgid "Create account"
msgstr ""
#: src/strings.ts:2650
msgid "Create API Key"
msgstr ""
#: src/strings.ts:2667
msgid "Create Key"
msgstr ""
#: src/strings.ts:581
msgid "Create link"
msgstr ""
@@ -1903,15 +1971,27 @@ msgstr ""
msgid "Create your account"
msgstr ""
#: src/strings.ts:2666
msgid "Create your first api key to get started."
msgstr ""
#: src/strings.ts:2229
msgid "Created at"
msgstr ""
#: src/strings.ts:2686
msgid "Created on"
msgstr ""
#. placeholder {0}: type === "full" ? " full" : ""
#: src/strings.ts:1344
msgid "Creating a{0} backup"
msgstr ""
#: src/strings.ts:2658
msgid "Creating..."
msgstr ""
#: src/strings.ts:2049
msgid "Credentials"
msgstr ""
@@ -2186,6 +2266,10 @@ msgstr ""
msgid "Disable editor margins"
msgstr ""
#: src/strings.ts:2644
msgid "Disable Inbox API"
msgstr ""
#: src/strings.ts:1087
msgid "Disable realtime sync"
msgstr ""
@@ -2198,6 +2282,10 @@ msgstr ""
msgid "Disabled"
msgstr ""
#: src/strings.ts:2646
msgid "Disabling will delete all your unsynced inbox items. Additionally, disabling will revoke all existing API keys, they will no longer work. Are you sure?"
msgstr ""
#: src/strings.ts:565
msgid "Discard"
msgstr ""
@@ -2363,6 +2451,10 @@ msgstr ""
msgid "Duplicate"
msgstr ""
#: src/strings.ts:2652
msgid "e.g., Todo integration"
msgstr ""
#: src/strings.ts:644
msgid "Earliest first"
msgstr ""
@@ -2465,6 +2557,10 @@ msgstr ""
msgid "Enable editor margins"
msgstr ""
#: src/strings.ts:2639
msgid "Enable Inbox API"
msgstr ""
#: src/strings.ts:2465
msgid "Enable ligatures for common symbols like →, ←, etc"
msgstr ""
@@ -2481,6 +2577,10 @@ msgstr ""
msgid "Enable two-factor authentication to add an extra layer of security to your account."
msgstr ""
#: src/strings.ts:2640
msgid "Enable/Disable Inbox API"
msgstr ""
#: src/strings.ts:1234
msgid "Encrypt your backups for added security"
msgstr ""
@@ -2689,6 +2789,18 @@ msgstr ""
msgid "Experience the next level of private note taking\""
msgstr ""
#: src/strings.ts:2688
msgid "Expired"
msgstr ""
#: src/strings.ts:2653
msgid "Expires in"
msgstr ""
#: src/strings.ts:2689
msgid "Expires on"
msgstr ""
#: src/strings.ts:2632
msgid "Expiry date"
msgstr ""
@@ -2750,6 +2862,15 @@ msgstr ""
msgid "Failed to copy note"
msgstr ""
#: src/strings.ts:2678
msgid "Failed to copy to clipboard"
msgstr ""
#. placeholder {0}: message ? `: ${message}` : ""
#: src/strings.ts:2657
msgid "Failed to create API key{0}"
msgstr ""
#: src/strings.ts:1560
msgid "Failed to decrypt backup"
msgstr ""
@@ -2770,6 +2891,10 @@ msgstr ""
msgid "Failed to install theme."
msgstr ""
#: src/strings.ts:2664
msgid "Failed to load API keys. Please try again."
msgstr ""
#: src/strings.ts:948
msgid "Failed to open"
msgstr ""
@@ -2786,6 +2911,10 @@ msgstr ""
msgid "Failed to resolve download url"
msgstr ""
#: src/strings.ts:2683
msgid "Failed to revoke API key"
msgstr ""
#: src/strings.ts:773
msgid "Failed to send recovery email"
msgstr ""
@@ -3332,6 +3461,18 @@ msgstr ""
msgid "import guide"
msgstr ""
#: src/strings.ts:2636
msgid "Inbox API"
msgstr ""
#: src/strings.ts:2641
msgid "Inbox Keys"
msgstr ""
#: src/strings.ts:2696
msgid "Inbox keys saved"
msgstr ""
#: src/strings.ts:174
msgid "Incoming"
msgstr ""
@@ -3412,6 +3553,14 @@ msgstr ""
msgid "Invalid email"
msgstr ""
#: src/strings.ts:2676
msgid "Invalid password"
msgstr ""
#: src/strings.ts:2695
msgid "Invalid PGP key pair. Please check your keys and try again."
msgstr ""
#: src/strings.ts:224
msgid "Issue created"
msgstr ""
@@ -3494,6 +3643,10 @@ msgstr ""
msgid "Keep your data safe"
msgstr ""
#: src/strings.ts:2651
msgid "Key name"
msgstr ""
#: src/strings.ts:2128
msgid "Languages"
msgstr ""
@@ -3502,6 +3655,10 @@ msgstr ""
msgid "Last edited at"
msgstr ""
#: src/strings.ts:2684
msgid "Last used on"
msgstr ""
#: src/strings.ts:590
msgid "Later"
msgstr ""
@@ -3627,6 +3784,10 @@ msgstr ""
msgid "Loading {0}, please wait..."
msgstr ""
#: src/strings.ts:2663
msgid "Loading API keys..."
msgstr ""
#: src/strings.ts:1664
msgid "Loading editor. Please wait..."
msgstr ""
@@ -3992,6 +4153,10 @@ msgstr ""
msgid "Never ask again"
msgstr ""
#: src/strings.ts:2687
msgid "Never expires"
msgstr ""
#: src/strings.ts:1037
msgid "Never hesitate to choose privacy"
msgstr ""
@@ -4000,6 +4165,10 @@ msgstr ""
msgid "Never show again"
msgstr ""
#: src/strings.ts:2685
msgid "Never used"
msgstr ""
#: src/strings.ts:642
msgid "New - old"
msgstr ""
@@ -4331,6 +4500,10 @@ msgstr ""
msgid "Offline"
msgstr ""
#: src/strings.ts:2668
msgid "OK"
msgstr ""
#: src/strings.ts:2227
msgid "Okay"
msgstr ""
@@ -4602,6 +4775,10 @@ msgstr ""
msgid "Please enable automatic backups to avoid losing important data."
msgstr ""
#: src/strings.ts:2654
msgid "Please enter a key name"
msgstr ""
#: src/strings.ts:1512
msgid "Please enter a valid email address"
msgstr ""
@@ -4638,6 +4815,10 @@ msgstr ""
msgid "Please enter the password to view this version"
msgstr ""
#: src/strings.ts:2674
msgid "Please enter your account password to view this API key."
msgstr ""
#: src/strings.ts:1021
msgid "Please enter your app lock password to continue"
msgstr ""
@@ -4844,6 +5025,10 @@ msgstr ""
msgid "private analytics and bug reports."
msgstr ""
#: src/strings.ts:2693
msgid "Private Key:"
msgstr ""
#: src/strings.ts:821
msgid "Private."
msgstr ""
@@ -4892,6 +5077,10 @@ msgstr ""
msgid "Proxy"
msgstr ""
#: src/strings.ts:2692
msgid "Public Key:"
msgstr ""
#: src/strings.ts:486
msgid "Publish"
msgstr ""
@@ -5383,6 +5572,10 @@ msgstr ""
msgid "Resubscribe to Pro"
msgstr ""
#: src/strings.ts:2665
msgid "Retry"
msgstr ""
#: src/strings.ts:513
msgid "Reupload"
msgstr ""
@@ -5399,6 +5592,10 @@ msgstr ""
msgid "Revoke biometric unlocking"
msgstr ""
#: src/strings.ts:2679
msgid "Revoke Inbox API Key - {name}"
msgstr ""
#: src/strings.ts:450
msgid "Revoke vault fingerprint unlock"
msgstr ""
@@ -5942,6 +6139,10 @@ msgstr ""
msgid "Share Notesnook with friends!"
msgstr ""
#: src/strings.ts:2638
msgid "Share things to Notesbook from anywhere using the Inbox API"
msgstr ""
#: src/strings.ts:594
msgid "Share to cloud"
msgstr ""
@@ -7042,6 +7243,14 @@ msgstr ""
msgid "View all linked notebooks"
msgstr ""
#: src/strings.ts:2643
msgid "View and edit your inbox public/private key pair"
msgstr ""
#: src/strings.ts:2649
msgid "View and manage inbox API keys"
msgstr ""
#: src/strings.ts:1270
msgid "View and share debug logs"
msgstr ""

View File

@@ -2632,5 +2632,66 @@ Use this if changes from other devices are not appearing on this device. This wi
expiryDate: () => t`Expiry date`,
exportCsv: () => t`Export CSV`,
importCsv: () => t`Import CSV`,
noContent: () => t`This note is empty`
noContent: () => t`This note is empty`,
inboxAPI: () => t`Inbox API`,
inboxAPIDesc: () =>
t`Share things to Notesbook from anywhere using the Inbox API`,
enableInboxAPI: () => t`Enable Inbox API`,
enableInboxAPIDesc: () => t`Enable/Disable Inbox API`,
manageInboxKeys: () => t`Inbox Keys`,
manageInboxKeysDesc: () =>
t`View and edit your inbox public/private key pair`,
disableInboxAPI: () => t`Disable Inbox API`,
disableInboxAPIDesc: () =>
t`Disabling will delete all your unsynced inbox items. Additionally, disabling will revoke all existing API keys, they will no longer work. Are you sure?`,
addKey: () => t`Add key`,
viewAPIKeys: () => t`API Keys`,
viewAPIKeysDesc: () => t`View and manage inbox API keys`,
createApiKey: () => t`Create API Key`,
keyName: () => t`Key name`,
exampleKeyName: () => t`e.g., Todo integration`,
expiresIn: () => t`Expires in`,
enterKeyName: () => t`Please enter a key name`,
apiKeyCreatedSuccessfully: () => t`API key created successfully`,
failedToCreateApiKey: (message: string) =>
t`Failed to create API key${message ? `: ${message}` : ""}`,
creating: () => t`Creating...`,
expiryOneDay: () => t`1 day`,
expiryOneWeek: () => t`1 week`,
expiryOneMonth: () => t`1 month`,
expiryOneYear: () => t`1 year`,
loadingApiKeys: () => t`Loading API keys...`,
failedToLoadApiKeys: () => t`Failed to load API keys. Please try again.`,
retry: () => t`Retry`,
createFirstApiKey: () => t`Create your first api key to get started.`,
createKey: () => t`Create Key`,
ok: () => t`OK`,
apiKeysLimitReached: () => t`API Keys Limit Reached`,
apiKeysLimitReachedMessage: () =>
t`Cannot create more than 10 api keys at a time. Please revoke some existing keys before creating new ones.`,
authenticateToViewApiKey: () => t`Authenticate to view API key`,
enterPasswordToViewApiKey: () =>
t`Please enter your account password to view this API key.`,
authenticate: () => t`Authenticate`,
invalidPassword: () => t`Invalid password`,
apiKeyCopiedToClipboard: () => t`API key copied to clipboard`,
failedToCopyToClipboard: () => t`Failed to copy to clipboard`,
revokeInboxApiKey: (name: string) => t`Revoke Inbox API Key - ${name}`,
revokeApiKeyConfirmation: (name: string) =>
t`Are you sure you want to revoke the key "${name}"? All inbox actions using this key will stop working immediately.`,
apiKeyRevoked: () => t`API key revoked`,
failedToRevokeApiKey: () => t`Failed to revoke API key`,
lastUsedOn: () => t`Last used on`,
neverUsed: () => t`Never used`,
createdOn: () => t`Created on`,
neverExpires: () => t`Never expires`,
expired: () => t`Expired`,
expiresOn: () => t`Expires on`,
changingInboxPgpKeysNotice: () =>
t`Changing Inbox PGP keys will delete all your unsynced inbox items.`,
publicKey: () => t`Public Key:`,
privateKey: () => t`Private Key:`,
invalidPgpKeyPair: () =>
t`Invalid PGP key pair. Please check your keys and try again.`,
inboxKeysSaved: () => t`Inbox keys saved`
};