Compare commits

...

112 Commits

Author SHA1 Message Date
Ammar Ahmed
977d6f9246 mobile: fix selection state causing delete to fail 2023-10-30 13:22:03 +05:00
Ammar Ahmed
d412679fd7 mobile: fix relogin in session expired mode 2023-10-30 11:56:52 +05:00
Ammar Ahmed
22c52d4432 core: reset lastSynced if new login 2023-10-30 11:55:43 +05:00
Ammar Ahmed
9e5bdf9e33 core: fix access token not saved 2023-10-30 11:55:14 +05:00
Abdullah Atta
7253eca5c0 core: do not allow saving empty token response 2023-10-30 10:55:39 +05:00
Abdullah Atta
b1f3dc29c5 core: use single sse command for logging the user out 2023-10-30 10:55:39 +05:00
Abdullah Atta
8e3df8d41b editor: disallow links in inline code 2023-10-30 10:41:04 +05:00
Ammar Ahmed
efad22c00a mobile: fix 24 hour reminder time 2023-10-30 10:26:15 +05:00
Ammar Ahmed
b7690f13b1 mobile: hide pinned notification subtitle 2023-10-30 09:58:52 +05:00
Ammar Ahmed
6e1739da2e mobile: fix note not added to default notebook in widget 2023-10-24 17:35:53 +05:00
Ammar Ahmed
77ab423041 mobile: fix keep in view in editor (#3612) 2023-10-24 16:54:00 +05:00
Ammar Ahmed
96a8e885d3 Fix session expiry dialog not presented when user encryption key is not found (#3625)
* core: fix session expired dialog not shown when
user encryption key does not
exist

* core: add watch command
2023-10-24 15:58:26 +05:00
Ammar Ahmed
2b917c7eca mobile: fix pin input hide behind keyboard on session expiry sheet (#3624) 2023-10-24 15:57:20 +05:00
Ammar Ahmed
942d2f7a4e mobile: fix system bar colors (#3611) 2023-10-24 12:44:41 +05:00
Ammar Ahmed
75142ff1b2 mobile: fix session id mismatch causing editor to get stuck.(#3613) 2023-10-24 09:18:55 +05:00
Abdullah Atta
74172dc3fa docs: update organizing notes using notebooks doc 2023-10-03 14:42:54 +05:00
Abdullah Atta
848fdda8d7 docs: update outdated documentation 2023-10-03 13:44:21 +05:00
Abdullah Atta
3895569a0c setup: make flatpak source generation more robust 2023-10-03 12:02:27 +05:00
Abdullah Atta
0aac29ca76 web: bump version to 2.6.7 2023-10-02 21:06:08 +05:00
Abdullah Atta
25f9eece8d web: remove blur from dialogs 2023-10-02 21:06:08 +05:00
Ammar Ahmed
0e22b8ab2c mobile: release v2.6.7 2023-10-02 19:01:16 +05:00
Abdullah Atta
577c2ce6cd core: auto create vault if non exists & user opens a locked note 2023-10-02 18:00:36 +05:00
Abdullah Atta
5b9cb8ca4b desktop: fix close to system tray only works once 2023-10-02 17:56:41 +05:00
Ammar Ahmed
2eda93c0c2 mobile: fix add to notebook sheet hangs with many notebooks (#3505)
Signed-off-by: Ammar Ahmed <40239442+ammarahm-ed@users.noreply.github.com>
2023-10-02 17:06:28 +05:00
Ammar Ahmed
d916adf2e3 mobile: fix dialog show above app lock 2023-10-02 17:05:41 +05:00
Abdullah Atta
1f065bcbb2 web: do not show save dialog when Ctrl+S is pressed 2023-10-02 16:37:09 +05:00
Abdullah Atta
3efdd9505e editor: do not open keyboard on task item drop 2023-10-02 16:22:20 +05:00
Abdullah Atta
ab3f5f6a6c editor: hide scrollbar in math nodes 2023-10-02 16:17:39 +05:00
Muhammad Ali
9027be7bbb web: add menu item to allow copying a note as text or markdown (#3193)
Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2023-10-02 16:09:35 +05:00
Abdullah Atta
7b08b5c035 core: fix vault key not getting synced 2023-10-02 16:07:52 +05:00
Abdullah Atta
4a557c67b7 core: fix require prismjs on desktop build 2023-10-02 15:28:47 +05:00
Abdullah Atta
a6ebe092e8 core: fix undefined is not an object when publishing empty note 2023-10-02 15:15:21 +05:00
Midhun Sudhir
9759e1b396 mobile: fix typo in pricing plans (#3477)
Signed-off-by: Midhun Sudhir <60651970+midhun3301@users.noreply.github.com>
2023-09-28 23:19:15 +05:00
Ammar Ahmed
b6147ca5a1 mobile: release v2.6.6 2023-09-25 13:26:40 +05:00
Ammar Ahmed
83887db77a mobile: pass e2e tests 2023-09-25 13:26:40 +05:00
Abdullah Atta
1facfbec0e web: bump version to 2.6.6 2023-09-25 12:38:49 +05:00
Abdullah Atta
d6608325b4 web: skip education plan in tests 2023-09-25 12:27:09 +05:00
Ammar Ahmed
439b090470 mobile: fix learn more button is empty 2023-09-25 12:23:37 +05:00
Ammar Ahmed
ed98319a21 mobile: fix topic sheet size 2023-09-25 12:23:37 +05:00
Ammar Ahmed
54f94f44c0 mobile: remove icon animation 2023-09-25 12:23:37 +05:00
Ammar Ahmed
57cf0e23cf core: fix sorting of debug logs 2023-09-25 12:23:37 +05:00
Abdullah Atta
9e66269aca core: fix core tests 2023-09-25 12:20:54 +05:00
Abdullah Atta
a4f50fa2c3 web: fix backup tests 2023-09-25 11:47:29 +05:00
Abdullah Atta
7a0bafb02c editor: improve drag/drop support in task lists 2023-09-25 11:06:05 +05:00
Abdullah Atta
a24658ac0e core: fix "Cannot read property type of undefined" 2023-09-25 10:43:54 +05:00
Abdullah Atta
bb77385b66 editor: update tiptap to 2.1.11 2023-09-25 10:36:36 +05:00
Ammar Ahmed
e8b1bb649c editor: focus editor on press enter on mobile 2023-09-22 17:32:01 +05:00
Ammar Ahmed
023347da3f editor: fix link color in tool 2023-09-22 17:31:36 +05:00
Ammar Ahmed
f10146be03 mobile: fix image preview not loading image 2023-09-22 17:17:25 +05:00
Ammar Ahmed
7bac3c1326 mobile: fix selection is not reset when switching topics 2023-09-22 16:35:40 +05:00
Ammar Ahmed
528c0a10de mobile: skip clipping images from webpage 2023-09-22 10:32:52 +05:00
Ammar Ahmed
c1e1a8d1a9 clipper: support full page clips without styles and images 2023-09-22 10:32:52 +05:00
Ammar Ahmed
21720a510d editor: cache src of image when loading from network 2023-09-22 10:32:52 +05:00
Ammar Ahmed
a2d5e7f32f editor: layout images as block on mobile 2023-09-22 10:32:52 +05:00
Ammar Ahmed
629fb7b9cd mobile: patch lib to support asset reading 2023-09-22 10:32:52 +05:00
Ammar Ahmed
f6a4af8c00 clipper: convert relative urls to absolute 2023-09-22 10:32:52 +05:00
Ammar Ahmed
837e60316a mobile: fix loading clip on android 2023-09-22 10:32:52 +05:00
Ammar Ahmed
2592a90853 mobile: fix clipper build output path 2023-09-22 10:32:52 +05:00
ammarahm-ed
788429efb7 mobile: clip dynamic websites 2023-09-22 10:32:52 +05:00
Ammar Ahmed
674d8672f0 mobile: set title max length to 500 chars 2023-09-21 15:29:47 +05:00
ammarahm-ed
8d371fce79 mobile: multi-line title 2023-09-21 15:29:47 +05:00
Muhammad Ali
f0f391ec73 editors: add support for write protecting a specific task list (#3285)
* editor: added readonly attr for tasklist

* Update packages/editor/src/extensions/task-list/task-list.ts

Signed-off-by: Abdullah Atta <thecodrr@protonmail.com>

* editor: fixed tasklist title input

* editor: allow write protecting nested task lists

---------

Signed-off-by: Abdullah Atta <thecodrr@protonmail.com>
Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2023-09-21 14:52:55 +05:00
Muhammad Ali
abc3b5569c core: fix upcoming reminder time calculation (#3341)
* core: added missing equality sign

* core: added test
2023-09-21 14:04:20 +05:00
Muhammad Ali
c42dc0f12e editor: add drag/drop support for attachments (#3325)
* editor: added drag for attachments

* editor: refactor attachment dragging check

---------

Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2023-09-21 13:59:41 +05:00
luzpaz
7ec14f2eff mobile: fix typos in apps/mobile subdirectory
Found via `codespell -q 3 -S "*.patch"`
2023-09-21 13:51:28 +05:00
ammarahm-ed
31d4e88efd mobile: check if file exists based on file size 2023-09-21 13:43:16 +05:00
Abdullah Atta
da06184d51 core: increment progress even if file exists 2023-09-21 13:43:16 +05:00
Abdullah Atta
08296793f1 web: improve attachment progress events & ui 2023-09-21 13:43:16 +05:00
Abdullah Atta
3b6fde2ea6 web: check file size when checking for file existence 2023-09-21 13:43:16 +05:00
Abdullah Atta
1f2948c9a5 core: check for file existence before calling downloadFile 2023-09-21 13:43:16 +05:00
ammarahm-ed
e62267042e mobile: add support for progress 2023-09-21 13:43:16 +05:00
ammarahm-ed
883fe48946 core: add download start & canceled events 2023-09-21 13:43:16 +05:00
Abdullah Atta
6ba18c5bd1 web: use new file upload/download events 2023-09-21 13:43:16 +05:00
Abdullah Atta
207347190d core: fix download/upload cancellation 2023-09-21 13:43:16 +05:00
Ammar Ahmed
0cf76e1f11 mobile: fix sorting notes in topics (#3348)
* mobile: fix sorting notes in topics

* mobile: fix list is not updated
2023-09-21 13:30:10 +05:00
ammarahm-ed
9d76311f82 mobile: support font scaling 2023-09-21 13:29:44 +05:00
ammarahm-ed
c327a292c7 mobile: show +, # and export icon in selection header 2023-09-21 13:24:25 +05:00
ammarahm-ed
5a965f6d52 mobile: simplify deleting topic 2023-09-21 13:24:25 +05:00
ammarahm-ed
a81c621d49 mobile: migrate to persisted app cache
We now use app files directory on android
& LibraryPath on iOS to store cache files
such as images etc so they don't get deleted
by the system
2023-09-21 13:19:46 +05:00
ammarahm-ed
2e7b5d0d08 mobile: fix attachments fail to encrypt from share extension 2023-09-21 13:19:46 +05:00
ammarahm-ed
6d324fe8da mobile: improve editor content loading 2023-09-21 13:10:55 +05:00
ammarahm-ed
6d2be3a083 mobile: clear download/upload progress on cancel token 2023-09-21 13:10:55 +05:00
ammarahm-ed
d252c6fc5c mobile: fix editor not reset session id 2023-09-21 13:10:55 +05:00
ammarahm-ed
30c5e87c67 mobile: support running pending sync 2023-09-21 13:06:38 +05:00
Abdullah Atta
2db819de2b web: add support for running pending sync 2023-09-21 13:06:38 +05:00
Muhammad Ali
bff5e64484 editor: fix plain text pasting on windows (#3402)
* editor: added check for empty <p/> with <br/>

* editor: improve paragraph empty check

* editor: add tests

* editor: fix CRLF line breaks when pasting text

---------

Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2023-09-21 11:58:55 +05:00
Abdullah Atta
3492bef2c7 crypto: fix nodejs native encryption causing file corruption 2023-09-21 11:30:47 +05:00
Abdullah Atta
6d9aa56084 web: fix loading indicator in setting buttons 2023-09-21 11:30:23 +05:00
Abdullah Atta
94c40b3444 desktop: fix jumplist item activation when app is running 2023-09-21 11:30:23 +05:00
Abdullah Atta
278c8b1115 web: use update status in settings about screen 2023-09-21 11:30:23 +05:00
Abdullah Atta
8e8581cce5 desktop: auto check for updates every 12 hours 2023-09-21 11:30:23 +05:00
Abdullah Atta
bd29f4e9e2 web: hide "You are on latest version" notice 2023-09-21 11:30:23 +05:00
Abdullah Atta
eb2b92d85c web: only show loading indicator on button that was pressed 2023-09-21 11:30:23 +05:00
Abdullah Atta
042ac0d338 desktop: fix auto updater events not sent to app 2023-09-21 11:30:23 +05:00
Abdullah Atta
a7011f0d6b global: update @trpc/* to 10.38.3 2023-09-21 11:30:23 +05:00
Abdullah Atta
22144ee18d web: fix backup validation check 2023-09-19 22:28:16 +05:00
Abdullah Atta
b85484fceb desktop: update lockfile 2023-09-15 17:13:47 +05:00
Abdullah Atta
b58956371f desktop: bump electron to v25.8.1 fixing CVE-2023-4863 2023-09-15 17:10:54 +05:00
Abdullah Atta
f487e9f7e2 global: update lockfiles 2023-09-15 15:06:27 +05:00
Abdullah Atta
f14efd3b1e web: fallback to blob download if service worker not found 2023-09-15 11:29:40 +05:00
Abdullah Atta
3496a42c19 web: bump to version 2.6.5 2023-09-15 10:24:15 +05:00
Abdullah Atta
0882c3ecf5 web: use single service worker for everything 2023-09-15 10:23:56 +05:00
ammarahm-ed
1f6d76bac7 mobile: update versionCode 2023-09-15 00:06:42 +05:00
ammarahm-ed
db7c3f4321 mobile: release v2.6.5 2023-09-14 23:45:44 +05:00
ammarahm-ed
9ea4651fb0 core: fix backup fail if item in null/undefined 2023-09-14 23:45:13 +05:00
Abdullah Atta
ed5a75447f web: register stream saver service worker on app start 2023-09-14 19:03:15 +05:00
ammarahm-ed
d08994a314 mobile: bump version code 2023-09-13 18:51:36 +05:00
ammarahm-ed
2bf6e7073c core: fix migration not running on colors 2023-09-13 18:21:55 +05:00
ammarahm-ed
7990458cf3 core: call migrateItem with backup key 2023-09-13 18:15:44 +05:00
ammarahm-ed
f3b13735f3 mobile: fix color of button in sheet 2023-09-13 18:14:03 +05:00
ammarahm-ed
ae680a32bc core: fix migration 2023-09-13 17:32:17 +05:00
ammarahm-ed
cbd0f18c6e mobile: release 2.6.4 2023-09-13 14:25:24 +05:00
220 changed files with 7063 additions and 2615 deletions

View File

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

View File

@@ -1,18 +1,18 @@
{
"name": "@notesnook/desktop",
"version": "2.6.4",
"version": "2.6.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/desktop",
"version": "2.6.4",
"version": "2.6.7",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook/crypto": "file:../../packages/crypto",
"@trpc/client": "10.31.0",
"@trpc/server": "10.31.0",
"@trpc/client": "10.38.3",
"@trpc/server": "10.38.3",
"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.0",
"electron": "25.8.1",
"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.31.0",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.31.0.tgz",
"integrity": "sha512-VCqbJEvFJb8C4hQFw7AD+dkQTjgEdV/QAzO4D+/cX5e93u5NpfNXI+PKS0QFXwG/zqgwQwVV6OkYc/D/MFwA6g==",
"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.31.0"
"@trpc/server": "10.38.3"
}
},
"node_modules/@trpc/server": {
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.31.0.tgz",
"integrity": "sha512-9EnRTSDE9nF11LZsvSOqNKqkRYzHqFX4ch5AJ6VIu8uta2vxVTN4FxxsNRSOluTzVYZDeaCISbwmOJ5iihCCIg==",
"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"
]
@@ -1751,9 +1751,9 @@
}
},
"node_modules/electron": {
"version": "25.8.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-25.8.0.tgz",
"integrity": "sha512-T3kC1a/3ntSaYMCVVfUUc9v7myPzi6J2GP0Ad/CyfWKDPp054dGyKxb2EEjKnxQQ7wfjsT1JTEdBG04x6ekVBw==",
"version": "25.8.1",
"resolved": "https://registry.npmjs.org/electron/-/electron-25.8.1.tgz",
"integrity": "sha512-GtcP1nMrROZfFg0+mhyj1hamrHvukfF6of2B/pcWxmWkd5FVY1NJib0tlhiorFZRzQN5Z+APLPr7aMolt7i2AQ==",
"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.4",
"version": "2.6.7",
"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.31.0",
"@trpc/server": "10.31.0",
"@trpc/client": "10.38.3",
"@trpc/server": "10.38.3",
"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.0",
"electron": "25.8.1",
"electron-builder": "^24.6.4",
"electron-builder-notarize": "^1.5.1",
"esbuild": "^0.17.19",
@@ -191,6 +191,7 @@
"allowNativeWayland": true
},
"extraResources": [
"app-update.yml",
"./assets/**"
],
"extraMetadata": {

View File

@@ -27,19 +27,23 @@ export type CLIOptions = {
hidden: boolean;
};
export async function parseArguments(): Promise<CLIOptions> {
export async function parseArguments(argv: string[]): Promise<CLIOptions> {
const result: CLIOptions = {
note: false,
notebook: false,
reminder: false,
hidden: false
};
const { hidden } = await yargs(hideBin(process.argv))
const { hidden } = await yargs(hideBin(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,6 +34,7 @@ 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()) {
@@ -63,7 +64,7 @@ process.on("unhandledRejection", (reason) => {
app.commandLine.appendSwitch("lang", "en-US");
async function createWindow() {
const cliOptions = await parseArguments();
const cliOptions = await parseArguments(process.argv);
setTheme(getTheme());
const mainWindowState = new WindowState({});
@@ -90,6 +91,7 @@ async function createWindow() {
}
});
createIPCHandler({ router, windows: [mainWindow] });
globalThis.window = mainWindow;
mainWindowState.manage(mainWindow);
@@ -105,7 +107,6 @@ async function createWindow() {
await AssetManager.loadIcons();
setupDesktopIntegration();
createIPCHandler({ router, windows: [mainWindow] });
mainWindow.webContents.session.setSpellCheckerDictionaryDownloadURL(
"http://dictionaries.notesnook.com/"
@@ -146,8 +147,12 @@ app.once("window-all-closed", () => {
}
});
app.on("second-instance", () => {
app.on("second-instance", async (_ev, argv) => {
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();
});
@@ -188,7 +193,7 @@ function setupDesktopIntegration() {
app.on("before-quit", () => app.exit(0));
}
globalThis.window?.once("close", (e) => {
globalThis.window?.on("close", (e) => {
if (config.desktopSettings.closeToSystemTray) {
e.preventDefault();
if (process.platform == "darwin") {

View File

@@ -34,6 +34,7 @@ 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,
@@ -62,6 +63,7 @@ export async function downloadAttachments(
canceled,
groupId
) {
await createCacheDir();
if (!attachments || !attachments.length) return;
const result = new Map();
@@ -182,6 +184,8 @@ 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,15 +24,18 @@ 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;
let { url, headers } = data;
await createCacheDir();
let { url, headers } = data;
let path = `${cacheDir}/${filename}`;
try {
let exists = await RNFetchBlob.fs.exists(path);
if (exists) {
if (await exists(filename)) {
return true;
}
@@ -60,29 +63,34 @@ export async function downloadFile(filename, data, cancelToken) {
console.log("downloading: ", recieved, total);
});
cancelToken.cancel = request.cancel;
cancelToken.cancel = () => {
useAttachmentStore.getState().remove(filename);
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) {
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"
});
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"
});
}
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,32 +20,25 @@ 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, getRandomId } from "./utils";
import { cacheDir, cacheDirOld, 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 {
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) {
if (!(await exists(filename))) {
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,
{
@@ -59,6 +52,7 @@ 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(
@@ -70,7 +64,7 @@ export async function readEncrypted(filename, key, cipherData) {
return output;
} catch (e) {
RNFetchBlob.fs.unlink(path).catch(console.log);
console.log(e);
console.log("readEncrypted", e);
return false;
}
}
@@ -88,6 +82,7 @@ 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, {
@@ -103,6 +98,7 @@ export async function writeEncryptedBase64({ data, key }) {
}
export async function deleteFile(filename, data) {
await createCacheDir();
let delFilePath = cacheDir + `/${filename}`;
if (!data) {
if (!filename) return;
@@ -128,19 +124,89 @@ 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) {
try {
await RNFetchBlob.fs.unlink(cacheDir + `/${file}`);
} catch (e) {
console.log(e);
}
await RNFetchBlob.fs.unlink(cacheDir + `/${file}`).catch(console.log);
}
for (let file of oldCache) {
await RNFetchBlob.fs.unlink(cacheDirOld + `/${file}`).catch(console.log);
}
} catch (e) {
console.log(e);
console.log("clearFileStorage", 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 exists = await RNFetchBlob.fs.exists(`${cacheDir}/${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;
}
return exists;
}

View File

@@ -24,11 +24,12 @@ 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 {
@@ -72,7 +73,10 @@ export async function uploadFile(filename, data, cancelToken) {
);
});
cancelToken.cancel = request.cancel;
cancelToken.cancel = () => {
useAttachmentStore.getState().remove(filename);
request.cancel();
};
let response = await request;
let status = response.info().status;

View File

@@ -21,7 +21,12 @@ import * as ScopedStorage from "react-native-scoped-storage";
import { Platform } from "react-native";
import RNFetchBlob from "react-native-blob-util";
export const cacheDir = RNFetchBlob.fs.dirs.CacheDir;
export const cacheDirOld = RNFetchBlob.fs.dirs.CacheDir;
export const cacheDir =
Platform.OS == "ios"
? RNFetchBlob.fs.dirs.LibraryDir + "/.cache"
: RNFetchBlob.fs.dirs.DocumentDir + "/.cache";
export function getRandomId(prefix) {
return Math.random()

View File

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

View File

@@ -85,11 +85,13 @@ const AuthModal = () => {
background={colors.primary.background}
transparent={false}
animated={false}
centered={false}
>
<KeyboardAwareScrollView
style={{
width: "100%"
}}
enableAutomaticScroll={false}
keyboardShouldPersistTaps="handled"
>
{currentAuthMode !== AuthMode.login ? (

View File

@@ -46,6 +46,7 @@ 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 "";
@@ -68,7 +69,8 @@ export const SessionExpired = () => {
eSendEvent(eUserLoggedIn, true);
setVisible(false);
setFocused(false);
}
},
true
);
const logout = async () => {
@@ -130,15 +132,20 @@ export const SessionExpired = () => {
return (
visible && (
<Modal
<BaseDialog
transparent={false}
background={colors.primary.background}
bounce={false}
animated={false}
centered={false}
onShow={async () => {
await sleep(300);
passwordInputRef.current?.focus();
setFocused(true);
}}
enableSheetKeyboardHandler={true}
visible={true}
>
<SheetProvider context="two_factor_verify" />
<View
style={{
width: focused ? "100%" : "99.9%",
@@ -231,7 +238,9 @@ export const SessionExpired = () => {
</View>
<Toast context="local" />
<Dialog context="session_expiry" />
</Modal>
<SheetProvider context="two_factor_verify" />
</BaseDialog>
)
);
};

View File

@@ -33,7 +33,7 @@ export const LoginSteps = {
passwordAuth: 3
};
export const useLogin = (onFinishLogin) => {
export const useLogin = (onFinishLogin, sessionExpired = false) => {
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
const setUser = useUserStore((state) => state.setUser);
@@ -69,6 +69,7 @@ export const useLogin = (onFinishLogin) => {
switch (step) {
case LoginSteps.emailAuth: {
const mfaInfo = await db.user.authenticateEmail(email.current);
console.log("email auth", mfaInfo);
if (mfaInfo) {
TwoFactorVerification.present(async (mfa, callback) => {
try {
@@ -101,7 +102,12 @@ export const useLogin = (onFinishLogin) => {
break;
}
case LoginSteps.passwordAuth: {
await db.user.authenticatePassword(email.current, password.current);
await db.user.authenticatePassword(
email.current,
password.current,
null,
sessionExpired
);
finishLogin();
break;
}

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 } from "react";
import React, { useEffect, useRef, useState } from "react";
import {
KeyboardAvoidingView,
Modal,
@@ -31,6 +31,9 @@ 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,
@@ -48,9 +51,13 @@ const BaseDialog = ({
bounce = true,
closeOnTouch = true,
useSafeArea = true,
avoidKeyboardResize = false
avoidKeyboardResize = false,
enableSheetKeyboardHandler = false
}) => {
const floating = useIsFloatingKeyboard();
const appState = useAppState();
const lockEvents = useRef(false);
const [internalVisible, setIntervalVisible] = useState(true);
useEffect(() => {
return () => {
@@ -58,14 +65,33 @@ 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}
visible={visible && internalVisible}
transparent={true}
animated
statusBarTranslucent={statusBarTranslucent}
supportedOrientations={[
"portrait",
@@ -75,13 +101,17 @@ const BaseDialog = ({
"landscape-right"
]}
onShow={() => {
if (lockEvents.current) return;
if (onShow) {
onShow();
useSettingStore.getState().setSheetKeyboardHandler(false);
if (!enableSheetKeyboardHandler) {
useSettingStore.getState().setSheetKeyboardHandler(false);
}
}
}}
animationType={animation}
onRequestClose={() => {
if (lockEvents.current) return;
if (!closeOnTouch) return null;
useSettingStore.getState().setSheetKeyboardHandler(true);
onRequestClose && onRequestClose();
@@ -107,6 +137,7 @@ const BaseDialog = ({
style={[
styles.backdrop,
{
alignItems: centered ? "center" : undefined,
justifyContent: centered
? "center"
: bottom
@@ -133,8 +164,7 @@ const styles = StyleSheet.create({
backdrop: {
width: "100%",
height: "100%",
justifyContent: "center",
alignItems: "center"
justifyContent: "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 imporant always locked"
content: "A private vault to keep everything important always locked"
},
{
content:

View File

@@ -442,6 +442,7 @@ 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) {
@@ -452,7 +453,6 @@ export class VaultDialog extends Component {
await this._copyNote(note);
}
} catch (e) {
console.log(e);
this._takeErrorAction(e);
}
};
@@ -467,44 +467,40 @@ export class VaultDialog extends Component {
}
async _enrollFingerprint(password) {
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;
}
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
});
}
);
} catch (e) {
this._takeErrorAction(e);
}
}
);
}
async _createVault() {
@@ -543,7 +539,7 @@ export class VaultDialog extends Component {
.remove(this.state.note.id, this.password)
.then(() => {
ToastEvent.show({
heading: "Note permanantly unlocked.",
heading: "Note permanently 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 occured"
issueTitle="An exception occurred"
/>
<Dialog />
</SafeAreaView>

View File

@@ -17,35 +17,25 @@ 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 { useSettingStore } from "../../../stores/use-setting-store";
import {
eSendEvent,
eSubscribeEvent,
eUnSubscribeEvent,
presentSheet
} from "../../../services/event-manager";
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 { GROUP } from "../../../utils/constants";
import { useSettingStore } from "../../../stores/use-setting-store";
import { ColorValues } from "../../../utils/colors";
import { db } from "../../../common/database";
import { GROUP } from "../../../utils/constants";
import { eOpenJumpToDialog } from "../../../utils/events";
import { SIZE } from "../../../utils/size";
import { IconButton } from "../../ui/icon-button";
import { Button } from "../../ui/button";
import Sort from "../../sheets/sort";
import { Button } from "../../ui/button";
import { IconButton } from "../../ui/icon-button";
import Heading from "../../ui/typography/heading";
import { useCallback } from "react";
export const SectionHeader = React.memo(
function SectionHeader({ item, index, type, color, screen }) {
function SectionHeader({ item, index, type, color, screen, groupOptions }) {
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
);
@@ -65,17 +55,6 @@ 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: "Permanantly deleted items",
heading: "Permanently deleted items",
type: "success",
context: "local"
});

View File

@@ -43,6 +43,9 @@ const SelectionWrapper = ({
const onLongPress = () => {
if (!useSelectionStore.getState().selectionMode) {
useSelectionStore.setState({
selectedItemsList: []
});
useSelectionStore.getState().setSelectionMode(true);
}
useSelectionStore.getState().setSelectedItem(item);

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { View } from "react-native";
import { Dimensions, 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,6 +32,7 @@ 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
@@ -44,7 +45,6 @@ export const Card = ({ color, warning }) => {
type="gray"
customStyle={{
paddingVertical: 12,
width: "95%",
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
@@ -54,17 +54,18 @@ export const Card = ({ color, warning }) => {
<View
style={{
flexDirection: "row",
alignItems: "center"
alignItems: "center",
flexShrink: 1
}}
>
<View
style={{
width: 40,
width: 40 * fontScale,
backgroundColor:
messageBoardState.type === "error"
? hexToRGBA(colors.static.red, 0.15)
: hexToRGBA(color, 0.15),
height: 40,
height: 40 * fontScale,
borderRadius: 100,
alignItems: "center",
justifyContent: "center"
@@ -75,6 +76,7 @@ export const Card = ({ color, warning }) => {
color={
messageBoardState.type === "error" ? colors.error.icon : color
}
allowFontScaling
name={messageBoardState.icon}
/>
</View>
@@ -91,7 +93,7 @@ export const Card = ({ color, warning }) => {
</Paragraph>
<Paragraph
style={{
flexWrap: "wrap",
flexWrap: "nowrap",
flexShrink: 1
}}
color={colors.primary.heading}
@@ -101,22 +103,24 @@ export const Card = ({ color, warning }) => {
</View>
</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>
{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>
)}
</PressableButton>
</View>
);

View File

@@ -39,6 +39,7 @@ 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,
@@ -99,9 +100,10 @@ const List = ({
type === "notebooks" ||
notebooksListMode === "compact";
const groupType =
screen === "Notes" ? "home" : screen === "Favorites" ? "favorites" : type;
screen === "Home" ? "home" : screen === "Favorites" ? "favorites" : type;
const groupOptions = useGroupOptions(groupType);
const groupOptions = db.settings?.getGroupOptions(groupType);
const dateBy =
groupOptions.sortBy !== "title" ? groupOptions.sortBy : "dateEdited";
@@ -113,18 +115,21 @@ const List = ({
color={headerProps?.color}
title={headerProps?.heading}
dateBy={dateBy}
type={
screen === "Notes"
? "home"
: screen === "Favorites"
? "favorites"
: type
}
type={groupType}
screen={screen}
isSheet={isSheet}
groupOptions={groupOptions}
/>
),
[headerProps?.color, headerProps?.heading, screen, type, isSheet, dateBy]
[
headerProps?.color,
headerProps?.heading,
screen,
isSheet,
dateBy,
groupType,
groupOptions
]
);
const _onRefresh = async () => {
@@ -230,7 +235,7 @@ const List = ({
<JumpToSectionDialog
screen={screen}
data={listData}
type={screen === "Notes" ? "home" : type}
type={screen === "Home" ? "home" : type}
scrollRef={scrollRef}
/>
) : null}

View File

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

View File

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

View File

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

View File

@@ -98,7 +98,7 @@ export const features = [
icon: "bell"
},
{
highlight: "Daily, weekly & montly",
highlight: "Daily, weekly & monthly",
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 formating",
highlight: "Basic formatting",
content: "and lists",
icon: "format-bold"
},

View File

@@ -500,7 +500,7 @@ export const PricingPlans = ({
textAlign: "center"
}}
>
By subscribing, your will be charged on your Google Account, and
By subscribing, you 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 from "react";
import { Platform, View } from "react-native";
import React, { useRef } from "react";
import { Dimensions, Platform, View, useWindowDimensions } from "react-native";
import { FlatList } from "react-native-actions-sheet";
import { db } from "../../common/database";
import { DDS } from "../../services/device-detection";
@@ -54,7 +54,6 @@ 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" }}>
@@ -62,6 +61,7 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
</Paragraph>
);
}
return (
<FlatList
keyboardShouldPersistTaps="always"
@@ -135,6 +135,7 @@ 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 { FlatList, ScrollView, View } from "react-native";
import { Dimensions, 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,9 +33,11 @@ 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;
let columnItemsCount = DDS.isLargeTablet() ? 7 : 5;
const shouldShrink =
Dimensions.get("window").fontScale > 1 &&
Dimensions.get("window").width < 450;
let columnItemsCount = DDS.isLargeTablet() ? 7 : shouldShrink ? 4 : 5;
let columnItemWidth = DDS.isTab
? (width - 12) / columnItemsCount
: (width - 12) / columnItemsCount;
@@ -66,6 +68,7 @@ export const Items = ({ item, buttons, close }) => {
}}
>
<Icon
allowFontScaling
name={item.icon}
size={DDS.isTab ? SIZE.xxl : SIZE.lg}
color={
@@ -78,7 +81,11 @@ export const Items = ({ item, buttons, close }) => {
/>
</PressableButton>
<Paragraph size={SIZE.xs} style={{ textAlign: "center" }}>
<Paragraph
size={SIZE.xs}
textBreakStrategy="simple"
style={{ textAlign: "center" }}
>
{item.title}
</Paragraph>
</View>
@@ -139,6 +146,7 @@ export const Items = ({ item, buttons, close }) => {
>
<Icon
name={item.icon}
allowFontScaling
size={DDS.isTab ? SIZE.xxl : SIZE.md + 4}
color={
item.on
@@ -150,7 +158,11 @@ export const Items = ({ item, buttons, close }) => {
/>
</PressableButton>
<Paragraph size={SIZE.xxs + 1} style={{ textAlign: "center" }}>
<Paragraph
textBreakStrategy="simple"
size={SIZE.xxs + 1}
style={{ textAlign: "center" }}
>
{item.title}
</Paragraph>
</PressableButton>
@@ -163,9 +175,12 @@ export const Items = ({ item, buttons, close }) => {
"copy",
"share",
"export",
"lock-unlock",
"publish"
"lock-unlock"
];
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 React from "react";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useThemeColors } from "@notesnook/theme";
import React from "react";
import { View, useWindowDimensions } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useUserStore } from "../../stores/use-user-store";
import { openLinkInBrowser } from "../../utils/functions";
import { SIZE } from "../../utils/size";
@@ -33,6 +33,8 @@ 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={{
@@ -49,7 +51,11 @@ export const Synced = ({ item, close }) => {
borderTopColor: colors.secondary.background
}}
>
<Icon name="shield-key-outline" color={colors.primary.accent} size={SIZE.xxxl} />
<Icon
name="shield-key-outline"
color={colors.primary.accent}
size={shouldShrink ? SIZE.xxl : SIZE.xxxl}
/>
<View
style={{
@@ -67,15 +73,17 @@ export const Synced = ({ item, close }) => {
>
Encrypted and synced
</Heading>
<Paragraph
style={{
flexWrap: "wrap"
}}
size={SIZE.xs}
color={colors.primary.paragraph}
>
No one can view this {item.itemType || item.type} except you.
</Paragraph>
{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>
)}
</View>
<Button
@@ -91,8 +99,8 @@ export const Synced = ({ item, close }) => {
console.error(e);
}
}}
fontSize={SIZE.xs}
title="Learn more"
fontSize={SIZE.xs}
height={30}
type="grayAccent"
/>

View File

@@ -207,7 +207,6 @@ export const SelectionHeader = React.memo(() => {
{screen === "Trash" ||
screen === "Notebooks" ||
screen === "Notebook" ||
screen === "Reminders" ? null : (
<>
<IconButton
@@ -224,6 +223,21 @@ 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);
@@ -239,20 +253,6 @@ 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}
/>
</>
)}

View File

@@ -198,7 +198,6 @@ 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 { FlatList } from "react-native-actions-sheet";
import { FlashList } 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 (
<FlatList
<FlashList
{...restProps}
data={filtered}
ref={listRef}

View File

@@ -161,9 +161,6 @@ 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
@@ -176,9 +173,6 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
: "deselected";
if (itemState[topic.id] === "selected") {
count++;
contextValue.select(topic);
} else {
contextValue.deselect(topic);
}
}
}
@@ -189,7 +183,7 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
}
useItemSelectionStore.getState().setItemState(itemState);
},
[contextValue, getSelectedNotesCountInItem, selectedItemsList]
[getSelectedNotesCountInItem, selectedItemsList]
);
const getItemsForItem = (item) => {
@@ -214,7 +208,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
};
@@ -370,56 +364,93 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
</View>
<SelectionProvider value={contextValue}>
<FilteredList
<View
style={{
paddingHorizontal: 12,
maxHeight: dimensions.height * 0.85
maxHeight: dimensions.height * 0.85,
height: 50 * (notebooks.length + 2)
}}
ListEmptyComponent={
notebooks.length > 0 ? null : (
<View
style={{
width: "100%",
height: "100%",
justifyContent: "center",
alignItems: "center"
>
<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();
}}
>
<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) => {
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];
@@ -429,47 +460,16 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
} 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();
}}
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 }} />}
/>
}}
/>
)}
itemType="notebook"
onAddItem={async (title) => {
return await onAddNotebook(title);
}}
ListFooterComponent={<View style={{ height: 20 }} />}
/>
</View>
</SelectionProvider>
</View>
</>

View File

@@ -273,6 +273,7 @@ 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 occured",
heading: "An error occurred",
message: e.message,
type: "error"
});

View File

@@ -177,7 +177,7 @@ export default function Migrate() {
textAlign: "center"
}}
>
An error occured while migrating your data. You can logout of your
An error occurred 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,7 +40,9 @@ import { requestInAppReview } from "../../../services/app-review";
const PublishNoteSheet = ({ note: item, update }) => {
const { colors } = useThemeColors();
const actionSheetRef = useRef();
const loading = useAttachmentStore((state) => state.loading);
const attachmentDownloads = useAttachmentStore((state) => state.downloading);
const downloading = attachmentDownloads[`monograph-${item.id}`];
const [selfDestruct, setSelfDestruct] = useState(false);
const [isLocked, setIsLocked] = useState(false);
const [note, setNote] = useState(item);
@@ -137,9 +139,9 @@ const PublishNoteSheet = ({ note: item, update }) => {
}}
>
Please wait...
{loading && loading.current && loading.total
{downloading && downloading.current && downloading.total
? `\nDownloading attachments (${
loading?.current / loading?.total
downloading?.current / downloading?.total
})`
: ""}
</Paragraph>

View File

@@ -253,6 +253,57 @@ 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}
@@ -280,15 +331,21 @@ export default function ReminderSheet({
}}
height={80}
wrapperStyle={{
marginBottom: 20
marginBottom: 12
}}
/>
<View
<ScrollView
style={{
flexDirection: "row",
marginBottom: 12
marginBottom: 12,
height: 50,
borderWidth: 1,
borderRadius: 5,
borderColor: colors.primary.border,
paddingLeft: 12
}}
horizontal
>
{Object.keys(ReminderModes).map((mode) => (
<Button
@@ -327,7 +384,7 @@ export default function ReminderSheet({
}}
/>
))}
</View>
</ScrollView>
{reminderMode === ReminderModes.Repeat ? (
<View
@@ -474,9 +531,7 @@ export default function ReminderSheet({
androidVariant="nativeAndroid"
is24hourSource="locale"
locale={
db.settings?.getTimeFormat() === "24-hour"
? "en_GB.UTF8"
: "en_US.UTF8"
db.settings?.getTimeFormat() === "24-hour" ? "en_GB" : "en_US"
}
mode={reminderMode === ReminderModes.Repeat ? "time" : "datetime"}
/>
@@ -498,53 +553,6 @@ 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
@@ -595,6 +603,11 @@ export default function ReminderSheet({
}}
/>
</ScrollView>
<View
style={{
height: 10
}}
/>
</View>
);
}

View File

@@ -16,6 +16,7 @@ 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,
@@ -26,7 +27,7 @@ import React, {
useRef,
useState
} from "react";
import { RefreshControl, View } from "react-native";
import { RefreshControl, useWindowDimensions, View } from "react-native";
import ActionSheet, {
ActionSheetRef,
FlatList
@@ -45,7 +46,6 @@ import {
import useNavigationStore, {
NotebookScreenParams
} from "../../../stores/use-navigation-store";
import { useThemeColors } from "@notesnook/theme";
import {
eOnNewTopicAdded,
eOnTopicSheetUpdate,
@@ -54,18 +54,17 @@ 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 { getTotalNotes } from "@notesnook/common";
import { useSelectionStore } from "../../../stores/use-selection-store";
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 {
@@ -108,7 +107,8 @@ export const TopicsSheet = () => {
)
: []
);
const currentItem = useRef<string>();
const { fontScale } = useWindowDimensions();
const [groupOptions, setGroupOptions] = useState(
db.settings?.getGroupOptions("topics")
);
@@ -206,6 +206,11 @@ 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
@@ -226,6 +231,8 @@ export const TopicsSheet = () => {
}
}, 300);
} else {
setSelection([]);
setEnabled(false);
ref.current?.hide();
}
}, [
@@ -271,7 +278,7 @@ export const TopicsSheet = () => {
backgroundColor: colors.secondary.background
}}
keyboardHandlerEnabled={false}
snapPoints={Config.isTesting === "true" ? [100] : [25, 100]}
snapPoints={Config.isTesting === "true" ? [100] : [20, 100]}
initialSnapIndex={1}
backgroundInteractionEnabled
gestureEnabled
@@ -305,8 +312,8 @@ export const TopicsSheet = () => {
</View>
<View
style={{
maxHeight: 300,
height: 300,
maxHeight: 450,
height: 450,
width: "100%"
}}
>
@@ -329,30 +336,19 @@ export const TopicsSheet = () => {
{enabled ? (
<IconButton
customStyle={{
marginLeft: 10
marginLeft: 10,
width: 40 * fontScale,
height: 40 * fontScale
}}
onPress={async () => {
//@ts-ignore
useSelectionStore.setState({
selectedItemsList: selection
});
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"
});
await deleteItems();
useSelectionStore.getState().clearSelection();
setEnabled(false);
setSelection([]);
return;
}}
color={colors.primary.icon}
@@ -378,8 +374,8 @@ export const TopicsSheet = () => {
color={colors.primary.icon}
size={22}
customStyle={{
width: 40,
height: 40
width: 40 * fontScale,
height: 40 * fontScale
}}
/>
<IconButton
@@ -389,8 +385,8 @@ export const TopicsSheet = () => {
color={colors.primary.icon}
size={22}
customStyle={{
width: 40,
height: 40
width: 40 * fontScale,
height: 40 * fontScale
}}
/>
@@ -408,8 +404,8 @@ export const TopicsSheet = () => {
color={colors.primary.icon}
size={22}
customStyle={{
width: 40,
height: 40
width: 40 * fontScale,
height: 40 * fontScale
}}
/>
</>
@@ -483,6 +479,7 @@ 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
@@ -519,6 +516,10 @@ 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"
@@ -538,8 +539,8 @@ const TopicItem = ({
<IconButton
name="dots-horizontal"
customStyle={{
width: 40,
height: 40
width: 40 * fontScale,
height: 40 * fontScale
}}
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 { View } from "react-native";
import { Dimensions, 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,6 +109,7 @@ export const MenuItem = React.memo(
textAlignVertical: "center",
textAlign: "left"
}}
allowFontScaling
name={item.icon}
color={
item.icon === "crown"

View File

@@ -209,13 +209,19 @@ export const PinItem = React.memo(
justifyContent: "center"
}}
>
<Icon color={color} size={SIZE.lg - 2} name={icons[item.type]} />
<Icon
allowFontScaling
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,6 +113,7 @@ export const UserStatus = () => {
<Icon
name="checkbox-blank-circle"
size={11}
allowFontScaling
color={
!user || lastSyncStatus === SyncStatus.Failed
? colors.error.icon
@@ -149,9 +150,15 @@ export const UserStatus = () => {
color={colors.error.icon}
name="sync-alert"
size={SIZE.lg}
allowFontScaling
/>
) : (
<Icon color={colors.primary.accent} name="sync" size={SIZE.lg} />
<Icon
allowFontScaling
color={colors.primary.accent}
name="sync"
size={SIZE.lg}
/>
)
) : null}
</PressableButton>

View File

@@ -134,6 +134,7 @@ export const Button = ({
{icon && !loading && iconPosition === "left" ? (
<Icon
name={icon}
allowFontScaling
style={[{ marginRight: 0 }, iconStyle as any]}
color={iconColor || buttonType?.text || textColor}
size={iconSize}
@@ -170,6 +171,7 @@ 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,7 +40,6 @@ interface IconButtonProps extends PressableButtonProps {
iconStyle?: TextStyle;
}
const AnimatedIcon = Animated.createAnimatedComponent(Icon);
export const IconButton = ({
onPress,
name,
@@ -88,10 +87,10 @@ export const IconButton = ({
...customStyle
}}
>
<AnimatedIcon
layout={Layout}
<Icon
name={name}
style={iconStyle as any}
allowFontScaling
color={
restProps.disabled
? RGB_Linear_Shade(-0.05, hexToRGBA(colors.secondary.background))

View File

@@ -17,15 +17,17 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { ScopedThemeProvider, useThemeColors } from "@notesnook/theme";
import React, { useEffect, useRef } 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 { BouncingView } from "../transitions/bouncing-view";
import { useAppState } from "../../../hooks/use-app-state";
import SettingsService from "../../../services/settings";
import { useUserStore } from "../../../stores/use-user-store";
const SheetWrapper = ({
children,
@@ -41,6 +43,7 @@ const SheetWrapper = ({
enableGesturesInScrollView = false,
bottomPadding = true
}) => {
const localRef = useRef(null);
const { colors } = useThemeColors("sheet");
const deviceMode = useSettingStore((state) => state.deviceMode);
const sheetKeyboardHandler = useSettingStore(
@@ -50,6 +53,8 @@ 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(() => {
@@ -68,19 +73,40 @@ 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}
ref={fwdRef || localRef}
testIDs={{
backdrop: "sheet-backdrop"
}}

View File

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

View File

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

View File

@@ -70,8 +70,8 @@ const NotebookWelcome = () => {
count: 5
},
{
title: "Recipies",
description: "I love cooking and collecting recipies",
title: "Recipes",
description: "I love cooking and collecting recipes",
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" />{" "}
Feburary 2022 Week 2
February 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" />{" "}
Feburary 2022 Week 1
February 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

@@ -188,7 +188,7 @@ export const useActions = ({ close = () => null, item }) => {
Notifications.displayNotification({
title: item.title,
message: item.headline || text,
subtitle: item.headline || text,
subtitle: "",
bigText: html,
ongoing: true,
actions: ["UNPIN"],
@@ -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} permanantly from trash?`,
paragraph: `Are you sure you want to delete this ${item.itemType} permanently 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: "Permanantly deleted items",
heading: "Permanently deleted items",
type: "success",
context: "local"
});
@@ -649,7 +649,7 @@ export const useActions = ({ close = () => null, item }) => {
},
{
id: "favorite",
title: item.favorite ? "Unfavorite" : "Favorite",
title: item.favorite ? "Unfav" : "Fav",
icon: item.favorite ? "star-off" : "star-outline",
func: addToFavorites,
close: false,

View File

@@ -83,7 +83,6 @@ 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();
@@ -107,10 +106,20 @@ const onFileEncryptionProgress = ({ total, progress }) => {
.setEncryptionProgress((progress / total).toFixed(2));
};
const onLoadingAttachmentProgress = (data) => {
useAttachmentStore
.getState()
.setLoading(data.total === data.current ? null : data);
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 onUserSessionExpired = async () => {
@@ -301,7 +310,16 @@ export const useAppEvents = () => {
EVENTS.userSubscriptionUpdated,
onUserSubscriptionStatusChanged
),
EV.subscribe(EVENTS.attachmentsLoading, onLoadingAttachmentProgress),
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);
}),
eSubscribeEvent(eUserLoggedIn, onUserUpdated)
];
@@ -449,7 +467,7 @@ export const useAppEvents = () => {
});
}
} catch (e) {
ToastEvent.error(e, "An error occured", "global");
ToastEvent.error(e, "An error occurred", "global");
}
user = await db.user.getUser();

View File

@@ -0,0 +1,49 @@
/*
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,7 +384,16 @@ const _TabsHolder = () => {
}, []);
useEffect(() => {
changeNavigationBarColor(colors.primary.background, isDark, true);
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);
}, [colors.primary.background, isDark]);
return (
@@ -406,11 +415,7 @@ const _TabsHolder = () => {
: 0
}}
>
<StatusBar
barStyle={isDark ? "light-content" : "dark-content"}
translucent={true}
backgroundColor="transparent"
/>
<StatusBar 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.23",
"react-native-actions-sheet": "0.9.0-alpha.24",
"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

@@ -167,7 +167,7 @@ const Editor = React.memo(
globalThis.noToolbar=${noToolbar};
globalThis.noHeader=${noHeader};
`}
injectedJavaScript={`globalThis.sessionId="${editor.sessionId}";`}
useSharedProcessPool={false}
javaScriptEnabled={true}
focusable={true}
onContentProcessDidTerminate={onError}

View File

@@ -1,81 +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, { 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

@@ -0,0 +1,136 @@
/*
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

@@ -113,7 +113,7 @@ typeof globalThis.statusBar !== "undefined" && statusBar.current.set({date:"",sa
};
setSessionId = async (id: string | null) =>
await this.doAsync(`globalThis.sessionId = "${id}"`);
await this.doAsync(`globalThis.sessionId = "${id}";`);
setStatus = async (date: string | undefined, saved: string) =>
await this.doAsync(

View File

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

View File

@@ -28,7 +28,8 @@ import {
InteractionManager,
Keyboard,
KeyboardEventListener,
NativeEventSubscription
NativeEventSubscription,
useWindowDimensions
} from "react-native";
import { WebViewMessageEvent } from "react-native-webview";
import { db } from "../../../common/database";
@@ -142,6 +143,8 @@ 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
);
@@ -195,13 +198,13 @@ export const useEditorEvents = (
: defaultFontSize,
fontFamily: SettingsService.get().defaultFontFamily,
dateFormat: db.settings?.getDateFormat(),
timeFormat: db.settings?.getTimeFormat()
timeFormat: db.settings?.getTimeFormat(),
fontScale
});
}, [
fullscreen,
isPremium,
readonly,
editor.sessionId,
editor.loading,
deviceMode,
tools,
@@ -215,7 +218,8 @@ export const useEditorEvents = (
defaultFontFamily,
dateFormat,
timeFormat,
loading
loading,
fontScale
]);
const onBackPress = useCallback(async () => {
@@ -224,6 +228,8 @@ export const useEditorEvents = (
logger.info("editor handled back event", editorHandledBack);
return;
}
editorState().currentlyEditing = false;
editor.reset();
setTimeout(async () => {
if (deviceMode !== "mobile" && fullscreen) {
if (fullscreen) {
@@ -236,14 +242,10 @@ export const useEditorEvents = (
editorState().movedAway = true;
tabBarRef.current?.goToPage(0);
}
setImmediate(() => {
useEditorStore.getState().setCurrentlyEditingNote(null);
setTimeout(() => {
Navigation.queueRoutesForUpdate();
}, 500);
});
editorState().currentlyEditing = false;
editor.reset();
setTimeout(() => {
Navigation.queueRoutesForUpdate();
}, 500);
}, 1);
}, [editor, deviceMode, fullscreen]);
@@ -339,8 +341,12 @@ export const useEditorEvents = (
});
}
if (editorMessage.type === EventTypes.back) {
return onBackPress();
}
if (
editorMessage.sessionId !== editor.sessionId &&
editorMessage.sessionId !== editor.sessionId.current &&
editorMessage.type !== EditorEvents.status
) {
return;
@@ -426,9 +432,6 @@ export const useEditorEvents = (
editorState().isFullscreen = true;
eSendEvent(eOpenFullscreenEditor);
break;
case EventTypes.back:
onBackPress();
break;
case EventTypes.link:
openLinkInBrowser(editorMessage.value as string);
break;

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 { db } from "../../../common/database";
import { DatabaseLogger, db } from "../../../common/database";
import useGlobalSafeAreaInsets from "../../../hooks/use-global-safe-area-insets";
import { DDS } from "../../../services/device-detection";
import {
@@ -63,8 +63,7 @@ export const useEditor = (
const theme = useThemeEngineStore((state) => state.theme);
const [loading, setLoading] = useState(false);
const [sessionId, setSessionId] = useState<string>(makeSessionId());
const sessionIdRef = useRef(sessionId);
const sessionIdRef = useRef(makeSessionId());
const editorRef = useRef<WebView>(null);
const currentNote = useRef<NoteType | null>();
const currentContent = useRef<Content | null>();
@@ -99,10 +98,6 @@ export const useEditor = (
postMessage(EditorEvents.theme, theme);
}, [theme, postMessage]);
useEffect(() => {
sessionIdRef.current = sessionId;
}, [sessionId]);
useEffect(() => {
commands.setTags(currentNote.current);
}, [commands, tags]);
@@ -134,20 +129,27 @@ export const useEditor = (
const reset = useCallback(
async (resetState = true, resetContent = true) => {
currentNote.current?.id && db.fs?.cancel(currentNote.current.id, null);
currentNote.current?.id &&
db.fs?.cancel(currentNote.current.id, "download");
currentNote.current = null;
loadedImages.current = {};
currentContent.current = null;
clearTimeout(timers.current["loading-images"]);
sessionHistoryId.current = undefined;
saveCount.current = 0;
loadingState.current = undefined;
lock.current = false;
useEditorStore.getState().setReadonly(false);
resetContent && postMessage(EditorEvents.title, "");
lastContentChangeTime.current = 0;
resetContent && (await commands.clearContent());
resetContent && (await commands.clearTags());
if (resetState) {
const newSessionId = makeSessionId();
sessionIdRef.current = newSessionId;
await commands.setSessionId(newSessionId);
isDefaultEditor &&
useEditorStore.getState().setCurrentlyEditingNote(null);
placeholderTip.current = TipManager.placeholderTip();
@@ -264,7 +266,8 @@ export const useEditor = (
saveCount.current++;
return id;
} catch (e) {
console.log("Error saving note: ", e);
console.error(e);
DatabaseLogger.error(e as Error);
}
},
[commands, isDefaultEditor, postMessage, readonly, reset]
@@ -279,6 +282,7 @@ export const useEditor = (
noteId: currentNote.current?.id as string
};
} else {
if (!note.contentId) return;
currentContent.current = await db.content?.raw(note.contentId);
}
}, []);
@@ -355,7 +359,6 @@ export const useEditor = (
if (item && item.type === "new") {
currentNote.current && (await reset());
const nextSessionId = makeSessionId(item as NoteType);
setSessionId(nextSessionId);
sessionIdRef.current = nextSessionId;
sessionHistoryId.current = Date.now();
await commands.setSessionId(nextSessionId);
@@ -366,12 +369,23 @@ export const useEditor = (
if (!item.forced && currentNote.current?.id === item.id) return;
state.current.movedAway = false;
state.current.currentlyEditing = true;
isDefaultEditor && editorState.setCurrentlyEditingNote(item.id);
currentNote.current && (await reset(false, false));
if (currentNote.current?.id !== item.id) {
currentNote.current && (await reset(false, false));
isDefaultEditor && editorState.setCurrentlyEditingNote(item.id);
}
await loadContent(item as NoteType);
if (loadingState.current === currentContent.current?.data) {
if (
currentNote.current?.id === item.id &&
loadingState.current &&
currentContent.current?.data &&
loadingState.current === currentContent.current?.data
) {
return;
}
if (
!currentContent.current?.data ||
currentContent.current?.data.length < 50000
@@ -386,20 +400,21 @@ export const useEditor = (
}
lastContentChangeTime.current = item.dateEdited;
const nextSessionId = makeSessionId(item as NoteType);
sessionIdRef.current = nextSessionId;
lockedSessionId.current = nextSessionId;
sessionHistoryId.current = Date.now();
setSessionId(nextSessionId);
commands.setSessionId(nextSessionId);
sessionIdRef.current = nextSessionId;
await commands.setSessionId(nextSessionId);
currentNote.current = item as NoteType;
await commands.setStatus(getFormattedDate(item.dateEdited), "Saved");
await postMessage(EditorEvents.title, item.title);
loadingState.current = currentContent.current?.data;
await postMessage(
EditorEvents.html,
currentContent.current?.data,
10000
);
if (currentContent.current?.data) {
await postMessage(
EditorEvents.html,
currentContent.current?.data,
10000
);
}
loadingState.current = undefined;
useEditorStore.getState().setReadonly(item.readonly);
await commands.setTags(currentNote.current);
@@ -525,6 +540,14 @@ 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,
@@ -608,7 +631,7 @@ export const useEditor = (
useEffect(() => {
state.current.saveCount = 0;
}, [sessionId, loading]);
}, [loading]);
const onReady = useCallback(async () => {
if (!(await isEditorLoaded(editorRef, sessionIdRef.current))) {
@@ -660,8 +683,7 @@ export const useEditor = (
loading,
setLoading,
state,
sessionId,
setSessionId,
sessionId: sessionIdRef,
note: currentNote,
onReady,
saveContent,

View File

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

View File

@@ -71,7 +71,7 @@ export const SearchBar = () => {
} catch (e) {
console.log(e);
ToastEvent.show({
heading: "Error occured while searching",
heading: "Error occurred 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 permanantly. Make sure you have saved backup of your notes. This action is IRREVERSIBLE.",
"All your data will be removed permanently. 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 permanantly. Make sure you have saved backup of your notes. This action is IRREVERSIBLE.",
"All your data will be removed permanently. Make sure you have saved backup of your notes. This action is IRREVERSIBLE.",
positiveType: "errorShade",
input: true,
inputPlaceholder: "Enter account password",
@@ -628,7 +628,9 @@ 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"
defaultValue: "https://cors.notesnook.com",
autoCorrect: false,
keyboardType: "url"
},
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 permanantly.",
"All notes and notebooks in the trash have been removed permanently.",
type: "success",
context: "local"
});

View File

@@ -50,7 +50,7 @@ export function setRateAppMessage() {
const recoveryKeyMessage = {
visible: true,
message: "Keep your data safe if you lose password",
message: "Keep your data safe",
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 imporant always locked"
content: "A private vault to keep everything important 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 seemless sync and keep all notes in one place."
paragraph="Manage your work on another level, enjoy seamless sync and keep all notes in one place."
padding={12}
/>
<Seperator />

View File

@@ -17,15 +17,14 @@ 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",
@@ -33,7 +32,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",
@@ -43,10 +42,18 @@ const run = async (
lastSyncTime
) => {
if (useUserStore.getState().syncing) {
DatabaseLogger.log("Sync in progress");
console.log("Sync in progress");
DatabaseLogger.info("Sync in progress");
pendingSync = {
full: full
};
return;
}
if (pendingSync) {
pendingSync = undefined;
DatabaseLogger.info("Running pending sync...");
}
clearTimeout(syncTimer);
syncTimer = setTimeout(async () => {
const status = await NetInfo.fetch();
@@ -55,56 +62,54 @@ 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 {
let res = await BackgroundSync.doInBackground(async () => {
await BackgroundSync.doInBackground(async () => {
try {
await db.sync(full, forced, lastSyncTime);
return true;
} catch (e) {
error = e;
return e.message;
}
});
if (!res) {
initAfterSync();
userstore.setSyncing(false, SyncStatus.Failed);
return onCompleted?.(false);
if (error) {
throw error;
}
if (typeof res === "string") throw error;
userstore.setSyncing(false);
return onCompleted?.(true);
} catch (e) {
error = e;
if (
!ignoredMessages.find((im) => e.message?.includes(im)) &&
userstore.user
!ignoredMessages.find((message) => e.message?.includes(message)) &&
userstore.user &&
status.isConnected &&
status.isInternetReachable
) {
userstore.setSyncing(false, SyncStatus.Failed);
if (status.isConnected && status.isInternetReachable) {
ToastEvent.error(e, "Sync failed", context);
}
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
);
if (full || forced) {
db.eventManager.publish(EVENTS.syncCompleted);
}
onCompleted?.(error ? SyncStatus.Failed : SyncStatus.Passed);
setImmediate(() => {
if (pendingSync) Sync.run("global", false, pendingSync.full);
});
}
}, 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 accidently deleted something.",
"With note history, you can restore back to an older version of the note if you accidentally 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,6 +20,16 @@ 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]: {
@@ -30,6 +40,7 @@ interface AttachmentStore {
type: "upload" | "download";
} | null;
};
encryptionProgress: number;
setEncryptionProgress: (encryptionProgress: number) => void;
remove: (hash: string) => void;
@@ -40,8 +51,14 @@ interface AttachmentStore {
recieved: number,
type: "upload" | "download"
) => void;
loading: { total: number; current: number };
setLoading: (data: { total: number; current: number }) => void;
downloading?: {
[groupId: string]: AttachmentGroupProgress | undefined;
};
setDownloading: (data: AttachmentGroupProgress) => void;
uploading?: {
[groupId: string]: AttachmentGroupProgress | undefined;
};
setUploading: (data: AttachmentGroupProgress) => void;
}
export const useAttachmentStore = create<AttachmentStore>((set, get) => ({
@@ -73,6 +90,21 @@ export const useAttachmentStore = create<AttachmentStore>((set, get) => ({
encryptionProgress: 0,
setEncryptionProgress: (encryptionProgress) =>
set({ encryptionProgress: encryptionProgress }),
loading: { total: 0, current: 0 },
setLoading: (data) => set({ loading: data ? { ...data } : data })
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
}
})
}));

View File

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

View File

@@ -67,15 +67,10 @@ export const deleteItems = async (item, context) => {
});
return;
}
if (
item &&
item.id &&
useSelectionStore.getState().selectedItemsList.length === 0
) {
useSelectionStore.getState().setSelectedItem(item);
}
const { selectedItemsList } = useSelectionStore.getState();
const selectedItemsList = item
? [item]
: useSelectionStore.getState().selectedItemsList;
let notes = selectedItemsList.filter((i) => i.type === "note");
let notebooks = selectedItemsList.filter((i) => i.type === "notebook");
@@ -179,7 +174,9 @@ export const deleteItems = async (item, context) => {
});
}
Navigation.queueRoutesForUpdate();
useSelectionStore.getState().clearSelection();
if (!item) {
useSelectionStore.getState().clearSelection();
}
useMenuStore.getState().setMenuPins();
useMenuStore.getState().setColorNotes();
SearchService.updateAndSearch();

View File

@@ -24,6 +24,12 @@ 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);
@@ -60,25 +66,43 @@ async function createNotes(bundle) {
const sessionId = bundle.note.sessionId;
const id = await db.notes.add(bundle.note);
for (const item of bundle.notebooks) {
if (item.type === "notebook") {
db.relations.add(item, { id, type: "note" });
} else {
db.notes.addToNotebook(
{
id: item.notebookId,
topic: item.id
},
id
);
if (!bundle.notebooks || !bundle.notebooks.length) {
const defaultNotebook = db.settings?.getDefaultNotebook();
if (defaultNotebook) {
if (!defaultNotebook.topic) {
db.relations.add(
{ type: "notebook", id: defaultNotebook.id },
{ id, type: "note" }
);
} else {
db.notes.addToNotebook(
{
id: defaultNotebook?.id,
topic: defaultNotebook.topic
},
id
);
}
}
} else {
for (const item of bundle.notebooks) {
if (item.type === "notebook") {
db.relations.add(item, { id, type: "note" });
} else {
db.notes.addToNotebook(
{
id: item.notebookId,
topic: item.id
},
id
);
}
}
}
for (const file of bundle.files) {
const uri =
Platform.OS === "ios"
? `${file.value.replace("file://", "")}`
: `${file.value}`;
Platform.OS === "ios" ? santizeUri(file.value) : `${file.value}`;
const hash = await Sodium.hashFile({
uri: uri,
type: "cache"

View File

@@ -30,36 +30,10 @@ import {
elementByText,
sleep,
notVisibleByText,
visibleById
visibleById,
createNotebook
} 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,7 +25,9 @@ import {
prepare,
tapByText,
notVisibleByText,
sleep
sleep,
navigate,
createNotebook
} from "./utils";
async function sortBy(sorting, elementText = "Default") {
@@ -104,6 +106,23 @@ 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,8 +129,36 @@ 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 2059
versionCode 2065
versionName getNpmVersion()
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'

View File

@@ -1,4 +1,3 @@
- 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
- Bug fixes and performance improvements
Thank you for using Notesnook!

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 = 2053;
CURRENT_PROJECT_VERSION = 2058;
DEVELOPMENT_TEAM = 53CWBG3QUC;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1071,7 +1071,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.6.3;
MARKETING_VERSION = 2.6.7;
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 = 2053;
CURRENT_PROJECT_VERSION = 2058;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1176,7 +1176,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.6.3;
MARKETING_VERSION = 2.6.7;
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 = 2053;
CURRENT_PROJECT_VERSION = 2058;
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.3;
MARKETING_VERSION = 2.6.7;
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 = 2053;
CURRENT_PROJECT_VERSION = 2058;
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.3;
MARKETING_VERSION = 2.6.7;
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 = 2053;
CURRENT_PROJECT_VERSION = 2058;
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.3;
MARKETING_VERSION = 2.6.7;
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 = 2053;
CURRENT_PROJECT_VERSION = 2058;
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.3;
MARKETING_VERSION = 2.6.7;
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.7):
- react-native-mmkv-storage (0.10.0-alpha.9):
- 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.2):
- react-native-sodium (1.5.4):
- 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: ec32fd68168716755e1b30f09b476c236c6c68a8
react-native-mmkv-storage: d4ad55ab411b7f0d4e6269d801b31821ef48970b
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: 7d2bbb9ca840dc58d63f661b2ff733a38170fec5
react-native-sodium: 955bb0dc3ea05f8ea06d5e96cb89d1be7b5d7681
react-native-webview: 9f111dfbcfc826084d6c507f569e5e03342ee1c1
React-NativeModulesApple: 1d81d927ef1a67a3545a01e14c2e98500bf9b199
React-perflogger: 684a11499a0589cc42135d6d5cc04d0e4e0e261a

File diff suppressed because one or more lines are too long

View File

@@ -21,6 +21,12 @@
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.2",
"@ammarahmed/react-native-sodium": "1.5.4",
"@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 chararcter will be in the map.
// We know that this character 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 preceed the node under consideration in the array.
* have to check nodes that precede 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 sting or regexp)
// boundary must be in the same line(js string 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.2",
"version": "2.6.7",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@notesnook/mobile",
"version": "2.6.2",
"version": "2.6.7",
"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.31.0",
"@trpc/react-query": "10.31.0",
"@trpc/server": "^10.31.0",
"@trpc/client": "10.38.3",
"@trpc/react-query": "10.38.3",
"@trpc/server": "10.38.3",
"react": "18.2.0",
"react-native": "0.72.0"
},
@@ -85,7 +85,9 @@
"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",
@@ -108,28 +110,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.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",
"@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",
"clipboard-polyfill": "4.0.0",
"detect-indent": "^7.0.0",
"entities": "^4.5.0",
@@ -137,7 +139,7 @@
"nanoid": "^4.0.1",
"prism-themes": "^1.9.0",
"prosemirror-codemark": "^0.4.2",
"prosemirror-view": "^1.31.7",
"prosemirror-view": "^1.31.8",
"re-resizable": "^6.9.9",
"react-colorful": "^5.5.1",
"react-modal": "3.13.1",
@@ -222,7 +224,7 @@
"license": "ISC",
"dependencies": {
"@orama/orama": "^1.0.8",
"@trpc/server": "10.31.0",
"@trpc/server": "10.38.3",
"async-mutex": "^0.4.0",
"cors": "^2.8.5",
"util": "^0.12.5",
@@ -254,7 +256,7 @@
"katex": "0.16.2",
"phone": "^3.1.14",
"qclone": "^1.2.0",
"react-native-actions-sheet": "0.9.0-alpha.23",
"react-native-actions-sheet": "0.9.0-alpha.24",
"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",
@@ -279,7 +281,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.2",
"@ammarahmed/react-native-sodium": "1.5.4",
"@bam.tech/react-native-image-resizer": "3.0.5",
"@callstack/repack": "^3.2.0",
"@react-native-clipboard/clipboard": "^1.9.0",
@@ -2417,9 +2419,9 @@
}
},
"node_modules/@ammarahmed/react-native-sodium": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-sodium/-/react-native-sodium-1.5.2.tgz",
"integrity": "sha512-M309uV2DCK3EPNfsgWYthOApJhQgQKOOxYF19VerUeX7UYnm9VggW073oO0NNqqZqg5GS6bTlrtYMAz7MAKvUw=="
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-sodium/-/react-native-sodium-1.5.4.tgz",
"integrity": "sha512-+JwYnaSJxnwpI1947sUacFXxRxK1f9ykuxDJaGkCUKvh5CkDYC5VyZFnq2BbcuIcx4OTMOG8a/a46hWJbFKQPQ=="
},
"node_modules/@ampproject/remapping": {
"version": "2.2.1",
@@ -7012,35 +7014,35 @@
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
},
"node_modules/@trpc/client": {
"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==",
"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.31.0"
"@trpc/server": "10.38.3"
}
},
"node_modules/@trpc/react-query": {
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.31.0.tgz",
"integrity": "sha512-+M8sIsbf6e4H5XYvHlzDqhaf+ybfUigA/9OL3wXRp2vXhCedEiIERCnwNuHWFDRASl9vjOcM33AuJ4sbOOINEA==",
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.38.3.tgz",
"integrity": "sha512-j4xxg/y+vssGinZCrNQy0SMJNL2Nv8k3HcqMKa2mYt3jxOpaHuwxgarWvLWVqrUJqvp1JpGJ9sIjlOAZam5FeQ==",
"funding": [
"https://trpc.io/sponsor"
],
"peerDependencies": {
"@tanstack/react-query": "^4.18.0",
"@trpc/client": "10.31.0",
"@trpc/server": "10.31.0",
"@trpc/client": "10.38.3",
"@trpc/server": "10.38.3",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/@trpc/server": {
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.31.0.tgz",
"integrity": "sha512-9EnRTSDE9nF11LZsvSOqNKqkRYzHqFX4ch5AJ6VIu8uta2vxVTN4FxxsNRSOluTzVYZDeaCISbwmOJ5iihCCIg==",
"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"
]
@@ -17919,9 +17921,9 @@
}
},
"node_modules/react-native-actions-sheet": {
"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==",
"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==",
"peerDependencies": {
"react-native": "*",
"react-native-gesture-handler": "*"
@@ -23701,9 +23703,9 @@
}
},
"@ammarahmed/react-native-sodium": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-sodium/-/react-native-sodium-1.5.2.tgz",
"integrity": "sha512-M309uV2DCK3EPNfsgWYthOApJhQgQKOOxYF19VerUeX7UYnm9VggW073oO0NNqqZqg5GS6bTlrtYMAz7MAKvUw=="
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-sodium/-/react-native-sodium-1.5.4.tgz",
"integrity": "sha512-+JwYnaSJxnwpI1947sUacFXxRxK1f9ykuxDJaGkCUKvh5CkDYC5VyZFnq2BbcuIcx4OTMOG8a/a46hWJbFKQPQ=="
},
"@ampproject/remapping": {
"version": "2.2.1",
@@ -26438,7 +26440,9 @@
"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",
@@ -26469,28 +26473,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.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",
"@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",
"@types/katex": "^0.14.0",
"@types/prismjs": "^1.26.0",
"@types/react": "17.0.2",
@@ -26509,7 +26513,7 @@
"prism-themes": "^1.9.0",
"prosemirror-codemark": "^0.4.2",
"prosemirror-test-builder": "^1.1.0",
"prosemirror-view": "^1.31.7",
"prosemirror-view": "^1.31.8",
"re-resizable": "^6.9.9",
"react": "17.0.2",
"react-colorful": "^5.5.1",
@@ -26573,7 +26577,7 @@
"katex": "0.16.2",
"phone": "^3.1.14",
"qclone": "^1.2.0",
"react-native-actions-sheet": "0.9.0-alpha.23",
"react-native-actions-sheet": "0.9.0-alpha.24",
"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",
@@ -26596,7 +26600,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.2",
"@ammarahmed/react-native-sodium": "1.5.4",
"@babel/core": "^7.20.0",
"@babel/eslint-parser": "^7.16.5",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.16.5",
@@ -26716,7 +26720,7 @@
"requires": {
"@notesnook/theme": "file:../../packages/theme",
"@orama/orama": "^1.0.8",
"@trpc/server": "10.31.0",
"@trpc/server": "10.38.3",
"@types/cors": "^2.8.13",
"@vitejs/plugin-react": "^4.0.3",
"async-mutex": "^0.4.0",
@@ -27325,21 +27329,21 @@
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
},
"@trpc/client": {
"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==",
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.38.3.tgz",
"integrity": "sha512-hHPsElTL4sB+UGzuAZ4iwRVHjELrk/Nsl2owsYw9ITJz3EY7VWRsQ6vK48kJvlHPYPhP+efID5UOgyZMs4bFXA==",
"requires": {}
},
"@trpc/react-query": {
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.31.0.tgz",
"integrity": "sha512-+M8sIsbf6e4H5XYvHlzDqhaf+ybfUigA/9OL3wXRp2vXhCedEiIERCnwNuHWFDRASl9vjOcM33AuJ4sbOOINEA==",
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.38.3.tgz",
"integrity": "sha512-j4xxg/y+vssGinZCrNQy0SMJNL2Nv8k3HcqMKa2mYt3jxOpaHuwxgarWvLWVqrUJqvp1JpGJ9sIjlOAZam5FeQ==",
"requires": {}
},
"@trpc/server": {
"version": "10.31.0",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.31.0.tgz",
"integrity": "sha512-9EnRTSDE9nF11LZsvSOqNKqkRYzHqFX4ch5AJ6VIu8uta2vxVTN4FxxsNRSOluTzVYZDeaCISbwmOJ5iihCCIg=="
"version": "10.38.3",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.38.3.tgz",
"integrity": "sha512-9s8/kwo2IDB5hwB2SKZZrfevRhdb1f9fdXtIYd3lbQuf2jQaC/LyQuHaIQjDQoUx9updBfsHXcFFPiCP1DL6pg=="
},
"@tsconfig/react-native": {
"version": "3.0.2",
@@ -35559,9 +35563,9 @@
}
},
"react-native-actions-sheet": {
"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==",
"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==",
"requires": {}
},
"react-native-actions-shortcuts": {

View File

@@ -1,6 +1,6 @@
{
"name": "@notesnook/mobile",
"version": "2.6.3",
"version": "2.6.7",
"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.31.0",
"@trpc/react-query": "10.31.0",
"@trpc/server": "^10.31.0",
"@trpc/client": "10.38.3",
"@trpc/react-query": "10.38.3",
"@trpc/server": "10.38.3",
"react": "18.2.0",
"react-native": "0.72.0"
}

View File

@@ -1,3 +1,19 @@
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
@@ -109,7 +125,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..40a5c37 100644
index ecaddf9..70d6ba5 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,7 +7,8 @@ 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..e69de29
index 0000000..d4bdd72
Binary files /dev/null and b/node_modules/react-native-vector-icons/android/build/.transforms/f1314fc28eaff1170375cbb76465cb24/transformed/classes/classes.dex differ
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
@@ -84,10 +85,12 @@ 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..e69de29
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
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..e69de29
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
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
@@ -2050,11 +2053,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..2dd0b63
index 0000000..c671bf3
--- /dev/null
+++ b/node_modules/react-native-vector-icons/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties
@@ -0,0 +1 @@
+#Wed Aug 02 11:28:45 PKT 2023
+#Mon Oct 02 09:47:12 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
@@ -2093,16 +2096,20 @@ 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..e69de29
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
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..e69de29
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
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..e69de29
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
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..e69de29
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
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
@@ -2174,7 +2181,8 @@ 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..e69de29
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
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
@@ -3661,7 +3669,8 @@ 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..e69de29
index 0000000..26da0e3
Binary files /dev/null and b/node_modules/react-native-vector-icons/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin differ
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
@@ -3678,7 +3687,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..0962de1 100644
index c06a819..13c76cc 100644
--- a/node_modules/react-native-vector-icons/glyphmaps/MaterialCommunityIcons.json
+++ b/node_modules/react-native-vector-icons/glyphmaps/MaterialCommunityIcons.json
@@ -1,6598 +1 @@
@@ -10281,7 +10290,7 @@ index c06a819..0962de1 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,"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}
+{"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}
\ 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,7 +65,12 @@ const EXTRA_ICON_NAMES = [
"check-circle-outline",
"chevron-up",
"chevron-down",
"calendar"
"calendar",
"minus-circle-outline",
"close-circle-outline",
"qrcode",
"text",
"cloud"
];
const __filename = fileURLToPath(import.meta.url);

View File

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

View File

@@ -0,0 +1,181 @@
/*
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

@@ -21,7 +21,7 @@ import ShareExtension from "@ammarahmed/react-native-share-extension";
import { getPreviewData } from "@flyerhq/react-native-link-preview";
import { formatBytes } from "@notesnook/common";
import { isImage } from "@notesnook/core/dist/utils/filename";
import { parseHTML } from "@notesnook/core/dist/utils/html-parser";
import { useThemeColors } from "@notesnook/theme";
import React, { useCallback, useEffect, useRef, useState } from "react";
import {
ActivityIndicator,
@@ -53,18 +53,17 @@ import { getElevationStyle } from "../app/utils/elevation";
import { eOnLoadNote } from "../app/utils/events";
import { NoteBundle } from "../app/utils/note-bundle";
import { Editor } from "./editor";
import { HtmlLoadingWebViewAgent, fetchHandle } from "./fetch-webview";
import { Search } from "./search";
import { initDatabase, useShareStore } from "./store";
import { useThemeColors } from "@notesnook/theme";
const getLinkPreview = (url) => {
return getPreviewData(url, 5000);
};
async function sanitizeHtml(site) {
try {
let html = await fetch(site);
html = await html.text();
return sanitize(html, site);
let html = await fetchHandle.current?.processUrl(site);
return html;
} catch (e) {
return "";
}
@@ -82,93 +81,6 @@ 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,
@@ -210,6 +122,7 @@ 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 }
@@ -260,6 +173,10 @@ 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();
@@ -397,14 +314,19 @@ const ShareView = ({ quicknote = false }) => {
setLoading(true);
try {
if (m === 2) {
let html = await sanitizeHtml(rawData.value);
setNote((note) => {
note.content.data = html;
setLoadingPage(true);
setTimeout(async () => {
let html = await sanitizeHtml(rawData.value);
noteContent.current = html;
setLoadingPage(false);
onLoad();
return { ...note };
});
setNote((note) => {
note.content.data = html;
return { ...note };
});
}, 300);
} else {
setLoadingPage(false);
let html = isURL(rawData.value)
? makeHtmlFromUrl(rawData.value)
: makeHtmlFromPlainText(rawData.value);
@@ -450,6 +372,8 @@ const ShareView = ({ quicknote = false }) => {
justifyContent: quicknote ? "flex-start" : "flex-end"
}}
>
{loadingPage ? <HtmlLoadingWebViewAgent /> : null}
{quicknote && !searchMode ? (
<View
style={{
@@ -716,16 +640,27 @@ const ShareView = ({ quicknote = false }) => {
<SafeAreaProvider
style={{
flex: 1,
paddingTop: 10
paddingTop: 10,
justifyContent: loadingPage ? "center" : undefined,
alignItems: loadingPage ? "center" : undefined
}}
>
{!loadingExtension && (
{!loadingExtension && !loadingPage ? (
<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,3 +90,7 @@ export const useShareStore = create((set) => ({
set({ selectedTags });
}
}));
export const Config = {
corsProxy: appSettings?.corsProxy
};

View File

@@ -17,6 +17,7 @@
"@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",
@@ -1376,7 +1377,7 @@
},
"../web": {
"name": "@notesnook/web",
"version": "2.6.1",
"version": "2.6.5",
"license": "GPL-3.0-or-later",
"dependencies": {
"@aws-sdk/util-base64-browser": "^3.208.0",
@@ -1405,8 +1406,8 @@
"@theme-ui/color": "^0.14.7",
"@theme-ui/components": "^0.14.7",
"@theme-ui/core": "^0.14.7",
"@trpc/client": "10.31.0",
"@trpc/react-query": "10.31.0",
"@trpc/client": "10.38.3",
"@trpc/react-query": "10.38.3",
"allotment": "^1.19.0",
"axios": "^1.3.4",
"clipboard-polyfill": "4.0.0",
@@ -1445,7 +1446,7 @@
"devDependencies": {
"@babel/core": "^7.22.5",
"@playwright/test": "^1.36.2",
"@trpc/server": "10.31.0",
"@trpc/server": "10.38.3",
"@types/babel__core": "^7.20.1",
"@types/file-saver": "^2.0.5",
"@types/marked": "^4.0.7",
@@ -2394,6 +2395,26 @@
"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,6 +16,7 @@
"@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

@@ -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 { NOTE, USER } from "./utils";
import { USER } from "./utils";
test("create a backup", async ({ page }) => {
test("create an unencrypted backup", async ({ page }) => {
const app = new AppModel(page);
await app.goto();
const notes = await app.goToNotes();
await notes.createNote(NOTE);
await app.auth.goto();
await app.auth.login(USER.CURRENT);
const settings = await app.goToSettings();
await settings.toggleBackupEncryption(USER.CURRENT.password);
const backup = await settings.createBackup();
const backup = await settings.createBackup(USER.CURRENT.password);
expect(backup.length > 0).toBeTruthy();
});
test("restore a backup", async ({ page }) => {
test("restore an unencrypted 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(USER.CURRENT.password);
const backup = await settings.createBackup();
expect(backup.length > 0).toBeTruthy();
});

View File

@@ -46,7 +46,10 @@ export class CheckoutModel {
for await (const item of iterateList(
this.page.locator(getTestId("checkout-plan"))
)) {
plans.push(new Plan(item));
const plan = new Plan(item);
const planTitle = await plan.getTitle();
if (planTitle?.startsWith("Education")) continue;
plans.push(plan);
}
return plans;
}

File diff suppressed because it is too large Load Diff

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