mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-08-29 18:19:38 +02:00
Compare commits
182 Commits
2.6.1-andr
...
fix-codebl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74a0a117e6 | ||
|
|
e8e50bebcf | ||
|
|
fa0610e392 | ||
|
|
124489a5a5 | ||
|
|
22fcdc0fb1 | ||
|
|
1375300a91 | ||
|
|
e6f4aea4d7 | ||
|
|
d72c4057ff | ||
|
|
02d80ee4fa | ||
|
|
2da3e9e0be | ||
|
|
8333e7bdb3 | ||
|
|
cef2472aae | ||
|
|
a4946f7e89 | ||
|
|
3e95e0feae | ||
|
|
b81843cdf7 | ||
|
|
eedd50fc64 | ||
|
|
1cb00bca0d | ||
|
|
8c233570a7 | ||
|
|
8a3c8b85bb | ||
|
|
2ee8a807dc | ||
|
|
ec85f748fa | ||
|
|
051b7fcb8c | ||
|
|
9af88811d8 | ||
|
|
6c4672037c | ||
|
|
d59e0d9ee2 | ||
|
|
5a001a1457 | ||
|
|
44d6474b36 | ||
|
|
0607e005f5 | ||
|
|
308eb4b55f | ||
|
|
6abb6207c5 | ||
|
|
89189d52ae | ||
|
|
e653ce69f8 | ||
|
|
9b89b328f6 | ||
|
|
77ae71fab1 | ||
|
|
7f7c1e6b93 | ||
|
|
30341bea1c | ||
|
|
82d44ea890 | ||
|
|
5f0907168f | ||
|
|
48061962b1 | ||
|
|
24141b66cf | ||
|
|
41beee45ba | ||
|
|
cb7c70b0d6 | ||
|
|
2aa5a57557 | ||
|
|
17582bcefb | ||
|
|
1f5a5afb10 | ||
|
|
d1c724563f | ||
|
|
72aa5eccb7 | ||
|
|
95e0c4b0d6 | ||
|
|
9ec6ca0ded | ||
|
|
85b7611214 | ||
|
|
d256d435e4 | ||
|
|
577a976e01 | ||
|
|
07453834b0 | ||
|
|
59f6b5e411 | ||
|
|
ac9be8360a | ||
|
|
32d0b07f09 | ||
|
|
7b57639076 | ||
|
|
1fa174bab7 | ||
|
|
6c52b5a77d | ||
|
|
d4a6157ed3 | ||
|
|
a86358bbcd | ||
|
|
20d0e6d047 | ||
|
|
51fc4bf3e4 | ||
|
|
61d0dafd21 | ||
|
|
89398cb5e5 | ||
|
|
72ec4063de | ||
|
|
f8423eeea8 | ||
|
|
d91203990e | ||
|
|
fc84c1af51 | ||
|
|
58de07073d | ||
|
|
cafa5ff821 | ||
|
|
1859799ca3 | ||
|
|
271aa11f74 | ||
|
|
e42f1a65f5 | ||
|
|
73f3a31614 | ||
|
|
4d7792d06a | ||
|
|
1a0f17c059 | ||
|
|
89d941401a | ||
|
|
a076ee640d | ||
|
|
8c1629f7dd | ||
|
|
9a31c07ac5 | ||
|
|
11f39316b5 | ||
|
|
f157229e00 | ||
|
|
a0f25c4e6f | ||
|
|
003b3d2a84 | ||
|
|
1775e0bda1 | ||
|
|
d5038ac631 | ||
|
|
7eab77ba01 | ||
|
|
89413c56e2 | ||
|
|
4d89643203 | ||
|
|
e119590249 | ||
|
|
ace2dfac30 | ||
|
|
5843df0ce8 | ||
|
|
403ed8adb6 | ||
|
|
1eb5c8bc46 | ||
|
|
46f7ec5e00 | ||
|
|
52adece147 | ||
|
|
de50be9d1b | ||
|
|
0f9e32b49f | ||
|
|
b4c15adf5d | ||
|
|
a3d3886c51 | ||
|
|
0cfa7ce774 | ||
|
|
8299ea909e | ||
|
|
8b056fe610 | ||
|
|
511c40db5c | ||
|
|
42d0d42188 | ||
|
|
c80a998444 | ||
|
|
0a10df75d1 | ||
|
|
40d755d191 | ||
|
|
0409a610ab | ||
|
|
aa9cd23cf3 | ||
|
|
12d89114a4 | ||
|
|
d5b679187a | ||
|
|
463ba3754a | ||
|
|
2fa8fd14e7 | ||
|
|
fac788d2a9 | ||
|
|
6554f900d7 | ||
|
|
81d3ec83d9 | ||
|
|
339c5a357b | ||
|
|
b484992037 | ||
|
|
87e42e98c6 | ||
|
|
51bef01609 | ||
|
|
6a49244614 | ||
|
|
dad2b61a74 | ||
|
|
fabc595f3d | ||
|
|
a700787cf3 | ||
|
|
fb26229715 | ||
|
|
c4f894f8d0 | ||
|
|
ddd1c19c64 | ||
|
|
79cb3bdba4 | ||
|
|
8447c2150b | ||
|
|
bc465971be | ||
|
|
f8ce23aa11 | ||
|
|
84004c4d73 | ||
|
|
2b6aa9b89b | ||
|
|
54b8a3e789 | ||
|
|
7ff5f0001c | ||
|
|
d384aa9dcf | ||
|
|
1190da7c91 | ||
|
|
6561791530 | ||
|
|
26e233d3eb | ||
|
|
0417981538 | ||
|
|
81fc56937e | ||
|
|
cb778d7e35 | ||
|
|
8442b43715 | ||
|
|
28b3306506 | ||
|
|
f51f45aeb2 | ||
|
|
7f1184736c | ||
|
|
e4c8e7a0c5 | ||
|
|
44e4722de2 | ||
|
|
7c2b0c5947 | ||
|
|
6ea912ad0e | ||
|
|
124bbb6ac1 | ||
|
|
30d6345152 | ||
|
|
60ff7b2f97 | ||
|
|
c6e90142bb | ||
|
|
1289a025a5 | ||
|
|
18d0b72785 | ||
|
|
0157cf496f | ||
|
|
3450f2d19d | ||
|
|
e509c82807 | ||
|
|
d5afd6f32e | ||
|
|
fb34dd2864 | ||
|
|
0cd1ce3431 | ||
|
|
a24447d569 | ||
|
|
0bf26afa33 | ||
|
|
49455e8054 | ||
|
|
1136e43115 | ||
|
|
4b74cba4e4 | ||
|
|
c8a77934f2 | ||
|
|
e1739e04d1 | ||
|
|
a5d39a18a7 | ||
|
|
77eb661b0e | ||
|
|
667d0d16ea | ||
|
|
445ea660c3 | ||
|
|
7a35640739 | ||
|
|
f1650fd383 | ||
|
|
5d67a554d6 | ||
|
|
380bfba776 | ||
|
|
ed6d125391 | ||
|
|
adaa5fd56d | ||
|
|
0a8db237eb |
@@ -33,7 +33,8 @@ const SCOPES = [
|
||||
"misc",
|
||||
"common",
|
||||
"global",
|
||||
"docs"
|
||||
"docs",
|
||||
"themebuilder"
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -19,7 +19,6 @@ runs:
|
||||
packages/crypto/package-lock.json
|
||||
packages/sodium/package-lock.json
|
||||
packages/clipper/package-lock.json
|
||||
packages/crypto-worker/package-lock.json
|
||||
packages/editor-mobile/package-lock.json
|
||||
packages/editor/package-lock.json
|
||||
packages/logger/package-lock.json
|
||||
|
||||
31
.github/workflows/theme-builder.publish.yml
vendored
Normal file
31
.github/workflows/theme-builder.publish.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: Publish @notesnook/theme-builder
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node
|
||||
uses: ./.github/actions/setup-node-with-cache
|
||||
|
||||
- name: Install packages
|
||||
run: |
|
||||
npm ci --ignore-scripts --prefer-offline --no-audit
|
||||
npm run bootstrap -- --scope=themebuilder
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
|
||||
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate build
|
||||
run: npm run build:theme-builder
|
||||
|
||||
- name: Publish to Cloudflare Pages
|
||||
run: npx --yes wrangler pages deploy --project-name=notesnook-theme-builder ./apps/theme-builder/build/
|
||||
@@ -103,7 +103,7 @@ All commits must include valid scopes in the commit message. **Valid commit scop
|
||||
|
||||
**Packages:**
|
||||
|
||||
1. `crypto`: changes related to the cryptographic core (including `@notesnook/crypto-worker`)
|
||||
1. `crypto`: changes related to the cryptographic core
|
||||
2. `editor`: changes related to the editor (including `@notesnook/editor-mobile`)
|
||||
3. `logger`: changes related to the logger
|
||||
4. `theme`: changes related to the theme
|
||||
|
||||
@@ -46,7 +46,6 @@ Notesnook is built using the following technologies:
|
||||
| `@notesnook/editor-mobile` | [/packages/editor-mobile](/packages/editor-mobile) | A very thin wrapper around `@notesnook/editor` for mobile clients |
|
||||
| `@notesnook/logger` | [/packages/logger](/packages/logger) | Simple & pluggable logger |
|
||||
| `@notesnook/sodium` | [/packages/sodium](/packages/sodium) | Wrapper around libsodium to support Node.js & Browser |
|
||||
| `@notesnook/crypto-worker` | [/packages/crypto-worker](/packages/crypto-worker) | Helpers to use `@notesnook/crypto` from a Worker |
|
||||
| `@notesnook/streamable-fs` | [/packages/streamable-fs](/packages/streamable-fs) | Streaming interface around an IndexedDB based file system |
|
||||
| `@notesnook/theme` | [/packages/theme](/packages/theme) | The core theme used in web & desktop clients |
|
||||
|
||||
|
||||
31
apps/desktop/global.d.ts
vendored
31
apps/desktop/global.d.ts
vendored
@@ -19,9 +19,40 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
/* eslint-disable no-var */
|
||||
|
||||
import { BrowserWindow } from "electron";
|
||||
import {
|
||||
type FormData as FormDataType,
|
||||
type Headers as HeadersType,
|
||||
type Request as RequestType,
|
||||
type Response as ResponseType
|
||||
} from "undici";
|
||||
|
||||
declare global {
|
||||
var window: BrowserWindow | null;
|
||||
var RELEASE: boolean;
|
||||
var MAC_APP_STORE: boolean;
|
||||
|
||||
// Re-export undici fetch function and various classes to global scope.
|
||||
// These are classes and functions expected to be at global scope according to Node.js v18 API
|
||||
// documentation.
|
||||
// See: https://nodejs.org/dist/latest-v18.x/docs/api/globals.html
|
||||
// eslint-disable-next-line no-var
|
||||
export var {
|
||||
FormData,
|
||||
Headers,
|
||||
Request,
|
||||
Response,
|
||||
fetch
|
||||
}: typeof import("undici");
|
||||
|
||||
type FormData = FormDataType;
|
||||
type Headers = HeadersType;
|
||||
type Request = RequestType;
|
||||
type Response = ResponseType;
|
||||
}
|
||||
|
||||
// NOTE: the import in the global block above needs to be a var for this to work properly.
|
||||
globalThis.fetch = fetch;
|
||||
globalThis.FormData = FormData;
|
||||
globalThis.Headers = Headers;
|
||||
globalThis.Request = Request;
|
||||
globalThis.Response = Response;
|
||||
|
||||
1593
apps/desktop/package-lock.json
generated
1593
apps/desktop/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "2.6.0",
|
||||
"version": "2.6.3",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./dist/index.js",
|
||||
@@ -15,22 +15,22 @@
|
||||
"@trpc/client": "10.31.0",
|
||||
"@trpc/server": "10.31.0",
|
||||
"electron-trpc": "0.5.2",
|
||||
"electron-updater": "6.1.1",
|
||||
"electron-updater": "6.1.4",
|
||||
"icojs": "^0.17.1",
|
||||
"typed-emitter": "^2.1.0",
|
||||
"yargs": "^17.6.2",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.15.0",
|
||||
"@types/node": "18.16.1",
|
||||
"@types/yargs": "^17.0.24",
|
||||
"chokidar": "^3.5.3",
|
||||
"electron": "24.5.1",
|
||||
"electron-builder": "24.4.0",
|
||||
"electron": "25.8.0",
|
||||
"electron-builder": "^24.6.4",
|
||||
"electron-builder-notarize": "^1.5.1",
|
||||
"esbuild": "^0.17.19",
|
||||
"node-fetch": "^3.3.1",
|
||||
"tree-kill": "^1.2.2"
|
||||
"tree-kill": "^1.2.2",
|
||||
"undici": "^5.23.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"dmg-license": "^1.0.11"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js b/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js
|
||||
index 3ba5d6a..cf8e147 100644
|
||||
index fcb7f54..cb1c7f7 100644
|
||||
--- a/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js
|
||||
+++ b/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js
|
||||
@@ -105,6 +105,7 @@ class LinuxTargetHelper {
|
||||
@@ -116,6 +116,7 @@ class LinuxTargetHelper {
|
||||
StartupWMClass: appInfo.productName,
|
||||
...extra,
|
||||
...targetSpecificOptions.desktop,
|
||||
@@ -10,7 +10,7 @@ index 3ba5d6a..cf8e147 100644
|
||||
};
|
||||
const description = this.getDescription(targetSpecificOptions);
|
||||
if (!(0, builder_util_1.isEmptyOrSpaces)(description)) {
|
||||
@@ -148,6 +149,23 @@ class LinuxTargetHelper {
|
||||
@@ -159,6 +160,23 @@ class LinuxTargetHelper {
|
||||
data += `\n${name}=${desktopMeta[name]}`;
|
||||
}
|
||||
data += "\n";
|
||||
@@ -53,6 +53,13 @@ if (process.platform === "win32") {
|
||||
app.setAppUserModelId(app.name);
|
||||
}
|
||||
|
||||
process.on("uncaughtException", (error) => {
|
||||
console.error("uncaughtException:", error);
|
||||
});
|
||||
process.on("unhandledRejection", (reason) => {
|
||||
console.error("unhandledRejection:", reason);
|
||||
});
|
||||
|
||||
app.commandLine.appendSwitch("lang", "en-US");
|
||||
|
||||
async function createWindow() {
|
||||
|
||||
@@ -17,16 +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 { protocol, ProtocolRequest } from "electron";
|
||||
import { protocol, net } from "electron";
|
||||
import { isDevelopment } from "./index";
|
||||
import { createReadStream } from "fs";
|
||||
import { extname, normalize } from "path";
|
||||
import { URL } from "url";
|
||||
import fetch, { Response } from "node-fetch";
|
||||
|
||||
const BASE_PATH = isDevelopment() ? "../public" : "";
|
||||
const HOSTNAME = `app.notesnook.com`;
|
||||
const FILE_NOT_FOUND = -6;
|
||||
const SCHEME = "https";
|
||||
const extensionToMimeType: Record<string, string> = {
|
||||
html: "text/html",
|
||||
@@ -34,101 +32,42 @@ const extensionToMimeType: Record<string, string> = {
|
||||
js: "application/javascript",
|
||||
css: "text/css",
|
||||
svg: "image/svg+xml",
|
||||
png: "image/png"
|
||||
png: "image/png",
|
||||
jpg: "image/jpg",
|
||||
ttf: "font/ttf",
|
||||
woff: "font/woff",
|
||||
woff2: "font/woff2"
|
||||
};
|
||||
|
||||
function registerProtocol() {
|
||||
const protocolInterceptionResult = protocol.interceptStreamProtocol(
|
||||
SCHEME,
|
||||
async (request, callback) => {
|
||||
const url = new URL(request.url);
|
||||
if (shouldInterceptRequest(url)) {
|
||||
console.info("Intercepting request:", request.url);
|
||||
|
||||
const loadIndex = !extname(url.pathname);
|
||||
const filePath = normalize(
|
||||
`${__dirname}${
|
||||
loadIndex
|
||||
? `${BASE_PATH}/index.html`
|
||||
: `${BASE_PATH}/${url.pathname}`
|
||||
}`
|
||||
);
|
||||
if (!filePath) {
|
||||
console.error("Local asset file not found at", filePath);
|
||||
callback({ error: FILE_NOT_FOUND });
|
||||
return;
|
||||
}
|
||||
const fileExtension = extname(filePath).replace(".", "");
|
||||
|
||||
const data = createReadStream(filePath);
|
||||
callback({
|
||||
data,
|
||||
mimeType: extensionToMimeType[fileExtension]
|
||||
});
|
||||
} else {
|
||||
let response: Response;
|
||||
try {
|
||||
const body = await getBody(request);
|
||||
response = await fetch(request.url, {
|
||||
...request,
|
||||
body,
|
||||
headers: {
|
||||
...request.headers
|
||||
// origin: `${PROTOCOL}://${HOSTNAME}/`
|
||||
},
|
||||
referrer: request.referrer,
|
||||
redirect: "manual"
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
console.error(`Error sending request to `, request.url, "Error: ", e);
|
||||
callback({ statusCode: 400 });
|
||||
return;
|
||||
}
|
||||
callback({
|
||||
statusCode: response.status,
|
||||
data: response.body || undefined,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
mimeType: response.headers.get("Content-Type") || undefined
|
||||
protocol.handle(SCHEME, async (request) => {
|
||||
const url = new URL(request.url);
|
||||
if (shouldInterceptRequest(url)) {
|
||||
console.info("Intercepting request:", request.url);
|
||||
const loadIndex = !extname(url.pathname);
|
||||
const filePath = normalize(
|
||||
`${__dirname}${
|
||||
loadIndex ? `${BASE_PATH}/index.html` : `${BASE_PATH}/${url.pathname}`
|
||||
}`
|
||||
);
|
||||
if (!filePath) {
|
||||
console.error("Local asset file not found at", filePath);
|
||||
return new Response(undefined, {
|
||||
status: 404,
|
||||
statusText: "FILE_NOT_FOUND"
|
||||
});
|
||||
}
|
||||
const fileExtension = extname(filePath).replace(".", "");
|
||||
return new Response(createReadStream(filePath), {
|
||||
headers: { "Content-Type": extensionToMimeType[fileExtension] }
|
||||
});
|
||||
} else {
|
||||
return net.fetch(request, {
|
||||
bypassCustomProtocolHandlers: true
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
console.info(
|
||||
`${SCHEME} protocol inteception ${
|
||||
protocolInterceptionResult ? "successful" : "failed"
|
||||
}.`
|
||||
);
|
||||
|
||||
// protocol.handle(SCHEME, (request) => {
|
||||
// const url = new URL(request.url);
|
||||
// if (shouldInterceptRequest(url)) {
|
||||
// console.info("Intercepting request:", request.url);
|
||||
// const loadIndex = !extname(url.pathname);
|
||||
// const absoluteFilePath = normalize(
|
||||
// `${__dirname}${
|
||||
// loadIndex ? `${BASE_PATH}/index.html` : `${BASE_PATH}/${url.pathname}`
|
||||
// }`
|
||||
// );
|
||||
// const filePath = getPath(absoluteFilePath);
|
||||
// if (!filePath) {
|
||||
// console.error("Local asset file not found at", filePath);
|
||||
// return new Response(undefined, {
|
||||
// status: 404,
|
||||
// statusText: "FILE_NOT_FOUND"
|
||||
// });
|
||||
// }
|
||||
// const fileExtension = extname(filePath).replace(".", "");
|
||||
// const data = createReadStream(filePath);
|
||||
// return new Response(data, {
|
||||
// headers: { "Content-Type": extensionToMimeType[fileExtension] }
|
||||
// });
|
||||
// } else {
|
||||
// return net.fetch(request);
|
||||
// }
|
||||
// });
|
||||
// console.info(`${SCHEME} protocol inteception "successful"`);
|
||||
});
|
||||
console.info(`${SCHEME} protocol inteception "successful"`);
|
||||
}
|
||||
|
||||
const bypassedRoutes: string[] = [];
|
||||
@@ -139,22 +78,3 @@ function shouldInterceptRequest(url: URL) {
|
||||
|
||||
const PROTOCOL_URL = `${SCHEME}://${HOSTNAME}/`;
|
||||
export { registerProtocol, PROTOCOL_URL };
|
||||
|
||||
async function getBody(request: ProtocolRequest) {
|
||||
const session = globalThis?.window?.webContents?.session;
|
||||
|
||||
const blobParts = [];
|
||||
if (!request.uploadData || !request.uploadData.length) return null;
|
||||
for (const data of request.uploadData) {
|
||||
if (data.bytes) {
|
||||
blobParts.push(new Uint8Array(data.bytes));
|
||||
} else if (session && data.blobUUID) {
|
||||
const buffer = await session.getBlobData(data.blobUUID);
|
||||
if (!buffer) continue;
|
||||
blobParts.push(new Uint8Array(buffer));
|
||||
}
|
||||
}
|
||||
const blob = new Blob(blobParts);
|
||||
return blob;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 "@azure/core-asynciterator-polyfill";
|
||||
import SettingsService from "./services/settings";
|
||||
import {
|
||||
THEME_COMPATIBILITY_VERSION,
|
||||
@@ -45,6 +46,7 @@ const App = () => {
|
||||
if (appLockMode && appLockMode !== "none") {
|
||||
useUserStore.getState().lockApp(true);
|
||||
}
|
||||
globalThis["IS_MAIN_APP_RUNNING"] = true;
|
||||
init();
|
||||
setTimeout(async () => {
|
||||
SettingsService.onFirstLaunch();
|
||||
@@ -92,6 +94,12 @@ const App = () => {
|
||||
);
|
||||
};
|
||||
|
||||
let currTheme =
|
||||
useThemeStore.getState().colorScheme === "dark"
|
||||
? SettingsService.getProperty("darkTheme")
|
||||
: SettingsService.getProperty("lightTheme");
|
||||
useThemeEngineStore.getState().setTheme(currTheme);
|
||||
|
||||
export const withTheme = (Element) => {
|
||||
return function AppWithThemeProvider() {
|
||||
const [colorScheme, darkTheme, lightTheme] = useThemeStore((state) => [
|
||||
@@ -123,11 +131,13 @@ export const withTheme = (Element) => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const nextTheme = colorScheme === "dark" ? darkTheme : lightTheme;
|
||||
if (JSON.stringify(nextTheme) !== JSON.stringify(currTheme)) {
|
||||
useThemeEngineStore
|
||||
.getState()
|
||||
.setTheme(colorScheme === "dark" ? darkTheme : lightTheme);
|
||||
}, [colorScheme, darkTheme, lightTheme]);
|
||||
currTheme = nextTheme;
|
||||
}
|
||||
|
||||
return <Element />;
|
||||
};
|
||||
|
||||
@@ -126,6 +126,18 @@ export async function decrypt(password, data) {
|
||||
return await Sodium.decrypt(password, _data);
|
||||
}
|
||||
|
||||
export async function decryptMulti(password, data) {
|
||||
if (!password.password && !password.key) return undefined;
|
||||
if (password.password && password.password === "" && !password.key)
|
||||
return undefined;
|
||||
|
||||
data = data.map((d) => {
|
||||
d.output = "plain";
|
||||
return d;
|
||||
});
|
||||
return await Sodium.decryptMulti(password, data);
|
||||
}
|
||||
|
||||
export function parseAlgorithm(alg) {
|
||||
if (!alg) return {};
|
||||
const [enc, kdf, compressed, compressionAlg, base64variant] = alg.split("-");
|
||||
@@ -154,3 +166,24 @@ export async function encrypt(password, data) {
|
||||
alg: getAlgorithm(7)
|
||||
};
|
||||
}
|
||||
|
||||
export async function encryptMulti(password, data) {
|
||||
if (!password.password && !password.key) return undefined;
|
||||
if (password.password && password.password === "" && !password.key)
|
||||
return undefined;
|
||||
|
||||
let results = await Sodium.encryptMulti(
|
||||
password,
|
||||
data.map((item) => ({
|
||||
type: "plain",
|
||||
data: item
|
||||
}))
|
||||
);
|
||||
|
||||
return !results
|
||||
? []
|
||||
: results.map((result) => ({
|
||||
...result,
|
||||
alg: getAlgorithm(7)
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -17,18 +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 { database } from "@notesnook/common";
|
||||
import { initalize, logger as dbLogger } from "@notesnook/core/logger";
|
||||
import { logger as dbLogger } from "@notesnook/core/dist/logger";
|
||||
import { Platform } from "react-native";
|
||||
import { MMKVLoader } from "react-native-mmkv-storage";
|
||||
import filesystem from "../filesystem";
|
||||
import * as Gzip from "react-native-gzip";
|
||||
import EventSource from "../../utils/sse/even-source-ios";
|
||||
import AndroidEventSource from "../../utils/sse/event-source";
|
||||
import Storage, { KV } from "./storage";
|
||||
import * as Gzip from "react-native-gzip";
|
||||
|
||||
const LoggerStorage = new MMKVLoader()
|
||||
.withInstanceID("notesnook_logs")
|
||||
.initialize();
|
||||
import filesystem from "../filesystem";
|
||||
import "./logger";
|
||||
import Storage from "./storage";
|
||||
|
||||
database.host(
|
||||
__DEV__
|
||||
@@ -38,11 +34,11 @@ database.host(
|
||||
SSE_HOST: "https://events.streetwriters.co",
|
||||
SUBSCRIPTIONS_HOST: "https://subscriptions.streetwriters.co",
|
||||
ISSUES_HOST: "https://issues.streetwriters.co"
|
||||
// API_HOST: "http://192.168.8.101:5264",
|
||||
// AUTH_HOST: "http://192.168.8.101:8264",
|
||||
// SSE_HOST: "http://192.168.8.101:7264",
|
||||
// SUBSCRIPTIONS_HOST: "http://192.168.8.101:9264",
|
||||
// ISSUES_HOST: "http://192.168.8.101:2624"
|
||||
// API_HOST: "http://192.168.43.108:5264",
|
||||
// AUTH_HOST: "http://192.168.43.108:8264",
|
||||
// SSE_HOST: "http://192.168.43.108:7264",
|
||||
// SUBSCRIPTIONS_HOST: "http://192.168.43.108:9264",
|
||||
// ISSUES_HOST: "http://192.168.43.108:2624"
|
||||
}
|
||||
: {
|
||||
API_HOST: "https://api.notesnook.com",
|
||||
@@ -63,7 +59,5 @@ database.setup(
|
||||
}
|
||||
);
|
||||
|
||||
initalize(new KV(LoggerStorage), true);
|
||||
|
||||
export const db = database;
|
||||
export const DatabaseLogger = dbLogger;
|
||||
|
||||
29
apps/mobile/app/common/database/logger.js
Normal file
29
apps/mobile/app/common/database/logger.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
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 { MMKVLoader } from "react-native-mmkv-storage";
|
||||
import { initalize } from "@notesnook/core/dist/logger";
|
||||
import { KV } from "./storage";
|
||||
|
||||
const LoggerStorage = new MMKVLoader()
|
||||
.withInstanceID("notesnook_logs")
|
||||
.initialize();
|
||||
|
||||
initalize(new KV(LoggerStorage));
|
||||
|
||||
export {};
|
||||
@@ -18,12 +18,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Platform } from "react-native";
|
||||
import MMKVStorage, { ProcessingModes } from "react-native-mmkv-storage";
|
||||
import { ProcessingModes, MMKVLoader } from "react-native-mmkv-storage";
|
||||
|
||||
export const MMKV = new MMKVStorage.Loader()
|
||||
export const MMKV = new MMKVLoader()
|
||||
.setProcessingMode(
|
||||
Platform.OS === "ios"
|
||||
? ProcessingModes.MULTI_PROCESS
|
||||
: ProcessingModes.SINGLE_PROCESS
|
||||
)
|
||||
.disableIndexing()
|
||||
.initialize();
|
||||
|
||||
@@ -27,11 +27,16 @@ import {
|
||||
getCryptoKey,
|
||||
getRandomBytes,
|
||||
hash,
|
||||
removeCryptoKey
|
||||
removeCryptoKey,
|
||||
decryptMulti,
|
||||
encryptMulti
|
||||
} from "./encryption";
|
||||
import { MMKV } from "./mmkv";
|
||||
|
||||
export class KV {
|
||||
/**
|
||||
* @type {typeof MMKV}
|
||||
*/
|
||||
storage = null;
|
||||
constructor(storage) {
|
||||
this.storage = storage;
|
||||
@@ -53,6 +58,7 @@ export class KV {
|
||||
key,
|
||||
typeof data === "string" ? data : JSON.stringify(data)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -60,27 +66,32 @@ export class KV {
|
||||
if (keys.length <= 0) {
|
||||
return [];
|
||||
} else {
|
||||
let data = await this.storage.getMultipleItemsAsync(keys.slice());
|
||||
|
||||
return data.map(([key, value]) => {
|
||||
let obj;
|
||||
try {
|
||||
obj = JSON.parse(value);
|
||||
} catch (e) {
|
||||
obj = value;
|
||||
}
|
||||
|
||||
return [key, obj];
|
||||
});
|
||||
try {
|
||||
let data = await this.storage.getMultipleItemsAsync(
|
||||
keys.slice(),
|
||||
"string"
|
||||
);
|
||||
return data.map(([key, value]) => {
|
||||
let obj;
|
||||
try {
|
||||
obj = JSON.parse(value);
|
||||
} catch (e) {
|
||||
obj = value;
|
||||
}
|
||||
return [key, obj];
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async remove(key) {
|
||||
return await this.storage.removeItem(key);
|
||||
return this.storage.removeItem(key);
|
||||
}
|
||||
|
||||
async clear() {
|
||||
return await this.storage.clearStore();
|
||||
return this.storage.clearStore();
|
||||
}
|
||||
|
||||
async getAllKeys() {
|
||||
@@ -96,6 +107,10 @@ export class KV {
|
||||
);
|
||||
return keys;
|
||||
}
|
||||
|
||||
async writeMulti(items) {
|
||||
return this.storage.setMultipleItemsAsync(items, "object");
|
||||
}
|
||||
}
|
||||
|
||||
const DefaultStorage = new KV(MMKV);
|
||||
@@ -129,8 +144,10 @@ export default {
|
||||
remove: (key) => DefaultStorage.remove(key),
|
||||
clear: () => DefaultStorage.clear(),
|
||||
getAllKeys: () => DefaultStorage.getAllKeys(),
|
||||
writeMulti: (items) => DefaultStorage.writeMulti(items),
|
||||
encrypt,
|
||||
decrypt,
|
||||
decryptMulti,
|
||||
getRandomBytes,
|
||||
checkAndCreateDir,
|
||||
requestPermission,
|
||||
@@ -138,5 +155,6 @@ export default {
|
||||
getCryptoKey,
|
||||
removeCryptoKey,
|
||||
hash,
|
||||
generateCryptoKey
|
||||
generateCryptoKey,
|
||||
encryptMulti
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
getFileNameWithExtension,
|
||||
isImage,
|
||||
isDocument
|
||||
} from "@notesnook/core/utils/filename";
|
||||
} from "@notesnook/core/dist/utils/filename";
|
||||
import React from "react";
|
||||
import { Platform } from "react-native";
|
||||
import * as ScopedStorage from "react-native-scoped-storage";
|
||||
|
||||
@@ -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 hosts from "@notesnook/core/utils/constants";
|
||||
import hosts from "@notesnook/core/dist/utils/constants";
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
import RNFetchBlob from "react-native-blob-util";
|
||||
import { ToastEvent } from "../../services/event-manager";
|
||||
|
||||
@@ -21,7 +21,7 @@ import RNFetchBlob from "react-native-blob-util";
|
||||
import { useAttachmentStore } from "../../stores/use-attachment-store";
|
||||
import { DatabaseLogger, db } from "../database";
|
||||
import { cacheDir } from "./utils";
|
||||
import { isImage, isDocument } from "@notesnook/core/utils/filename";
|
||||
import { isImage, isDocument } from "@notesnook/core/dist/utils/filename";
|
||||
import { Platform } from "react-native";
|
||||
import { IOS_APPGROUPID } from "../../utils/constants";
|
||||
|
||||
|
||||
@@ -128,7 +128,9 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
|
||||
fontSize={SIZE.md}
|
||||
buttonType={{
|
||||
color: color ? color : colors.primary.accent,
|
||||
text: colors.static.white,
|
||||
text: color
|
||||
? colors.static.white
|
||||
: colors.primary.accentForeground,
|
||||
selected: color ? color : colors.primary.accent,
|
||||
opacity: 1
|
||||
}}
|
||||
|
||||
@@ -40,7 +40,7 @@ import {
|
||||
isDocument,
|
||||
isImage,
|
||||
isVideo
|
||||
} from "@notesnook/core/utils/filename";
|
||||
} from "@notesnook/core/dist/utils/filename";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { FlashList } from "react-native-actions-sheet/dist/src/views/FlashList";
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ export const Signup = ({ changeMode, trial }) => {
|
||||
|
||||
const signup = async () => {
|
||||
if (!validateInfo() || error) return;
|
||||
if (loading) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
await db.user.signup(email.current.toLowerCase(), password.current);
|
||||
|
||||
@@ -214,6 +214,7 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo }) => {
|
||||
code.current = value;
|
||||
//onNext();
|
||||
}}
|
||||
caretHidden
|
||||
inputStyle={{
|
||||
fontSize: SIZE.lg,
|
||||
height: 60,
|
||||
|
||||
@@ -64,6 +64,7 @@ export const useLogin = (onFinishLogin) => {
|
||||
const login = async () => {
|
||||
if (!validateInfo() || error) return;
|
||||
try {
|
||||
if (loading) return;
|
||||
setLoading(true);
|
||||
switch (step) {
|
||||
case LoginSteps.emailAuth: {
|
||||
|
||||
@@ -17,12 +17,12 @@ 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 React, { PropsWithChildren } from "react";
|
||||
import { View } from "react-native";
|
||||
import { useSelectionStore } from "../../stores/use-selection-store";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
|
||||
export const ContainerHeader = ({ children }) => {
|
||||
export const ContainerHeader = (props: PropsWithChildren) => {
|
||||
const { colors } = useThemeColors();
|
||||
const selectionMode = useSelectionStore((state) => state.selectionMode);
|
||||
|
||||
@@ -34,7 +34,7 @@ export const ContainerHeader = ({ children }) => {
|
||||
overflow: "hidden"
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
{props.children}
|
||||
</View>
|
||||
) : null;
|
||||
};
|
||||
@@ -17,8 +17,9 @@ 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, { useCallback, useEffect } from "react";
|
||||
import { Keyboard, Platform, View } from "react-native";
|
||||
import { Keyboard, View } from "react-native";
|
||||
import Animated, {
|
||||
Easing,
|
||||
useAnimatedStyle,
|
||||
@@ -34,14 +35,20 @@ import { getElevationStyle } from "../../utils/elevation";
|
||||
import { SIZE, normalize } from "../../utils/size";
|
||||
import NativeTooltip from "../../utils/tooltip";
|
||||
import { PressableButton } from "../ui/pressable";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
|
||||
export const FloatingButton = ({
|
||||
interface FloatingButton {
|
||||
title?: string;
|
||||
onPress: () => void;
|
||||
color?: string;
|
||||
alwaysVisible?: boolean;
|
||||
}
|
||||
|
||||
const FloatingButton = ({
|
||||
title,
|
||||
onPress,
|
||||
color,
|
||||
shouldShow = false
|
||||
}) => {
|
||||
alwaysVisible = false
|
||||
}: FloatingButton) => {
|
||||
const { colors } = useThemeColors();
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
const selectionMode = useSelectionStore((state) => state.selectionMode);
|
||||
@@ -60,12 +67,8 @@ export const FloatingButton = ({
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
animate(selectionMode ? 150 : 0);
|
||||
}, [animate, selectionMode]);
|
||||
|
||||
const animate = useCallback(
|
||||
(toValue) => {
|
||||
(toValue: number) => {
|
||||
translate.value = withTiming(toValue, {
|
||||
duration: 250,
|
||||
easing: Easing.elastic(1)
|
||||
@@ -74,39 +77,39 @@ export const FloatingButton = ({
|
||||
[translate]
|
||||
);
|
||||
|
||||
const onKeyboardHide = useCallback(async () => {
|
||||
editorState().keyboardState = false;
|
||||
if (deviceMode !== "mobile") return;
|
||||
animate(0);
|
||||
}, [animate, deviceMode]);
|
||||
|
||||
const onKeyboardShow = useCallback(async () => {
|
||||
editorState().keyboardState = true;
|
||||
if (deviceMode !== "mobile") return;
|
||||
animate(150);
|
||||
}, [animate, deviceMode]);
|
||||
useEffect(() => {
|
||||
animate(selectionMode ? 150 : 0);
|
||||
}, [animate, selectionMode]);
|
||||
|
||||
useEffect(() => {
|
||||
let sub1 = Keyboard.addListener("keyboardDidShow", onKeyboardShow);
|
||||
let sub2 = Keyboard.addListener("keyboardDidHide", onKeyboardHide);
|
||||
return () => {
|
||||
sub1?.remove();
|
||||
sub2?.remove();
|
||||
const onKeyboardHide = () => {
|
||||
editorState().keyboardState = false;
|
||||
if (deviceMode !== "mobile") return;
|
||||
animate(0);
|
||||
};
|
||||
}, [deviceMode, onKeyboardHide, onKeyboardShow]);
|
||||
const paddings = {
|
||||
ios: 20,
|
||||
android: 20,
|
||||
iPad: 20
|
||||
};
|
||||
|
||||
return deviceMode !== "mobile" && !shouldShow ? null : (
|
||||
const onKeyboardShow = () => {
|
||||
editorState().keyboardState = true;
|
||||
if (deviceMode !== "mobile") return;
|
||||
animate(150);
|
||||
};
|
||||
|
||||
const sub = [
|
||||
Keyboard.addListener("keyboardDidShow", onKeyboardShow),
|
||||
Keyboard.addListener("keyboardDidHide", onKeyboardHide)
|
||||
];
|
||||
return () => {
|
||||
sub.forEach((sub) => sub?.remove?.());
|
||||
};
|
||||
}, [deviceMode, animate]);
|
||||
|
||||
return deviceMode !== "mobile" && !alwaysVisible ? null : (
|
||||
<Animated.View
|
||||
style={[
|
||||
{
|
||||
position: "absolute",
|
||||
right: 12,
|
||||
bottom: paddings[Platform.isPad ? "iPad" : Platform.OS],
|
||||
bottom: 20,
|
||||
zIndex: 10
|
||||
},
|
||||
animatedStyle
|
||||
@@ -115,16 +118,15 @@ export const FloatingButton = ({
|
||||
<PressableButton
|
||||
testID={notesnook.buttons.add}
|
||||
type="accent"
|
||||
buttonType={{
|
||||
color: colors.static[color],
|
||||
text: colors.static.white
|
||||
}}
|
||||
accentColor={colors.static[color as keyof typeof colors.static]}
|
||||
customStyle={{
|
||||
...getElevationStyle(5),
|
||||
borderRadius: 100
|
||||
}}
|
||||
onLongPress={(event) => {
|
||||
NativeTooltip.show(event, title, NativeTooltip.POSITIONS.LEFT);
|
||||
if (title) {
|
||||
NativeTooltip.show(event, title, NativeTooltip.POSITIONS.LEFT);
|
||||
}
|
||||
}}
|
||||
onPress={onPress}
|
||||
>
|
||||
@@ -138,7 +140,7 @@ export const FloatingButton = ({
|
||||
>
|
||||
<Icon
|
||||
name={title === "Clear all trash" ? "delete" : "plus"}
|
||||
color="white"
|
||||
color={colors.primary.accentForeground}
|
||||
size={SIZE.xxl}
|
||||
/>
|
||||
</View>
|
||||
@@ -146,3 +148,5 @@ export const FloatingButton = ({
|
||||
</Animated.View>
|
||||
);
|
||||
};
|
||||
|
||||
export { FloatingButton };
|
||||
@@ -17,44 +17,40 @@ 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 { KeyboardAvoidingView, Platform, View } from "react-native";
|
||||
import React, { PropsWithChildren } from "react";
|
||||
import { KeyboardAvoidingView, Platform } from "react-native";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import useIsFloatingKeyboard from "../../hooks/use-is-floating-keyboard";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { Header } from "../header";
|
||||
import SelectionHeader from "../selection-header";
|
||||
export const Container = ({ children }) => {
|
||||
|
||||
export const Container = ({ children }: PropsWithChildren) => {
|
||||
const floating = useIsFloatingKeyboard();
|
||||
const introCompleted = useSettingStore(
|
||||
(state) => state.settings.introCompleted
|
||||
);
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
behavior="padding"
|
||||
enabled={Platform.OS === "ios" && !floating}
|
||||
style={{
|
||||
flex: 1
|
||||
flex: 1,
|
||||
overflow: "hidden",
|
||||
paddingTop: Platform.OS === "android" ? 0 : insets.top,
|
||||
paddingBottom: Platform.OS === "android" ? 0 : insets.bottom
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
overflow: "hidden",
|
||||
paddingTop: Platform.OS === "android" ? 0 : insets.top,
|
||||
paddingBottom: Platform.OS === "android" ? 0 : insets.bottom
|
||||
}}
|
||||
>
|
||||
{!introCompleted ? null : (
|
||||
<>
|
||||
<SelectionHeader />
|
||||
<Header title="Header" screen="Header" />
|
||||
</>
|
||||
)}
|
||||
{!introCompleted ? null : (
|
||||
<>
|
||||
<SelectionHeader />
|
||||
<Header />
|
||||
</>
|
||||
)}
|
||||
|
||||
{children}
|
||||
</View>
|
||||
{children}
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
};
|
||||
@@ -43,7 +43,7 @@ const _Header = () => {
|
||||
);
|
||||
|
||||
const onScroll = useCallback(
|
||||
(data) => {
|
||||
(data: { x: number; y: number }) => {
|
||||
if (data.y > 150) {
|
||||
if (!hide) return;
|
||||
setHide(false);
|
||||
@@ -43,12 +43,6 @@ export const LeftMenus = () => {
|
||||
return;
|
||||
}
|
||||
Navigation.goBack();
|
||||
if (
|
||||
useNavigationStore.getState().currentScreen.name === "Signup" ||
|
||||
useNavigationStore.getState().currentScreen.name === "Login"
|
||||
) {
|
||||
tabBarRef.current.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
return isTablet && !canGoBack ? null : (
|
||||
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useRef } from "react";
|
||||
import { Platform, StyleSheet, View } from "react-native";
|
||||
//@ts-ignore
|
||||
import Menu from "react-native-reanimated-material-menu";
|
||||
import { notesnook } from "../../../e2e/test.ids";
|
||||
import Navigation from "../../services/navigation";
|
||||
@@ -35,10 +36,13 @@ export const RightMenus = () => {
|
||||
const { colors } = useThemeColors();
|
||||
const { colors: contextMenuColors } = useThemeColors("contextMenu");
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
const rightButtons = useNavigationStore((state) => state.headerRightButtons);
|
||||
const buttons = useNavigationStore((state) => state.headerRightButtons);
|
||||
const currentScreen = useNavigationStore((state) => state.currentScreen.name);
|
||||
const buttonAction = useNavigationStore((state) => state.buttonAction);
|
||||
const menuRef = useRef();
|
||||
const menuRef = useRef<{
|
||||
show: () => void;
|
||||
hide: () => void;
|
||||
}>();
|
||||
|
||||
return (
|
||||
<View style={styles.rightBtnContainer}>
|
||||
@@ -46,9 +50,12 @@ export const RightMenus = () => {
|
||||
<IconButton
|
||||
onPress={async () => {
|
||||
SearchService.prepareSearch();
|
||||
Navigation.navigate({
|
||||
name: "Search"
|
||||
});
|
||||
Navigation.navigate(
|
||||
{
|
||||
name: "Search"
|
||||
},
|
||||
{}
|
||||
);
|
||||
}}
|
||||
testID="icon-search"
|
||||
name="magnify"
|
||||
@@ -82,7 +89,7 @@ export const RightMenus = () => {
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{rightButtons && rightButtons.length > 0 ? (
|
||||
{buttons && buttons.length > 0 ? (
|
||||
<Menu
|
||||
ref={menuRef}
|
||||
animationDuration={200}
|
||||
@@ -104,7 +111,7 @@ export const RightMenus = () => {
|
||||
/>
|
||||
}
|
||||
>
|
||||
{rightButtons.map((item) => (
|
||||
{buttons.map((item) => (
|
||||
<Button
|
||||
style={{
|
||||
width: 150,
|
||||
@@ -17,8 +17,9 @@ 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, useState } from "react";
|
||||
import { Platform, View } from "react-native";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { Platform } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
import Notebook from "../../screens/notebook";
|
||||
import {
|
||||
@@ -26,14 +27,12 @@ import {
|
||||
eUnSubscribeEvent
|
||||
} from "../../services/event-manager";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { eScrollEvent } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import { useCallback } from "react";
|
||||
import Tag from "../ui/tag";
|
||||
import Heading from "../ui/typography/heading";
|
||||
|
||||
const titleState = {};
|
||||
const titleState: { [name: string]: boolean } = {};
|
||||
|
||||
export const Title = () => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -42,12 +41,12 @@ export const Title = () => {
|
||||
const isTopic = currentScreen?.name === "TopicNotes";
|
||||
const [hide, setHide] = useState(
|
||||
isNotebook
|
||||
? typeof titleState[currentScreen.id] === "boolean"
|
||||
? titleState[currentScreen.id]
|
||||
? typeof titleState[currentScreen.id as string] === "boolean"
|
||||
? titleState[currentScreen.id as string]
|
||||
: true
|
||||
: false
|
||||
);
|
||||
const isHidden = titleState[currentScreen.id];
|
||||
const isHidden = titleState[currentScreen.id as string];
|
||||
const notebook =
|
||||
isTopic && currentScreen.notebookId
|
||||
? db.notebooks?.notebook(currentScreen.notebookId)?.data
|
||||
@@ -56,18 +55,18 @@ export const Title = () => {
|
||||
const isTag = currentScreen?.name === "TaggedNotes";
|
||||
|
||||
const onScroll = useCallback(
|
||||
(data) => {
|
||||
(data: { x: number; y: number }) => {
|
||||
if (currentScreen.name !== "Notebook") {
|
||||
setHide(false);
|
||||
return;
|
||||
}
|
||||
if (data.y > 150) {
|
||||
if (!hide) return;
|
||||
titleState[currentScreen.id] = false;
|
||||
titleState[currentScreen.id as string] = false;
|
||||
setHide(false);
|
||||
} else {
|
||||
if (hide) return;
|
||||
titleState[currentScreen.id] = true;
|
||||
titleState[currentScreen.id as string] = true;
|
||||
setHide(true);
|
||||
}
|
||||
},
|
||||
@@ -76,13 +75,13 @@ export const Title = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (currentScreen.name === "Notebook") {
|
||||
let value =
|
||||
typeof titleState[currentScreen.id] === "boolean"
|
||||
? titleState[currentScreen.id]
|
||||
const value =
|
||||
typeof titleState[currentScreen.id as string] === "boolean"
|
||||
? titleState[currentScreen.id as string]
|
||||
: true;
|
||||
setHide(value);
|
||||
} else {
|
||||
setHide(titleState[currentScreen.id]);
|
||||
setHide(titleState[currentScreen.id as string]);
|
||||
}
|
||||
}, [currentScreen.id, currentScreen.name]);
|
||||
|
||||
@@ -98,14 +97,7 @@ export const Title = () => {
|
||||
Notebook.navigate(notebook, true);
|
||||
}
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
opacity: 1,
|
||||
flexShrink: 1,
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<>
|
||||
{!hide && !isHidden ? (
|
||||
<Heading
|
||||
onPress={navigateToNotebook}
|
||||
@@ -122,10 +114,17 @@ export const Title = () => {
|
||||
#
|
||||
</Heading>
|
||||
) : null}
|
||||
{title}
|
||||
{title}{" "}
|
||||
<Tag
|
||||
visible={currentScreen.beta}
|
||||
text="BETA"
|
||||
style={{
|
||||
backgroundColor: "transparent"
|
||||
}}
|
||||
textColor={colors.primary.accent}
|
||||
/>
|
||||
</Heading>
|
||||
) : null}
|
||||
<Tag visible={currentScreen.beta} text="BETA" />
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Sodium from "@ammarahmed/react-native-sodium";
|
||||
import dataurl from "@notesnook/core/utils/dataurl";
|
||||
import dataurl from "@notesnook/core/dist/utils/dataurl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Platform, View } from "react-native";
|
||||
|
||||
@@ -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 { getUpcomingReminder } from "@notesnook/core/collections/reminders";
|
||||
import { getUpcomingReminder } from "@notesnook/core/dist/collections/reminders";
|
||||
import { decode, EntityLevel } from "entities";
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
@@ -40,6 +40,7 @@ import { TimeSince } from "../../ui/time-since";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
|
||||
import { useEditorStore } from "../../../stores/use-editor-store";
|
||||
|
||||
function navigateToTag(item) {
|
||||
const tag = db.tags.tag(item.id);
|
||||
@@ -98,6 +99,9 @@ const NoteItem = ({
|
||||
dateBy = "dateCreated",
|
||||
noOpen = false
|
||||
}) => {
|
||||
const currentEditingNote = useEditorStore(
|
||||
(state) => state.currentEditingNote
|
||||
);
|
||||
const { colors } = useThemeColors();
|
||||
const compactMode = useIsCompactModeEnabled(item);
|
||||
const attachmentCount = db.attachments?.ofNote(item.id, "all")?.length || 0;
|
||||
@@ -108,6 +112,9 @@ const NoteItem = ({
|
||||
const reminder = getUpcomingReminder(reminders);
|
||||
const noteColor = ColorValues[item.color?.toLowerCase()];
|
||||
const tags = getTags(item);
|
||||
const primaryColors =
|
||||
currentEditingNote === item.id ? colors.selected : colors.primary;
|
||||
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
@@ -148,7 +155,7 @@ const NoteItem = ({
|
||||
borderRadius: 5,
|
||||
marginRight: 5,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.primary.border,
|
||||
borderColor: primaryColors.border,
|
||||
paddingHorizontal: 6,
|
||||
marginBottom: 5
|
||||
}}
|
||||
@@ -179,7 +186,7 @@ const NoteItem = ({
|
||||
<Paragraph
|
||||
numberOfLines={1}
|
||||
color={
|
||||
ColorValues[item.color?.toLowerCase()] || colors.primary.heading
|
||||
ColorValues[item.color?.toLowerCase()] || primaryColors.heading
|
||||
}
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
@@ -192,7 +199,7 @@ const NoteItem = ({
|
||||
<Heading
|
||||
numberOfLines={1}
|
||||
color={
|
||||
ColorValues[item.color?.toLowerCase()] || colors.primary.heading
|
||||
ColorValues[item.color?.toLowerCase()] || primaryColors.heading
|
||||
}
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
@@ -208,6 +215,7 @@ const NoteItem = ({
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
color={primaryColors.paragraph}
|
||||
numberOfLines={2}
|
||||
>
|
||||
{decode(item.headline, {
|
||||
@@ -262,7 +270,7 @@ const NoteItem = ({
|
||||
<Icon
|
||||
name="attachment"
|
||||
size={SIZE.md}
|
||||
color={colors.primary.icon}
|
||||
color={primaryColors.icon}
|
||||
/>
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
@@ -283,7 +291,7 @@ const NoteItem = ({
|
||||
}}
|
||||
color={
|
||||
ColorValues[item.color?.toLowerCase()] ||
|
||||
colors.primary.accent
|
||||
primaryColors.accent
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
@@ -296,7 +304,7 @@ const NoteItem = ({
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
color={colors.primary.icon}
|
||||
color={primaryColors.icon}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -354,7 +362,7 @@ const NoteItem = ({
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph
|
||||
color={colors.primary.accent}
|
||||
color={primaryColors.accent}
|
||||
size={SIZE.xs}
|
||||
style={{
|
||||
marginRight: 6
|
||||
@@ -424,7 +432,7 @@ const NoteItem = ({
|
||||
|
||||
<IconButton
|
||||
testID={notesnook.listitem.menu}
|
||||
color={colors.primary.paragraph}
|
||||
color={primaryColors.paragraph}
|
||||
name="dots-horizontal"
|
||||
size={SIZE.xl}
|
||||
onPress={() => !noOpen && showActionSheet(item, isTrash)}
|
||||
|
||||
@@ -53,15 +53,10 @@ const renderItems = {
|
||||
const RenderItem = ({ item, index, type, ...restArgs }) => {
|
||||
if (!item) return <View />;
|
||||
const Item = renderItems[item.itemType || item.type] || View;
|
||||
const groupOptions = db.settings?.getGroupOptions(type);
|
||||
const dateBy =
|
||||
groupOptions.sortBy !== "title" ? groupOptions.sortBy : "dateEdited";
|
||||
const totalNotes = getTotalNotes(item);
|
||||
|
||||
return (
|
||||
<Item
|
||||
item={item}
|
||||
dateBy={dateBy}
|
||||
index={index}
|
||||
type={type}
|
||||
totalNotes={totalNotes}
|
||||
@@ -103,6 +98,12 @@ const List = ({
|
||||
(type === "notes" && notesListMode === "compact") ||
|
||||
type === "notebooks" ||
|
||||
notebooksListMode === "compact";
|
||||
const groupType =
|
||||
screen === "Notes" ? "home" : screen === "Favorites" ? "favorites" : type;
|
||||
|
||||
const groupOptions = db.settings?.getGroupOptions(groupType);
|
||||
const dateBy =
|
||||
groupOptions.sortBy !== "title" ? groupOptions.sortBy : "dateEdited";
|
||||
|
||||
const renderItem = React.useCallback(
|
||||
({ item, index }) => (
|
||||
@@ -111,6 +112,7 @@ const List = ({
|
||||
index={index}
|
||||
color={headerProps?.color}
|
||||
title={headerProps?.heading}
|
||||
dateBy={dateBy}
|
||||
type={
|
||||
screen === "Notes"
|
||||
? "home"
|
||||
@@ -122,7 +124,7 @@ const List = ({
|
||||
isSheet={isSheet}
|
||||
/>
|
||||
),
|
||||
[headerProps?.color, headerProps?.heading, screen, type, isSheet]
|
||||
[headerProps?.color, headerProps?.heading, screen, type, isSheet, dateBy]
|
||||
);
|
||||
|
||||
const _onRefresh = async () => {
|
||||
|
||||
@@ -35,10 +35,14 @@ import { presentDialog } from "../../dialog/functions";
|
||||
import { Button } from "../../ui/button";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { useStoredRef } from "../../../hooks/use-stored-ref";
|
||||
|
||||
export const Issue = ({ defaultTitle, defaultBody, issueTitle }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const body = useRef(defaultBody);
|
||||
const title = useRef(defaultTitle);
|
||||
|
||||
const body = useStoredRef("issueBody", defaultBody);
|
||||
const title = useStoredRef("issueTitle", defaultTitle);
|
||||
|
||||
const user = useUserStore((state) => state.user);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const bodyRef = useRef();
|
||||
@@ -70,6 +74,8 @@ Logged in: ${user ? "yes" : "no"}`,
|
||||
});
|
||||
setLoading(false);
|
||||
eSendEvent(eCloseSheet);
|
||||
body.reset();
|
||||
title.reset();
|
||||
await sleep(300);
|
||||
presentDialog({
|
||||
title: "Issue reported",
|
||||
|
||||
@@ -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 { EVENTS } from "@notesnook/core/common";
|
||||
import { EVENTS } from "@notesnook/core/dist/common";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { Platform, View } from "react-native";
|
||||
import { db } from "../../../common/database";
|
||||
|
||||
@@ -64,7 +64,7 @@ export const Progress = () => {
|
||||
width={null}
|
||||
animated={true}
|
||||
useNativeDriver
|
||||
progress={currentProgress || 0.1}
|
||||
indeterminate
|
||||
unfilledColor={colors.secondary.background}
|
||||
color={colors.primary.accent}
|
||||
borderWidth={0}
|
||||
@@ -74,7 +74,7 @@ export const Progress = () => {
|
||||
{progress ? (
|
||||
<Paragraph color={colors.secondary.paragraph}>
|
||||
{progress.type?.slice(0, 1).toUpperCase() + progress.type?.slice(1)}
|
||||
ing {progress?.current}/{progress?.total}
|
||||
ing {progress?.current}
|
||||
</Paragraph>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
@@ -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 { EVENTS } from "@notesnook/core/common";
|
||||
import { EVENTS } from "@notesnook/core/dist/common";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { ActivityIndicator, Platform, View } from "react-native";
|
||||
import { FlatList } from "react-native-actions-sheet";
|
||||
@@ -377,7 +377,10 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
|
||||
height: 100
|
||||
}}
|
||||
>
|
||||
<ActivityIndicator color={colors.primary.accent} size={SIZE.lg} />
|
||||
<ActivityIndicator
|
||||
color={colors.primary.accent}
|
||||
size={SIZE.lg}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<View
|
||||
@@ -434,7 +437,9 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
|
||||
</Paragraph>
|
||||
</>
|
||||
) : (
|
||||
<Paragraph color={colors.secondary.paragraph}>No backups found</Paragraph>
|
||||
<Paragraph color={colors.secondary.paragraph}>
|
||||
No backups found
|
||||
</Paragraph>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ import {
|
||||
import { normalize, SIZE } from "../../../utils/size";
|
||||
import { GroupHeader, NotebookType, TopicType } from "../../../utils/types";
|
||||
|
||||
import { groupArray } from "@notesnook/core/utils/grouping";
|
||||
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";
|
||||
|
||||
@@ -17,20 +17,18 @@ 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, useState } from "react";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import ToggleSwitch from "toggle-switch-react-native";
|
||||
import Navigation from "../../services/navigation";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { normalize, SIZE } from "../../utils/size";
|
||||
import { SIZE, normalize } from "../../utils/size";
|
||||
import { Button } from "../ui/button";
|
||||
import { PressableButton } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
import Tag from "../ui/tag";
|
||||
|
||||
export const MenuItem = React.memo(
|
||||
function MenuItem({ item, index, testID, rightBtn }) {
|
||||
@@ -40,6 +38,7 @@ export const MenuItem = React.memo(
|
||||
);
|
||||
const screenId = item.name.toLowerCase() + "_navigation";
|
||||
let isFocused = headerTextState?.id === screenId;
|
||||
const primaryColors = isFocused ? colors.selected : colors.primary;
|
||||
|
||||
const _onPress = () => {
|
||||
if (item.func) {
|
||||
@@ -128,14 +127,28 @@ export const MenuItem = React.memo(
|
||||
<Paragraph size={SIZE.md}>{item.name}</Paragraph>
|
||||
)}
|
||||
|
||||
<Tag visible={item.isBeta} text="BETA" />
|
||||
{item.isBeta ? (
|
||||
<View
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
backgroundColor: primaryColors.accent,
|
||||
paddingHorizontal: 4,
|
||||
marginLeft: 5,
|
||||
paddingVertical: 2
|
||||
}}
|
||||
>
|
||||
<Paragraph color={primaryColors.accentForeground} size={SIZE.xxs}>
|
||||
BETA
|
||||
</Paragraph>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
{item.switch ? (
|
||||
<ToggleSwitch
|
||||
isOn={item.on}
|
||||
onColor={colors.primary.accent}
|
||||
offColor={colors.primary.icon}
|
||||
onColor={primaryColors.accent}
|
||||
offColor={primaryColors.icon}
|
||||
size="small"
|
||||
animationSpeed={150}
|
||||
onToggle={_onPress}
|
||||
|
||||
@@ -108,9 +108,12 @@ export const PinItem = React.memo(
|
||||
alias = item?.alias || item?.title;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [headerTextState, setHeaderTextState] = useState(null);
|
||||
const primaryColors =
|
||||
headerTextState?.id === item.id ? colors.selected : colors.primary;
|
||||
|
||||
const color =
|
||||
headerTextState?.id === item.id
|
||||
? colors.primary.accent
|
||||
? colors.selected.accent
|
||||
: colors.primary.icon;
|
||||
const fwdRef = useRef();
|
||||
|
||||
@@ -230,7 +233,7 @@ export const PinItem = React.memo(
|
||||
style={{
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
color={colors.primary.heading}
|
||||
color={primaryColors.heading}
|
||||
size={SIZE.md}
|
||||
>
|
||||
{alias}
|
||||
@@ -238,7 +241,7 @@ export const PinItem = React.memo(
|
||||
) : (
|
||||
<Paragraph
|
||||
numberOfLines={1}
|
||||
color={colors.primary.paragraph}
|
||||
color={primaryColors.paragraph}
|
||||
size={SIZE.md}
|
||||
>
|
||||
{alias}
|
||||
|
||||
@@ -135,7 +135,7 @@ export const UserStatus = () => {
|
||||
? "Last sync failed, tap to try again"
|
||||
: syncing
|
||||
? `Syncing your notes${
|
||||
progress ? ` (${progress.current}/${progress.total})` : ""
|
||||
progress ? ` (${progress.current})` : ""
|
||||
}`
|
||||
: "Tap here to sync your notes."}
|
||||
</Paragraph>
|
||||
|
||||
@@ -77,7 +77,9 @@ export const Tip = ({
|
||||
alignSelf: "flex-start",
|
||||
borderRadius: 100,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.static[color as never] || colors.primary[color as never] as string
|
||||
borderColor:
|
||||
colors.static[color as never] ||
|
||||
(colors.primary[color as never] as string)
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -139,7 +141,7 @@ export const Tip = ({
|
||||
icon={tip.button.icon}
|
||||
buttonType={{
|
||||
color: colors.static[color as never],
|
||||
text: colors.static.white
|
||||
text: colors.primary.accentForeground
|
||||
}}
|
||||
style={{
|
||||
marginTop: 10
|
||||
|
||||
@@ -108,7 +108,7 @@ export const useButton = ({
|
||||
},
|
||||
accent: {
|
||||
primary: accent || colors.primary.accent,
|
||||
text: text || colors.primary.paragraph,
|
||||
text: text || colors.primary.accentForeground,
|
||||
selected: accent || colors.primary.accent
|
||||
},
|
||||
inverted: {
|
||||
|
||||
@@ -16,7 +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 { isReminderActive } from "@notesnook/core/collections/reminders";
|
||||
import { isReminderActive } from "@notesnook/core/dist/collections/reminders";
|
||||
import React from "react";
|
||||
import { ViewStyle } from "react-native";
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ const SheetWrapper = ({
|
||||
const largeTablet = deviceMode === "tablet";
|
||||
const smallTablet = deviceMode === "smallTablet";
|
||||
const dimensions = useSettingStore((state) => state.dimensions);
|
||||
const pitchBlack = useSettingStore((state) => state.settings.pitchBlack);
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
let width = dimensions.width > 600 ? 600 : 500;
|
||||
|
||||
@@ -121,19 +120,17 @@ const SheetWrapper = ({
|
||||
}
|
||||
onClose={_onClose}
|
||||
>
|
||||
<BouncingView>
|
||||
{children}
|
||||
{bottomPadding ? (
|
||||
<View
|
||||
style={{
|
||||
height:
|
||||
Platform.OS === "ios" && insets.bottom !== 0
|
||||
? insets.bottom + 5
|
||||
: 20
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</BouncingView>
|
||||
{children}
|
||||
{bottomPadding ? (
|
||||
<View
|
||||
style={{
|
||||
height:
|
||||
Platform.OS === "ios" && insets.bottom !== 0
|
||||
? insets.bottom + 5
|
||||
: 20
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</ActionSheet>
|
||||
</ScopedThemeProvider>
|
||||
);
|
||||
|
||||
@@ -16,9 +16,9 @@ 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 { View, ViewStyle } from "react-native";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { ViewStyle } from "react-native";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import Paragraph from "../typography/paragraph";
|
||||
|
||||
@@ -37,7 +37,7 @@ export default function Tag({
|
||||
}) {
|
||||
const { colors } = useThemeColors();
|
||||
return !visible ? null : (
|
||||
<View
|
||||
<Paragraph
|
||||
style={{
|
||||
backgroundColor: background || colors.primary.accent,
|
||||
borderRadius: 100,
|
||||
@@ -46,13 +46,14 @@ export default function Tag({
|
||||
marginLeft: 2,
|
||||
marginTop: -10,
|
||||
height: 20,
|
||||
justifyContent: "center",
|
||||
textAlignVertical: "center",
|
||||
textAlign: "center",
|
||||
...style
|
||||
}}
|
||||
color={textColor || colors.primary.accentForeground}
|
||||
size={SIZE.xxs}
|
||||
>
|
||||
<Paragraph color={textColor || colors.static.white} size={SIZE.xxs}>
|
||||
{text}
|
||||
</Paragraph>
|
||||
</View>
|
||||
{text}
|
||||
</Paragraph>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 { EV, EVENTS, SYNC_CHECK_IDS } from "@notesnook/core/common";
|
||||
import { EV, EVENTS, SYNC_CHECK_IDS } from "@notesnook/core/dist/common";
|
||||
import notifee from "@notifee/react-native";
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
import React, { useCallback, useEffect, useRef } from "react";
|
||||
@@ -101,13 +101,6 @@ const onSyncAborted = () => {
|
||||
useUserStore.getState().setSyncing(false, SyncStatus.Failed);
|
||||
};
|
||||
|
||||
const onSyncProgress = ({ type, total, current }) => {
|
||||
if (type !== "download") return;
|
||||
if (total < 10 || current % 10 === 0) {
|
||||
initAfterSync();
|
||||
}
|
||||
};
|
||||
|
||||
const onFileEncryptionProgress = ({ total, progress }) => {
|
||||
useAttachmentStore
|
||||
.getState()
|
||||
@@ -167,13 +160,15 @@ const onUserSubscriptionStatusChanged = async (userStatus) => {
|
||||
useMessageStore.getState().setAnnouncement();
|
||||
};
|
||||
|
||||
const onRequestPartialSync = async (full, force) => {
|
||||
const onRequestPartialSync = async (full, force, lastSyncTime) => {
|
||||
if (SettingsService.get().disableAutoSync) return;
|
||||
DatabaseLogger.info(`onRequestPartialSync full:${full}, force:${force}`);
|
||||
DatabaseLogger.info(
|
||||
`onRequestPartialSync full:${full}, force:${force}, lastSyncTime:${lastSyncTime}`
|
||||
);
|
||||
if (full || force) {
|
||||
await Sync.run("global", force, full);
|
||||
await Sync.run("global", force, full, undefined, lastSyncTime);
|
||||
} else {
|
||||
await Sync.run("global", false, false);
|
||||
await Sync.run("global", false, false, undefined, lastSyncTime);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -253,7 +248,6 @@ export const useAppEvents = () => {
|
||||
]);
|
||||
|
||||
const syncedOnLaunch = useRef(false);
|
||||
const { isDark } = useThemeColors();
|
||||
const refValues = useRef({
|
||||
subsriptionSuccessListener: null,
|
||||
subsriptionErrorListener: null,
|
||||
@@ -278,7 +272,6 @@ export const useAppEvents = () => {
|
||||
const eventManager = db?.eventManager;
|
||||
eventSubscriptions = [
|
||||
eventManager?.subscribe(EVENTS.syncCompleted, onSyncComplete),
|
||||
eventManager?.subscribe(EVENTS.syncProgress, onSyncProgress),
|
||||
eventManager?.subscribe(
|
||||
EVENTS.databaseSyncRequested,
|
||||
onRequestPartialSync
|
||||
@@ -533,6 +526,12 @@ export const useAppEvents = () => {
|
||||
if (refValues.current?.isReconnecting || !refValues.current?.isUserReady)
|
||||
return;
|
||||
|
||||
if (useSettingStore.getState().appDidEnterBackgroundForAction) {
|
||||
useSettingStore.getState().setAppDidEnterBackgroundForAction(false);
|
||||
console.log("AppDidEnterForegroundAfterAction");
|
||||
return;
|
||||
}
|
||||
|
||||
if (SettingsService.get().sessionExpired) {
|
||||
refValues.current.isReconnecting = false;
|
||||
return;
|
||||
|
||||
52
apps/mobile/app/hooks/use-stored-ref.ts
Normal file
52
apps/mobile/app/hooks/use-stored-ref.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
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 { useRef } from "react";
|
||||
import { MMKV } from "../common/database/mmkv";
|
||||
|
||||
export function useStoredRef<T>(
|
||||
key: string,
|
||||
initialValue: T
|
||||
): {
|
||||
current: T;
|
||||
reset(): void;
|
||||
} {
|
||||
const refKey = `storedRef:${key}`;
|
||||
const value = useRef(
|
||||
MMKV.getMap<{ current: T }>(refKey)?.current || initialValue
|
||||
);
|
||||
const frameRef = useRef(0);
|
||||
|
||||
return {
|
||||
get current() {
|
||||
return value.current;
|
||||
},
|
||||
set current(next: T) {
|
||||
value.current = next;
|
||||
cancelAnimationFrame(frameRef.current);
|
||||
frameRef.current = requestAnimationFrame(() => {
|
||||
MMKV.setMap(refKey, {
|
||||
current: value.current
|
||||
});
|
||||
});
|
||||
},
|
||||
reset() {
|
||||
MMKV.removeItem(refKey);
|
||||
}
|
||||
};
|
||||
}
|
||||
49
apps/mobile/app/hooks/use-stored-state.ts
Normal file
49
apps/mobile/app/hooks/use-stored-state.ts
Normal 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 { useRef, useState } from "react";
|
||||
import { MMKV } from "../common/database/mmkv";
|
||||
|
||||
export function useStoredValue<T>(
|
||||
key: string,
|
||||
initialValue: T
|
||||
): { value: T; reset(): void } {
|
||||
const refKey = `storedState:${key}`;
|
||||
const [value, setValue] = useState<T>(
|
||||
MMKV.getMap<{ value: T }>(refKey)?.value || initialValue
|
||||
);
|
||||
const frameRef = useRef(0);
|
||||
|
||||
return {
|
||||
get value() {
|
||||
return value;
|
||||
},
|
||||
set value(next: T) {
|
||||
setValue(next);
|
||||
cancelAnimationFrame(frameRef.current);
|
||||
frameRef.current = requestAnimationFrame(() => {
|
||||
MMKV.setMap(refKey, {
|
||||
value: value
|
||||
});
|
||||
});
|
||||
},
|
||||
reset() {
|
||||
MMKV.removeItem(refKey);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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 { EVENTS } from "@notesnook/core/common";
|
||||
import { EVENTS } from "@notesnook/core/dist/common";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { db } from "../common/database";
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
import { EV, EVENTS } from "@notesnook/core/common";
|
||||
import { EV, EVENTS } from "@notesnook/core/dist/common";
|
||||
import React, {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Sodium from "@ammarahmed/react-native-sodium";
|
||||
import { isImage } from "@notesnook/core/utils/filename";
|
||||
import { isImage } from "@notesnook/core/dist/utils/filename";
|
||||
import { Platform } from "react-native";
|
||||
import RNFetchBlob from "react-native-blob-util";
|
||||
import DocumentPicker from "react-native-document-picker";
|
||||
@@ -34,6 +34,7 @@ import PremiumService from "../../../services/premium";
|
||||
import { FILE_SIZE_LIMIT, IMAGE_SIZE_LIMIT } from "../../../utils/constants";
|
||||
import { eCloseSheet } from "../../../utils/events";
|
||||
import { editorController, editorState } from "./utils";
|
||||
import { useSettingStore } from "../../../stores/use-setting-store";
|
||||
|
||||
const showEncryptionSheet = (file) => {
|
||||
presentSheet({
|
||||
@@ -62,6 +63,7 @@ const file = async (fileOptions) => {
|
||||
|
||||
let file;
|
||||
try {
|
||||
useSettingStore.getState().setAppDidEnterBackgroundForAction(true);
|
||||
file = await DocumentPicker.pick(options);
|
||||
} catch (e) {
|
||||
return;
|
||||
@@ -135,6 +137,7 @@ const file = async (fileOptions) => {
|
||||
const camera = async (options) => {
|
||||
try {
|
||||
await db.attachments.generateKey();
|
||||
useSettingStore.getState().setAppDidEnterBackgroundForAction(true);
|
||||
launchCamera(
|
||||
{
|
||||
includeBase64: true,
|
||||
@@ -156,6 +159,7 @@ const camera = async (options) => {
|
||||
const gallery = async (options) => {
|
||||
try {
|
||||
await db.attachments.generateKey();
|
||||
useSettingStore.getState().setAppDidEnterBackgroundForAction(true);
|
||||
launchImageLibrary(
|
||||
{
|
||||
includeBase64: true,
|
||||
|
||||
@@ -17,7 +17,8 @@ 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/common";
|
||||
import { getFormattedDate } from "@notesnook/common";
|
||||
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";
|
||||
@@ -31,6 +32,7 @@ import {
|
||||
openVault
|
||||
} from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import Notifications from "../../../services/notifications";
|
||||
import SettingsService from "../../../services/settings";
|
||||
import { TipManager } from "../../../services/tip-manager";
|
||||
import { useEditorStore } from "../../../stores/use-editor-store";
|
||||
@@ -52,7 +54,6 @@ import {
|
||||
makeSessionId,
|
||||
post
|
||||
} from "./utils";
|
||||
import { getFormattedDate } from "@notesnook/common";
|
||||
|
||||
export const useEditor = (
|
||||
editorId = "",
|
||||
@@ -133,13 +134,14 @@ export const useEditor = (
|
||||
|
||||
const reset = useCallback(
|
||||
async (resetState = true, resetContent = true) => {
|
||||
currentNote.current?.id && db.fs?.cancel(currentNote.current.id);
|
||||
currentNote.current?.id && db.fs?.cancel(currentNote.current.id, null);
|
||||
currentNote.current = null;
|
||||
loadedImages.current = {};
|
||||
currentContent.current = null;
|
||||
clearTimeout(timers.current["loading-images"]);
|
||||
sessionHistoryId.current = undefined;
|
||||
saveCount.current = 0;
|
||||
lock.current = false;
|
||||
useEditorStore.getState().setReadonly(false);
|
||||
resetContent && postMessage(EditorEvents.title, "");
|
||||
lastContentChangeTime.current = 0;
|
||||
@@ -234,6 +236,10 @@ export const useEditor = (
|
||||
id && useEditorStore.getState().setCurrentlyEditingNote(id);
|
||||
});
|
||||
}
|
||||
|
||||
if (Notifications.isNotePinned(id as string)) {
|
||||
Notifications.pinNote(id as string);
|
||||
}
|
||||
} else {
|
||||
noteData.contentId = note?.contentId;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
@@ -55,6 +55,7 @@ export const EditorWrapper = ({ width }) => {
|
||||
prevState.current = state;
|
||||
return;
|
||||
}
|
||||
if (useSettingStore.getState().appDidEnterBackgroundForAction) return;
|
||||
if (state === "active") {
|
||||
editorController.current.onReady();
|
||||
editorController.current.overlay(false);
|
||||
|
||||
@@ -29,6 +29,7 @@ import SettingsService from "../../services/settings";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useNoteStore } from "../../stores/use-notes-store";
|
||||
import { openEditor } from "../notes/common";
|
||||
|
||||
const prepareSearch = () => {
|
||||
SearchService.update({
|
||||
placeholder: "Type a keyword to search in notes",
|
||||
|
||||
@@ -16,7 +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 { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import { groupArray } from "@notesnook/core/dist/utils/grouping";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { db } from "../../common/database";
|
||||
import DelayLayout from "../../components/delay-layout";
|
||||
|
||||
@@ -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 { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import { groupArray } from "@notesnook/core/dist/utils/grouping";
|
||||
import React from "react";
|
||||
import NotesPage, { PLACEHOLDER_DATA } from ".";
|
||||
import { db } from "../../common/database";
|
||||
|
||||
@@ -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 { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import { groupArray } from "@notesnook/core/dist/utils/grouping";
|
||||
import React from "react";
|
||||
import NotesPage, { PLACEHOLDER_DATA } from ".";
|
||||
import { db } from "../../common/database";
|
||||
|
||||
@@ -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 { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import { groupArray } from "@notesnook/core/dist/utils/grouping";
|
||||
import React from "react";
|
||||
import NotesPage, { PLACEHOLDER_DATA } from ".";
|
||||
import { db } from "../../common/database";
|
||||
|
||||
@@ -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 { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import { groupArray } from "@notesnook/core/dist/utils/grouping";
|
||||
import React from "react";
|
||||
import NotesPage, { PLACEHOLDER_DATA } from ".";
|
||||
import { db } from "../../common/database";
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Clipboard from "@react-native-clipboard/clipboard";
|
||||
import { LogMessage } from "@notesnook/logger";
|
||||
import { format, LogLevel, logManager } from "@notesnook/core/logger";
|
||||
import { format, LogLevel, logManager } from "@notesnook/core/dist/logger";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { FlatList, Platform, TouchableOpacity, View } from "react-native";
|
||||
import * as ScopedStorage from "react-native-scoped-storage";
|
||||
|
||||
@@ -42,7 +42,8 @@ export async function verifyUser(
|
||||
negativeText: closeText || "Cancel",
|
||||
positivePress: async (value) => {
|
||||
try {
|
||||
let verified = await db.user.verifyPassword(value);
|
||||
const user = await db.user.getUser();
|
||||
let verified = !user ? true : await db.user.verifyPassword(value);
|
||||
if (verified) {
|
||||
sleep(300).then(async () => {
|
||||
await onsuccess();
|
||||
@@ -58,7 +59,7 @@ export async function verifyUser(
|
||||
}
|
||||
} catch (e) {
|
||||
ToastEvent.show({
|
||||
heading: "Failed to backup data",
|
||||
heading: "Failed to verify",
|
||||
message: e.message,
|
||||
type: "error",
|
||||
context: "global"
|
||||
|
||||
@@ -87,12 +87,6 @@ const Home = ({
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Heading color={colors.primary.heading} size={SIZE.lg}>
|
||||
Logging out
|
||||
</Heading>
|
||||
<Paragraph color={colors.secondary.icon}>
|
||||
Please wait while we log out and clear app data.
|
||||
</Paragraph>
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
|
||||
@@ -27,6 +27,8 @@ import PremiumService from "../../../services/premium";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { sleep } from "../../../utils/time";
|
||||
import { verifyUser } from "../functions";
|
||||
import { Dialog } from "../../../components/dialog";
|
||||
|
||||
interface PickerOptions<T> {
|
||||
getValue: () => T;
|
||||
@@ -37,6 +39,7 @@ interface PickerOptions<T> {
|
||||
options: T[];
|
||||
premium?: boolean;
|
||||
onCheckOptionIsPremium?: (item: T) => boolean;
|
||||
requiresVerification?: () => boolean;
|
||||
}
|
||||
|
||||
export function SettingsPicker<T>({
|
||||
@@ -47,7 +50,8 @@ export function SettingsPicker<T>({
|
||||
options,
|
||||
getItemKey,
|
||||
premium,
|
||||
onCheckOptionIsPremium = () => true
|
||||
onCheckOptionIsPremium = () => true,
|
||||
requiresVerification = () => false
|
||||
}: PickerOptions<T>) {
|
||||
const { colors } = useThemeColors("contextMenu");
|
||||
const menuRef = useRef<any>();
|
||||
@@ -118,11 +122,18 @@ export function SettingsPicker<T>({
|
||||
</PressableButton>
|
||||
}
|
||||
>
|
||||
<Dialog context="local" />
|
||||
{options.map((item) => (
|
||||
<MenuItem
|
||||
key={getItemKey(item)}
|
||||
onPress={async () => {
|
||||
onChange(item);
|
||||
if (requiresVerification?.()) {
|
||||
verifyUser("local", () => {
|
||||
onChange(item);
|
||||
});
|
||||
} else {
|
||||
onChange(item);
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
backgroundColor: compareValue(currentValue, item)
|
||||
|
||||
@@ -24,8 +24,9 @@ import { useSettingStore } from "../../../stores/use-setting-store";
|
||||
import { MenuItemsList } from "../../../utils/menu-items";
|
||||
import { createSettingsPicker } from ".";
|
||||
import { getFontById, getFonts } from "@notesnook/editor/dist/utils/font";
|
||||
import { DATE_FORMATS, TIME_FORMATS } from "@notesnook/core/common";
|
||||
import { DATE_FORMATS, TIME_FORMATS } from "@notesnook/core/dist/common";
|
||||
import dayjs from "dayjs";
|
||||
import { useUserStore } from "../../../stores/use-user-store";
|
||||
|
||||
export const FontPicker = createSettingsPicker({
|
||||
getValue: () => useSettingStore.getState().settings.defaultFontFamily,
|
||||
@@ -127,6 +128,12 @@ export const BackupReminderPicker = createSettingsPicker({
|
||||
options: ["useroff", "daily", "weekly", "monthly"],
|
||||
compareValue: (current, item) => current === item,
|
||||
premium: true,
|
||||
requiresVerification: () => {
|
||||
return (
|
||||
!useSettingStore.getState().settings.encryptedBackup &&
|
||||
useUserStore.getState().user
|
||||
);
|
||||
},
|
||||
onCheckOptionIsPremium: (item) => {
|
||||
return item !== "useroff";
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ 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 { ThemeDark, ThemePitchBlack } from "@notesnook/theme";
|
||||
import notifee from "@notifee/react-native";
|
||||
import dayjs from "dayjs";
|
||||
import React from "react";
|
||||
@@ -288,9 +287,9 @@ export const settingsGroups: SettingSection[] = [
|
||||
positiveText: "Logout",
|
||||
positivePress: async () => {
|
||||
try {
|
||||
eSendEvent("settings-loading", true);
|
||||
setImmediate(async () => {
|
||||
eSendEvent(eCloseSimpleDialog);
|
||||
eSendEvent(eCloseSimpleDialog);
|
||||
setTimeout(async () => {
|
||||
eSendEvent("settings-loading", true);
|
||||
Navigation.popToTop();
|
||||
await db.user?.logout();
|
||||
setLoginMessage();
|
||||
@@ -306,7 +305,7 @@ export const settingsGroups: SettingSection[] = [
|
||||
setTimeout(() => {
|
||||
eSendEvent("settings-loading", false);
|
||||
}, 2000);
|
||||
});
|
||||
}, 300);
|
||||
} catch (e) {
|
||||
ToastEvent.error(e as Error, "Error logging out");
|
||||
eSendEvent("settings-loading", false);
|
||||
@@ -783,10 +782,11 @@ export const settingsGroups: SettingSection[] = [
|
||||
description: "Create a backup of your data",
|
||||
modifer: async () => {
|
||||
const user = useUserStore.getState().user;
|
||||
if (!user) {
|
||||
if (!user || SettingsService.getProperty("encryptedBackup")) {
|
||||
await BackupService.run(true);
|
||||
return;
|
||||
}
|
||||
|
||||
verifyUser(null, () => BackupService.run(true));
|
||||
}
|
||||
},
|
||||
@@ -870,9 +870,17 @@ export const settingsGroups: SettingSection[] = [
|
||||
});
|
||||
return;
|
||||
}
|
||||
SettingsService.set({
|
||||
encryptedBackup: !settings.encryptedBackup
|
||||
});
|
||||
if (settings.encryptedBackup) {
|
||||
await verifyUser(null, () => {
|
||||
SettingsService.set({
|
||||
encryptedBackup: false
|
||||
});
|
||||
});
|
||||
} else {
|
||||
SettingsService.set({
|
||||
encryptedBackup: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -902,7 +910,9 @@ export const settingsGroups: SettingSection[] = [
|
||||
description:
|
||||
"Export all notes as pdf, markdown, html or text in a single zip file",
|
||||
modifer: () => {
|
||||
ExportNotesSheet.present(undefined, true);
|
||||
verifyUser(null, () => {
|
||||
ExportNotesSheet.present(undefined, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -748,7 +748,7 @@ const ThemeSetter = ({
|
||||
paddingVertical: 12
|
||||
}}
|
||||
>
|
||||
<Heading color={colors.accent} size={SIZE.md}>
|
||||
<Heading color={colors.accentForeground} size={SIZE.md}>
|
||||
{darkTheme.id === theme.id
|
||||
? "Applied as dark theme"
|
||||
: "Applied as light theme"}
|
||||
|
||||
@@ -114,7 +114,7 @@ export const Trash = ({ navigation, route }: NavigationProps<"Trash">) => {
|
||||
<FloatingButton
|
||||
title="Clear all trash"
|
||||
onPress={onPressFloatingButton}
|
||||
shouldShow={true}
|
||||
alwaysVisible={true}
|
||||
/>
|
||||
) : null}
|
||||
</DelayLayout>
|
||||
|
||||
@@ -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 EventManager from "@notesnook/core/utils/event-manager";
|
||||
import EventManager from "@notesnook/core/dist/utils/event-manager";
|
||||
import Clipboard from "@react-native-clipboard/clipboard";
|
||||
import { RefObject } from "react";
|
||||
import { ActionSheetRef } from "react-native-actions-sheet";
|
||||
|
||||
@@ -46,6 +46,8 @@ import { useRelationStore } from "../stores/use-relation-store";
|
||||
import { useReminderStore } from "../stores/use-reminder-store";
|
||||
import { presentDialog } from "../components/dialog/functions";
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
import { encodeNonAsciiHTML } from "entities";
|
||||
import { convertNoteToText } from "../utils/note-to-text";
|
||||
|
||||
export type Reminder = {
|
||||
id: string;
|
||||
@@ -86,6 +88,28 @@ async function getNextMonthlyReminderDate(
|
||||
return await getNextMonthlyReminderDate(reminder, dayjs().year() + 1);
|
||||
}
|
||||
|
||||
export function textToHTML(src: string) {
|
||||
return src
|
||||
.split(/[\r\n]/)
|
||||
.map((line) =>
|
||||
line
|
||||
? `<p data-spacing="single">${encodeLine(line)}</p>`
|
||||
: `<p data-spacing="single"></p>`
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
function encodeLine(line: string) {
|
||||
line = encodeNonAsciiHTML(line);
|
||||
line = line.replace(/(^ +)|( {2,})/g, (sub, ...args) => {
|
||||
const [starting, inline] = args;
|
||||
if (starting) return " ".repeat(starting.length);
|
||||
if (inline) return " ".repeat(inline.length);
|
||||
return sub;
|
||||
});
|
||||
return line;
|
||||
}
|
||||
|
||||
async function initDatabase(notes = true) {
|
||||
if (!db.isInitialized) {
|
||||
await db.initCollections();
|
||||
@@ -117,6 +141,7 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
const ReminderNotify =
|
||||
require("../components/sheets/reminder-notify").default;
|
||||
ReminderNotify.present(reminder);
|
||||
useRelationStore.getState().update();
|
||||
return;
|
||||
}
|
||||
editorState().movedAway = false;
|
||||
@@ -206,16 +231,41 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
});
|
||||
if (!db.isInitialized) await db.init();
|
||||
await db.notes?.init();
|
||||
await db.notes?.add({
|
||||
|
||||
const id = await db.notes?.add({
|
||||
content: {
|
||||
type: "tiptap",
|
||||
data: `<p>${input} </p>`
|
||||
data: textToHTML(input as string)
|
||||
}
|
||||
});
|
||||
|
||||
const defaultNotebook = db.settings?.getDefaultNotebook();
|
||||
|
||||
if (defaultNotebook) {
|
||||
if (!defaultNotebook.topic) {
|
||||
await db.relations?.add(
|
||||
{ type: "notebook", id: defaultNotebook.id },
|
||||
{ type: "note", id: id }
|
||||
);
|
||||
} else {
|
||||
await db.notes?.addToNotebook(
|
||||
{
|
||||
topic: defaultNotebook.topic,
|
||||
id: defaultNotebook?.id
|
||||
},
|
||||
id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const status = await NetInfo.fetch();
|
||||
if (status.isInternetReachable) {
|
||||
try {
|
||||
await db.sync(false, false);
|
||||
if (!globalThis["IS_MAIN_APP_RUNNING" as never]) {
|
||||
await db.sync(false, false);
|
||||
} else {
|
||||
console.log("main app running, skipping sync");
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e, (e as Error).stack);
|
||||
}
|
||||
@@ -757,6 +807,11 @@ function getPinnedNotes(): DisplayedNotification[] {
|
||||
return pinned;
|
||||
}
|
||||
|
||||
function isNotePinned(id: string) {
|
||||
if (Platform.OS !== "android") return false;
|
||||
return pinned.findIndex((notification) => notification.id === id) > -1;
|
||||
}
|
||||
|
||||
function get(): Promise<DisplayedNotification[]> {
|
||||
return new Promise((resolve) => {
|
||||
if (Platform.OS === "ios") resolve([]);
|
||||
@@ -844,6 +899,26 @@ async function setupReminders(checkNeedsScheduling = false) {
|
||||
);
|
||||
}
|
||||
|
||||
async function pinNote(id: string) {
|
||||
try {
|
||||
const note = db.notes?.note(id as string) as any;
|
||||
let text = await convertNoteToText(note as any, false);
|
||||
if (!text) text = "";
|
||||
let html = text.replace(/\n/g, "<br />");
|
||||
Notifications.displayNotification({
|
||||
title: note.title,
|
||||
message: note.headline || text,
|
||||
subtitle: note.headline || text,
|
||||
bigText: html,
|
||||
ongoing: true,
|
||||
actions: ["UNPIN"],
|
||||
id: note.id
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
const Notifications = {
|
||||
init,
|
||||
displayNotification,
|
||||
@@ -859,7 +934,9 @@ const Notifications = {
|
||||
checkAndRequestPermissions,
|
||||
clearAllTriggers,
|
||||
setupReminders,
|
||||
getChannelId
|
||||
getChannelId,
|
||||
isNotePinned,
|
||||
pinNote
|
||||
};
|
||||
|
||||
export default Notifications;
|
||||
|
||||
@@ -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 { CHECK_IDS } from "@notesnook/core/common";
|
||||
import { CHECK_IDS } from "@notesnook/core/dist/common";
|
||||
import React from "react";
|
||||
import { Platform } from "react-native";
|
||||
import Config from "react-native-config";
|
||||
|
||||
@@ -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 { EVENTS } from "@notesnook/core/common";
|
||||
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";
|
||||
@@ -39,8 +39,14 @@ const run = async (
|
||||
context = "global",
|
||||
forced = false,
|
||||
full = true,
|
||||
onCompleted
|
||||
onCompleted,
|
||||
lastSyncTime
|
||||
) => {
|
||||
if (useUserStore.getState().syncing) {
|
||||
DatabaseLogger.log("Sync in progress");
|
||||
console.log("Sync in progress");
|
||||
return;
|
||||
}
|
||||
clearTimeout(syncTimer);
|
||||
syncTimer = setTimeout(async () => {
|
||||
const status = await NetInfo.fetch();
|
||||
@@ -63,7 +69,7 @@ const run = async (
|
||||
try {
|
||||
let res = await BackgroundSync.doInBackground(async () => {
|
||||
try {
|
||||
await db.sync(full, forced);
|
||||
await db.sync(full, forced, lastSyncTime);
|
||||
return true;
|
||||
} catch (e) {
|
||||
error = e;
|
||||
|
||||
@@ -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 { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import { groupArray } from "@notesnook/core/dist/utils/grouping";
|
||||
import create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import { NoteType } from "../utils/types";
|
||||
|
||||
@@ -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 { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import { groupArray } from "@notesnook/core/dist/utils/grouping";
|
||||
import create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import { NotebookType } from "../utils/types";
|
||||
|
||||
@@ -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 { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import { groupArray } from "@notesnook/core/dist/utils/grouping";
|
||||
import create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import { NoteType } from "../utils/types";
|
||||
|
||||
@@ -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 { groupReminders } from "@notesnook/core/utils/grouping";
|
||||
import { groupReminders } from "@notesnook/core/dist/utils/grouping";
|
||||
import create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import { Reminder } from "../services/notifications";
|
||||
|
||||
@@ -103,6 +103,8 @@ export interface SettingStore extends State {
|
||||
sheetKeyboardHandler: boolean;
|
||||
requestBiometrics: boolean;
|
||||
setRequestBiometrics: (requestBiometrics: boolean) => void;
|
||||
appDidEnterBackgroundForAction: boolean;
|
||||
setAppDidEnterBackgroundForAction: (value: boolean) => void;
|
||||
insets: Insets;
|
||||
setInsets: (insets: Insets) => void;
|
||||
timeFormat: string;
|
||||
@@ -155,7 +157,7 @@ export const defaultSettings: SettingStore["settings"] = {
|
||||
darkTheme: ThemeDark
|
||||
};
|
||||
|
||||
export const useSettingStore = create<SettingStore>((set) => ({
|
||||
export const useSettingStore = create<SettingStore>((set, get) => ({
|
||||
settings: { ...defaultSettings },
|
||||
sheetKeyboardHandler: true,
|
||||
fullscreen: false,
|
||||
@@ -174,6 +176,12 @@ export const useSettingStore = create<SettingStore>((set) => ({
|
||||
setInsets: (insets) => set({ insets }),
|
||||
timeFormat: "12-hour",
|
||||
dateFormat: "DD-MM-YYYY",
|
||||
setAppDidEnterBackgroundForAction: (value: boolean) => {
|
||||
set({
|
||||
appDidEnterBackgroundForAction: value
|
||||
});
|
||||
},
|
||||
appDidEnterBackgroundForAction: false,
|
||||
insets: initialWindowMetrics?.insets
|
||||
? initialWindowMetrics.insets
|
||||
: { top: 0, right: 0, left: 0, bottom: 0 }
|
||||
|
||||
@@ -17,8 +17,8 @@ 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 "@notesnook/core/types";
|
||||
import { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import "@notesnook/core/dist/types";
|
||||
import { groupArray } from "@notesnook/core/dist/utils/grouping";
|
||||
import create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import { TagType } from "../utils/types";
|
||||
|
||||
@@ -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 { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import { groupArray } from "@notesnook/core/dist/utils/grouping";
|
||||
import create, { State } from "zustand";
|
||||
import { db } from "../common/database";
|
||||
import { TrashType } from "../utils/types";
|
||||
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Sodium from "@ammarahmed/react-native-sodium";
|
||||
import { isImage } from "@notesnook/core/utils/filename";
|
||||
import { isImage } from "@notesnook/core/dist/utils/filename";
|
||||
import { Platform } from "react-native";
|
||||
import RNFetchBlob from "react-native-blob-util";
|
||||
import { db } from "../common/database";
|
||||
|
||||
@@ -111,7 +111,7 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
multiDexEnabled true
|
||||
versionCode 2057
|
||||
versionCode 2059
|
||||
versionName getNpmVersion()
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
- Added support for custom themes
|
||||
- Syntax highlighting and rendered Math in exports
|
||||
- Improved copy/pasting to and from Notesnook
|
||||
- Support copying link & link text in directly from the Link toolbar
|
||||
- Many other bug fixes and performance improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
|
||||
- Much improved and faster sync
|
||||
- Note pinned in notifications will update automatically when content changes
|
||||
- Quick notes from notifications now respect paragraph spacing settings.
|
||||
- Many bug fixes and small improvements
|
||||
@@ -6,6 +6,7 @@ const configs = {
|
||||
plugins: [
|
||||
'@babel/plugin-transform-named-capturing-groups-regex',
|
||||
'react-native-reanimated/plugin',
|
||||
"@babel/plugin-transform-export-namespace-from"
|
||||
]
|
||||
},
|
||||
test: {
|
||||
@@ -22,6 +23,7 @@ const configs = {
|
||||
'transform-remove-console',
|
||||
'@babel/plugin-transform-named-capturing-groups-regex',
|
||||
'react-native-reanimated/plugin',
|
||||
"@babel/plugin-transform-export-namespace-from"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
<dict>
|
||||
<key>NSExtensionActivationRule</key>
|
||||
<dict>
|
||||
<key>NSExtensionActivationDictionaryVersion</key>
|
||||
<integer>2</integer>
|
||||
<key>NSExtensionActivationSupportsFileWithMaxCount</key>
|
||||
<integer>5</integer>
|
||||
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
||||
|
||||
@@ -997,7 +997,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2050;
|
||||
CURRENT_PROJECT_VERSION = 2053;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1071,7 +1071,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
MARKETING_VERSION = 2.6.3;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -1102,7 +1102,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 2050;
|
||||
CURRENT_PROJECT_VERSION = 2053;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1176,7 +1176,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
MARKETING_VERSION = 2.6.3;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -1335,7 +1335,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2050;
|
||||
CURRENT_PROJECT_VERSION = 2053;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1347,7 +1347,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
MARKETING_VERSION = 2.6.3;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
@@ -1378,7 +1378,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2050;
|
||||
CURRENT_PROJECT_VERSION = 2053;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
@@ -1391,7 +1391,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
MARKETING_VERSION = 2.6.3;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1421,7 +1421,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2050;
|
||||
CURRENT_PROJECT_VERSION = 2053;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1495,7 +1495,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
MARKETING_VERSION = 2.6.3;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
@@ -1526,7 +1526,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2050;
|
||||
CURRENT_PROJECT_VERSION = 2053;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
@@ -1601,7 +1601,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
MARKETING_VERSION = 2.6.3;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "NSZombieEnabled"
|
||||
value = "YES"
|
||||
value = "NO"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
@@ -77,13 +77,6 @@
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<AdditionalOptions>
|
||||
<AdditionalOption
|
||||
key = "NSZombieEnabled"
|
||||
value = "YES"
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -153,5 +153,7 @@
|
||||
</array>
|
||||
<key>appGroupId</key>
|
||||
<string>group.org.streetwriters.notesnook</string>
|
||||
<key>disableMMKVBackup</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -19,9 +19,9 @@ PODS:
|
||||
- glog (0.3.5)
|
||||
- GZIP (1.3.0)
|
||||
- JWTDecode (3.0.1)
|
||||
- MMKV (1.2.13):
|
||||
- MMKVCore (~> 1.2.13)
|
||||
- MMKVCore (1.2.13)
|
||||
- MMKV (1.3.1):
|
||||
- MMKVCore (~> 1.3.1)
|
||||
- MMKVCore (1.3.1)
|
||||
- pop (1.0.12)
|
||||
- RCT-Folly (2021.07.22.00):
|
||||
- boost
|
||||
@@ -313,7 +313,7 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-get-random-values (1.9.0):
|
||||
- React-Core
|
||||
- react-native-gzip (1.0.0):
|
||||
- react-native-gzip (1.1.0):
|
||||
- Base64
|
||||
- GZIP
|
||||
- React-Core
|
||||
@@ -327,8 +327,9 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-keep-awake (1.2.0):
|
||||
- React-Core
|
||||
- react-native-mmkv-storage (0.9.1):
|
||||
- MMKV (= 1.2.13)
|
||||
- react-native-mmkv-storage (0.10.0-alpha.7):
|
||||
- MMKV (~> 1.3.1)
|
||||
- React
|
||||
- React-Core
|
||||
- react-native-netinfo (9.3.10):
|
||||
- React-Core
|
||||
@@ -346,7 +347,7 @@ PODS:
|
||||
- ReactCommon/turbomodule/core
|
||||
- react-native-share-extension (2.5.6):
|
||||
- React
|
||||
- react-native-sodium (1.4.1):
|
||||
- react-native-sodium (1.5.2):
|
||||
- React
|
||||
- react-native-webview (11.26.1):
|
||||
- React-Core
|
||||
@@ -841,8 +842,8 @@ SPEC CHECKSUMS:
|
||||
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
|
||||
GZIP: 416858efbe66b41b206895ac6dfd5493200d95b3
|
||||
JWTDecode: 2eed97c2fa46ccaf3049a787004eedf0be474a87
|
||||
MMKV: aac95d817a100479445633f2b3ed8961b4ac5043
|
||||
MMKVCore: 3388952ded307e41b3ed8a05892736a236ed1b8e
|
||||
MMKV: 5a07930c70c70b86cd87761a42c8f3836fb681d7
|
||||
MMKVCore: e50135dbd33235b6ab390635991bab437ab873c0
|
||||
pop: d582054913807fd11fd50bfe6a539d91c7e1a55a
|
||||
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
|
||||
RCTRequired: 656ef0536dd60a9740961ade6a64ba0cb0572d2b
|
||||
@@ -868,20 +869,20 @@ SPEC CHECKSUMS:
|
||||
react-native-document-picker: ec07866a30707f23660c0f3ae591d669d3e89096
|
||||
react-native-fingerprint-scanner: be63e626b31fb951780a5fac5328b065a61a3d6e
|
||||
react-native-get-random-values: dee677497c6a740b71e5612e8dbd83e7539ed5bb
|
||||
react-native-gzip: 02f9968afa759e189f0414d41f8f4a951a86b4f1
|
||||
react-native-gzip: c5e87ee9e359f02350e3a2ee52eb35eddc398868
|
||||
react-native-html-to-pdf-lite: 21bfb169bf4cbcd7bec9f736975ee1b3f5292d4a
|
||||
react-native-image-picker: 9c8a2687b69300ad9e95cec5d38f35ab9d32467d
|
||||
react-native-image-resizer: 00ceb0e05586c7aadf061eea676957a6c2ec60fa
|
||||
react-native-in-app-review: db8bb167a5f238e7ceca5c242d6b36ce8c4404a4
|
||||
react-native-keep-awake: caee3ff89eaa21dfe29010f0d143566874a04441
|
||||
react-native-mmkv-storage: cfb6854594cfdc5f7383a9e464bb025417d1721c
|
||||
react-native-mmkv-storage: ec32fd68168716755e1b30f09b476c236c6c68a8
|
||||
react-native-netinfo: ccbe1085dffd16592791d550189772e13bf479e2
|
||||
react-native-notification-sounds: da78c828fe1bcbb92d8b505d5261890ed315ff39
|
||||
react-native-orientation: f1caf84d65f1a4fd4511a18f2b924e634ad7a628
|
||||
react-native-pdf: 33c622cbdf776a649929e8b9d1ce2d313347c4fa
|
||||
react-native-safe-area-context: 36cc67648134e89465663b8172336a19eeda493d
|
||||
react-native-share-extension: df66a2ee48a62277d79898375e2142bde0782063
|
||||
react-native-sodium: f4e3986ddcb73482f8679e534b448a0675d0cf13
|
||||
react-native-sodium: 7d2bbb9ca840dc58d63f661b2ff733a38170fec5
|
||||
react-native-webview: 9f111dfbcfc826084d6c507f569e5e03342ee1c1
|
||||
React-NativeModulesApple: 1d81d927ef1a67a3545a01e14c2e98500bf9b199
|
||||
React-perflogger: 684a11499a0589cc42135d6d5cc04d0e4e0e261a
|
||||
@@ -930,4 +931,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: b0cadd188aa428b98d1eaa0b84b3b6208e714119
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
COCOAPODS: 1.12.1
|
||||
|
||||
@@ -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.4.1",
|
||||
"@ammarahmed/react-native-sodium": "1.5.2",
|
||||
"@bam.tech/react-native-image-resizer": "3.0.5",
|
||||
"@callstack/repack": "^3.2.0",
|
||||
"@react-native-clipboard/clipboard": "^1.9.0",
|
||||
@@ -38,13 +38,13 @@
|
||||
"react-native-fingerprint-scanner": "https://github.com/ammarahm-ed/react-native-fingerprint-scanner.git",
|
||||
"react-native-gesture-handler": "^2.12.0",
|
||||
"react-native-get-random-values": "^1.7.0",
|
||||
"react-native-gzip": "1.0.0",
|
||||
"react-native-gzip": "1.1.0",
|
||||
"react-native-html-to-pdf-lite": "^0.9.1",
|
||||
"react-native-iap": "7.5.6",
|
||||
"react-native-image-picker": "4.1.2",
|
||||
"react-native-in-app-review": "4.3.3",
|
||||
"react-native-keychain": "4.0.5",
|
||||
"react-native-mmkv-storage": "^0.9.1",
|
||||
"react-native-mmkv-storage": "^0.10.0-alpha.9",
|
||||
"react-native-modal-datetime-picker": "14.0.0",
|
||||
"react-native-navigation-bar-color": "2.0.2",
|
||||
"react-native-notification-sounds": "0.5.5",
|
||||
@@ -53,7 +53,7 @@
|
||||
"react-native-privacy-snapshot": "https://github.com/standardnotes/react-native-privacy-snapshot.git",
|
||||
"react-native-reanimated": "3.3.0",
|
||||
"react-native-safe-area-context": "^4.3.1",
|
||||
"react-native-scoped-storage": "^1.9.3",
|
||||
"react-native-scoped-storage": "^1.9.5",
|
||||
"react-native-screens": "^3.13.1",
|
||||
"react-native-securerandom": "^1.0.1",
|
||||
"react-native-share": "^7.2.0",
|
||||
|
||||
@@ -185,6 +185,8 @@ module.exports = (env) => {
|
||||
/node_modules(.*[/\\])+@tanstack[/\\]react-query/,
|
||||
/node_modules(.*[/\\])+@trpc[/\\]react-query/,
|
||||
/node_modules(.*[/\\])+katex/,
|
||||
/node_modules(.*[/\\])+@notesnook[/\\]core/,
|
||||
|
||||
],
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
|
||||
670
apps/mobile/package-lock.json
generated
670
apps/mobile/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "2.6.1",
|
||||
"version": "2.6.3",
|
||||
"private": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
@@ -29,17 +29,18 @@
|
||||
"react-refresh": "0.14.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.2",
|
||||
"@notesnook/common": "file:../../packages/common",
|
||||
"@notesnook/core": "file:../../packages/core",
|
||||
"@notesnook/editor": "file:../../packages/editor",
|
||||
"@notesnook/editor-mobile": "file:../../packages/editor-mobile",
|
||||
"@notesnook/logger": "file:../../packages/logger",
|
||||
"@notesnook/themes-server": "file:../../servers/themes",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.72.0",
|
||||
"@tanstack/react-query": "^4.29.19",
|
||||
"@trpc/client": "10.31.0",
|
||||
"@trpc/react-query": "10.31.0",
|
||||
"@trpc/server": "^10.31.0",
|
||||
"@tanstack/react-query": "^4.29.19"
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.72.0"
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
diff --git a/node_modules/react-native-mmkv-storage/ios/MMKVNative.mm b/node_modules/react-native-mmkv-storage/ios/MMKVNative.mm
|
||||
index 9af089d..f64a04a 100644
|
||||
--- a/node_modules/react-native-mmkv-storage/ios/MMKVNative.mm
|
||||
+++ b/node_modules/react-native-mmkv-storage/ios/MMKVNative.mm
|
||||
@@ -30,13 +30,23 @@ - (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
RCTExecuteOnMainQueue(^{
|
||||
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
||||
- NSUserDomainMask, YES);
|
||||
- NSString *libraryPath = (NSString *)[paths firstObject];
|
||||
- NSString *rootDir = [libraryPath stringByAppendingPathComponent:@"mmkv"];
|
||||
+// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
||||
+// NSUserDomainMask, YES);
|
||||
+// NSString *libraryPath = (NSString *)[paths firstObject];
|
||||
+
|
||||
+ NSString *myGroupID = @"group.org.streetwriters.notesnook"; // the group dir that can be accessed by App & extensions
|
||||
+
|
||||
+ NSString *groupDir = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:myGroupID].path;
|
||||
+ NSString *rootDir = [groupDir stringByAppendingPathComponent:@"mmkv"];
|
||||
+
|
||||
+ // Do not include this directory in cloud backups.
|
||||
+ NSError *error = nil;
|
||||
+ NSURL *url = [NSURL fileURLWithPath:rootDir isDirectory:YES];
|
||||
+ [url setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
|
||||
rPath = rootDir;
|
||||
+ // Set the groupDir
|
||||
_secureStorage = [[SecureStorage alloc] init];
|
||||
- [MMKV initializeMMKV:rootDir];
|
||||
+ [MMKV initializeMMKV:nil groupDir:rootDir logLevel:MMKVLogInfo];
|
||||
});
|
||||
|
||||
|
||||
@@ -706,7 +716,7 @@ static void install(jsi::Runtime &jsiRuntime) {
|
||||
}
|
||||
|
||||
- (void)migrate {
|
||||
- MMKV *kv = [MMKV mmkvWithID:@"mmkvIdStore"];
|
||||
+ MMKV *kv = [MMKV mmkvWithID:@"mmkvIdStore" mode:MMKVMultiProcess];
|
||||
[mmkvInstances setObject:kv forKey:@"mmkvIdStore"];
|
||||
if ([kv containsKey:@"mmkvIdData"]) {
|
||||
NSMutableDictionary *oldStore =
|
||||
@@ -34,6 +34,7 @@ import { db } from "../app/common/database";
|
||||
import { getElevationStyle } from "../app/utils/elevation";
|
||||
import { initDatabase, useShareStore } from "./store";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { groupArray } from "@notesnook/core/dist/utils/grouping";
|
||||
|
||||
const ListItem = ({ item, mode, close }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -97,7 +98,7 @@ const ListItem = ({ item, mode, close }) => {
|
||||
style={{
|
||||
flexDirection: "column",
|
||||
borderBottomWidth: item.topics?.length > 0 ? 0 : 1,
|
||||
borderBottomColor: colors.secondary.background,
|
||||
borderBottomColor: colors.primary.border,
|
||||
justifyContent: "center",
|
||||
paddingVertical: 12
|
||||
}}
|
||||
@@ -160,8 +161,15 @@ const ListItem = ({ item, mode, close }) => {
|
||||
};
|
||||
|
||||
const SearchGetters = {
|
||||
appendNote: () => db.notes.all,
|
||||
selectNotebooks: () => db.notebooks.all,
|
||||
appendNote: () =>
|
||||
groupArray([...db.notes.all], db.settings.getGroupOptions("notes")).filter(
|
||||
(item) => item.type === "note"
|
||||
),
|
||||
selectNotebooks: () =>
|
||||
groupArray(
|
||||
[...db.notebooks.all],
|
||||
db.settings.getGroupOptions("notebooks")
|
||||
).filter((item) => item.type === "notebook"),
|
||||
selectTags: () => {
|
||||
const selected = useShareStore.getState().selectedTags;
|
||||
const tags = [];
|
||||
@@ -179,14 +187,30 @@ const SearchGetters = {
|
||||
if (index > -1) continue;
|
||||
tags.push(tag);
|
||||
}
|
||||
return tags;
|
||||
return groupArray([...tags], {
|
||||
groupBy: "none",
|
||||
sortDirection: "asc",
|
||||
sortBy: "title"
|
||||
}).filter((item) => item.type === "tag");
|
||||
}
|
||||
};
|
||||
|
||||
const SearchLookup = {
|
||||
appendNote: (items, kwd) => db.lookup.notes(items, kwd),
|
||||
selectNotebooks: (items, kwd) => db.lookup.notebooks(items, kwd),
|
||||
selectTags: (items, kwd) => db.lookup.tags(items, kwd)
|
||||
appendNote: (items, kwd) => {
|
||||
return db.lookup.notes(items, kwd);
|
||||
},
|
||||
selectNotebooks: (items, kwd) => {
|
||||
return db.lookup.notebooks(items, kwd);
|
||||
},
|
||||
selectTags: (items, kwd) => {
|
||||
return db.lookup.tags(items, kwd);
|
||||
}
|
||||
};
|
||||
|
||||
const SearchPlaceholder = {
|
||||
appendNote: "Search for a note",
|
||||
selectNotebooks: "Search for a notebook",
|
||||
selectTags: "Search for a tag"
|
||||
};
|
||||
|
||||
export const Search = ({ close, getKeyboardHeight, quicknote, mode }) => {
|
||||
@@ -286,7 +310,7 @@ export const Search = ({ close, getKeyboardHeight, quicknote, mode }) => {
|
||||
/>
|
||||
<TextInput
|
||||
ref={inputRef}
|
||||
placeholder="Search for a note"
|
||||
placeholder={SearchPlaceholder[mode]}
|
||||
placeholderTextColor={colors.primary.placeholder}
|
||||
style={{
|
||||
fontSize: 15,
|
||||
|
||||
@@ -20,8 +20,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
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/utils/filename";
|
||||
import { parseHTML } from "@notesnook/core/utils/html-parser";
|
||||
import { isImage } from "@notesnook/core/dist/utils/filename";
|
||||
import { parseHTML } from "@notesnook/core/dist/utils/html-parser";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
@@ -377,7 +377,11 @@ const ShareView = ({ quicknote = false }) => {
|
||||
});
|
||||
|
||||
try {
|
||||
await db.sync(false, false);
|
||||
if (!globalThis["IS_MAIN_APP_RUNNING"]) {
|
||||
await db.sync(false, false);
|
||||
} else {
|
||||
console.log("main app running, skipping sync");
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e, e.stack);
|
||||
}
|
||||
@@ -598,8 +602,9 @@ const ShareView = ({ quicknote = false }) => {
|
||||
marginBottom: 0
|
||||
}}
|
||||
loading={loading}
|
||||
iconColor={colors.static.white}
|
||||
iconColor={colors.primary.accentForeground}
|
||||
onPress={onPress}
|
||||
textColor={colors.primary.accentForeground}
|
||||
textStyle={{
|
||||
fontSize: 16,
|
||||
marginLeft: 0
|
||||
|
||||
@@ -42,20 +42,24 @@ let appSettings = MMKV.getString(StorageKeys.appSettings);
|
||||
if (appSettings) {
|
||||
appSettings = JSON.parse(appSettings);
|
||||
}
|
||||
|
||||
const systemColorScheme = Appearance.getColorScheme();
|
||||
const appColorScheme = appSettings?.colorScheme;
|
||||
const useSystemTheme = appSettings?.useSystemTheme;
|
||||
const currentColorScheme = useSystemTheme ? systemColorScheme : appColorScheme;
|
||||
|
||||
const theme =
|
||||
Appearance.getColorScheme() !== "dark"
|
||||
? appSettings?.darkThem
|
||||
currentColorScheme === "dark"
|
||||
? appSettings?.darkTheme
|
||||
: appSettings?.lightTheme;
|
||||
|
||||
useThemeEngineStore
|
||||
.getState()
|
||||
.setTheme(
|
||||
theme || (Appearance.getColorScheme() === "dark" ? ThemeDark : ThemeLight)
|
||||
);
|
||||
const currentTheme =
|
||||
theme || (currentColorScheme === "dark" ? ThemeDark : ThemeLight);
|
||||
|
||||
useThemeEngineStore.getState().setTheme(currentTheme);
|
||||
|
||||
export const useShareStore = create((set) => ({
|
||||
theme:
|
||||
theme || (Appearance.getColorScheme() === "dark" ? ThemeDark : ThemeLight),
|
||||
theme: currentTheme,
|
||||
appendNote: null,
|
||||
setAppendNote: (note) => {
|
||||
MMKV.setItem(StorageKeys.appendNote, JSON.stringify(note));
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
"baseUrl": "./",
|
||||
"jsx": "react-native",
|
||||
"noEmit": true,
|
||||
"maxNodeModuleJsDepth": 5,
|
||||
"types": ["node", "jest", "detox"],
|
||||
"paths": {
|
||||
"@notesnook/*": ["../../packages"],
|
||||
|
||||
33
apps/theme-builder/.gitignore
vendored
Normal file
33
apps/theme-builder/.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
.now
|
||||
|
||||
__diff_output__
|
||||
|
||||
dist
|
||||
public/workbox
|
||||
scripts/secrets
|
||||
test-results
|
||||
.swc
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user