mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-23 19:49:56 +01:00
mobile: add inbox api settings
This commit is contained in:
@@ -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();
|
||||
|
||||
169
apps/mobile/app/components/sheets/add-api-key/index.tsx
Normal file
169
apps/mobile/app/components/sheets/add-api-key/index.tsx
Normal 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} />
|
||||
)
|
||||
});
|
||||
};
|
||||
@@ -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={{
|
||||
|
||||
@@ -155,14 +155,6 @@ const SheetWrapper = ({
|
||||
onClose={_onClose}
|
||||
>
|
||||
{children}
|
||||
|
||||
{bottomPadding ? (
|
||||
<View
|
||||
style={{
|
||||
height: bottomInsets
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</ActionSheet>
|
||||
</ScopedThemeProvider>
|
||||
);
|
||||
|
||||
@@ -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 />
|
||||
};
|
||||
|
||||
474
apps/mobile/app/screens/settings/manage-inbox-keys.tsx
Normal file
474
apps/mobile/app/screens/settings/manage-inbox-keys.tsx
Normal 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 };
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -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
|
||||
}));
|
||||
|
||||
Binary file not shown.
@@ -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", {
|
||||
|
||||
31
apps/mobile/package-lock.json
generated
31
apps/mobile/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -121,7 +121,8 @@ const EXTRA_ICON_NAMES = [
|
||||
"calendar-today",
|
||||
"bomb",
|
||||
"bomb-off",
|
||||
"cancel"
|
||||
"cancel",
|
||||
"inbox"
|
||||
];
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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`
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user