Compare commits

..

1 Commits

Author SHA1 Message Date
ammarahm-ed
74a0a117e6 editor: fix code-block ui 2023-09-11 12:35:04 +05:00
234 changed files with 3734 additions and 8590 deletions

View File

@@ -97,7 +97,6 @@ jobs:
- name: Get App Store Version
id: appstore
uses: streetwriters/appstore-connect-app-version@develop
if: inputs.publish-apple
with:
app-id: ${{ steps.app_metadata.outputs.apple_app_id }}
key-id: ${{ secrets.api_key_id }}

View File

@@ -1,3 +0,0 @@
owner: streetwriters
repo: notesnook
provider: github

View File

@@ -1,18 +1,18 @@
{
"name": "@notesnook/desktop",
"version": "2.6.7",
"version": "2.6.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/desktop",
"version": "2.6.7",
"version": "2.6.3",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook/crypto": "file:../../packages/crypto",
"@trpc/client": "10.38.3",
"@trpc/server": "10.38.3",
"@trpc/client": "10.31.0",
"@trpc/server": "10.31.0",
"electron-trpc": "0.5.2",
"electron-updater": "6.1.4",
"icojs": "^0.17.1",
@@ -24,7 +24,7 @@
"@types/node": "18.16.1",
"@types/yargs": "^17.0.24",
"chokidar": "^3.5.3",
"electron": "25.8.1",
"electron": "25.8.0",
"electron-builder": "^24.6.4",
"electron-builder-notarize": "^1.5.1",
"esbuild": "^0.17.19",
@@ -831,20 +831,20 @@
}
},
"node_modules/@trpc/client": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.38.3.tgz",
"integrity": "sha512-hHPsElTL4sB+UGzuAZ4iwRVHjELrk/Nsl2owsYw9ITJz3EY7VWRsQ6vK48kJvlHPYPhP+efID5UOgyZMs4bFXA==",
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.31.0.tgz",
"integrity": "sha512-VCqbJEvFJb8C4hQFw7AD+dkQTjgEdV/QAzO4D+/cX5e93u5NpfNXI+PKS0QFXwG/zqgwQwVV6OkYc/D/MFwA6g==",
"funding": [
"https://trpc.io/sponsor"
],
"peerDependencies": {
"@trpc/server": "10.38.3"
"@trpc/server": "10.31.0"
}
},
"node_modules/@trpc/server": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.38.3.tgz",
"integrity": "sha512-9s8/kwo2IDB5hwB2SKZZrfevRhdb1f9fdXtIYd3lbQuf2jQaC/LyQuHaIQjDQoUx9updBfsHXcFFPiCP1DL6pg==",
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.31.0.tgz",
"integrity": "sha512-9EnRTSDE9nF11LZsvSOqNKqkRYzHqFX4ch5AJ6VIu8uta2vxVTN4FxxsNRSOluTzVYZDeaCISbwmOJ5iihCCIg==",
"funding": [
"https://trpc.io/sponsor"
]
@@ -1751,9 +1751,9 @@
}
},
"node_modules/electron": {
"version": "25.8.1",
"resolved": "https://registry.npmjs.org/electron/-/electron-25.8.1.tgz",
"integrity": "sha512-GtcP1nMrROZfFg0+mhyj1hamrHvukfF6of2B/pcWxmWkd5FVY1NJib0tlhiorFZRzQN5Z+APLPr7aMolt7i2AQ==",
"version": "25.8.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-25.8.0.tgz",
"integrity": "sha512-T3kC1a/3ntSaYMCVVfUUc9v7myPzi6J2GP0Ad/CyfWKDPp054dGyKxb2EEjKnxQQ7wfjsT1JTEdBG04x6ekVBw==",
"hasInstallScript": true,
"dependencies": {
"@electron/get": "^2.0.0",

View File

@@ -2,7 +2,7 @@
"name": "@notesnook/desktop",
"productName": "Notesnook",
"description": "Your private note taking space",
"version": "2.6.7",
"version": "2.6.3",
"appAppleId": "1544027013",
"private": true,
"main": "./dist/index.js",
@@ -12,8 +12,8 @@
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook/crypto": "file:../../packages/crypto",
"@trpc/client": "10.38.3",
"@trpc/server": "10.38.3",
"@trpc/client": "10.31.0",
"@trpc/server": "10.31.0",
"electron-trpc": "0.5.2",
"electron-updater": "6.1.4",
"icojs": "^0.17.1",
@@ -25,7 +25,7 @@
"@types/node": "18.16.1",
"@types/yargs": "^17.0.24",
"chokidar": "^3.5.3",
"electron": "25.8.1",
"electron": "25.8.0",
"electron-builder": "^24.6.4",
"electron-builder-notarize": "^1.5.1",
"esbuild": "^0.17.19",
@@ -191,7 +191,6 @@
"allowNativeWayland": true
},
"extraResources": [
"app-update.yml",
"./assets/**"
],
"extraMetadata": {

View File

@@ -117,14 +117,6 @@ export const osIntegrationRouter = t.router({
writeFileSync(resolvedPath, data);
}),
resolvePath: t.procedure
.input(z.object({ filePath: z.string() }))
.query(({ input }) => {
const { filePath } = input;
if (!filePath) return;
return resolvePath(filePath);
}),
showNotification: t.procedure
.input(NotificationOptions)
.query(({ input }) => {

View File

@@ -27,23 +27,19 @@ export type CLIOptions = {
hidden: boolean;
};
export async function parseArguments(argv: string[]): Promise<CLIOptions> {
export async function parseArguments(): Promise<CLIOptions> {
const result: CLIOptions = {
note: false,
notebook: false,
reminder: false,
hidden: false
};
const { hidden } = await yargs(hideBin(argv))
const { hidden } = await yargs(hideBin(process.argv))
.boolean("hidden")
// have to account for this flag added on Windows when launching
// via Jumplist
.boolean("allow-file-access-from-files")
.command("new", "Create a new item", (yargs) => {
return yargs
.command("note", "Create a new note", {}, () => {
result.note = true;
console.log("HERE!");
})
.command("notebook", "Create a new notebook", {}, () => {
result.notebook = true;

View File

@@ -34,7 +34,6 @@ import { router, api } from "./api";
import { config } from "./utils/config";
import path from "path";
import { bringToFront } from "./utils/bring-to-front";
import { bridge } from "./api/bridge";
// only run a single instance
if (!MAC_APP_STORE && !app.requestSingleInstanceLock()) {
@@ -64,7 +63,7 @@ process.on("unhandledRejection", (reason) => {
app.commandLine.appendSwitch("lang", "en-US");
async function createWindow() {
const cliOptions = await parseArguments(process.argv);
const cliOptions = await parseArguments();
setTheme(getTheme());
const mainWindowState = new WindowState({});
@@ -91,7 +90,6 @@ async function createWindow() {
}
});
createIPCHandler({ router, windows: [mainWindow] });
globalThis.window = mainWindow;
mainWindowState.manage(mainWindow);
@@ -107,6 +105,7 @@ async function createWindow() {
await AssetManager.loadIcons();
setupDesktopIntegration();
createIPCHandler({ router, windows: [mainWindow] });
mainWindow.webContents.session.setSpellCheckerDictionaryDownloadURL(
"http://dictionaries.notesnook.com/"
@@ -147,12 +146,8 @@ app.once("window-all-closed", () => {
}
});
app.on("second-instance", async (_ev, argv) => {
app.on("second-instance", () => {
if (!globalThis.window) return;
const cliOptions = await parseArguments(argv);
if (cliOptions.note) bridge.onCreateItem("note");
if (cliOptions.notebook) bridge.onCreateItem("notebook");
if (cliOptions.reminder) bridge.onCreateItem("reminder");
bringToFront();
});
@@ -193,7 +188,7 @@ function setupDesktopIntegration() {
app.on("before-quit", () => app.exit(0));
}
globalThis.window?.on("close", (e) => {
globalThis.window?.once("close", (e) => {
if (config.desktopSettings.closeToSystemTray) {
e.preventDefault();
if (process.platform == "darwin") {

View File

@@ -31,6 +31,7 @@ declare global {
}
process.once("loaded", async () => {
console.log("HELLO!");
const electronTRPC: RendererGlobalElectronTRPC = {
sendMessage: (operation) =>
ipcRenderer.send(ELECTRON_TRPC_CHANNEL, operation),

View File

@@ -34,7 +34,6 @@ import { useAttachmentStore } from "../../stores/use-attachment-store";
import { db } from "../database";
import Storage from "../database/storage";
import { cacheDir, copyFileAsync, releasePermissions } from "./utils";
import { createCacheDir } from "./io";
export const FileDownloadStatus = {
Success: 1,
@@ -63,7 +62,6 @@ export async function downloadAttachments(
canceled,
groupId
) {
await createCacheDir();
if (!attachments || !attachments.length) return;
const result = new Map();
@@ -184,8 +182,6 @@ export default async function downloadAttachment(
groupId: undefined
}
) {
await createCacheDir();
let attachment = db.attachments.attachment(hash);
if (!attachment) {
console.log("attachment not found");

View File

@@ -24,18 +24,15 @@ import { ToastEvent } from "../../services/event-manager";
import { useAttachmentStore } from "../../stores/use-attachment-store";
import { db } from "../database";
import { cacheDir, fileCheck } from "./utils";
import { createCacheDir, exists } from "./io";
export async function downloadFile(filename, data, cancelToken) {
if (!data) return false;
await createCacheDir();
let { url, headers } = data;
let path = `${cacheDir}/${filename}`;
let path = `${cacheDir}/${filename}`;
try {
if (await exists(filename)) {
let exists = await RNFetchBlob.fs.exists(path);
if (exists) {
return true;
}
@@ -63,34 +60,29 @@ export async function downloadFile(filename, data, cancelToken) {
console.log("downloading: ", recieved, total);
});
cancelToken.cancel = () => {
useAttachmentStore.getState().remove(filename);
request.cancel();
};
cancelToken.cancel = request.cancel;
let response = await request;
await fileCheck(response, totalSize);
let status = response.info().status;
useAttachmentStore.getState().remove(filename);
return status >= 200 && status < 300;
} catch (e) {
if (e.message !== "canceled") {
ToastEvent.show({
heading: "Error downloading file",
message: e.message,
type: "error",
context: "global"
});
ToastEvent.show({
heading: "Error downloading file",
message: e.message,
type: "error",
context: "local"
});
}
ToastEvent.show({
heading: "Error downloading file",
message: e.message,
type: "error",
context: "global"
});
ToastEvent.show({
heading: "Error downloading file",
message: e.message,
type: "error",
context: "local"
});
useAttachmentStore.getState().remove(filename);
RNFetchBlob.fs.unlink(path).catch(console.log);
console.log("Download file error:", e, url, headers);
console.log("download file error: ", e, url, headers);
return false;
}
}

View File

@@ -20,25 +20,32 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { Platform } from "react-native";
import Sodium from "@ammarahmed/react-native-sodium";
import RNFetchBlob from "react-native-blob-util";
import { cacheDir, cacheDirOld, getRandomId } from "./utils";
import { cacheDir, getRandomId } from "./utils";
import { db } from "../database";
import { compressToBase64 } from "./compress";
import { IOS_APPGROUPID } from "../../utils/constants";
export async function readEncrypted(filename, key, cipherData) {
await migrateFilesFromCache();
console.log("Read encrypted file...");
let path = `${cacheDir}/${filename}`;
try {
if (!(await exists(filename))) {
const iosAppGroup =
Platform.OS === "ios"
? await RNFetchBlob.fs.pathForAppGroup(IOS_APPGROUPID)
: null;
const appGroupPath = `${iosAppGroup}/${filename}`;
let exists =
(await RNFetchBlob.fs.exists(path)) ||
(Platform.OS === "ios" && (await RNFetchBlob.fs.exists(appGroupPath)));
if (!exists) {
return false;
}
const attachment = db.attachments.attachment(filename);
const isPng = /(png)/g.test(attachment?.metadata.type);
const isJpeg = /(jpeg|jpg)/g.test(attachment?.metadata.type);
console.log("decrypting....");
let output = await Sodium.decryptFile(
key,
{
@@ -52,7 +59,6 @@ export async function readEncrypted(filename, key, cipherData) {
: "base64"
: "text"
);
console.log("file decrypted...");
if (cipherData.outputType === "base64" && (isPng || isJpeg)) {
const dCachePath = `${cacheDir}/${output}`;
output = await compressToBase64(
@@ -64,7 +70,7 @@ export async function readEncrypted(filename, key, cipherData) {
return output;
} catch (e) {
RNFetchBlob.fs.unlink(path).catch(console.log);
console.log("readEncrypted", e);
console.log(e);
return false;
}
}
@@ -82,7 +88,6 @@ export async function hashBase64(data) {
}
export async function writeEncryptedBase64({ data, key }) {
await createCacheDir();
let filepath = cacheDir + `/${getRandomId("imagecache_")}`;
await RNFetchBlob.fs.writeFile(filepath, data, "base64");
let output = await Sodium.encryptFile(key, {
@@ -98,7 +103,6 @@ export async function writeEncryptedBase64({ data, key }) {
}
export async function deleteFile(filename, data) {
await createCacheDir();
let delFilePath = cacheDir + `/${filename}`;
if (!data) {
if (!filename) return;
@@ -124,89 +128,19 @@ export async function deleteFile(filename, data) {
export async function clearFileStorage() {
try {
let files = await RNFetchBlob.fs.ls(cacheDir);
let oldCache = await RNFetchBlob.fs.ls(cacheDirOld);
for (let file of files) {
await RNFetchBlob.fs.unlink(cacheDir + `/${file}`).catch(console.log);
}
for (let file of oldCache) {
await RNFetchBlob.fs.unlink(cacheDirOld + `/${file}`).catch(console.log);
try {
await RNFetchBlob.fs.unlink(cacheDir + `/${file}`);
} catch (e) {
console.log(e);
}
}
} catch (e) {
console.log("clearFileStorage", e);
console.log(e);
}
}
export async function createCacheDir() {
if (!(await RNFetchBlob.fs.exists(cacheDir))) {
await RNFetchBlob.fs.mkdir(cacheDir);
console.log("Cache directory created");
}
}
export async function migrateFilesFromCache() {
try {
await createCacheDir();
const migratedFilesPath = cacheDir + "/.migrated_1";
const migrated = await RNFetchBlob.fs.exists(migratedFilesPath);
if (migrated) {
console.log("Files migrated already");
return;
}
let files = await RNFetchBlob.fs.ls(cacheDir);
console.log("Files to migrate:", files.join(","));
let oldCache = await RNFetchBlob.fs.ls(cacheDirOld);
for (let file of oldCache) {
if (file.startsWith("org.") || file.startsWith("com.")) continue;
RNFetchBlob.fs
.mv(cacheDirOld + `/${file}`, cacheDir + `/${file}`)
.catch(console.log);
console.log("Moved", file);
}
await RNFetchBlob.fs.createFile(migratedFilesPath, "1", "utf8");
} catch (e) {
console.log("migrateFilesFromCache", e);
}
}
const ABYTES = 17;
export async function exists(filename) {
let path = `${cacheDir}/${filename}`;
const iosAppGroup =
Platform.OS === "ios"
? await RNFetchBlob.fs.pathForAppGroup(IOS_APPGROUPID)
: null;
const appGroupPath = `${iosAppGroup}/${filename}`;
let exists = await RNFetchBlob.fs.exists(path);
// Check if file is present in app group path.
let existsInAppGroup = false;
if (!exists && Platform.OS === "ios") {
existsInAppGroup = await RNFetchBlob.fs.exists(appGroupPath);
}
if (exists || existsInAppGroup) {
const attachment = db.attachments.attachment(filename);
const totalChunks = Math.ceil(attachment.length / attachment.chunkSize);
const totalAbytes = totalChunks * ABYTES;
const expectedFileSize = attachment.length + totalAbytes;
const stat = await RNFetchBlob.fs.stat(
existsInAppGroup ? appGroupPath : path
);
if (stat.size !== expectedFileSize) {
RNFetchBlob.fs
.unlink(existsInAppGroup ? appGroupPath : path)
.catch(console.log);
return false;
}
exists = true;
}
let exists = await RNFetchBlob.fs.exists(`${cacheDir}/${filename}`);
return exists;
}

View File

@@ -24,12 +24,11 @@ import { cacheDir } from "./utils";
import { isImage, isDocument } from "@notesnook/core/dist/utils/filename";
import { Platform } from "react-native";
import { IOS_APPGROUPID } from "../../utils/constants";
import { createCacheDir } from "./io";
export async function uploadFile(filename, data, cancelToken) {
if (!data) return false;
let { url, headers } = data;
await createCacheDir();
DatabaseLogger.info(`Preparing to upload file: ${filename}`);
try {
@@ -73,10 +72,7 @@ export async function uploadFile(filename, data, cancelToken) {
);
});
cancelToken.cancel = () => {
useAttachmentStore.getState().remove(filename);
request.cancel();
};
cancelToken.cancel = request.cancel;
let response = await request;
let status = response.info().status;

View File

@@ -21,12 +21,7 @@ import * as ScopedStorage from "react-native-scoped-storage";
import { Platform } from "react-native";
import RNFetchBlob from "react-native-blob-util";
export const cacheDirOld = RNFetchBlob.fs.dirs.CacheDir;
export const cacheDir =
Platform.OS == "ios"
? RNFetchBlob.fs.dirs.LibraryDir + "/.cache"
: RNFetchBlob.fs.dirs.DocumentDir + "/.cache";
export const cacheDir = RNFetchBlob.fs.dirs.CacheDir;
export function getRandomId(prefix) {
return Math.random()
@@ -71,12 +66,9 @@ export function cancelable(operation) {
}
export function copyFileAsync(source, dest) {
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
ScopedStorage.copyFile(source, dest, (e, r) => {
if (e) {
reject(e);
return;
}
console.log(e, r);
resolve();
});
});

View File

@@ -132,7 +132,7 @@ export const AttachmentItem = ({
activeOpacity={0.9}
onPress={() => {
if (encryption || !pressable) return;
db.fs.cancel(attachment.metadata.hash, currentProgress.type);
db.fs.cancel(attachment.metadata.hash);
setCurrentProgress(null);
}}
style={{

View File

@@ -85,7 +85,6 @@ const AuthModal = () => {
background={colors.primary.background}
transparent={false}
animated={false}
centered={false}
>
<KeyboardAwareScrollView
style={{

View File

@@ -46,7 +46,6 @@ import Input from "../ui/input";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { LoginSteps, useLogin } from "./use-login";
import BaseDialog from "../dialog/base-dialog";
function getObfuscatedEmail(email) {
if (!email) return "";
@@ -131,12 +130,7 @@ export const SessionExpired = () => {
return (
visible && (
<BaseDialog
transparent={false}
background={colors.primary.background}
bounce={false}
animated={false}
centered={false}
<Modal
onShow={async () => {
await sleep(300);
passwordInputRef.current?.focus();
@@ -237,7 +231,7 @@ export const SessionExpired = () => {
</View>
<Toast context="local" />
<Dialog context="session_expiry" />
</BaseDialog>
</Modal>
)
);
};

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useEffect, useRef, useState } from "react";
import React, { useEffect } from "react";
import {
KeyboardAvoidingView,
Modal,
@@ -31,9 +31,6 @@ import useIsFloatingKeyboard from "../../hooks/use-is-floating-keyboard";
import { useSettingStore } from "../../stores/use-setting-store";
import { BouncingView } from "../ui/transitions/bouncing-view";
import { ScopedThemeProvider } from "@notesnook/theme";
import SettingsService from "../../services/settings";
import { useUserStore } from "../../stores/use-user-store";
import { useAppState } from "../../hooks/use-app-state";
const BaseDialog = ({
visible,
@@ -54,9 +51,6 @@ const BaseDialog = ({
avoidKeyboardResize = false
}) => {
const floating = useIsFloatingKeyboard();
const appState = useAppState();
const lockEvents = useRef(false);
const [internalVisible, setIntervalVisible] = useState(true);
useEffect(() => {
return () => {
@@ -64,33 +58,14 @@ const BaseDialog = ({
};
}, []);
useEffect(() => {
if (SettingsService.get().appLockMode === "background") {
if (appState === "background") {
setIntervalVisible(false);
if (useUserStore.getState().appLocked) {
lockEvents.current = true;
const unsub = useUserStore.subscribe((state) => {
if (!state.appLocked) {
setIntervalVisible(true);
unsub();
setTimeout(() => {
lockEvents.current = false;
});
}
});
}
}
}
}, [appState]);
const Wrapper = useSafeArea ? SafeAreaView : View;
return (
<ScopedThemeProvider value="dialog">
<Modal
visible={visible && internalVisible}
visible={visible}
transparent={true}
animated
statusBarTranslucent={statusBarTranslucent}
supportedOrientations={[
"portrait",
@@ -100,7 +75,6 @@ const BaseDialog = ({
"landscape-right"
]}
onShow={() => {
if (lockEvents.current) return;
if (onShow) {
onShow();
useSettingStore.getState().setSheetKeyboardHandler(false);
@@ -108,7 +82,6 @@ const BaseDialog = ({
}}
animationType={animation}
onRequestClose={() => {
if (lockEvents.current) return;
if (!closeOnTouch) return null;
useSettingStore.getState().setSheetKeyboardHandler(true);
onRequestClose && onRequestClose();
@@ -134,7 +107,6 @@ const BaseDialog = ({
style={[
styles.backdrop,
{
alignItems: centered ? "center" : undefined,
justifyContent: centered
? "center"
: bottom
@@ -161,7 +133,8 @@ const styles = StyleSheet.create({
backdrop: {
width: "100%",
height: "100%",
justifyContent: "center"
justifyContent: "center",
alignItems: "center"
},
overlayButton: {
width: "100%",

View File

@@ -48,7 +48,7 @@ export const ProFeatures = ({ count = 6 }) => {
content: "Instantly sync to unlimited devices"
},
{
content: "A private vault to keep everything important always locked"
content: "A private vault to keep everything imporant always locked"
},
{
content:

View File

@@ -442,7 +442,6 @@ export class VaultDialog extends Component {
if (this.state.biometricUnlock && !this.state.isBiometryEnrolled) {
await this._enrollFingerprint(this.password);
}
if (this.state.goToEditor) {
this._openInEditor(note);
} else if (this.state.share) {
@@ -453,6 +452,7 @@ export class VaultDialog extends Component {
await this._copyNote(note);
}
} catch (e) {
console.log(e);
this._takeErrorAction(e);
}
};
@@ -467,40 +467,44 @@ export class VaultDialog extends Component {
}
async _enrollFingerprint(password) {
this.setState(
{
loading: true
},
async () => {
try {
await db.vault.unlock(password);
await BiometricService.storeCredentials(password);
this.setState({
loading: false
});
eSendEvent("vaultUpdated");
ToastEvent.show({
heading: "Biometric unlocking enabled!",
message: "Now you can unlock notes in vault with biometrics.",
type: "success",
context: "global"
});
this.close();
} catch (e) {
this.close();
ToastEvent.show({
heading: "Incorrect password",
message:
"Please enter the correct vault password to enable biometrics.",
type: "error",
context: "local"
});
this.setState({
loading: false
});
try {
this.setState(
{
loading: true
},
async () => {
try {
await db.vault.unlock(password);
await BiometricService.storeCredentials(password);
this.setState({
loading: false
});
eSendEvent("vaultUpdated");
ToastEvent.show({
heading: "Biometric unlocking enabled!",
message: "Now you can unlock notes in vault with biometrics.",
type: "success",
context: "global"
});
this.close();
} catch (e) {
ToastEvent.show({
heading: "Incorrect password",
message:
"Please enter the correct vault password to enable biometrics.",
type: "error",
context: "local"
});
this.setState({
loading: false
});
return;
}
}
}
);
);
} catch (e) {
this._takeErrorAction(e);
}
}
async _createVault() {
@@ -539,7 +543,7 @@ export class VaultDialog extends Component {
.remove(this.state.note.id, this.password)
.then(() => {
ToastEvent.show({
heading: "Note permanently unlocked.",
heading: "Note permanantly unlocked.",
type: "success",
context: "global"
});

View File

@@ -39,9 +39,9 @@ class ExceptionHandler extends React.Component<{
error: Error | null;
hasError: boolean;
} = {
hasError: false,
error: null
};
hasError: false,
error: null
};
static getDerivedStateFromError(error: Error) {
return { hasError: true, error: error };
}
@@ -69,7 +69,7 @@ class ExceptionHandler extends React.Component<{
this.props.component
)}
defaultTitle={this.state.error?.message}
issueTitle="An exception occurred"
issueTitle="An exception occured"
/>
<Dialog />
</SafeAreaView>

View File

@@ -17,25 +17,35 @@ 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, { useEffect, useRef, useState } from "react";
import { TouchableOpacity, useWindowDimensions, View } from "react-native";
import { useThemeColors } from "@notesnook/theme";
import React, { useRef } from "react";
import { TouchableOpacity, View, useWindowDimensions } from "react-native";
import { eSendEvent, presentSheet } from "../../../services/event-manager";
import SettingsService from "../../../services/settings";
import { useSettingStore } from "../../../stores/use-setting-store";
import { ColorValues } from "../../../utils/colors";
import {
eSendEvent,
eSubscribeEvent,
eUnSubscribeEvent,
presentSheet
} from "../../../services/event-manager";
import SettingsService from "../../../services/settings";
import { GROUP } from "../../../utils/constants";
import { ColorValues } from "../../../utils/colors";
import { db } from "../../../common/database";
import { eOpenJumpToDialog } from "../../../utils/events";
import { SIZE } from "../../../utils/size";
import Sort from "../../sheets/sort";
import { Button } from "../../ui/button";
import { IconButton } from "../../ui/icon-button";
import { Button } from "../../ui/button";
import Sort from "../../sheets/sort";
import Heading from "../../ui/typography/heading";
import { useCallback } from "react";
export const SectionHeader = React.memo(
function SectionHeader({ item, index, type, color, screen, groupOptions }) {
function SectionHeader({ item, index, type, color, screen }) {
const { colors } = useThemeColors();
const { fontScale } = useWindowDimensions();
const [groupOptions, setGroupOptions] = useState(
db.settings?.getGroupOptions(type)
);
let groupBy = Object.keys(GROUP).find(
(key) => GROUP[key] === groupOptions.groupBy
);
@@ -55,6 +65,17 @@ export const SectionHeader = React.memo(
? "Default"
: groupBy.slice(0, 1).toUpperCase() + groupBy.slice(1, groupBy.length);
const onUpdate = useCallback(() => {
setGroupOptions({ ...db.settings?.getGroupOptions(type) });
}, [type]);
useEffect(() => {
eSubscribeEvent("groupOptionsUpdate", onUpdate);
return () => {
eUnSubscribeEvent("groupOptionsUpdate", onUpdate);
};
}, [onUpdate]);
return (
<View
style={{

View File

@@ -77,7 +77,7 @@ export const openNotebookTopic = (item) => {
useTrashStore.getState().setTrash();
useSelectionStore.getState().setSelectionMode(false);
ToastEvent.show({
heading: "Permanently deleted items",
heading: "Permanantly deleted items",
type: "success",
context: "local"
});

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { Dimensions, View } from "react-native";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useMessageStore } from "../../stores/use-message-store";
import { useThemeColors } from "@notesnook/theme";
@@ -32,7 +32,6 @@ export const Card = ({ color, warning }) => {
color = color ? color : colors.primary.accent;
const messageBoardState = useMessageStore((state) => state.message);
const announcement = useMessageStore((state) => state.announcement);
const fontScale = Dimensions.get("window").fontScale;
return !messageBoardState.visible || announcement || warning ? null : (
<View
@@ -45,6 +44,7 @@ export const Card = ({ color, warning }) => {
type="gray"
customStyle={{
paddingVertical: 12,
width: "95%",
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
@@ -54,18 +54,17 @@ export const Card = ({ color, warning }) => {
<View
style={{
flexDirection: "row",
alignItems: "center",
flexShrink: 1
alignItems: "center"
}}
>
<View
style={{
width: 40 * fontScale,
width: 40,
backgroundColor:
messageBoardState.type === "error"
? hexToRGBA(colors.static.red, 0.15)
: hexToRGBA(color, 0.15),
height: 40 * fontScale,
height: 40,
borderRadius: 100,
alignItems: "center",
justifyContent: "center"
@@ -76,7 +75,6 @@ export const Card = ({ color, warning }) => {
color={
messageBoardState.type === "error" ? colors.error.icon : color
}
allowFontScaling
name={messageBoardState.icon}
/>
</View>
@@ -93,7 +91,7 @@ export const Card = ({ color, warning }) => {
</Paragraph>
<Paragraph
style={{
flexWrap: "nowrap",
flexWrap: "wrap",
flexShrink: 1
}}
color={colors.primary.heading}
@@ -103,24 +101,22 @@ export const Card = ({ color, warning }) => {
</View>
</View>
{fontScale > 1 ? null : (
<View
style={{
width: 40,
height: 40,
justifyContent: "center",
alignItems: "center"
}}
>
<Icon
name="chevron-right"
color={
messageBoardState.type === "error" ? colors.error.icon : color
}
size={SIZE.lg}
/>
</View>
)}
<View
style={{
width: 40,
height: 40,
justifyContent: "center",
alignItems: "center"
}}
>
<Icon
name="chevron-right"
color={
messageBoardState.type === "error" ? colors.error.icon : color
}
size={SIZE.lg}
/>
</View>
</PressableButton>
</View>
);

View File

@@ -39,7 +39,6 @@ import { Empty } from "./empty";
import { getTotalNotes } from "@notesnook/common";
import { useSettingStore } from "../../stores/use-setting-store";
import ReminderItem from "../list-items/reminder";
import { useGroupOptions } from "../../hooks/use-group-options";
const renderItems = {
note: NoteWrapper,
@@ -100,10 +99,9 @@ const List = ({
type === "notebooks" ||
notebooksListMode === "compact";
const groupType =
screen === "Home" ? "home" : screen === "Favorites" ? "favorites" : type;
const groupOptions = useGroupOptions(groupType);
screen === "Notes" ? "home" : screen === "Favorites" ? "favorites" : type;
const groupOptions = db.settings?.getGroupOptions(groupType);
const dateBy =
groupOptions.sortBy !== "title" ? groupOptions.sortBy : "dateEdited";
@@ -115,21 +113,18 @@ const List = ({
color={headerProps?.color}
title={headerProps?.heading}
dateBy={dateBy}
type={groupType}
type={
screen === "Notes"
? "home"
: screen === "Favorites"
? "favorites"
: type
}
screen={screen}
isSheet={isSheet}
groupOptions={groupOptions}
/>
),
[
headerProps?.color,
headerProps?.heading,
screen,
isSheet,
dateBy,
groupType,
groupOptions
]
[headerProps?.color, headerProps?.heading, screen, type, isSheet, dateBy]
);
const _onRefresh = async () => {
@@ -235,7 +230,7 @@ const List = ({
<JumpToSectionDialog
screen={screen}
data={listData}
type={screen === "Home" ? "home" : type}
type={screen === "Notes" ? "home" : type}
scrollRef={scrollRef}
/>
) : null}

View File

@@ -245,17 +245,13 @@ const MergeConflicts = () => {
};
return !visible ? null : (
<BaseDialog
<Modal
statusBarTranslucent
transparent={false}
animationType="slide"
animated={false}
bounce={false}
onRequestClose={() => {
close();
}}
centered={false}
background={colors?.primary.background}
supportedOrientations={[
"portrait",
"portrait-upside-down",
@@ -367,7 +363,7 @@ const MergeConflicts = () => {
</Animated.View>
</View>
</SafeAreaView>
</BaseDialog>
</Modal>
);
};

View File

@@ -84,7 +84,7 @@ export default function NotePreview({ session, content, note }) {
useTrashStore.getState().setTrash();
useSelectionStore.getState().setSelectionMode(false);
ToastEvent.show({
heading: "Permanently deleted items",
heading: "Permanantly deleted items",
type: "success",
context: "local"
});

View File

@@ -56,7 +56,7 @@ export const CompactFeatures = ({
icon: "shield"
},
{
highlight: "Daily, weekly & monthly",
highlight: "Daily, weekly & montly",
content: "recurring reminders",
icon: "bell"
},

View File

@@ -98,7 +98,7 @@ export const features = [
icon: "bell"
},
{
highlight: "Daily, weekly & monthly",
highlight: "Daily, weekly & montly",
content: "reminders",
icon: "refresh",
pro: true
@@ -194,7 +194,7 @@ export const features = [
"Having the right tool at the right time is crucial for note taking. Lists, tables, codeblocks — you name it, we have it.",
features: [
{
highlight: "Basic formatting",
highlight: "Basic formating",
content: "and lists",
icon: "format-bold"
},

View File

@@ -500,7 +500,7 @@ export const PricingPlans = ({
textAlign: "center"
}}
>
By subscribing, you will be charged on your Google Account, and
By subscribing, your will be charged on your Google Account, and
your subscription will automatically renew until you cancel prior
to the end of the then current period.
</Paragraph>

View File

@@ -16,8 +16,8 @@ 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 } from "react";
import { Dimensions, Platform, View, useWindowDimensions } from "react-native";
import React from "react";
import { Platform, View } from "react-native";
import { FlatList } from "react-native-actions-sheet";
import { db } from "../../common/database";
import { DDS } from "../../services/device-detection";
@@ -54,6 +54,7 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
const { colors } = useThemeColors();
const alias = item.alias || item.title;
const isColor = !!ColorValues[item.title];
if (!item || !item.id) {
return (
<Paragraph style={{ marginVertical: 10, alignSelf: "center" }}>
@@ -61,7 +62,6 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
</Paragraph>
);
}
return (
<FlatList
keyboardShouldPersistTaps="always"
@@ -135,7 +135,6 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
}, 1000);
}}
/>
<Synced item={item} close={close} />
{DDS.isTab ? (

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { Dimensions, FlatList, ScrollView, View } from "react-native";
import { FlatList, ScrollView, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useActions } from "../../hooks/use-actions";
import { DDS } from "../../services/device-detection";
@@ -33,11 +33,9 @@ export const Items = ({ item, buttons, close }) => {
const dimensions = useSettingStore((state) => state.dimensions);
const actions = useActions({ item, close });
const data = actions.filter((i) => buttons.indexOf(i.id) > -1 && !i.hidden);
let width = dimensions.width > 600 ? 600 : dimensions.width;
const shouldShrink =
Dimensions.get("window").fontScale > 1 &&
Dimensions.get("window").width < 450;
let columnItemsCount = DDS.isLargeTablet() ? 7 : shouldShrink ? 4 : 5;
let columnItemsCount = DDS.isLargeTablet() ? 7 : 5;
let columnItemWidth = DDS.isTab
? (width - 12) / columnItemsCount
: (width - 12) / columnItemsCount;
@@ -68,7 +66,6 @@ export const Items = ({ item, buttons, close }) => {
}}
>
<Icon
allowFontScaling
name={item.icon}
size={DDS.isTab ? SIZE.xxl : SIZE.lg}
color={
@@ -81,11 +78,7 @@ export const Items = ({ item, buttons, close }) => {
/>
</PressableButton>
<Paragraph
size={SIZE.xs}
textBreakStrategy="simple"
style={{ textAlign: "center" }}
>
<Paragraph size={SIZE.xs} style={{ textAlign: "center" }}>
{item.title}
</Paragraph>
</View>
@@ -146,7 +139,6 @@ export const Items = ({ item, buttons, close }) => {
>
<Icon
name={item.icon}
allowFontScaling
size={DDS.isTab ? SIZE.xxl : SIZE.md + 4}
color={
item.on
@@ -158,11 +150,7 @@ export const Items = ({ item, buttons, close }) => {
/>
</PressableButton>
<Paragraph
textBreakStrategy="simple"
size={SIZE.xxs + 1}
style={{ textAlign: "center" }}
>
<Paragraph size={SIZE.xxs + 1} style={{ textAlign: "center" }}>
{item.title}
</Paragraph>
</PressableButton>
@@ -175,12 +163,9 @@ export const Items = ({ item, buttons, close }) => {
"copy",
"share",
"export",
"lock-unlock"
"lock-unlock",
"publish"
];
if (!shouldShrink) {
topBarItemsList.push("publish");
}
const topBarItems = data.filter(
(item) => topBarItemsList.indexOf(item.id) > -1
);

View File

@@ -17,10 +17,10 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useThemeColors } from "@notesnook/theme";
import React from "react";
import { View, useWindowDimensions } from "react-native";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useThemeColors } from "@notesnook/theme";
import { useUserStore } from "../../stores/use-user-store";
import { openLinkInBrowser } from "../../utils/functions";
import { SIZE } from "../../utils/size";
@@ -33,8 +33,6 @@ export const Synced = ({ item, close }) => {
const user = useUserStore((state) => state.user);
const lastSynced = useUserStore((state) => state.lastSynced);
const dimensions = useWindowDimensions();
const shouldShrink = dimensions.fontScale > 1 && dimensions.width < 450;
return user && lastSynced >= item.dateModified ? (
<View
style={{
@@ -51,11 +49,7 @@ export const Synced = ({ item, close }) => {
borderTopColor: colors.secondary.background
}}
>
<Icon
name="shield-key-outline"
color={colors.primary.accent}
size={shouldShrink ? SIZE.xxl : SIZE.xxxl}
/>
<Icon name="shield-key-outline" color={colors.primary.accent} size={SIZE.xxxl} />
<View
style={{
@@ -73,17 +67,15 @@ export const Synced = ({ item, close }) => {
>
Encrypted and synced
</Heading>
{shouldShrink ? null : (
<Paragraph
style={{
flexWrap: "wrap"
}}
size={SIZE.xs}
color={colors.primary.paragraph}
>
No one can view this {item.itemType || item.type} except you.
</Paragraph>
)}
<Paragraph
style={{
flexWrap: "wrap"
}}
size={SIZE.xs}
color={colors.primary.paragraph}
>
No one can view this {item.itemType || item.type} except you.
</Paragraph>
</View>
<Button
@@ -99,8 +91,8 @@ export const Synced = ({ item, close }) => {
console.error(e);
}
}}
title="Learn more"
fontSize={SIZE.xs}
title="Learn more"
height={30}
type="grayAccent"
/>

View File

@@ -207,6 +207,7 @@ export const SelectionHeader = React.memo(() => {
{screen === "Trash" ||
screen === "Notebooks" ||
screen === "Notebook" ||
screen === "Reminders" ? null : (
<>
<IconButton
@@ -223,21 +224,6 @@ export const SelectionHeader = React.memo(() => {
name="pound"
size={SIZE.xl}
/>
<IconButton
onPress={async () => {
ExportNotesSheet.present(selectedItemsList);
}}
tooltipText="Export"
tooltipPosition={4}
customStyle={{
marginLeft: 10
}}
color={colors.primary.paragraph}
name="export"
size={SIZE.xl}
/>
<IconButton
onPress={async () => {
//setSelectionMode(false);
@@ -253,6 +239,20 @@ export const SelectionHeader = React.memo(() => {
name="plus"
size={SIZE.xl}
/>
<IconButton
onPress={async () => {
ExportNotesSheet.present(selectedItemsList);
}}
tooltipText="Export"
tooltipPosition={4}
customStyle={{
marginLeft: 10
}}
color={colors.primary.paragraph}
name="export"
size={SIZE.xl}
/>
</>
)}
@@ -317,8 +317,23 @@ export const SelectionHeader = React.memo(() => {
customStyle={{
marginLeft: 10
}}
onPress={() => {
deleteItems();
onPress={async () => {
presentDialog({
title: `Delete ${
selectedItemsList.length > 1 ? "items" : "item"
}`,
paragraph: `Are you sure you want to delete ${
selectedItemsList.length > 1 ? "these items?" : "this item?"
}`,
positiveText: "Delete",
negativeText: "Cancel",
positivePress: () => {
deleteItems();
},
positiveType: "errorShade"
});
return;
}}
tooltipText="Move to trash"
tooltipPosition={1}

View File

@@ -198,6 +198,7 @@ const SheetProvider = ({ context = "global" }) => {
key={data.actionText}
title={data.actionText}
accentColor={data.iconColor}
accentText="light"
type="accent"
height={40}
width={250}

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useCallback, useEffect, useRef, useState } from "react";
import { FlashList } from "react-native-actions-sheet";
import { FlatList } from "react-native-actions-sheet";
import { db } from "../../../common/database";
import { ListHeaderInputItem } from "./list-header-item.js";
@@ -54,7 +54,7 @@ export const FilteredList = ({
}, [data, onChangeText]);
return (
<FlashList
<FlatList
{...restProps}
data={filtered}
ref={listRef}

View File

@@ -161,6 +161,9 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
: "deselected";
if (itemState[notebook.id] === "selected") {
count++;
contextValue.select(notebook);
} else {
contextValue.deselect(notebook);
}
for (let topic of notebook.topics) {
itemState[topic.id] = state
@@ -173,6 +176,9 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
: "deselected";
if (itemState[topic.id] === "selected") {
count++;
contextValue.select(topic);
} else {
contextValue.deselect(topic);
}
}
}
@@ -183,7 +189,7 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
}
useItemSelectionStore.getState().setItemState(itemState);
},
[getSelectedNotesCountInItem, selectedItemsList]
[contextValue, getSelectedNotesCountInItem, selectedItemsList]
);
const getItemsForItem = (item) => {
@@ -208,7 +214,7 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
}
const updateItemState = useCallback(function (item, state) {
const itemState = { ...useItemSelectionStore.getState().itemState };
const itemState = useItemSelectionStore.getState().itemState;
const mergeState = {
[item.id]: state
};
@@ -364,93 +370,56 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
</View>
<SelectionProvider value={contextValue}>
<View
<FilteredList
style={{
paddingHorizontal: 12,
maxHeight: dimensions.height * 0.85,
height: 50 * (notebooks.length + 2)
maxHeight: dimensions.height * 0.85
}}
>
<FilteredList
ListEmptyComponent={
notebooks.length > 0 ? null : (
<View
style={{
width: "100%",
height: "100%",
justifyContent: "center",
alignItems: "center"
}}
>
<Icon
name="book-outline"
color={colors.primary.icon}
size={100}
/>
<Paragraph style={{ marginBottom: 10 }}>
You do not have any notebooks.
</Paragraph>
</View>
)
}
estimatedItemSize={50}
data={notebooks}
hasHeaderSearch={true}
renderItem={({ item, index }) => (
<ListItem
item={item}
key={item.id}
index={index}
hasNotes={getSelectedNotesCountInItem(item) > 0}
sheetRef={actionSheetRef}
infoText={
<>
{item.topics.length === 1
? item.topics.length + " topic"
: item.topics.length + " topics"}
</>
}
getListItems={getItemsForItem}
getSublistItemProps={(topic) => ({
hasNotes: getSelectedNotesCountInItem(topic) > 0,
style: {
marginBottom: 0,
height: 40
},
onPress: (item) => {
const itemState =
useItemSelectionStore.getState().itemState;
const currentState = itemState[item.id];
if (currentState !== "selected") {
resetItemState("deselected");
contextValue.select(item);
} else {
contextValue.deselect(item);
}
},
key: item.id,
type: "transparent"
})}
icon={(expanded) => ({
name: expanded ? "chevron-up" : "chevron-down",
color: expanded
? colors.primary.accent
: colors.primary.paragraph
})}
onScrollEnd={() => {
actionSheetRef.current?.handleChildScrollEnd();
ListEmptyComponent={
notebooks.length > 0 ? null : (
<View
style={{
width: "100%",
height: "100%",
justifyContent: "center",
alignItems: "center"
}}
hasSubList={true}
hasHeaderSearch={false}
type="grayBg"
sublistItemType="topic"
onAddItem={(title) => {
return onAddTopic(title, item);
}}
onAddSublistItem={(item) => {
openAddTopicDialog(item);
}}
onPress={(item) => {
>
<Icon
name="book-outline"
color={colors.primary.icon}
size={100}
/>
<Paragraph style={{ marginBottom: 10 }}>
You do not have any notebooks.
</Paragraph>
</View>
)
}
data={notebooks}
hasHeaderSearch={true}
renderItem={({ item, index }) => (
<ListItem
item={item}
key={item.id}
index={index}
hasNotes={getSelectedNotesCountInItem(item) > 0}
sheetRef={actionSheetRef}
infoText={
<>
{item.topics.length === 1
? item.topics.length + " topic"
: item.topics.length + " topics"}
</>
}
getListItems={getItemsForItem}
getSublistItemProps={(topic) => ({
hasNotes: getSelectedNotesCountInItem(topic) > 0,
style: {
marginBottom: 0,
height: 40
},
onPress: (item) => {
const itemState =
useItemSelectionStore.getState().itemState;
const currentState = itemState[item.id];
@@ -460,16 +429,47 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
} else {
contextValue.deselect(item);
}
}}
/>
)}
itemType="notebook"
onAddItem={async (title) => {
return await onAddNotebook(title);
}}
ListFooterComponent={<View style={{ height: 20 }} />}
/>
</View>
},
key: item.id,
type: "transparent"
})}
icon={(expanded) => ({
name: expanded ? "chevron-up" : "chevron-down",
color: expanded
? colors.primary.accent
: colors.primary.paragraph
})}
onScrollEnd={() => {
actionSheetRef.current?.handleChildScrollEnd();
}}
hasSubList={true}
hasHeaderSearch={false}
type="grayBg"
sublistItemType="topic"
onAddItem={(title) => {
return onAddTopic(title, item);
}}
onAddSublistItem={(item) => {
openAddTopicDialog(item);
}}
onPress={(item) => {
const itemState = useItemSelectionStore.getState().itemState;
const currentState = itemState[item.id];
if (currentState !== "selected") {
resetItemState("deselected");
contextValue.select(item);
} else {
contextValue.deselect(item);
}
}}
/>
)}
itemType="notebook"
onAddItem={async (title) => {
return await onAddNotebook(title);
}}
ListFooterComponent={<View style={{ height: 20 }} />}
/>
</SelectionProvider>
</View>
</>

View File

@@ -273,7 +273,6 @@ export const ListItem = ({
alignSelf: "flex-end",
maxHeight: 250
}}
estimatedItemSize={40}
itemType={sublistItemType}
hasHeaderSearch={hasHeaderSearch}
renderItem={({ item, index }) => (

View File

@@ -111,7 +111,7 @@ Logged in: ${user ? "yes" : "no"}`,
} catch (e) {
setLoading(false);
ToastEvent.show({
heading: "An error occurred",
heading: "An error occured",
message: e.message,
type: "error"
});

View File

@@ -177,7 +177,7 @@ export default function Migrate() {
textAlign: "center"
}}
>
An error occurred while migrating your data. You can logout of your
An error occured while migrating your data. You can logout of your
account and try to relogin. However this is not recommended as it
may result in some data loss if your data was not synced.
</Paragraph>

View File

@@ -40,9 +40,7 @@ import { requestInAppReview } from "../../../services/app-review";
const PublishNoteSheet = ({ note: item, update }) => {
const { colors } = useThemeColors();
const actionSheetRef = useRef();
const attachmentDownloads = useAttachmentStore((state) => state.downloading);
const downloading = attachmentDownloads[`monograph-${item.id}`];
const loading = useAttachmentStore((state) => state.loading);
const [selfDestruct, setSelfDestruct] = useState(false);
const [isLocked, setIsLocked] = useState(false);
const [note, setNote] = useState(item);
@@ -139,9 +137,9 @@ const PublishNoteSheet = ({ note: item, update }) => {
}}
>
Please wait...
{downloading && downloading.current && downloading.total
{loading && loading.current && loading.total
? `\nDownloading attachments (${
downloading?.current / downloading?.total
loading?.current / loading?.total
})`
: ""}
</Paragraph>

View File

@@ -253,57 +253,6 @@ export default function ReminderSheet({
marginBottom: DDS.isTab ? 25 : undefined
}}
>
{reminderMode === ReminderModes.Permanent ? null : (
<ScrollView
style={{
flexDirection: "row",
borderWidth: 1,
marginTop: 12,
borderRadius: 5,
borderColor: colors.primary.border,
paddingLeft: 12,
height: 50
}}
horizontal
>
{Object.keys(ReminderNotificationModes).map((mode) => (
<Button
key={mode}
title={mode}
style={{
marginRight: 12,
borderRadius: 100
}}
icon={
mode === "Silent"
? "minus-circle"
: mode === "Vibrate"
? "vibrate"
: "volume-high"
}
height={35}
type={
reminderNotificationMode ===
ReminderNotificationModes[
mode as keyof typeof ReminderNotificationModes
]
? "grayAccent"
: "gray"
}
onPress={() => {
const _mode = ReminderNotificationModes[
mode as keyof typeof ReminderNotificationModes
] as Reminder["priority"];
SettingsService.set({
reminderNotificationMode: _mode
});
setReminderNotificatioMode(_mode);
}}
/>
))}
</ScrollView>
)}
<Input
fwdRef={titleRef}
defaultValue={reminder?.title || referencedItem?.title}
@@ -331,21 +280,15 @@ export default function ReminderSheet({
}}
height={80}
wrapperStyle={{
marginBottom: 12
marginBottom: 20
}}
/>
<ScrollView
<View
style={{
flexDirection: "row",
marginBottom: 12,
height: 50,
borderWidth: 1,
borderRadius: 5,
borderColor: colors.primary.border,
paddingLeft: 12
marginBottom: 12
}}
horizontal
>
{Object.keys(ReminderModes).map((mode) => (
<Button
@@ -384,7 +327,7 @@ export default function ReminderSheet({
}}
/>
))}
</ScrollView>
</View>
{reminderMode === ReminderModes.Repeat ? (
<View
@@ -555,6 +498,53 @@ export default function ReminderSheet({
</View>
)}
{reminderMode === ReminderModes.Permanent ? null : (
<View
style={{
flexDirection: "row",
marginBottom: 12,
paddingTop: 12,
borderTopWidth: 1,
borderTopColor: colors.secondary.background
}}
>
{Object.keys(ReminderNotificationModes).map((mode) => (
<Button
key={mode}
title={mode}
style={{
marginRight: 12,
borderRadius: 100
}}
icon={
mode === "Silent"
? "minus-circle"
: mode === "Vibrate"
? "vibrate"
: "volume-high"
}
height={35}
type={
reminderNotificationMode ===
ReminderNotificationModes[
mode as keyof typeof ReminderNotificationModes
]
? "grayAccent"
: "gray"
}
onPress={() => {
const _mode = ReminderNotificationModes[
mode as keyof typeof ReminderNotificationModes
] as Reminder["priority"];
SettingsService.set({
reminderNotificationMode: _mode
});
setReminderNotificatioMode(_mode);
}}
/>
))}
</View>
)}
{reminderMode === ReminderModes.Once ||
reminderMode === ReminderModes.Permanent ? null : (
<View
@@ -605,11 +595,6 @@ export default function ReminderSheet({
}}
/>
</ScrollView>
<View
style={{
height: 10
}}
/>
</View>
);
}

View File

@@ -22,9 +22,7 @@ import React, { useCallback, useEffect, useRef, useState } from "react";
import { ActivityIndicator, Platform, View } from "react-native";
import { FlatList } from "react-native-actions-sheet";
import RNFetchBlob from "react-native-blob-util";
import DocumentPicker, {
DocumentPickerResponse
} from "react-native-document-picker";
import DocumentPicker from "react-native-document-picker";
import * as ScopedStorage from "react-native-scoped-storage";
import { db } from "../../../common/database";
import storage from "../../../common/database/storage";
@@ -47,8 +45,6 @@ import Seperator from "../../ui/seperator";
import SheetWrapper from "../../ui/sheet";
import Paragraph from "../../ui/typography/paragraph";
import { getFormattedDate } from "@notesnook/common";
import { unzip } from "react-native-zip-archive";
import { cacheDir, copyFileAsync } from "../../../common/filesystem/utils";
const RestoreDataSheet = () => {
const [visible, setVisible] = useState(false);
@@ -133,71 +129,75 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
useEffect(() => {
setTimeout(() => {
checkBackups();
}, 1000);
}, 300);
}, []);
const restore = async (item) => {
if (restoring) {
return;
}
try {
const file = Platform.OS === "ios" ? item.path : item.uri;
console.log(file);
if (file.endsWith(".nnbackupz")) {
setRestoring(true);
setRestoring(true);
let prefix = Platform.OS === "ios" ? "" : "file:/";
let backup;
if (Platform.OS === "android") {
backup = await ScopedStorage.readFile(item.uri, "utf8");
} else {
backup = await RNFetchBlob.fs.readFile(prefix + item.path, "utf8");
}
backup = JSON.parse(backup);
if (Platform.OS === "android") {
const cacheFile = `file://${RNFetchBlob.fs.dirs.CacheDir}/backup.zip`;
if (await RNFetchBlob.fs.exists(cacheFile)) {
await RNFetchBlob.fs.unlink(cacheFile);
if (backup.data.iv && backup.data.salt) {
withPassword(
async (value) => {
try {
await restoreBackup(backup, value);
close();
setRestoring(false);
return true;
} catch (e) {
backupError(e);
return false;
}
},
() => {
setRestoring(false);
}
await RNFetchBlob.fs.createFile(cacheFile, "", "utf8");
console.log("copying");
await copyFileAsync(file, cacheFile);
console.log("copied");
await restoreFromZip(cacheFile);
} else {
await restoreFromZip(file, false);
}
} else if (file.endsWith(".nnbackup")) {
let backup;
if (Platform.OS === "android") {
backup = await ScopedStorage.readFile(file, "utf8");
} else {
backup = await RNFetchBlob.fs.readFile(file, "utf8");
}
await restoreFromNNBackup(JSON.parse(backup));
);
} else {
await restoreBackup(backup);
close();
}
} catch (e) {
console.log("error", e);
setRestoring(false);
backupError(e);
}
};
const withPassword = () => {
return new Promise((resolve) => {
let resolved = false;
presentDialog({
context: "local",
title: "Encrypted backup",
input: true,
inputPlaceholder: "Password",
paragraph: "Please enter password of this backup file to restore it",
positiveText: "Restore",
secureTextEntry: true,
onClose: () => {
if (resolved) return;
resolve(undefined);
},
negativeText: "Cancel",
positivePress: async (password) => {
resolve(password);
resolved = true;
return true;
const withPassword = (onsubmit, onclose = () => {}) => {
presentDialog({
context: "local",
title: "Encrypted backup",
input: true,
inputPlaceholder: "Password",
paragraph: "Please enter password of this backup file to restore it",
positiveText: "Restore",
secureTextEntry: true,
onClose: onclose,
negativeText: "Cancel",
positivePress: async (password) => {
try {
return await onsubmit(password);
} catch (e) {
ToastEvent.show({
heading: "Failed to backup data",
message: e.message,
type: "error",
context: "global"
});
return false;
}
});
}
});
};
@@ -217,164 +217,21 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
let path = await storage.checkAndCreateDir("/backups/");
files = await RNFetchBlob.fs.lstat(path);
}
files = files
.filter((file) => {
const name = Platform.OS === "android" ? file.name : file.filename;
return name.endsWith(".nnbackup") || name.endsWith(".nnbackupz");
})
.sort(function (a, b) {
let timeA = a.lastModified;
let timeB = b.lastModified;
return timeB - timeA;
});
files = files.sort(function (a, b) {
let timeA = a.lastModified;
let timeB = b.lastModified;
return timeB - timeA;
});
setFiles(files);
setLoading(false);
setTimeout(() => {
setLoading(false);
}, 1000);
} catch (e) {
console.log(e);
setLoading(false);
}
};
const restoreBackup = async (backup, password) => {
await db.backup.import(backup, password);
await db.initCollections();
initialize();
ToastEvent.show({
heading: "Backup restored successfully.",
type: "success",
context: "global"
});
return true;
};
const backupError = (e) => {
ToastEvent.show({
heading: "Restore failed",
message:
e.message ||
"The selected backup data file is invalid. You must select a *.nnbackup file to restore.",
type: "error",
context: "local"
});
};
/**
*
* @param {string} file
*/
async function restoreFromZip(file, remove) {
try {
const zipOutputFolder = `${cacheDir}/backup_extracted`;
if (await RNFetchBlob.fs.exists(zipOutputFolder)) {
await RNFetchBlob.fs.unlink(zipOutputFolder);
await RNFetchBlob.fs.mkdir(zipOutputFolder);
}
await unzip(file, zipOutputFolder);
console.log("Unzipped files successfully to", zipOutputFolder);
const backupFiles = await RNFetchBlob.fs.ls(zipOutputFolder);
if (backupFiles.findIndex((file) => file === ".nnbackup") === -1) {
throw new Error("Backup file is invalid");
}
let password;
console.log(`Found ${backupFiles?.length} files to restore from backup`);
for (const path of backupFiles) {
if (path === ".nnbackup") continue;
const filePath = `${zipOutputFolder}/${path}`;
const data = await RNFetchBlob.fs.readFile(filePath, "utf8");
const parsed = JSON.parse(data);
if (parsed.encrypted && !password) {
console.log("Backup is encrypted...", "requesting password");
password = await withPassword();
if (!password) throw new Error("Failed to decrypt backup");
}
await db.backup.import(parsed, password);
console.log("Imported", path);
}
// Remove files from cache
RNFetchBlob.fs.unlink(zipOutputFolder).catch(console.log);
if (remove) {
RNFetchBlob.fs.unlink(file).catch(console.log);
}
await db.initCollections();
initialize();
setRestoring(false);
close();
ToastEvent.show({
heading: "Backup restored successfully.",
type: "success",
context: "global"
});
} catch (e) {
backupError(e);
setRestoring(false);
}
}
/**
*
* @param {string} file
*/
async function restoreFromNNBackup(backup) {
try {
if (backup.data.iv && backup.data.salt) {
const password = await withPassword();
if (password) {
try {
await restoreBackup(backup, password);
close();
setRestoring(false);
} catch (e) {
setRestoring(false);
backupError(e);
}
} else {
setRestoring(false);
}
} else {
await restoreBackup(backup);
setRestoring(false);
close();
}
} catch (e) {
setRestoring(false);
backupError(e);
}
}
const button = {
title: "Restore from files",
onPress: async () => {
if (restoring) {
return;
}
try {
const file = await DocumentPicker.pickSingle({
copyTo: "cachesDirectory"
});
if (file.name.endsWith(".nnbackupz")) {
setRestoring(true);
await restoreFromZip(file.fileCopyUri, true);
} else if (file.name.endsWith(".nnbackup")) {
RNFetchBlob.fs.unlink(file.fileCopyUri).catch(console.log);
setRestoring(true);
const data = await fetch(file.uri);
await restoreFromNNBackup(await data.json());
}
} catch (e) {
console.log("error", e.stack);
setRestoring(false);
backupError(e);
}
}
};
const renderItem = ({ item, index }) => (
<View
style={{
@@ -414,6 +271,76 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
</View>
);
const restoreBackup = async (backup, password) => {
await db.backup.import(backup, password);
setRestoring(false);
initialize();
ToastEvent.show({
heading: "Backup restored successfully.",
type: "success",
context: "global"
});
};
const backupError = (e) => {
ToastEvent.show({
heading: "Restore failed",
message:
e.message ||
"The selected backup data file is invalid. You must select a *.nnbackup file to restore.",
type: "error",
context: "local"
});
};
const button = {
title: "Restore from files",
onPress: () => {
if (restoring) {
return;
}
DocumentPicker.pickSingle()
.then((r) => {
setRestoring(true);
fetch(r.uri)
.then(async (r) => {
try {
let backup = await r.json();
if (backup.data.iv && backup.data.salt) {
withPassword(
async (value) => {
try {
restoreBackup(backup, value).then(() => {
close();
setRestoring(false);
});
return true;
} catch (e) {
backupError(e);
setRestoring(false);
return false;
}
},
() => {
setRestoring(false);
}
);
} else {
await restoreBackup(backup);
close();
}
} catch (e) {
setRestoring(false);
backupError(e);
}
})
.catch(console.log);
})
.catch(console.log);
}
};
return (
<>
<View>

View File

@@ -16,7 +16,6 @@ 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 { useThemeColors } from "@notesnook/theme";
import qclone from "qclone";
import React, {
createContext,
@@ -27,7 +26,7 @@ import React, {
useRef,
useState
} from "react";
import { RefreshControl, useWindowDimensions, View } from "react-native";
import { RefreshControl, View } from "react-native";
import ActionSheet, {
ActionSheetRef,
FlatList
@@ -46,6 +45,7 @@ import {
import useNavigationStore, {
NotebookScreenParams
} from "../../../stores/use-navigation-store";
import { useThemeColors } from "@notesnook/theme";
import {
eOnNewTopicAdded,
eOnTopicSheetUpdate,
@@ -54,17 +54,18 @@ import {
import { normalize, SIZE } from "../../../utils/size";
import { GroupHeader, NotebookType, TopicType } from "../../../utils/types";
import { getTotalNotes } from "@notesnook/common";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import Config from "react-native-config";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { notesnook } from "../../../../e2e/test.ids";
import { MMKV } from "../../../common/database/mmkv";
import { openEditor } from "../../../screens/notes/common";
import { useSelectionStore } from "../../../stores/use-selection-store";
import { getTotalNotes } from "@notesnook/common";
import { deleteItems } from "../../../utils/functions";
import { presentDialog } from "../../dialog/functions";
import { Properties } from "../../properties";
import Sort from "../sort";
import { useSelectionStore } from "../../../stores/use-selection-store";
type ConfigItem = { id: string; type: string };
class TopicSheetConfig {
@@ -107,8 +108,7 @@ export const TopicsSheet = () => {
)
: []
);
const currentItem = useRef<string>();
const { fontScale } = useWindowDimensions();
const [groupOptions, setGroupOptions] = useState(
db.settings?.getGroupOptions("topics")
);
@@ -206,11 +206,6 @@ export const TopicsSheet = () => {
if (canShow) {
setTimeout(() => {
const id = isTopic ? currentScreen?.notebookId : currentScreen?.id;
if (currentItem.current !== id) {
setSelection([]);
setEnabled(false);
}
currentItem.current = id;
const notebook = db.notebooks?.notebook(id as string)?.data;
const snapPoint = isTopic
? 0
@@ -231,8 +226,6 @@ export const TopicsSheet = () => {
}
}, 300);
} else {
setSelection([]);
setEnabled(false);
ref.current?.hide();
}
}, [
@@ -278,7 +271,7 @@ export const TopicsSheet = () => {
backgroundColor: colors.secondary.background
}}
keyboardHandlerEnabled={false}
snapPoints={Config.isTesting === "true" ? [100] : [20, 100]}
snapPoints={Config.isTesting === "true" ? [100] : [25, 100]}
initialSnapIndex={1}
backgroundInteractionEnabled
gestureEnabled
@@ -312,8 +305,8 @@ export const TopicsSheet = () => {
</View>
<View
style={{
maxHeight: 450,
height: 450,
maxHeight: 300,
height: 300,
width: "100%"
}}
>
@@ -336,19 +329,30 @@ export const TopicsSheet = () => {
{enabled ? (
<IconButton
customStyle={{
marginLeft: 10,
width: 40 * fontScale,
height: 40 * fontScale
marginLeft: 10
}}
onPress={async () => {
//@ts-ignore
useSelectionStore.setState({
selectedItemsList: selection
});
await deleteItems();
useSelectionStore.getState().clearSelection();
setEnabled(false);
setSelection([]);
presentDialog({
title: `Delete ${
selection.length > 1 ? "topics" : "topics"
}`,
paragraph: `Are you sure you want to delete ${
selection.length > 1 ? "these topics?" : "this topic?"
}`,
positiveText: "Delete",
negativeText: "Cancel",
positivePress: async () => {
await deleteItems();
useSelectionStore.getState().clearSelection();
setEnabled(false);
setSelection([]);
},
positiveType: "errorShade"
});
return;
}}
color={colors.primary.icon}
@@ -374,8 +378,8 @@ export const TopicsSheet = () => {
color={colors.primary.icon}
size={22}
customStyle={{
width: 40 * fontScale,
height: 40 * fontScale
width: 40,
height: 40
}}
/>
<IconButton
@@ -385,8 +389,8 @@ export const TopicsSheet = () => {
color={colors.primary.icon}
size={22}
customStyle={{
width: 40 * fontScale,
height: 40 * fontScale
width: 40,
height: 40
}}
/>
@@ -404,8 +408,8 @@ export const TopicsSheet = () => {
color={colors.primary.icon}
size={22}
customStyle={{
width: 40 * fontScale,
height: 40 * fontScale
width: 40,
height: 40
}}
/>
</>
@@ -479,7 +483,6 @@ const TopicItem = ({
selection.selection.findIndex((selected) => selected.id === item.id) > -1;
const isFocused = screen.id === item.id;
const notesCount = getTotalNotes(item);
const { fontScale } = useWindowDimensions();
return (
<PressableButton
@@ -516,10 +519,6 @@ const TopicItem = ({
<IconButton
size={SIZE.lg}
color={isSelected ? colors.selected.icon : colors.primary.icon}
top={0}
left={0}
bottom={0}
right={0}
name={
isSelected
? "check-circle-outline"
@@ -539,8 +538,8 @@ const TopicItem = ({
<IconButton
name="dots-horizontal"
customStyle={{
width: 40 * fontScale,
height: 40 * fontScale
width: 40,
height: 40
}}
testID={notesnook.ids.notebook.menu}
onPress={() => {

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { useThemeColors } from "@notesnook/theme";
import React, { useCallback, useEffect, useState } from "react";
import { Dimensions, View } from "react-native";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import ToggleSwitch from "toggle-switch-react-native";
import Navigation from "../../services/navigation";
@@ -109,7 +109,6 @@ export const MenuItem = React.memo(
textAlignVertical: "center",
textAlign: "left"
}}
allowFontScaling
name={item.icon}
color={
item.icon === "crown"

View File

@@ -209,19 +209,13 @@ export const PinItem = React.memo(
justifyContent: "center"
}}
>
<Icon
allowFontScaling
color={color}
size={SIZE.lg - 2}
name={icons[item.type]}
/>
<Icon color={color} size={SIZE.lg - 2} name={icons[item.type]} />
<Icon
style={{
position: "absolute",
bottom: -6,
left: -6
}}
allowFontScaling
color={color}
size={SIZE.xs}
name="arrow-top-right-thick"

View File

@@ -113,7 +113,6 @@ export const UserStatus = () => {
<Icon
name="checkbox-blank-circle"
size={11}
allowFontScaling
color={
!user || lastSyncStatus === SyncStatus.Failed
? colors.error.icon
@@ -150,15 +149,9 @@ export const UserStatus = () => {
color={colors.error.icon}
name="sync-alert"
size={SIZE.lg}
allowFontScaling
/>
) : (
<Icon
allowFontScaling
color={colors.primary.accent}
name="sync"
size={SIZE.lg}
/>
<Icon color={colors.primary.accent} name="sync" size={SIZE.lg} />
)
) : null}
</PressableButton>

View File

@@ -134,7 +134,6 @@ export const Button = ({
{icon && !loading && iconPosition === "left" ? (
<Icon
name={icon}
allowFontScaling
style={[{ marginRight: 0 }, iconStyle as any]}
color={iconColor || buttonType?.text || textColor}
size={iconSize}
@@ -171,7 +170,6 @@ export const Button = ({
{icon && !loading && iconPosition === "right" ? (
<Icon
name={icon}
allowFontScaling
style={[{ marginLeft: 0 }, iconStyle as any]}
color={iconColor || buttonType?.text || textColor}
size={iconSize}

View File

@@ -40,6 +40,7 @@ interface IconButtonProps extends PressableButtonProps {
iconStyle?: TextStyle;
}
const AnimatedIcon = Animated.createAnimatedComponent(Icon);
export const IconButton = ({
onPress,
name,
@@ -87,10 +88,10 @@ export const IconButton = ({
...customStyle
}}
>
<Icon
<AnimatedIcon
layout={Layout}
name={name}
style={iconStyle as any}
allowFontScaling
color={
restProps.disabled
? RGB_Linear_Shade(-0.05, hexToRGBA(colors.secondary.background))

View File

@@ -17,17 +17,15 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ScopedThemeProvider, useThemeColors } from "@notesnook/theme";
import React, { useEffect, useRef } from "react";
import React from "react";
import { Platform, View } from "react-native";
import ActionSheet from "react-native-actions-sheet";
import useGlobalSafeAreaInsets from "../../../hooks/use-global-safe-area-insets";
import { useSettingStore } from "../../../stores/use-setting-store";
import { ScopedThemeProvider, useThemeColors } from "@notesnook/theme";
import { PremiumToast } from "../../premium/premium-toast";
import { Toast } from "../../toast";
import { useAppState } from "../../../hooks/use-app-state";
import SettingsService from "../../../services/settings";
import { useUserStore } from "../../../stores/use-user-store";
import { BouncingView } from "../transitions/bouncing-view";
const SheetWrapper = ({
children,
@@ -43,7 +41,6 @@ const SheetWrapper = ({
enableGesturesInScrollView = false,
bottomPadding = true
}) => {
const localRef = useRef(null);
const { colors } = useThemeColors("sheet");
const deviceMode = useSettingStore((state) => state.deviceMode);
const sheetKeyboardHandler = useSettingStore(
@@ -53,8 +50,6 @@ const SheetWrapper = ({
const smallTablet = deviceMode === "smallTablet";
const dimensions = useSettingStore((state) => state.dimensions);
const insets = useGlobalSafeAreaInsets();
const appState = useAppState();
const lockEvents = useRef(false);
let width = dimensions.width > 600 ? 600 : 500;
const style = React.useMemo(() => {
@@ -73,40 +68,19 @@ const SheetWrapper = ({
}, [colors.primary.background, largeTablet, smallTablet, width]);
const _onOpen = () => {
if (lockEvents.current) return;
onOpen && onOpen();
};
const _onClose = async () => {
if (lockEvents.current) return;
if (onClose) {
onClose();
}
};
useEffect(() => {
if (SettingsService.get().appLockMode === "background") {
if (appState === "background") {
const ref = fwdRef || localRef;
ref?.current?.hide();
if (useUserStore.getState().appLocked) {
lockEvents.current = true;
const unsub = useUserStore.subscribe((state) => {
if (!state.appLocked) {
ref?.current?.show();
unsub();
lockEvents.current = false;
}
});
}
}
}
}, [appState, fwdRef]);
return (
<ScopedThemeProvider value="sheet">
<ActionSheet
ref={fwdRef || localRef}
ref={fwdRef}
testIDs={{
backdrop: "sheet-backdrop"
}}

View File

@@ -59,6 +59,7 @@ const Heading = ({
<Component
layout={restProps.layout || Layout}
allowFontScaling={true}
maxFontSizeMultiplier={1}
{...restProps}
style={[
{

View File

@@ -45,6 +45,8 @@ const Paragraph = ({
return (
<Component
layout={restProps.layout || Layout}
allowFontScaling
maxFontSizeMultiplier={1}
{...restProps}
style={[
{

View File

@@ -70,8 +70,8 @@ const NotebookWelcome = () => {
count: 5
},
{
title: "Recipes",
description: "I love cooking and collecting recipes",
title: "Recipies",
description: "I love cooking and collecting recipies",
count: 10
}
]);
@@ -195,7 +195,7 @@ const notebooks: { id: string; steps: TStep[] } = {
>
<Paragraph size={SIZE.xs}>
<Icon color={colors.primary.icon} size={SIZE.sm} name="note" />{" "}
February 2022 Week 2
Feburary 2022 Week 2
</Paragraph>
</View>
<View
@@ -211,7 +211,7 @@ const notebooks: { id: string; steps: TStep[] } = {
>
<Paragraph size={SIZE.xs}>
<Icon color={colors.primary.icon} size={SIZE.sm} name="note" />{" "}
February 2022 Week 1
Feburary 2022 Week 1
</Paragraph>
</View>
<View
@@ -257,7 +257,7 @@ const notebooks: { id: string; steps: TStep[] } = {
title: "Tasks",
type: "topic"
}}
onPress={() => { }}
onPress={() => {}}
/>
<PinItem
@@ -267,7 +267,7 @@ const notebooks: { id: string; steps: TStep[] } = {
title: "Work and office",
type: "notebook"
}}
onPress={() => { }}
onPress={() => {}}
/>
</View>
),

View File

@@ -520,7 +520,7 @@ export const useActions = ({ close = () => null, item }) => {
await sleep(300);
presentDialog({
title: "Permanent delete",
paragraph: `Are you sure you want to delete this ${item.itemType} permanently from trash?`,
paragraph: `Are you sure you want to delete this ${item.itemType} permanantly from trash?`,
positiveText: "Delete",
negativeText: "Cancel",
positivePress: async () => {
@@ -529,7 +529,7 @@ export const useActions = ({ close = () => null, item }) => {
Navigation.queueRoutesForUpdate();
useSelectionStore.getState().setSelectionMode(false);
ToastEvent.show({
heading: "Permanently deleted items",
heading: "Permanantly deleted items",
type: "success",
context: "local"
});
@@ -649,7 +649,7 @@ export const useActions = ({ close = () => null, item }) => {
},
{
id: "favorite",
title: item.favorite ? "Unfav" : "Fav",
title: item.favorite ? "Unfavorite" : "Favorite",
icon: item.favorite ? "star-off" : "star-outline",
func: addToFavorites,
close: false,

View File

@@ -83,6 +83,7 @@ import {
import { getGithubVersion } from "../utils/github-version";
import { tabBarRef } from "../utils/global-refs";
import { sleep } from "../utils/time";
import { useThemeColors } from "@notesnook/theme";
const onCheckSyncStatus = async (type) => {
const { disableSync, disableAutoSync } = SettingsService.get();
@@ -106,20 +107,10 @@ const onFileEncryptionProgress = ({ total, progress }) => {
.setEncryptionProgress((progress / total).toFixed(2));
};
const onDownloadingAttachmentProgress = (data) => {
useAttachmentStore.getState().setDownloading(data);
};
const onUploadingAttachmentProgress = (data) => {
useAttachmentStore.getState().setUploading(data);
};
const onDownloadedAttachmentProgress = (data) => {
useAttachmentStore.getState().setDownloading(data);
};
const onUploadedAttachmentProgress = (data) => {
useAttachmentStore.getState().setUploading(data);
const onLoadingAttachmentProgress = (data) => {
useAttachmentStore
.getState()
.setLoading(data.total === data.current ? null : data);
};
const onUserSessionExpired = async () => {
@@ -310,16 +301,7 @@ export const useAppEvents = () => {
EVENTS.userSubscriptionUpdated,
onUserSubscriptionStatusChanged
),
EV.subscribe(EVENTS.fileDownload, onDownloadingAttachmentProgress),
EV.subscribe(EVENTS.fileUpload, onUploadingAttachmentProgress),
EV.subscribe(EVENTS.fileDownloaded, onDownloadedAttachmentProgress),
EV.subscribe(EVENTS.fileUploaded, onUploadedAttachmentProgress),
EV.subscribe(EVENTS.downloadCanceled, (data) => {
useAttachmentStore.getState().setDownloading(data);
}),
EV.subscribe(EVENTS.uploadCanceled, (data) => {
useAttachmentStore.getState().setUploading(data);
}),
EV.subscribe(EVENTS.attachmentsLoading, onLoadingAttachmentProgress),
eSubscribeEvent(eUserLoggedIn, onUserUpdated)
];
@@ -467,7 +449,7 @@ export const useAppEvents = () => {
});
}
} catch (e) {
ToastEvent.error(e, "An error occurred", "global");
ToastEvent.error(e, "An error occured", "global");
}
user = await db.user.getUser();

View File

@@ -1,49 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useEffect, useState } from "react";
import { db } from "../common/database";
import { eSubscribeEvent, eUnSubscribeEvent } from "../services/event-manager";
import Navigation from "../services/navigation";
export function useGroupOptions(type: any) {
const [groupOptions, setGroupOptions] = useState(
db.settings?.getGroupOptions(type)
);
useEffect(() => {
const onUpdate = () => {
const options = db.settings?.getGroupOptions(type) as any;
if (
groupOptions?.groupBy !== options.groupBy ||
groupOptions?.sortBy !== options.sortBy ||
groupOptions?.sortDirection !== groupOptions?.sortDirection
) {
setGroupOptions({ ...options });
Navigation.queueRoutesForUpdate();
}
};
eSubscribeEvent("groupOptionsUpdate", onUpdate);
return () => {
eUnSubscribeEvent("groupOptionsUpdate", onUpdate);
};
}, [type, groupOptions]);
return groupOptions;
}

View File

@@ -384,16 +384,7 @@ const _TabsHolder = () => {
}, []);
useEffect(() => {
function updateSystemBars() {
changeNavigationBarColor(colors.primary.background, isDark, true);
StatusBar.setBackgroundColor("transparent");
StatusBar.setTranslucent(true);
StatusBar.setBarStyle(isDark ? "light-content" : "dark-content");
}
updateSystemBars();
setTimeout(() => {
updateSystemBars();
}, 1000);
changeNavigationBarColor(colors.primary.background, isDark, true);
}, [colors.primary.background, isDark]);
return (
@@ -415,7 +406,11 @@ const _TabsHolder = () => {
: 0
}}
>
<StatusBar translucent={true} backgroundColor="transparent" />
<StatusBar
barStyle={isDark ? "light-content" : "dark-content"}
translucent={true}
backgroundColor="transparent"
/>
{!introCompleted ? (
<NavigationStack />

View File

@@ -16,7 +16,7 @@
"html-to-text": "9.0.5",
"phone": "^3.1.14",
"qclone": "^1.2.0",
"react-native-actions-sheet": "0.9.0-alpha.24",
"react-native-actions-sheet": "0.9.0-alpha.23",
"react-native-check-version": "https://github.com/flexible-agency/react-native-check-version",
"react-native-drax": "^0.10.2",
"react-native-image-zoom-viewer": "^3.0.1",

View File

@@ -0,0 +1,81 @@
/*
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, { useEffect, useRef, useState } from "react";
import { View } from "react-native";
import { ProgressBarComponent } from "../../components/ui/svg/lazy";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import { useAttachmentStore } from "../../stores/use-attachment-store";
import { useThemeColors } from "@notesnook/theme";
import { SIZE } from "../../utils/size";
export const ProgressBar = () => {
const { colors } = useThemeColors();
const loading = useAttachmentStore((state) => state.loading);
const [prog, setProg] = useState(0);
const [visible, setVisible] = useState(false);
const timer = useRef();
const insets = useGlobalSafeAreaInsets();
const [width, setWidth] = useState(false);
useEffect(() => {
if (loading) {
if (loading.current !== loading.total) {
setVisible(true);
setProg(loading.current / loading.total);
} else {
clear();
}
} else {
clear();
}
}, [loading]);
const clear = () => {
clearTimeout(timer.current);
timer.current = null;
timer.current = setTimeout(() => {
setProg(1);
setTimeout(() => {
setVisible(false);
}, 1000);
}, 100);
};
return visible ? (
<View
style={{
justifyContent: "center",
position: "absolute",
zIndex: 1,
marginTop: insets.top + 45,
width: "100%"
}}
onLayout={(event) => setWidth(event.nativeEvent.layout.width)}
>
<ProgressBarComponent
size={SIZE.xxl}
progress={prog}
color={colors.primary.accent}
borderWidth={0}
height={1}
width={width || 400}
/>
</View>
) : null;
};

View File

@@ -1,136 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useRef, useState } from "react";
import { View } from "react-native";
import { ProgressBarComponent } from "../../components/ui/svg/lazy";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import { useAttachmentStore } from "../../stores/use-attachment-store";
import { useEditorStore } from "../../stores/use-editor-store";
export const ProgressBar = () => {
const { colors } = useThemeColors();
const currentlyEditingNote = useEditorStore(
(state) => state.currentEditingNote
);
const downloading = useAttachmentStore((state) => state.downloading);
const loading = currentlyEditingNote
? downloading?.[currentlyEditingNote]
: undefined;
const attachmentProgress = useAttachmentStore((state) => state.progress);
const [progress, setProgress] = useState(0);
const [visible, setVisible] = useState(false);
const timer = useRef<NodeJS.Timeout>();
const insets = useGlobalSafeAreaInsets();
const [width, setWidth] = useState(400);
const groupProgressInfo = useRef<{
[name: string]: {
total: number;
current: number;
};
}>({});
const currentItemProgress = loading?.filename
? attachmentProgress?.[loading?.filename]
: undefined;
useEffect(() => {
if (loading) {
console.log(loading);
if (
loading.current === loading.total &&
typeof loading.success === "boolean"
) {
clear();
return;
}
setVisible(true);
if (!loading.filename) return;
if (!groupProgressInfo.current[loading.filename]) {
groupProgressInfo.current[loading.filename] = {
total: 1,
current: 0
};
}
const itemProgressCurrent = groupProgressInfo.current[loading.filename];
const itemTotalSize =
currentItemProgress?.total || itemProgressCurrent.total;
const itemCurrentProgress =
currentItemProgress?.recieved ||
currentItemProgress?.sent ||
itemProgressCurrent.current;
groupProgressInfo.current[loading.filename] = {
current: itemCurrentProgress,
total: itemTotalSize
};
const itemProgressPercent = itemCurrentProgress / itemTotalSize;
setProgress(
((loading.current || 0) + itemProgressPercent) / (loading.total || 1)
);
} else {
clear();
}
}, [currentItemProgress, loading]);
const clear = () => {
clearTimeout(timer.current);
timer.current = undefined;
timer.current = setTimeout(() => {
setProgress(1);
setTimeout(() => {
setVisible(false);
setProgress(0);
groupProgressInfo.current = {};
}, 1000);
}, 0);
};
return (
<View
style={{
justifyContent: "center",
position: "absolute",
zIndex: visible ? 1 : -1,
marginTop: insets.top + 45,
width: "100%"
}}
onLayout={(event) => setWidth(event.nativeEvent.layout.width)}
>
<ProgressBarComponent
progress={progress}
color={colors.primary.accent}
borderWidth={0}
borderRadius={0}
height={2}
width={width || 400}
/>
</View>
);
};

View File

@@ -52,7 +52,6 @@ export type Settings = {
fontFamily: string;
dateFormat: string;
timeFormat: string;
fontScale: number;
};
export type EditorProps = {

View File

@@ -28,8 +28,7 @@ import {
InteractionManager,
Keyboard,
KeyboardEventListener,
NativeEventSubscription,
useWindowDimensions
NativeEventSubscription
} from "react-native";
import { WebViewMessageEvent } from "react-native-webview";
import { db } from "../../../common/database";
@@ -143,8 +142,6 @@ export const useEditorEvents = (
const handleBack = useRef<NativeEventSubscription>();
const readonly = useEditorStore((state) => state.readonly);
const isPremium = useUserStore((state) => state.premium);
const { fontScale } = useWindowDimensions();
const doubleSpacedLines = useSettingStore(
(state) => state.settings?.doubleSpacedLines
);
@@ -198,8 +195,7 @@ export const useEditorEvents = (
: defaultFontSize,
fontFamily: SettingsService.get().defaultFontFamily,
dateFormat: db.settings?.getDateFormat(),
timeFormat: db.settings?.getTimeFormat(),
fontScale
timeFormat: db.settings?.getTimeFormat()
});
}, [
fullscreen,
@@ -219,8 +215,7 @@ export const useEditorEvents = (
defaultFontFamily,
dateFormat,
timeFormat,
loading,
fontScale
loading
]);
const onBackPress = useCallback(async () => {

View File

@@ -22,7 +22,7 @@ import { EVENTS } from "@notesnook/core/dist/common";
import { useThemeEngineStore } from "@notesnook/theme";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import WebView from "react-native-webview";
import { DatabaseLogger, db } from "../../../common/database";
import { db } from "../../../common/database";
import useGlobalSafeAreaInsets from "../../../hooks/use-global-safe-area-insets";
import { DDS } from "../../../services/device-detection";
import {
@@ -134,8 +134,7 @@ export const useEditor = (
const reset = useCallback(
async (resetState = true, resetContent = true) => {
currentNote.current?.id &&
db.fs?.cancel(currentNote.current.id, "download");
currentNote.current?.id && db.fs?.cancel(currentNote.current.id, null);
currentNote.current = null;
loadedImages.current = {};
currentContent.current = null;
@@ -148,12 +147,7 @@ export const useEditor = (
lastContentChangeTime.current = 0;
resetContent && (await commands.clearContent());
resetContent && (await commands.clearTags());
if (resetState) {
const newSessionId = makeSessionId();
await commands.setSessionId(newSessionId);
setSessionId(newSessionId);
isDefaultEditor &&
useEditorStore.getState().setCurrentlyEditingNote(null);
placeholderTip.current = TipManager.placeholderTip();
@@ -270,8 +264,7 @@ export const useEditor = (
saveCount.current++;
return id;
} catch (e) {
console.error(e);
DatabaseLogger.error(e as Error);
console.log("Error saving note: ", e);
}
},
[commands, isDefaultEditor, postMessage, readonly, reset]
@@ -286,7 +279,6 @@ export const useEditor = (
noteId: currentNote.current?.id as string
};
} else {
if (!note.contentId) return;
currentContent.current = await db.content?.raw(note.contentId);
}
}, []);
@@ -374,23 +366,12 @@ export const useEditor = (
if (!item.forced && currentNote.current?.id === item.id) return;
state.current.movedAway = false;
state.current.currentlyEditing = true;
if (currentNote.current?.id !== item.id) {
currentNote.current && (await reset(false, false));
isDefaultEditor && editorState.setCurrentlyEditingNote(item.id);
}
isDefaultEditor && editorState.setCurrentlyEditingNote(item.id);
currentNote.current && (await reset(false, false));
await loadContent(item as NoteType);
if (
currentNote.current?.id === item.id &&
loadingState.current &&
currentContent.current?.data &&
loadingState.current === currentContent.current?.data
) {
if (loadingState.current === currentContent.current?.data) {
return;
}
if (
!currentContent.current?.data ||
currentContent.current?.data.length < 50000
@@ -408,20 +389,17 @@ export const useEditor = (
lockedSessionId.current = nextSessionId;
sessionHistoryId.current = Date.now();
setSessionId(nextSessionId);
commands.setSessionId(nextSessionId);
sessionIdRef.current = nextSessionId;
currentNote.current = item as NoteType;
await commands.setStatus(getFormattedDate(item.dateEdited), "Saved");
await postMessage(EditorEvents.title, item.title);
loadingState.current = currentContent.current?.data;
if (currentContent.current?.data) {
await postMessage(
EditorEvents.html,
currentContent.current?.data,
10000
);
}
await postMessage(
EditorEvents.html,
currentContent.current?.data,
10000
);
loadingState.current = undefined;
useEditorStore.getState().setReadonly(item.readonly);
await commands.setTags(currentNote.current);
@@ -547,14 +525,6 @@ export const useEditor = (
}) => {
if (lock.current || lockedSessionId.current === forSessionId) return;
lastContentChangeTime.current = Date.now();
if (
sessionHistoryId.current &&
Date.now() - sessionHistoryId.current > 5 * 60 * 1000
) {
sessionHistoryId.current = Date.now();
}
if (type === EditorEvents.content) {
currentContent.current = {
data: content,

View File

@@ -71,7 +71,7 @@ export const Home = ({ navigation, route }: NavigationProps<"Notes">) => {
<List
listData={notes}
type="notes"
screen="Home"
screen="Notes"
loading={loading || !isFocused}
headerProps={{
heading: "Notes"

View File

@@ -71,7 +71,7 @@ export const SearchBar = () => {
} catch (e) {
console.log(e);
ToastEvent.show({
heading: "Error occurred while searching",
heading: "Error occured while searching",
message: e.message,
type: "error"
});

View File

@@ -88,8 +88,8 @@ export const settingsGroups: SettingSection[] = [
return isBasic || !user.subscription?.type
? "Subscribe to Pro"
: isTrial
? "Your free trial has started"
: "Subscription details";
? "Your free trial has started"
: "Subscription details";
},
type: "component",
component: "subscription",
@@ -111,16 +111,16 @@ export const settingsGroups: SettingSection[] = [
return user.subscription?.type === 2
? "You signed up on " + startDate
: user.subscription?.type === 1
? "Your free trial will end on " + expiryDate
: user.subscription?.type === 6
? subscriptionDaysLeft.time < -3
? "Your subscription has ended"
: "Your account will be downgraded to Basic in 3 days"
: user.subscription?.type === 7
? `Your subscription will end on ${expiryDate}.`
: user.subscription?.type === 5
? `Your subscription will renew on ${expiryDate}.`
: "Never hesitate to choose privacy";
? "Your free trial will end on " + expiryDate
: user.subscription?.type === 6
? subscriptionDaysLeft.time < -3
? "Your subscription has ended"
: "Your account will be downgraded to Basic in 3 days"
: user.subscription?.type === 7
? `Your subscription will end on ${expiryDate}.`
: user.subscription?.type === 5
? `Your subscription will renew on ${expiryDate}.`
: "Never hesitate to choose privacy";
}
},
{
@@ -320,13 +320,13 @@ export const settingsGroups: SettingSection[] = [
name: "Delete account",
icon: "alert",
description:
"All your data will be removed permanently. Make sure you have saved backup of your notes. This action is IRREVERSIBLE.",
"All your data will be removed permanantly. Make sure you have saved backup of your notes. This action is IRREVERSIBLE.",
modifer: () => {
presentDialog({
title: "Delete account",
paragraphColor: "red",
paragraph:
"All your data will be removed permanently. Make sure you have saved backup of your notes. This action is IRREVERSIBLE.",
"All your data will be removed permanantly. Make sure you have saved backup of your notes. This action is IRREVERSIBLE.",
positiveType: "errorShade",
input: true,
inputPlaceholder: "Enter account password",
@@ -628,9 +628,7 @@ export const settingsGroups: SettingSection[] = [
name: "CORS bypass proxy",
description: "You can set a custom proxy URL to increase your privacy.",
inputProperties: {
defaultValue: "https://cors.notesnook.com",
autoCorrect: false,
keyboardType: "url"
defaultValue: "https://cors.notesnook.com"
},
property: "corsProxy",
icon: "arrow-decision-outline"

View File

@@ -52,7 +52,7 @@ const onPressFloatingButton = () => {
ToastEvent.show({
heading: "Trash cleared",
message:
"All notes and notebooks in the trash have been removed permanently.",
"All notes and notebooks in the trash have been removed permanantly.",
type: "success",
context: "local"
});

View File

@@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { sanitizeFilename } from "@notesnook/common";
import { Platform } from "react-native";
import RNFetchBlob from "react-native-blob-util";
import FileViewer from "react-native-file-viewer";
@@ -29,8 +30,6 @@ import { eCloseSheet } from "../utils/events";
import { sleep } from "../utils/time";
import { ToastEvent, eSendEvent, presentSheet } from "./event-manager";
import SettingsService from "./settings";
import { cacheDir, copyFileAsync } from "../common/filesystem/utils";
import { zip } from "react-native-zip-archive";
const MS_DAY = 86400000;
const MS_WEEK = MS_DAY * 7;
@@ -153,6 +152,8 @@ async function run(progress, context) {
let androidBackupDirectory = await checkBackupDirExists(false, context);
if (!androidBackupDirectory) return;
let backup;
if (progress) {
presentSheet({
title: "Backing up your data",
@@ -162,67 +163,43 @@ async function run(progress, context) {
});
}
let path;
let backupFilePath;
let backupFileName = "notesnook_backup_" + Date.now();
if (Platform.OS === "ios") {
path = await storage.checkAndCreateDir("/backups/");
}
const zipSourceFolder = `${cacheDir}/${backupFileName}`;
const zipOutputFile =
Platform.OS === "ios"
? `${path}/${backupFileName}.nnbackupz`
: `${cacheDir}/${backupFileName}.nnbackupz`;
if (await RNFetchBlob.fs.exists(zipSourceFolder))
await RNFetchBlob.fs.unlink(zipSourceFolder);
await RNFetchBlob.fs.mkdir(zipSourceFolder);
try {
for await (const file of db.backup.export(
backup = await db.backup.export(
"mobile",
SettingsService.get().encryptedBackup
)) {
console.log("Writing backup chunk of size...", file?.data?.length);
await RNFetchBlob.fs.writeFile(
`${zipSourceFolder}/${file.path}`,
file.data,
"utf8"
);
}
await zip(zipSourceFolder, zipOutputFile);
console.log("Final zip:", await RNFetchBlob.fs.stat(zipOutputFile));
if (Platform.OS === "android") {
// Move the zip to user selected directory.
const file = await ScopedStorage.createFile(
androidBackupDirectory.uri,
`${backupFileName}.nnbackupz`,
"application/nnbackupz"
);
await copyFileAsync(`file://${zipOutputFile}`, file.uri);
path = file.uri;
} else {
path = zipOutputFile;
}
RNFetchBlob.fs.unlink(zipSourceFolder).catch(console.log);
updateNextBackupTime();
let showBackupCompleteSheet = SettingsService.get().showBackupCompleteSheet;
if (context) return path;
);
if (!backup) throw new Error("Backup returned empty.");
} catch (e) {
await sleep(300);
if (showBackupCompleteSheet) {
presentBackupCompleteSheet(backupFilePath);
eSendEvent(eCloseSheet);
ToastEvent.error(e, "Backup failed!");
return null;
}
try {
let backupName = "notesnook_backup_" + Date.now();
backupName =
sanitizeFilename(backupName, { replacement: "_" }) + ".nnbackup";
let path;
let backupFilePath;
if (Platform.OS === "ios") {
path = await storage.checkAndCreateDir("/backups/");
await RNFetchBlob.fs.writeFile(path + backupName, backup, "utf8");
backupFilePath = path + backupName;
} else {
progress && eSendEvent(eCloseSheet);
backupFilePath = await ScopedStorage.writeFile(
androidBackupDirectory.uri,
backup,
backupName,
"nnbackup/json",
"utf8",
false
);
}
updateNextBackupTime();
ToastEvent.show({
heading: "Backup successful",
message: "Your backup is stored in Notesnook folder on your phone.",
@@ -230,10 +207,18 @@ async function run(progress, context) {
context: "global"
});
return path;
} catch (e) {
let showBackupCompleteSheet = SettingsService.get().showBackupCompleteSheet;
if (context) return backupFilePath;
await sleep(300);
eSendEvent(eCloseSheet);
if (showBackupCompleteSheet) {
presentBackupCompleteSheet(backupFilePath);
} else {
progress && eSendEvent(eCloseSheet);
}
return backupFilePath;
} catch (e) {
progress && eSendEvent(eCloseSheet);
ToastEvent.error(e, "Backup failed!");
return null;
}

View File

@@ -50,7 +50,7 @@ export function setRateAppMessage() {
const recoveryKeyMessage = {
visible: true,
message: "Keep your data safe",
message: "Keep your data safe if you lose password",
actionText: "Save your account recovery key",
onPress: () => {
verifyUser(

View File

@@ -362,7 +362,7 @@ const features_list = [
content: "Instantly sync to unlimited devices"
},
{
content: "A private vault to keep everything important always locked"
content: "A private vault to keep everything imporant always locked"
},
{
content:
@@ -382,7 +382,7 @@ const sheet = (context, promo, trial) => {
centered
title="Upgrade to Notesnook"
titlePart="Pro"
paragraph="Manage your work on another level, enjoy seamless sync and keep all notes in one place."
paragraph="Manage your work on another level, enjoy seemless sync and keep all notes in one place."
padding={12}
/>
<Seperator />

View File

@@ -17,14 +17,15 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EVENTS } from "@notesnook/core/dist/common";
import NetInfo from "@react-native-community/netinfo";
import { db } from "../common/database";
import { DatabaseLogger } from "../common/database/index";
import { initAfterSync } from "../stores/index";
import { SyncStatus, useUserStore } from "../stores/use-user-store";
import BackgroundSync from "./background-sync";
import { ToastEvent } from "./event-manager";
import SettingsService from "./settings";
import BackgroundSync from "./background-sync";
export const ignoredMessages = [
"Sync already running",
@@ -32,7 +33,7 @@ export const ignoredMessages = [
"WebSocket failed to connect",
"Failed to start the HttpConnection before"
];
let pendingSync = undefined;
let syncTimer = 0;
const run = async (
context = "global",
@@ -42,18 +43,10 @@ const run = async (
lastSyncTime
) => {
if (useUserStore.getState().syncing) {
DatabaseLogger.info("Sync in progress");
pendingSync = {
full: full
};
DatabaseLogger.log("Sync in progress");
console.log("Sync in progress");
return;
}
if (pendingSync) {
pendingSync = undefined;
DatabaseLogger.info("Running pending sync...");
}
clearTimeout(syncTimer);
syncTimer = setTimeout(async () => {
const status = await NetInfo.fetch();
@@ -62,54 +55,56 @@ const run = async (
if (!status.isInternetReachable) {
DatabaseLogger.warn("Internet not reachable");
}
if (
!user ||
!status.isInternetReachable ||
SettingsService.get().disableSync
) {
initAfterSync();
pendingSync = undefined;
return onCompleted?.(false);
}
userstore.setSyncing(true);
let error = null;
try {
await BackgroundSync.doInBackground(async () => {
let res = await BackgroundSync.doInBackground(async () => {
try {
await db.sync(full, forced, lastSyncTime);
return true;
} catch (e) {
error = e;
return e.message;
}
});
if (error) {
throw error;
if (!res) {
initAfterSync();
userstore.setSyncing(false, SyncStatus.Failed);
return onCompleted?.(false);
}
if (typeof res === "string") throw error;
userstore.setSyncing(false);
return onCompleted?.(true);
} catch (e) {
error = e;
if (
!ignoredMessages.find((message) => e.message?.includes(message)) &&
userstore.user &&
status.isConnected &&
status.isInternetReachable
!ignoredMessages.find((im) => e.message?.includes(im)) &&
userstore.user
) {
ToastEvent.error(e, "Sync failed", context);
userstore.setSyncing(false, SyncStatus.Failed);
if (status.isConnected && status.isInternetReachable) {
ToastEvent.error(e, "Sync failed", context);
}
}
DatabaseLogger.error(e, "[Client] Failed to sync");
onCompleted?.(false);
} finally {
initAfterSync();
userstore.setSyncing(
false,
error ? SyncStatus.Failed : SyncStatus.Passed
);
onCompleted?.(error ? SyncStatus.Failed : SyncStatus.Passed);
setImmediate(() => {
if (pendingSync) Sync.run("global", false, pendingSync.full);
});
if (full || forced) {
db.eventManager.publish(EVENTS.syncCompleted);
}
}
}, 300);
};

View File

@@ -215,7 +215,7 @@ const placeholderTips = [
"If you read someone else's diary, you get what you deserve. - David Sedaris",
"Take quick notes from notifications. Enable the option in Settings to try",
"Get Notesnook on all your devices. Or even open it in browser by going to https://app.notesnook.com to access all your notes",
"With note history, you can restore back to an older version of the note if you accidentally deleted something.",
"With note history, you can restore back to an older version of the note if you accidently deleted something.",
"When your heart speaks, take good notes. - Judith Campbell",
"You can publish a note and share it with anyone. Even if they don't use Notesnook!",
"Published notes can be encrypted. Which means only you and the person you share the password with can read them.",

View File

@@ -20,16 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import create from "zustand";
import { editorController } from "../screens/editor/tiptap/utils";
export type AttachmentGroupProgress = {
total: number;
current: number;
groupId: string;
filename: string;
canceled?: boolean;
success?: boolean;
error?: any;
};
interface AttachmentStore {
progress?: {
[name: string]: {
@@ -40,7 +30,6 @@ interface AttachmentStore {
type: "upload" | "download";
} | null;
};
encryptionProgress: number;
setEncryptionProgress: (encryptionProgress: number) => void;
remove: (hash: string) => void;
@@ -51,14 +40,8 @@ interface AttachmentStore {
recieved: number,
type: "upload" | "download"
) => void;
downloading?: {
[groupId: string]: AttachmentGroupProgress | undefined;
};
setDownloading: (data: AttachmentGroupProgress) => void;
uploading?: {
[groupId: string]: AttachmentGroupProgress | undefined;
};
setUploading: (data: AttachmentGroupProgress) => void;
loading: { total: number; current: number };
setLoading: (data: { total: number; current: number }) => void;
}
export const useAttachmentStore = create<AttachmentStore>((set, get) => ({
@@ -90,21 +73,6 @@ export const useAttachmentStore = create<AttachmentStore>((set, get) => ({
encryptionProgress: 0,
setEncryptionProgress: (encryptionProgress) =>
set({ encryptionProgress: encryptionProgress }),
downloading: {},
setDownloading: (data) =>
set({
downloading: {
...get().downloading,
[data.groupId]: data?.canceled ? undefined : data
}
}),
uploading: {},
setUploading: (data) =>
set({
uploading: {
...get().uploading,
[data.groupId]: data?.canceled ? undefined : data
}
})
loading: { total: 0, current: 0 },
setLoading: (data) => set({ loading: data ? { ...data } : data })
}));

View File

@@ -56,7 +56,7 @@ export const useSelectionStore = create<SelectionStore>((set, get) => ({
set({
selectedItemsList: selectedItems,
selectionMode: selectedItems.length === 0 ? false : get().selectionMode
selectionMode: get().selectionMode
});
},
clearSelection: () => {

View File

@@ -107,43 +107,46 @@ export const deleteItems = async (item, context) => {
if (topics?.length > 0) {
const result = await confirmDeleteAllNotes(topics, "topic", context);
if (!result.delete) return;
for (const topic of topics) {
if (result.deleteNotes) {
const notes = db.notebooks
.notebook(topic.notebookId)
.topics.topic(topic.id).all;
await db.notes.delete(...notes.map((note) => note.id));
}
await db.notebooks.notebook(topic.notebookId).topics.delete(topic.id);
}
useMenuStore.getState().setMenuPins();
ToastEvent.show({
heading: `${topics.length > 1 ? "Topics" : "Topic"} deleted`,
type: "success"
});
}
if (notebooks?.length > 0) {
const result = await confirmDeleteAllNotes(notebooks, "notebook", context);
if (!result.delete) return;
let ids = notebooks.map((i) => i.id);
if (result.deleteNotes) {
for (let id of ids) {
const notebook = db.notebooks.notebook(id);
const topics = notebook.topics.all;
for (let topic of topics) {
if (result.delete) {
for (const topic of topics) {
if (result.deleteNotes) {
const notes = db.notebooks
.notebook(topic.notebookId)
.topics.topic(topic.id).all;
await db.notes.delete(...notes.map((note) => note.id));
}
const notes = db.relations.from(notebook.data, "note");
await db.notes.delete(...notes.map((note) => note.id));
await db.notebooks.notebook(topic.notebookId).topics.delete(topic.id);
}
useMenuStore.getState().setMenuPins();
ToastEvent.show({
heading: `${topics.length > 1 ? "Topics" : "Topic"} deleted`,
type: "success"
});
}
}
if (notebooks?.length > 0) {
const result = await confirmDeleteAllNotes(notebooks, "notebook", context);
if (result.delete) {
let ids = notebooks.map((i) => i.id);
if (result.deleteNotes) {
for (let id of ids) {
const notebook = db.notebooks.notebook(id);
const topics = notebook.topics.all;
for (let topic of topics) {
const notes = db.notebooks
.notebook(topic.notebookId)
.topics.topic(topic.id).all;
await db.notes.delete(...notes.map((note) => note.id));
}
const notes = db.relations.from(notebook.data, "note");
await db.notes.delete(...notes.map((note) => note.id));
}
}
await db.notebooks.delete(...ids);
useMenuStore.getState().setMenuPins();
}
await db.notebooks.delete(...ids);
useMenuStore.getState().setMenuPins();
}
Navigation.queueRoutesForUpdate();

View File

@@ -24,12 +24,6 @@ import RNFetchBlob from "react-native-blob-util";
import { db } from "../common/database";
import { IOS_APPGROUPID } from "./constants";
const santizeUri = (uri) => {
uri = decodeURI(uri);
uri = Platform.OS === "ios" ? uri.replace("file:///", "/") : uri;
return uri;
};
export async function attachFile(uri, hash, type, filename, options) {
try {
let exists = db.attachments.exists(hash);
@@ -82,7 +76,9 @@ async function createNotes(bundle) {
for (const file of bundle.files) {
const uri =
Platform.OS === "ios" ? santizeUri(file.value) : `${file.value}`;
Platform.OS === "ios"
? `${file.value.replace("file://", "")}`
: `${file.value}`;
const hash = await Sodium.hashFile({
uri: uri,
type: "cache"

View File

@@ -30,10 +30,36 @@ import {
elementByText,
sleep,
notVisibleByText,
visibleById,
createNotebook
visibleById
} from "./utils";
async function createNotebook(
title = "Notebook 1",
description = true,
topic = true,
topicCount = 1
) {
await tapByText("Add your first notebook");
await elementById(notesnook.ids.dialogs.notebook.inputs.title).typeText(
title
);
if (description) {
await elementById(
notesnook.ids.dialogs.notebook.inputs.description
).typeText(`Description of ${title}`);
}
if (topic) {
for (let i = 1; i <= topicCount; i++) {
await elementById(notesnook.ids.dialogs.notebook.inputs.topic).typeText(
i === 1 ? "Topic" : "Topic " + i
);
await tapById("topic-add-button");
}
}
await tapByText("Save");
await sleep(500);
}
// async function addTopic(title = "Topic") {
// await tapById(notesnook.buttons.add);
// await elementById("input-title").typeText(title);

View File

@@ -25,9 +25,7 @@ import {
prepare,
tapByText,
notVisibleByText,
sleep,
navigate,
createNotebook
sleep
} from "./utils";
async function sortBy(sorting, elementText = "Default") {
@@ -106,23 +104,6 @@ describe("Sort & filter", () => {
await visibleByText("Month");
});
it("Sort notes in topic", async () => {
await prepare();
await navigate("Notebooks");
await sleep(500);
await createNotebook("Notebook 1", true, true);
await sleep(500);
await device.pressBack();
await sleep(500);
await tapByText("Topic");
await createNote("A", "A letter");
await sleep(500);
await createNote("B", "B letter");
await sortBy("Abc");
await sleep(300);
await visibleByText("N");
});
it("Compact mode", async () => {
await prepare();
await createNote("Note 1", "Note 1");

View File

@@ -129,36 +129,8 @@ async function matchSnapshot(element, name) {
});
}
async function createNotebook(
title = "Notebook 1",
description = true,
topic = true,
topicCount = 1
) {
await tapByText("Add your first notebook");
await elementById(notesnook.ids.dialogs.notebook.inputs.title).typeText(
title
);
if (description) {
await elementById(
notesnook.ids.dialogs.notebook.inputs.description
).typeText(`Description of ${title}`);
}
if (topic) {
for (let i = 1; i <= topicCount; i++) {
await elementById(notesnook.ids.dialogs.notebook.inputs.topic).typeText(
i === 1 ? "Topic" : "Topic " + i
);
await tapById("topic-add-button");
}
}
await tapByText("Save");
await sleep(500);
}
export {
matchSnapshot,
createNotebook,
prepare,
LaunchApp,
createNote,

View File

@@ -111,7 +111,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled true
versionCode 2065
versionCode 2059
versionName getNpmVersion()
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'

View File

@@ -1,3 +1,4 @@
- Bug fixes and performance improvements
Thank you for using Notesnook!
- Much improved and faster sync
- Note pinned in notifications will update automatically when content changes
- Quick notes from notifications now respect paragraph spacing settings.
- Many bug fixes and small improvements

View File

@@ -997,7 +997,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2058;
CURRENT_PROJECT_VERSION = 2053;
DEVELOPMENT_TEAM = 53CWBG3QUC;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1071,7 +1071,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.6.7;
MARKETING_VERSION = 2.6.3;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1102,7 +1102,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2058;
CURRENT_PROJECT_VERSION = 2053;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1176,7 +1176,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.6.7;
MARKETING_VERSION = 2.6.3;
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"$(inherited)",
@@ -1335,7 +1335,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2058;
CURRENT_PROJECT_VERSION = 2053;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1347,7 +1347,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.6.7;
MARKETING_VERSION = 2.6.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
@@ -1378,7 +1378,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2058;
CURRENT_PROJECT_VERSION = 2053;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
@@ -1391,7 +1391,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.6.7;
MARKETING_VERSION = 2.6.3;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1421,7 +1421,7 @@
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2058;
CURRENT_PROJECT_VERSION = 2053;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1495,7 +1495,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.6.7;
MARKETING_VERSION = 2.6.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
@@ -1526,7 +1526,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2058;
CURRENT_PROJECT_VERSION = 2053;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
@@ -1601,7 +1601,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.6.7;
MARKETING_VERSION = 2.6.3;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -327,7 +327,7 @@ PODS:
- React-Core
- react-native-keep-awake (1.2.0):
- React-Core
- react-native-mmkv-storage (0.10.0-alpha.9):
- react-native-mmkv-storage (0.10.0-alpha.7):
- MMKV (~> 1.3.1)
- React
- React-Core
@@ -347,7 +347,7 @@ PODS:
- ReactCommon/turbomodule/core
- react-native-share-extension (2.5.6):
- React
- react-native-sodium (1.5.4):
- react-native-sodium (1.5.2):
- React
- react-native-webview (11.26.1):
- React-Core
@@ -875,14 +875,14 @@ SPEC CHECKSUMS:
react-native-image-resizer: 00ceb0e05586c7aadf061eea676957a6c2ec60fa
react-native-in-app-review: db8bb167a5f238e7ceca5c242d6b36ce8c4404a4
react-native-keep-awake: caee3ff89eaa21dfe29010f0d143566874a04441
react-native-mmkv-storage: d4ad55ab411b7f0d4e6269d801b31821ef48970b
react-native-mmkv-storage: ec32fd68168716755e1b30f09b476c236c6c68a8
react-native-netinfo: ccbe1085dffd16592791d550189772e13bf479e2
react-native-notification-sounds: da78c828fe1bcbb92d8b505d5261890ed315ff39
react-native-orientation: f1caf84d65f1a4fd4511a18f2b924e634ad7a628
react-native-pdf: 33c622cbdf776a649929e8b9d1ce2d313347c4fa
react-native-safe-area-context: 36cc67648134e89465663b8172336a19eeda493d
react-native-share-extension: df66a2ee48a62277d79898375e2142bde0782063
react-native-sodium: 955bb0dc3ea05f8ea06d5e96cb89d1be7b5d7681
react-native-sodium: 7d2bbb9ca840dc58d63f661b2ff733a38170fec5
react-native-webview: 9f111dfbcfc826084d6c507f569e5e03342ee1c1
React-NativeModulesApple: 1d81d927ef1a67a3545a01e14c2e98500bf9b199
React-perflogger: 684a11499a0589cc42135d6d5cc04d0e4e0e261a

File diff suppressed because one or more lines are too long

View File

@@ -21,12 +21,6 @@
background-color: transparent !important;
}
img {
max-width: 100% !important;
background-color: transparent !important;
height: unset !important;
}
.editor {
overflow-x: hidden;
overflow-y: scroll;

View File

@@ -7,7 +7,7 @@
"dependencies": {
"@ammarahmed/notifee-react-native": "7.4.4",
"@ammarahmed/react-native-share-extension": "^2.5.5",
"@ammarahmed/react-native-sodium": "1.5.4",
"@ammarahmed/react-native-sodium": "1.5.2",
"@bam.tech/react-native-image-resizer": "3.0.5",
"@callstack/repack": "^3.2.0",
"@react-native-clipboard/clipboard": "^1.9.0",

View File

@@ -2087,7 +2087,7 @@ function getEscaper(regex, map) {
if (lastIdx !== match.index) {
result += data.substring(lastIdx, match.index);
}
// We know that this character will be in the map.
// We know that this chararcter will be in the map.
result += map.get(match[0].charCodeAt(0));
// Every match will be of length 1
lastIdx = match.index + 1;
@@ -2996,7 +2996,7 @@ function removeSubsets$1(nodes) {
/*
* Remove the node if it is not unique.
* We are going through the array from the end, so we only
* have to check nodes that precede the node under consideration in the array.
* have to check nodes that preceed the node under consideration in the array.
*/
if (idx > 0 && nodes.lastIndexOf(node, idx - 1) >= 0) {
nodes.splice(idx, 1);
@@ -9883,7 +9883,7 @@ CSSOM$2.CSSValueExpression.prototype._findMatchedIdx = function (token, idx, sep
}
}
// boundary must be in the same line(js string or regexp)
// boundary must be in the same line(js sting or regexp)
var nextNewLineIdx = token.indexOf('\n', idx + 1);
if (nextNewLineIdx < endIdx) {
endIdx = NOT_FOUND;

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/mobile",
"version": "2.6.7",
"version": "2.6.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@notesnook/mobile",
"version": "2.6.7",
"version": "2.6.2",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"workspaces": [
@@ -22,9 +22,9 @@
"@notesnook/logger": "file:../../packages/logger",
"@notesnook/themes-server": "file:../../servers/themes",
"@tanstack/react-query": "^4.29.19",
"@trpc/client": "10.38.3",
"@trpc/react-query": "10.38.3",
"@trpc/server": "10.38.3",
"@trpc/client": "10.31.0",
"@trpc/react-query": "10.31.0",
"@trpc/server": "^10.31.0",
"react": "18.2.0",
"react-native": "0.72.0"
},
@@ -85,9 +85,7 @@
"abortcontroller-polyfill": "^1.7.3",
"cross-env": "^7.0.3",
"dotenv": "^16.0.1",
"event-source-polyfill": "^1.0.31",
"eventsource": "^2.0.2",
"hash-wasm": "^4.9.0",
"isomorphic-fetch": "^3.0.0",
"jsdom": "^22.1.0",
"mockdate": "^3.0.5",
@@ -110,28 +108,28 @@
"@social-embed/lib": "^0.0.2-next.1",
"@theme-ui/components": ">=0.14.0",
"@theme-ui/core": ">=0.14.0",
"@tiptap/core": "2.1.11",
"@tiptap/extension-character-count": "2.1.11",
"@tiptap/extension-color": "2.1.11",
"@tiptap/extension-font-family": "2.1.11",
"@tiptap/extension-history": "2.1.11",
"@tiptap/extension-horizontal-rule": "2.1.11",
"@tiptap/extension-link": "2.1.11",
"@tiptap/extension-list-keymap": "2.1.11",
"@tiptap/extension-placeholder": "2.1.11",
"@tiptap/extension-subscript": "2.1.11",
"@tiptap/extension-superscript": "2.1.11",
"@tiptap/extension-table": "2.1.11",
"@tiptap/extension-table-cell": "2.1.11",
"@tiptap/extension-table-header": "2.1.11",
"@tiptap/extension-table-row": "2.1.11",
"@tiptap/extension-task-item": "2.1.11",
"@tiptap/extension-task-list": "2.1.11",
"@tiptap/extension-text-align": "2.1.11",
"@tiptap/extension-text-style": "2.1.11",
"@tiptap/extension-underline": "2.1.11",
"@tiptap/pm": "2.1.11",
"@tiptap/starter-kit": "2.1.11",
"@tiptap/core": "2.1.7",
"@tiptap/extension-character-count": "2.1.7",
"@tiptap/extension-color": "2.1.7",
"@tiptap/extension-font-family": "2.1.7",
"@tiptap/extension-history": "2.1.7",
"@tiptap/extension-horizontal-rule": "2.1.7",
"@tiptap/extension-link": "2.1.7",
"@tiptap/extension-list-keymap": "2.1.7",
"@tiptap/extension-placeholder": "2.1.7",
"@tiptap/extension-subscript": "2.1.7",
"@tiptap/extension-superscript": "2.1.7",
"@tiptap/extension-table": "2.1.7",
"@tiptap/extension-table-cell": "2.1.7",
"@tiptap/extension-table-header": "2.1.7",
"@tiptap/extension-table-row": "2.1.7",
"@tiptap/extension-task-item": "2.1.7",
"@tiptap/extension-task-list": "2.1.7",
"@tiptap/extension-text-align": "2.1.7",
"@tiptap/extension-text-style": "2.1.7",
"@tiptap/extension-underline": "2.1.7",
"@tiptap/pm": "2.1.7",
"@tiptap/starter-kit": "2.1.7",
"clipboard-polyfill": "4.0.0",
"detect-indent": "^7.0.0",
"entities": "^4.5.0",
@@ -139,7 +137,7 @@
"nanoid": "^4.0.1",
"prism-themes": "^1.9.0",
"prosemirror-codemark": "^0.4.2",
"prosemirror-view": "^1.31.8",
"prosemirror-view": "^1.31.7",
"re-resizable": "^6.9.9",
"react-colorful": "^5.5.1",
"react-modal": "3.13.1",
@@ -224,7 +222,7 @@
"license": "ISC",
"dependencies": {
"@orama/orama": "^1.0.8",
"@trpc/server": "10.38.3",
"@trpc/server": "10.31.0",
"async-mutex": "^0.4.0",
"cors": "^2.8.5",
"util": "^0.12.5",
@@ -256,7 +254,7 @@
"katex": "0.16.2",
"phone": "^3.1.14",
"qclone": "^1.2.0",
"react-native-actions-sheet": "0.9.0-alpha.24",
"react-native-actions-sheet": "0.9.0-alpha.23",
"react-native-check-version": "https://github.com/flexible-agency/react-native-check-version",
"react-native-drax": "^0.10.2",
"react-native-image-zoom-viewer": "^3.0.1",
@@ -281,7 +279,7 @@
"@ammarahmed/notifee-react-native": "7.4.4",
"@ammarahmed/react-native-eventsource": "1.1.0",
"@ammarahmed/react-native-share-extension": "^2.5.5",
"@ammarahmed/react-native-sodium": "1.5.4",
"@ammarahmed/react-native-sodium": "1.5.2",
"@bam.tech/react-native-image-resizer": "3.0.5",
"@callstack/repack": "^3.2.0",
"@react-native-clipboard/clipboard": "^1.9.0",
@@ -2419,9 +2417,9 @@
}
},
"node_modules/@ammarahmed/react-native-sodium": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-sodium/-/react-native-sodium-1.5.4.tgz",
"integrity": "sha512-+JwYnaSJxnwpI1947sUacFXxRxK1f9ykuxDJaGkCUKvh5CkDYC5VyZFnq2BbcuIcx4OTMOG8a/a46hWJbFKQPQ=="
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-sodium/-/react-native-sodium-1.5.2.tgz",
"integrity": "sha512-M309uV2DCK3EPNfsgWYthOApJhQgQKOOxYF19VerUeX7UYnm9VggW073oO0NNqqZqg5GS6bTlrtYMAz7MAKvUw=="
},
"node_modules/@ampproject/remapping": {
"version": "2.2.1",
@@ -7014,35 +7012,35 @@
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
},
"node_modules/@trpc/client": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.38.3.tgz",
"integrity": "sha512-hHPsElTL4sB+UGzuAZ4iwRVHjELrk/Nsl2owsYw9ITJz3EY7VWRsQ6vK48kJvlHPYPhP+efID5UOgyZMs4bFXA==",
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.31.0.tgz",
"integrity": "sha512-VCqbJEvFJb8C4hQFw7AD+dkQTjgEdV/QAzO4D+/cX5e93u5NpfNXI+PKS0QFXwG/zqgwQwVV6OkYc/D/MFwA6g==",
"funding": [
"https://trpc.io/sponsor"
],
"peerDependencies": {
"@trpc/server": "10.38.3"
"@trpc/server": "10.31.0"
}
},
"node_modules/@trpc/react-query": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.38.3.tgz",
"integrity": "sha512-j4xxg/y+vssGinZCrNQy0SMJNL2Nv8k3HcqMKa2mYt3jxOpaHuwxgarWvLWVqrUJqvp1JpGJ9sIjlOAZam5FeQ==",
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.31.0.tgz",
"integrity": "sha512-+M8sIsbf6e4H5XYvHlzDqhaf+ybfUigA/9OL3wXRp2vXhCedEiIERCnwNuHWFDRASl9vjOcM33AuJ4sbOOINEA==",
"funding": [
"https://trpc.io/sponsor"
],
"peerDependencies": {
"@tanstack/react-query": "^4.18.0",
"@trpc/client": "10.38.3",
"@trpc/server": "10.38.3",
"@trpc/client": "10.31.0",
"@trpc/server": "10.31.0",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/@trpc/server": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.38.3.tgz",
"integrity": "sha512-9s8/kwo2IDB5hwB2SKZZrfevRhdb1f9fdXtIYd3lbQuf2jQaC/LyQuHaIQjDQoUx9updBfsHXcFFPiCP1DL6pg==",
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.31.0.tgz",
"integrity": "sha512-9EnRTSDE9nF11LZsvSOqNKqkRYzHqFX4ch5AJ6VIu8uta2vxVTN4FxxsNRSOluTzVYZDeaCISbwmOJ5iihCCIg==",
"funding": [
"https://trpc.io/sponsor"
]
@@ -17921,9 +17919,9 @@
}
},
"node_modules/react-native-actions-sheet": {
"version": "0.9.0-alpha.24",
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.9.0-alpha.24.tgz",
"integrity": "sha512-NF0oO0vf3DrFsqI+pbQ+HTG2q+VEotkVwhtFr8aLiUFJT876icVOSurCaeqD1t4zHtH2U5qa8vKQxbA/j5Mu8w==",
"version": "0.9.0-alpha.23",
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.9.0-alpha.23.tgz",
"integrity": "sha512-d8sZJHKjme33i34zQ8+oIsGs8wY+GCDtxDboExgpO1OoB9np1y4tGOf3ZHyfIpClITpuy+LT7r9Uz+KfAJTMHA==",
"peerDependencies": {
"react-native": "*",
"react-native-gesture-handler": "*"
@@ -23703,9 +23701,9 @@
}
},
"@ammarahmed/react-native-sodium": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-sodium/-/react-native-sodium-1.5.4.tgz",
"integrity": "sha512-+JwYnaSJxnwpI1947sUacFXxRxK1f9ykuxDJaGkCUKvh5CkDYC5VyZFnq2BbcuIcx4OTMOG8a/a46hWJbFKQPQ=="
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-sodium/-/react-native-sodium-1.5.2.tgz",
"integrity": "sha512-M309uV2DCK3EPNfsgWYthOApJhQgQKOOxYF19VerUeX7UYnm9VggW073oO0NNqqZqg5GS6bTlrtYMAz7MAKvUw=="
},
"@ampproject/remapping": {
"version": "2.2.1",
@@ -26440,9 +26438,7 @@
"dayjs": "1.11.9",
"dotenv": "^16.0.1",
"entities": "^4.3.1",
"event-source-polyfill": "^1.0.31",
"eventsource": "^2.0.2",
"hash-wasm": "^4.9.0",
"html-to-text": "^9.0.5",
"htmlparser2": "^8.0.1",
"isomorphic-fetch": "^3.0.0",
@@ -26473,28 +26469,28 @@
"@social-embed/lib": "^0.0.2-next.1",
"@theme-ui/components": ">=0.14.0",
"@theme-ui/core": ">=0.14.0",
"@tiptap/core": "2.1.11",
"@tiptap/extension-character-count": "2.1.11",
"@tiptap/extension-color": "2.1.11",
"@tiptap/extension-font-family": "2.1.11",
"@tiptap/extension-history": "2.1.11",
"@tiptap/extension-horizontal-rule": "2.1.11",
"@tiptap/extension-link": "2.1.11",
"@tiptap/extension-list-keymap": "2.1.11",
"@tiptap/extension-placeholder": "2.1.11",
"@tiptap/extension-subscript": "2.1.11",
"@tiptap/extension-superscript": "2.1.11",
"@tiptap/extension-table": "2.1.11",
"@tiptap/extension-table-cell": "2.1.11",
"@tiptap/extension-table-header": "2.1.11",
"@tiptap/extension-table-row": "2.1.11",
"@tiptap/extension-task-item": "2.1.11",
"@tiptap/extension-task-list": "2.1.11",
"@tiptap/extension-text-align": "2.1.11",
"@tiptap/extension-text-style": "2.1.11",
"@tiptap/extension-underline": "2.1.11",
"@tiptap/pm": "2.1.11",
"@tiptap/starter-kit": "2.1.11",
"@tiptap/core": "2.1.7",
"@tiptap/extension-character-count": "2.1.7",
"@tiptap/extension-color": "2.1.7",
"@tiptap/extension-font-family": "2.1.7",
"@tiptap/extension-history": "2.1.7",
"@tiptap/extension-horizontal-rule": "2.1.7",
"@tiptap/extension-link": "2.1.7",
"@tiptap/extension-list-keymap": "2.1.7",
"@tiptap/extension-placeholder": "2.1.7",
"@tiptap/extension-subscript": "2.1.7",
"@tiptap/extension-superscript": "2.1.7",
"@tiptap/extension-table": "2.1.7",
"@tiptap/extension-table-cell": "2.1.7",
"@tiptap/extension-table-header": "2.1.7",
"@tiptap/extension-table-row": "2.1.7",
"@tiptap/extension-task-item": "2.1.7",
"@tiptap/extension-task-list": "2.1.7",
"@tiptap/extension-text-align": "2.1.7",
"@tiptap/extension-text-style": "2.1.7",
"@tiptap/extension-underline": "2.1.7",
"@tiptap/pm": "2.1.7",
"@tiptap/starter-kit": "2.1.7",
"@types/katex": "^0.14.0",
"@types/prismjs": "^1.26.0",
"@types/react": "17.0.2",
@@ -26513,7 +26509,7 @@
"prism-themes": "^1.9.0",
"prosemirror-codemark": "^0.4.2",
"prosemirror-test-builder": "^1.1.0",
"prosemirror-view": "^1.31.8",
"prosemirror-view": "^1.31.7",
"re-resizable": "^6.9.9",
"react": "17.0.2",
"react-colorful": "^5.5.1",
@@ -26577,7 +26573,7 @@
"katex": "0.16.2",
"phone": "^3.1.14",
"qclone": "^1.2.0",
"react-native-actions-sheet": "0.9.0-alpha.24",
"react-native-actions-sheet": "0.9.0-alpha.23",
"react-native-check-version": "https://github.com/flexible-agency/react-native-check-version",
"react-native-drax": "^0.10.2",
"react-native-image-zoom-viewer": "^3.0.1",
@@ -26600,7 +26596,7 @@
"@ammarahmed/notifee-react-native": "7.4.4",
"@ammarahmed/react-native-eventsource": "1.1.0",
"@ammarahmed/react-native-share-extension": "^2.5.5",
"@ammarahmed/react-native-sodium": "1.5.4",
"@ammarahmed/react-native-sodium": "1.5.2",
"@babel/core": "^7.20.0",
"@babel/eslint-parser": "^7.16.5",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.16.5",
@@ -26720,7 +26716,7 @@
"requires": {
"@notesnook/theme": "file:../../packages/theme",
"@orama/orama": "^1.0.8",
"@trpc/server": "10.38.3",
"@trpc/server": "10.31.0",
"@types/cors": "^2.8.13",
"@vitejs/plugin-react": "^4.0.3",
"async-mutex": "^0.4.0",
@@ -27329,21 +27325,21 @@
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
},
"@trpc/client": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.38.3.tgz",
"integrity": "sha512-hHPsElTL4sB+UGzuAZ4iwRVHjELrk/Nsl2owsYw9ITJz3EY7VWRsQ6vK48kJvlHPYPhP+efID5UOgyZMs4bFXA==",
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.31.0.tgz",
"integrity": "sha512-VCqbJEvFJb8C4hQFw7AD+dkQTjgEdV/QAzO4D+/cX5e93u5NpfNXI+PKS0QFXwG/zqgwQwVV6OkYc/D/MFwA6g==",
"requires": {}
},
"@trpc/react-query": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.38.3.tgz",
"integrity": "sha512-j4xxg/y+vssGinZCrNQy0SMJNL2Nv8k3HcqMKa2mYt3jxOpaHuwxgarWvLWVqrUJqvp1JpGJ9sIjlOAZam5FeQ==",
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.31.0.tgz",
"integrity": "sha512-+M8sIsbf6e4H5XYvHlzDqhaf+ybfUigA/9OL3wXRp2vXhCedEiIERCnwNuHWFDRASl9vjOcM33AuJ4sbOOINEA==",
"requires": {}
},
"@trpc/server": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.38.3.tgz",
"integrity": "sha512-9s8/kwo2IDB5hwB2SKZZrfevRhdb1f9fdXtIYd3lbQuf2jQaC/LyQuHaIQjDQoUx9updBfsHXcFFPiCP1DL6pg=="
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.31.0.tgz",
"integrity": "sha512-9EnRTSDE9nF11LZsvSOqNKqkRYzHqFX4ch5AJ6VIu8uta2vxVTN4FxxsNRSOluTzVYZDeaCISbwmOJ5iihCCIg=="
},
"@tsconfig/react-native": {
"version": "3.0.2",
@@ -35563,9 +35559,9 @@
}
},
"react-native-actions-sheet": {
"version": "0.9.0-alpha.24",
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.9.0-alpha.24.tgz",
"integrity": "sha512-NF0oO0vf3DrFsqI+pbQ+HTG2q+VEotkVwhtFr8aLiUFJT876icVOSurCaeqD1t4zHtH2U5qa8vKQxbA/j5Mu8w==",
"version": "0.9.0-alpha.23",
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.9.0-alpha.23.tgz",
"integrity": "sha512-d8sZJHKjme33i34zQ8+oIsGs8wY+GCDtxDboExgpO1OoB9np1y4tGOf3ZHyfIpClITpuy+LT7r9Uz+KfAJTMHA==",
"requires": {}
},
"react-native-actions-shortcuts": {

View File

@@ -1,6 +1,6 @@
{
"name": "@notesnook/mobile",
"version": "2.6.7",
"version": "2.6.3",
"private": true,
"license": "GPL-3.0-or-later",
"workspaces": [
@@ -37,9 +37,9 @@
"@notesnook/logger": "file:../../packages/logger",
"@notesnook/themes-server": "file:../../servers/themes",
"@tanstack/react-query": "^4.29.19",
"@trpc/client": "10.38.3",
"@trpc/react-query": "10.38.3",
"@trpc/server": "10.38.3",
"@trpc/client": "10.31.0",
"@trpc/react-query": "10.31.0",
"@trpc/server": "^10.31.0",
"react": "18.2.0",
"react-native": "0.72.0"
}

View File

@@ -1,19 +1,3 @@
diff --git a/node_modules/react-native-blob-util/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFS.java b/node_modules/react-native-blob-util/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFS.java
index c75347f..76d9b9e 100644
--- a/node_modules/react-native-blob-util/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFS.java
+++ b/node_modules/react-native-blob-util/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFS.java
@@ -257,9 +257,9 @@ class ReactNativeBlobUtilFS {
if (resolved != null && resolved.startsWith(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET)) {
String assetName = path.replace(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET, "");
// This fails should an asset file be >2GB
- length = (int) ReactNativeBlobUtilImpl.RCTContext.getAssets().openFd(assetName).getLength();
- bytes = new byte[length];
InputStream in = ReactNativeBlobUtilImpl.RCTContext.getAssets().open(assetName);
+ length = in.available();
+ bytes = new byte[length];
bytesRead = in.read(bytes, 0, length);
in.close();
}
diff --git a/node_modules/react-native-blob-util/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java b/node_modules/react-native-blob-util/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java
index 9aee829..0ecc59b 100644
--- a/node_modules/react-native-blob-util/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java
@@ -125,7 +109,7 @@ index 97e5263..640aaea 100644
}
diff --git a/node_modules/react-native-blob-util/index.js b/node_modules/react-native-blob-util/index.js
index ecaddf9..70d6ba5 100644
index ecaddf9..40a5c37 100644
--- a/node_modules/react-native-blob-util/index.js
+++ b/node_modules/react-native-blob-util/index.js
@@ -14,6 +14,7 @@ import ios from './ios';

View File

@@ -7,8 +7,7 @@ index 0000000..0d259dd
+o/classes
diff --git a/node_modules/react-native-vector-icons/android/build/.transforms/f1314fc28eaff1170375cbb76465cb24/transformed/classes/classes.dex b/node_modules/react-native-vector-icons/android/build/.transforms/f1314fc28eaff1170375cbb76465cb24/transformed/classes/classes.dex
new file mode 100644
index 0000000..d4bdd72
Binary files /dev/null and b/node_modules/react-native-vector-icons/android/build/.transforms/f1314fc28eaff1170375cbb76465cb24/transformed/classes/classes.dex differ
index 0000000..e69de29
diff --git a/node_modules/react-native-vector-icons/android/build/generated/source/buildConfig/debug/com/oblador/vectoricons/BuildConfig.java b/node_modules/react-native-vector-icons/android/build/generated/source/buildConfig/debug/com/oblador/vectoricons/BuildConfig.java
new file mode 100644
index 0000000..52a02e0
@@ -85,12 +84,10 @@ index 0000000..9e26dfe
\ No newline at end of file
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/compile_library_classes_jar/debug/classes.jar b/node_modules/react-native-vector-icons/android/build/intermediates/compile_library_classes_jar/debug/classes.jar
new file mode 100644
index 0000000..77c2a69
Binary files /dev/null and b/node_modules/react-native-vector-icons/android/build/intermediates/compile_library_classes_jar/debug/classes.jar differ
index 0000000..e69de29
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/compile_r_class_jar/debug/R.jar b/node_modules/react-native-vector-icons/android/build/intermediates/compile_r_class_jar/debug/R.jar
new file mode 100644
index 0000000..bd4434a
Binary files /dev/null and b/node_modules/react-native-vector-icons/android/build/intermediates/compile_r_class_jar/debug/R.jar differ
index 0000000..e69de29
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/compile_symbol_list/debug/R.txt b/node_modules/react-native-vector-icons/android/build/intermediates/compile_symbol_list/debug/R.txt
new file mode 100644
index 0000000..5347f17
@@ -2053,11 +2050,11 @@ index 0000000..5347f17
+int xml rn_dev_preferences 0x0
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties b/node_modules/react-native-vector-icons/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties
new file mode 100644
index 0000000..c671bf3
index 0000000..2dd0b63
--- /dev/null
+++ b/node_modules/react-native-vector-icons/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties
@@ -0,0 +1 @@
+#Mon Oct 02 09:47:12 PKT 2023
+#Wed Aug 02 11:28:45 PKT 2023
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml b/node_modules/react-native-vector-icons/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml
new file mode 100644
index 0000000..08d62cc
@@ -2096,20 +2093,16 @@ index 0000000..ef96fe3
\ No newline at end of file
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/BuildConfig.class b/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/BuildConfig.class
new file mode 100644
index 0000000..1276d6a
Binary files /dev/null and b/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/BuildConfig.class differ
index 0000000..e69de29
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/VectorIconsModule$Errors.class b/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/VectorIconsModule$Errors.class
new file mode 100644
index 0000000..3348b06
Binary files /dev/null and b/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/VectorIconsModule$Errors.class differ
index 0000000..e69de29
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/VectorIconsModule.class b/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/VectorIconsModule.class
new file mode 100644
index 0000000..de0d974
Binary files /dev/null and b/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/VectorIconsModule.class differ
index 0000000..e69de29
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/VectorIconsPackage.class b/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/VectorIconsPackage.class
new file mode 100644
index 0000000..07a935e
Binary files /dev/null and b/node_modules/react-native-vector-icons/android/build/intermediates/javac/debug/classes/com/oblador/vectoricons/VectorIconsPackage.class differ
index 0000000..e69de29
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/local_only_symbol_list/debug/R-def.txt b/node_modules/react-native-vector-icons/android/build/intermediates/local_only_symbol_list/debug/R-def.txt
new file mode 100644
index 0000000..78ac5b8
@@ -2181,8 +2174,7 @@ index 0000000..0be2a09
\ No newline at end of file
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/runtime_library_classes_jar/debug/classes.jar b/node_modules/react-native-vector-icons/android/build/intermediates/runtime_library_classes_jar/debug/classes.jar
new file mode 100644
index 0000000..f0a7660
Binary files /dev/null and b/node_modules/react-native-vector-icons/android/build/intermediates/runtime_library_classes_jar/debug/classes.jar differ
index 0000000..e69de29
diff --git a/node_modules/react-native-vector-icons/android/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt b/node_modules/react-native-vector-icons/android/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt
new file mode 100644
index 0000000..873e0a9
@@ -3669,8 +3661,7 @@ index 0000000..f4f75c1
+ INJECTED from /Users/ammarahmed/Repos/apps/notesnook/apps/mobile/node_modules/react-native-vector-icons/android/src/main/AndroidManifest.xml
diff --git a/node_modules/react-native-vector-icons/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin b/node_modules/react-native-vector-icons/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin
new file mode 100644
index 0000000..26da0e3
Binary files /dev/null and b/node_modules/react-native-vector-icons/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin differ
index 0000000..e69de29
diff --git a/node_modules/react-native-vector-icons/fonts.gradle b/node_modules/react-native-vector-icons/fonts.gradle
index 5485fac..ef3ccb3 100644
--- a/node_modules/react-native-vector-icons/fonts.gradle
@@ -3687,7 +3678,7 @@ index 5485fac..ef3ccb3 100644
generateAssetsTask.dependsOn(fontCopyTask)
}
diff --git a/node_modules/react-native-vector-icons/glyphmaps/MaterialCommunityIcons.json b/node_modules/react-native-vector-icons/glyphmaps/MaterialCommunityIcons.json
index c06a819..13c76cc 100644
index c06a819..0962de1 100644
--- a/node_modules/react-native-vector-icons/glyphmaps/MaterialCommunityIcons.json
+++ b/node_modules/react-native-vector-icons/glyphmaps/MaterialCommunityIcons.json
@@ -1,6598 +1 @@
@@ -10290,7 +10281,7 @@ index c06a819..13c76cc 100644
- "blank": 63116
-}
\ No newline at end of file
+{"menu":983900,"lock-open-outline":983872,"key-outline":986582,"pin-off-outline":985392,"pin-outline":985393,"star-off":984273,"star-outline":984274,"link-variant-remove":987393,"link-variant":983865,"bell":983194,"bell-off-outline":985745,"check":983340,"magnify":983881,"plus":984085,"view-list-outline":988299,"view-list":984434,"play":984074,"pause":984036,"notebook-outline":986815,"text-short":985513,"radiobox-marked":984126,"radiobox-blank":984125,"sort-descending":984253,"information":983804,"sort-ascending":984252,"alert":983078,"arrow-right":983124,"bookmark-outline":983235,"checkbox-marked":983346,"checkbox-blank-outline":983345,"unfold-less-horizontal":984398,"minus-circle":983926,"vibrate":984422,"volume-high":984446,"checkbox-blank-circle-outline":983344,"check-circle-outline":984545,"chevron-up":983363,"chevron-down":983360,"calendar":983277,"minus-circle-outline":983927,"close-circle-outline":983386,"qrcode":984114,"text":985512,"cloud":983391,"book-outline":985956,"pound":984099,"clock-plus-outline":989282,"cloud-upload-outline":985982,"export":983559,"message-badge-outline":989506,"square-edit-outline":985356,"content-copy":983439,"delete-restore":985113,"share-variant":984215,"pencil-lock":984046,"sync-off":984296,"content-duplicate":983441,"theme-light-dark":984334,"pencil":984043,"clock-outline":983376,"attachment":983142,"history":983770,"notebook":985134,"bookmark":983232,"delete-outline":985575,"delete":983476,"link":983863,"cloud-upload":983399,"star":984270,"key":983814,"account-outline":983059,"email":983534,"backup-restore":983151,"update":984752,"android":983090,"web":984479,"home-variant-outline":986023,"text-box-multiple-outline":985784,"download":983514,"arrow-left":983117,"dots-horizontal":983512,"chevron-right":983362,"close":983382,"cellphone-key":985422,"message-plus-outline":987323,"email-outline":983536,"shield-lock":985501,"chevron-left":983361,"minus":983924,"crown":983461,"account-cog":988016,"two-factor-authentication":985519,"information-outline":983805,"logout":983875,"autorenew":983146,"sync-alert":984295,"shape":985137,"circle-half":988053,"brightness-6":983263,"note-edit-outline":989058,"format-line-spacing":983672,"format-size":983679,"format-font":984790,"radar":984119,"arrow-decision-outline":985534,"fingerprint":983607,"eye-off-outline":984785,"folder":983627,"lock":983870,"form-textbox":984590,"bell-outline":983196,"bell-ring":983198,"bug":983268,"mail":986811,"file-document":983577,"mastodon":985809,"twitter":984388,"discord":984687,"open-source-initiative":986030,"monitor":983929,"chart-timeline":984686,"cellphone-arrow-down":985557,"alpha-v":985859,"circle-small":985567,"upload":984402,"file-check":983574,"file":983572,"alert-circle-outline":984534,"check-all":983341,"shield-key-outline":986053,"dots-vertical":983513,"emoticon-wink":986232,"sync":984294,"shield":984216,"billboard":987152,"cellphone":983324,"cellphone-lock":985423,"file-lock":983585,"image-multiple":983801,"harddisk":983754,"file-cabinet":985782,"refresh":984144,"emoticon":986216,"palette":984024,"pin":984067,"format-bold":983652,"table":984299,"language-markdown":983892,"gesture-tap-button":987816,"send-lock":985069,"bomb":984721,"file-pdf-box":983590,"language-html5":983837,"clipboard-text-outline":985656,"invert-colors":983809,"select-all":984198,"cog-outline":985275,"arrow-top-right-thick":985542,"checkbox-blank-circle":983343,"note":983962,"drag":983515,"menu-down":983901,"alert-circle":983080,"reload":984147,"card-text":985975,"open-in-new":984012,"eye":983560}
+{"menu":983900,"lock-open-outline":983872,"key-outline":986582,"pin-off-outline":985392,"pin-outline":985393,"star-off":984273,"star-outline":984274,"link-variant-remove":987393,"link-variant":983865,"bell":983194,"bell-off-outline":985745,"check":983340,"magnify":983881,"plus":984085,"view-list-outline":988299,"view-list":984434,"play":984074,"pause":984036,"notebook-outline":986815,"text-short":985513,"radiobox-marked":984126,"radiobox-blank":984125,"sort-descending":984253,"information":983804,"sort-ascending":984252,"alert":983078,"arrow-right":983124,"bookmark-outline":983235,"checkbox-marked":983346,"checkbox-blank-outline":983345,"unfold-less-horizontal":984398,"minus-circle":983926,"vibrate":984422,"volume-high":984446,"checkbox-blank-circle-outline":983344,"check-circle-outline":984545,"chevron-up":983363,"chevron-down":983360,"calendar":983277,"book-outline":985956,"pound":984099,"clock-plus-outline":989282,"cloud-upload-outline":985982,"export":983559,"message-badge-outline":989506,"square-edit-outline":985356,"content-copy":983439,"delete-restore":985113,"share-variant":984215,"pencil-lock":984046,"sync-off":984296,"content-duplicate":983441,"theme-light-dark":984334,"pencil":984043,"clock-outline":983376,"attachment":983142,"history":983770,"notebook":985134,"bookmark":983232,"minus-circle-outline":983927,"delete-outline":985575,"delete":983476,"link":983863,"cloud-upload":983399,"star":984270,"key":983814,"account-outline":983059,"email":983534,"backup-restore":983151,"update":984752,"android":983090,"web":984479,"home-variant-outline":986023,"text-box-multiple-outline":985784,"download":983514,"circle-small":985567,"upload":984402,"file-check":983574,"form-textbox":984590,"fingerprint":983607,"file":983572,"alert-circle-outline":984534,"check-all":983341,"shield-key-outline":986053,"arrow-left":983117,"message-plus-outline":987323,"email-outline":983536,"cellphone-key":985422,"dots-vertical":983513,"close":983382,"chevron-right":983362,"emoticon-wink":986232,"sync":984294,"shield":984216,"billboard":987152,"cellphone":983324,"cellphone-lock":985423,"lock":983870,"file-lock":983585,"image-multiple":983801,"harddisk":983754,"file-cabinet":985782,"refresh":984144,"emoticon":986216,"palette":984024,"pin":984067,"format-bold":983652,"table":984299,"language-markdown":983892,"gesture-tap-button":987816,"send-lock":985069,"bomb":984721,"file-pdf-box":983590,"language-html5":983837,"clipboard-text-outline":985656,"invert-colors":983809,"crown":983461,"select-all":984198,"minus":983924,"information-outline":983805,"cog-outline":985275,"arrow-top-right-thick":985542,"checkbox-blank-circle":983343,"sync-alert":984295,"note":983962,"dots-horizontal":983512,"shield-lock":985501,"chevron-left":983361,"account-cog":988016,"two-factor-authentication":985519,"logout":983875,"autorenew":983146,"shape":985137,"circle-half":988053,"brightness-6":983263,"note-edit-outline":989058,"format-line-spacing":983672,"format-size":983679,"format-font":984790,"radar":984119,"arrow-decision-outline":985534,"eye-off-outline":984785,"folder":983627,"bell-outline":983196,"bell-ring":983198,"bug":983268,"mail":986811,"file-document":983577,"mastodon":985809,"twitter":984388,"discord":984687,"open-source-initiative":986030,"monitor":983929,"chart-timeline":984686,"cellphone-arrow-down":985557,"alpha-v":985859,"alert-circle":983080,"reload":984147,"card-text":985975,"open-in-new":984012,"eye":983560,"drag":983515,"menu-down":983901}
\ No newline at end of file
diff --git a/node_modules/react-native-vector-icons/glyphmaps/MaterialCommunityIcons.old.json b/node_modules/react-native-vector-icons/glyphmaps/MaterialCommunityIcons.old.json
new file mode 100644

View File

@@ -65,12 +65,7 @@ const EXTRA_ICON_NAMES = [
"check-circle-outline",
"chevron-up",
"chevron-down",
"calendar",
"minus-circle-outline",
"close-circle-outline",
"qrcode",
"text",
"cloud"
"calendar"
];
const __filename = fileURLToPath(import.meta.url);

View File

@@ -167,9 +167,10 @@ export const Editor = ({ onChange, onLoad }) => {
}}
nestedScrollEnabled
javaScriptEnabled={true}
focusable={true}
setSupportMultipleWindows={false}
overScrollMode="never"
scrollEnabled={Platform.OS === "ios"}
scrollEnabled={false}
keyboardDisplayRequiresUserAction={false}
cacheMode="LOAD_DEFAULT"
cacheEnabled={true}

View File

@@ -1,181 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, {
createRef,
useEffect,
useImperativeHandle,
useRef,
useState
} from "react";
import { Platform } from "react-native";
import RNFetchBlob from "react-native-blob-util";
import WebView from "react-native-webview";
import { Config } from "./store";
import { db } from "../app/common/database";
import { SUBSCRIPTION_STATUS } from "../app/utils/constants";
export const fetchHandle = createRef();
export const HtmlLoadingWebViewAgent = React.memo(
() => {
const [source, setSource] = useState(null);
const [clipper, setClipper] = useState(null);
const loadHandler = useRef();
const htmlHandler = useRef();
const webview = useRef();
const premium = useRef(false);
const corsProxy = Config.corsProxy;
useImperativeHandle(
fetchHandle,
() => ({
processUrl: (url) => {
return new Promise((resolve) => {
setSource(url);
let resolved = false;
htmlHandler.current = (html) => {
if (resolved) return;
resolved = true;
setSource(null);
resolve(html);
};
loadHandler.current = (result) => {
if (resolved) return;
if (!result) {
resolved = true;
setSource(null);
resolve(null);
return;
}
};
});
}
}),
[]
);
useEffect(() => {
(async () => {
const user = await db.user.getUser();
const subscriptionStatus =
user?.subscription?.type || SUBSCRIPTION_STATUS.BASIC;
premium.current =
user && subscriptionStatus !== SUBSCRIPTION_STATUS.BASIC;
const clipperPath =
Platform.OS === "ios"
? RNFetchBlob.fs.dirs.MainBundleDir +
"/extension.bundle/clipper.bundle.js"
: "bundle-assets://clipper.bundle.js";
RNFetchBlob.fs
.readFile(clipperPath, "utf8")
.then((clipper) => {
setClipper(clipper);
})
.catch((e) => console.log(e));
})();
}, []);
return !source || !clipper ? null : (
<WebView
ref={webview}
onLoad={() => {
loadHandler.current?.(true);
}}
style={{
width: 100,
height: 100,
position: "absolute",
opacity: 0,
zIndex: -1
}}
useSharedProcessPool={false}
pointerEvents="none"
onMessage={(event) => {
try {
const data = JSON.parse(event.nativeEvent.data);
if (data && data.type === "html") {
console.log("message recieved page loaded");
htmlHandler.current?.(data.value);
} else {
if (data.type === "error") {
console.log("error", data.value);
htmlHandler.current?.(null);
}
}
} catch (e) {
console.log("Error handling webview message", e);
}
}}
injectedJavaScriptBeforeContentLoaded={script(clipper, premium.current)}
onError={() => {
console.log("Error loading page");
loadHandler.current?.();
}}
source={{
uri: source
}}
/>
);
},
() => true
);
const script = (clipper, pro) => `
${clipper}
function postMessage(type, value) {
if (window.ReactNativeWebView) {
window.ReactNativeWebView.postMessage(
JSON.stringify({
type: type,
value: value
})
);
}
}
(() => {
try {
const loadFn = () => {
if (!globalThis.Clipper.clipPage) {
postMessage("error", globalThis.Clipper.clipPage);
} else {
globalThis.Clipper.clipPage(document,false, {
images: ${pro},
inlineImages: false,
styles: false,
corsProxy: undefined
}).then(result => {
postMessage("html", result);
}).catch(e => {
postMessage("error");
});
}
};
window.addEventListener("load",loadFn, false);
} catch(e) {
postMessage("error", e.message);
}
})();
`;
HtmlLoadingWebViewAgent.displayName = "HtmlLoadingWebViewAgent";

View File

@@ -56,15 +56,15 @@ import { Editor } from "./editor";
import { Search } from "./search";
import { initDatabase, useShareStore } from "./store";
import { useThemeColors } from "@notesnook/theme";
import { HtmlLoadingWebViewAgent, fetchHandle } from "./fetch-webview";
const getLinkPreview = (url) => {
return getPreviewData(url, 5000);
};
async function sanitizeHtml(site) {
try {
let html = await fetchHandle.current?.processUrl(site);
return html;
let html = await fetch(site);
html = await html.text();
return sanitize(html, site);
} catch (e) {
return "";
}
@@ -82,6 +82,93 @@ function makeHtmlFromPlainText(text) {
.replace(/(?:\r\n|\r|\n)/g, "</p><p>")}</p>`;
}
function getBaseUrl(site) {
var url = site.split("/").slice(0, 3).join("/");
return url;
}
function wrapTablesWithDiv(document) {
const tables = document.getElementsByTagName("table");
for (let table of tables) {
table.setAttribute("contenteditable", "true");
const div = document.createElement("div");
div.setAttribute("contenteditable", "false");
div.innerHTML = table.outerHTML;
div.classList.add("table-container");
table.replaceWith(div);
}
return document;
}
let elementBlacklist = [
"script",
"button",
"input",
"textarea",
"style",
"form",
"link",
"head",
"nav",
"iframe",
"canvas",
"select",
"dialog",
"footer"
];
function removeInvalidElements(document) {
let elements = document.querySelectorAll(elementBlacklist.join(","));
for (let element of elements) {
element.remove();
}
return document;
}
function replaceSrcWithAbsoluteUrls(document, baseUrl) {
let images = document.querySelectorAll("img");
for (var i = 0; i < images.length; i++) {
let img = images[i];
let url = getBaseUrl(baseUrl);
let src = img.getAttribute("src");
if (src.startsWith("/")) {
if (src.startsWith("//")) {
src = src.replace("//", "https://");
} else {
src = url + src;
}
}
if (src.startsWith("data:")) {
img.remove();
} else {
img.setAttribute("src", src);
}
}
return document;
}
function fixCodeBlocks(document) {
let elements = document.querySelectorAll("code,pre");
for (let element of elements) {
element.classList.add(".hljs");
}
return document;
}
function sanitize(html, baseUrl) {
let parser = parseHTML(html);
parser = wrapTablesWithDiv(parser);
parser = removeInvalidElements(parser);
parser = replaceSrcWithAbsoluteUrls(parser, baseUrl);
parser = fixCodeBlocks(parser);
let htmlString = parser.body.outerHTML;
htmlString = htmlString + `<hr>${makeHtmlFromUrl(baseUrl)}`;
return htmlString;
}
let defaultNote = {
title: null,
id: null,
@@ -123,7 +210,6 @@ const ShareView = ({ quicknote = false }) => {
const [mode, setMode] = useState(1);
const keyboardHeight = useRef(0);
const { width, height } = useWindowDimensions();
const [loadingPage, setLoadingPage] = useState(false);
const insets =
Platform.OS === "android"
? { top: StatusBar.currentHeight }
@@ -174,10 +260,6 @@ const ShareView = ({ quicknote = false }) => {
const loadData = useCallback(async () => {
try {
if (noteContent.current) {
onLoad();
return;
}
defaultNote.content.data = null;
setNote({ ...defaultNote });
const data = await ShareExtension.data();
@@ -315,19 +397,14 @@ const ShareView = ({ quicknote = false }) => {
setLoading(true);
try {
if (m === 2) {
setLoadingPage(true);
setTimeout(async () => {
let html = await sanitizeHtml(rawData.value);
let html = await sanitizeHtml(rawData.value);
setNote((note) => {
note.content.data = html;
noteContent.current = html;
setLoadingPage(false);
onLoad();
setNote((note) => {
note.content.data = html;
return { ...note };
});
}, 300);
return { ...note };
});
} else {
setLoadingPage(false);
let html = isURL(rawData.value)
? makeHtmlFromUrl(rawData.value)
: makeHtmlFromPlainText(rawData.value);
@@ -373,8 +450,6 @@ const ShareView = ({ quicknote = false }) => {
justifyContent: quicknote ? "flex-start" : "flex-end"
}}
>
{loadingPage ? <HtmlLoadingWebViewAgent /> : null}
{quicknote && !searchMode ? (
<View
style={{
@@ -641,27 +716,16 @@ const ShareView = ({ quicknote = false }) => {
<SafeAreaProvider
style={{
flex: 1,
paddingTop: 10,
justifyContent: loadingPage ? "center" : undefined,
alignItems: loadingPage ? "center" : undefined
paddingTop: 10
}}
>
{!loadingExtension && !loadingPage ? (
{!loadingExtension && (
<Editor
onLoad={onLoadEditor}
onChange={(html) => {
noteContent.current = html;
}}
/>
) : (
<>
{loadingPage ? (
<>
<ActivityIndicator color={colors.primary.accent} />
<Text>Preparing web clip...</Text>
</>
) : null}
</>
)}
</SafeAreaProvider>
</View>

View File

@@ -90,7 +90,3 @@ export const useShareStore = create((set) => ({
set({ selectedTags });
}
}));
export const Config = {
corsProxy: appSettings?.corsProxy
};

View File

@@ -17,7 +17,6 @@
"@notesnook/web": "file:../web",
"@theme-ui/components": "^0.14.7",
"@theme-ui/core": "^0.14.7",
"@trpc/client": "^10.38.3",
"clipboard-polyfill": "^4.0.0",
"file-saver": "^2.0.5",
"katex": "^0.16.2",
@@ -1377,7 +1376,7 @@
},
"../web": {
"name": "@notesnook/web",
"version": "2.6.5",
"version": "2.6.1",
"license": "GPL-3.0-or-later",
"dependencies": {
"@aws-sdk/util-base64-browser": "^3.208.0",
@@ -1406,8 +1405,8 @@
"@theme-ui/color": "^0.14.7",
"@theme-ui/components": "^0.14.7",
"@theme-ui/core": "^0.14.7",
"@trpc/client": "10.38.3",
"@trpc/react-query": "10.38.3",
"@trpc/client": "10.31.0",
"@trpc/react-query": "10.31.0",
"allotment": "^1.19.0",
"axios": "^1.3.4",
"clipboard-polyfill": "4.0.0",
@@ -1446,7 +1445,7 @@
"devDependencies": {
"@babel/core": "^7.22.5",
"@playwright/test": "^1.36.2",
"@trpc/server": "10.38.3",
"@trpc/server": "10.31.0",
"@types/babel__core": "^7.20.1",
"@types/file-saver": "^2.0.5",
"@types/marked": "^4.0.7",
@@ -2395,26 +2394,6 @@
"react": ">16"
}
},
"node_modules/@trpc/client": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.38.3.tgz",
"integrity": "sha512-hHPsElTL4sB+UGzuAZ4iwRVHjELrk/Nsl2owsYw9ITJz3EY7VWRsQ6vK48kJvlHPYPhP+efID5UOgyZMs4bFXA==",
"funding": [
"https://trpc.io/sponsor"
],
"peerDependencies": {
"@trpc/server": "10.38.3"
}
},
"node_modules/@trpc/server": {
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.38.3.tgz",
"integrity": "sha512-9s8/kwo2IDB5hwB2SKZZrfevRhdb1f9fdXtIYd3lbQuf2jQaC/LyQuHaIQjDQoUx9updBfsHXcFFPiCP1DL6pg==",
"funding": [
"https://trpc.io/sponsor"
],
"peer": true
},
"node_modules/@types/babel__core": {
"version": "7.20.1",
"dev": true,

View File

@@ -16,7 +16,6 @@
"@notesnook/web": "file:../web",
"@theme-ui/components": "^0.14.7",
"@theme-ui/core": "^0.14.7",
"@trpc/client": "^10.38.3",
"clipboard-polyfill": "^4.0.0",
"file-saver": "^2.0.5",
"katex": "^0.16.2",

View File

@@ -643,25 +643,13 @@ function exportTheme(theme: ThemeDefinition) {
}),
`${theme.id}.json`
);
const confirmed = window.confirm(
"Do you also want to download code-block.css for this theme?"
);
if (confirmed) {
FileSaver.saveAs(
new Blob([theme.codeBlockCSS], {
type: "text/plain"
}),
`code-block.css`
);
}
}
function themeToJSON(theme: ThemeDefinition) {
return JSON.stringify(
{
$schema: JSON_SCHEMA_URL,
...theme,
codeBlockCSS: undefined
...theme
},
undefined,
2

View File

@@ -18,21 +18,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { test, expect } from "@playwright/test";
import { AppModel } from "./models/app.model";
import { USER } from "./utils";
import { NOTE, USER } from "./utils";
test("create an unencrypted backup", async ({ page }) => {
test("create a backup", async ({ page }) => {
const app = new AppModel(page);
await app.auth.goto();
await app.auth.login(USER.CURRENT);
await app.goto();
const notes = await app.goToNotes();
await notes.createNote(NOTE);
const settings = await app.goToSettings();
await settings.toggleBackupEncryption(USER.CURRENT.password);
const backup = await settings.createBackup(USER.CURRENT.password);
const backup = await settings.createBackup();
expect(backup.length > 0).toBeTruthy();
});
test("restore an unencrypted backup", async ({ page }) => {
test("restore a backup", async ({ page }) => {
const app = new AppModel(page);
await app.goto();
const settings = await app.goToSettings();
@@ -56,7 +56,7 @@ test("create an encrypted backup", async ({ page }, info) => {
await app.auth.login(USER.CURRENT);
const settings = await app.goToSettings();
const backup = await settings.createBackup();
const backup = await settings.createBackup(USER.CURRENT.password);
expect(backup.length > 0).toBeTruthy();
});

Some files were not shown because too many files have changed in this diff Show More