mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-08-31 19:19:34 +02:00
Compare commits
196 Commits
v3.2.0-bet
...
3.2.0-andr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ffc2a27a5 | ||
|
|
b0a9f3320b | ||
|
|
0ef844f08c | ||
|
|
bbe00b0f9a | ||
|
|
4dcaf70346 | ||
|
|
76e5e3758a | ||
|
|
f460772d75 | ||
|
|
1cf1605564 | ||
|
|
0abbd41ff2 | ||
|
|
f16818ea93 | ||
|
|
719ab6dff3 | ||
|
|
ed50d8041e | ||
|
|
9a0de8dff8 | ||
|
|
caba714798 | ||
|
|
154cf897b3 | ||
|
|
323e53a1ef | ||
|
|
9b097cf233 | ||
|
|
75cb2fe194 | ||
|
|
7aa975457c | ||
|
|
1932d27f1c | ||
|
|
f226bdbff1 | ||
|
|
7843943130 | ||
|
|
a92afab3fc | ||
|
|
1354ee683f | ||
|
|
891e311374 | ||
|
|
881099c2c9 | ||
|
|
2dde6b6150 | ||
|
|
a1f75dfed3 | ||
|
|
493ee81c42 | ||
|
|
7109a36006 | ||
|
|
6fccac9aea | ||
|
|
fa43f97bb4 | ||
|
|
e3a973d61e | ||
|
|
542a628435 | ||
|
|
fdd25a11e7 | ||
|
|
449ae78700 | ||
|
|
6bda4a9a73 | ||
|
|
2d316ed1ec | ||
|
|
570ae00453 | ||
|
|
c845f7c1e1 | ||
|
|
659e963b39 | ||
|
|
63b8f7ef91 | ||
|
|
841e229866 | ||
|
|
4098a27df0 | ||
|
|
918824f26b | ||
|
|
83735705d2 | ||
|
|
8ac6ccb701 | ||
|
|
9ae00db676 | ||
|
|
c389a1ce4d | ||
|
|
817a58611e | ||
|
|
bfa0f09fa0 | ||
|
|
0e461c19ed | ||
|
|
7b289f8e58 | ||
|
|
071052ce37 | ||
|
|
ec6ad79586 | ||
|
|
96205fd5b7 | ||
|
|
4028a29bdb | ||
|
|
d812024c25 | ||
|
|
92f4e33ac7 | ||
|
|
ad056e0e3b | ||
|
|
dc40601fb5 | ||
|
|
65f3338df4 | ||
|
|
4f9a5cb074 | ||
|
|
eb550e95dc | ||
|
|
84dbab5bdf | ||
|
|
c2aff26dfc | ||
|
|
5dd9ce9f25 | ||
|
|
e5998f51e9 | ||
|
|
538f1f1910 | ||
|
|
9c2fa4eb30 | ||
|
|
ab04b13582 | ||
|
|
a6ef69905e | ||
|
|
565a2396f1 | ||
|
|
5a395aca3c | ||
|
|
f99ee88499 | ||
|
|
dc7e5dfa50 | ||
|
|
4f1bb994f2 | ||
|
|
6357a8f3a1 | ||
|
|
6c083bd76d | ||
|
|
c53fbb7441 | ||
|
|
6c28075070 | ||
|
|
bb027c6f25 | ||
|
|
7dc5daffe8 | ||
|
|
3e4862d768 | ||
|
|
29b0c2eeda | ||
|
|
08e5f889f8 | ||
|
|
bc198b4cd7 | ||
|
|
5c71b77b98 | ||
|
|
5660178760 | ||
|
|
8dac907ead | ||
|
|
5b7c8eaa70 | ||
|
|
7ab4a2210a | ||
|
|
c861b11c5f | ||
|
|
4f540dfdcb | ||
|
|
0e0add2f71 | ||
|
|
29edb3a3c3 | ||
|
|
ff723e5c78 | ||
|
|
ea76929c80 | ||
|
|
5d4d84bded | ||
|
|
0faf267735 | ||
|
|
197e95e66f | ||
|
|
9d4ae71bfe | ||
|
|
422869c3d2 | ||
|
|
b7d478088b | ||
|
|
1827cbeb93 | ||
|
|
66041a45f6 | ||
|
|
ccb0c858a2 | ||
|
|
659b937852 | ||
|
|
de48cea9eb | ||
|
|
404e3147b0 | ||
|
|
c0d64ff674 | ||
|
|
bbcce64549 | ||
|
|
1ca30b8a5b | ||
|
|
22b037ea1d | ||
|
|
2d74e3d4c0 | ||
|
|
1be0e4790e | ||
|
|
3770091b58 | ||
|
|
0c86f11e21 | ||
|
|
73bf283fd7 | ||
|
|
208bd13cdd | ||
|
|
42887a1dd5 | ||
|
|
0ec2f07be0 | ||
|
|
82b70d2951 | ||
|
|
8da961f300 | ||
|
|
4fba380f2d | ||
|
|
e1b046ec0c | ||
|
|
5d01159e20 | ||
|
|
aeef53df55 | ||
|
|
29433c4149 | ||
|
|
0edac2ee9d | ||
|
|
4607dc3084 | ||
|
|
41babda9b7 | ||
|
|
0fec38610c | ||
|
|
3ecc43d976 | ||
|
|
9730560fb7 | ||
|
|
6c0e51dc9d | ||
|
|
2a313a0026 | ||
|
|
5d4e60b829 | ||
|
|
c0666d8547 | ||
|
|
a5fa261e3b | ||
|
|
fa8aa4d88f | ||
|
|
b63be2de15 | ||
|
|
173caf41d0 | ||
|
|
30e4f55218 | ||
|
|
f3895f534e | ||
|
|
ea14db77de | ||
|
|
9bb48f4896 | ||
|
|
62b5cc853b | ||
|
|
90900628a2 | ||
|
|
ebf98bc652 | ||
|
|
ddd3fe6ac5 | ||
|
|
2964e7a8f0 | ||
|
|
f6d1f5890a | ||
|
|
1cc0cf19c8 | ||
|
|
efc4f3566a | ||
|
|
85b7760e1e | ||
|
|
40ee0ecf47 | ||
|
|
513c9ee8a7 | ||
|
|
2aacadc24d | ||
|
|
716bb67b96 | ||
|
|
916b6a17aa | ||
|
|
813401ea91 | ||
|
|
70e5efbcea | ||
|
|
6c8dc223f2 | ||
|
|
5b09528e7e | ||
|
|
5de5ffe068 | ||
|
|
1b511c8ddd | ||
|
|
68d1a3f50e | ||
|
|
74edd466d4 | ||
|
|
34aa21790c | ||
|
|
e7ec9e2aa3 | ||
|
|
20bbb6dd5b | ||
|
|
f937b164e9 | ||
|
|
5b4e888ddd | ||
|
|
410d983842 | ||
|
|
16cd92f03a | ||
|
|
c6ee1e6303 | ||
|
|
0f00d0e508 | ||
|
|
21fdc39db7 | ||
|
|
bb5d5a5731 | ||
|
|
bf5e68a82e | ||
|
|
cc7f479627 | ||
|
|
9eb183f6b5 | ||
|
|
cb29d71619 | ||
|
|
a6120ed90f | ||
|
|
48040c955d | ||
|
|
18b43882e1 | ||
|
|
37dc409b60 | ||
|
|
8ab05c5a98 | ||
|
|
38509c66c5 | ||
|
|
fc40a05254 | ||
|
|
8078c3ed3c | ||
|
|
57280f3ebb | ||
|
|
dc54644b4f | ||
|
|
ce31b0495d | ||
|
|
a62d4b5d4b |
@@ -69,8 +69,6 @@ jobs:
|
||||
run: |
|
||||
sed -i -e 's/arguments/arguments "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache",/g' apps/mobile/node_modules/react-native-mmkv-storage/android/build.gradle
|
||||
sed -i -e 's/arguments/arguments "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache",/g' apps/mobile/node_modules/react-native-reanimated/android/build.gradle
|
||||
sed -i -e 's/defaultConfig {/ndkVersion safeExtGet('ndkVersion', "25.2.9519653")\n defaultConfig {/g' apps/mobile/node_modules/react-native-reanimated//android/build.gradle
|
||||
sed -i -e 's/defaultConfig {/ndkVersion safeExtGet('ndkVersion', "25.2.9519653")\n defaultConfig {/g' apps/mobile/node_modules/react-native-mmkv-storage/android/build.gradle
|
||||
|
||||
- name: CCache Stats Before Build
|
||||
run: ccache -sv
|
||||
|
||||
2
.github/workflows/android.publish.yml
vendored
2
.github/workflows/android.publish.yml
vendored
@@ -69,8 +69,6 @@ jobs:
|
||||
run: |
|
||||
sed -i -e 's/arguments/arguments "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache",/g' apps/mobile/node_modules/react-native-mmkv-storage/android/build.gradle
|
||||
sed -i -e 's/arguments/arguments "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache",/g' apps/mobile/node_modules/react-native-reanimated/android/build.gradle
|
||||
sed -i -e 's/defaultConfig {/ndkVersion safeExtGet('ndkVersion', "25.2.9519653")\n defaultConfig {/g' apps/mobile/node_modules/react-native-reanimated//android/build.gradle
|
||||
sed -i -e 's/defaultConfig {/ndkVersion safeExtGet('ndkVersion', "25.2.9519653")\n defaultConfig {/g' apps/mobile/node_modules/react-native-mmkv-storage/android/build.gradle
|
||||
|
||||
- name: CCache Stats Before Build
|
||||
run: ccache -sv
|
||||
|
||||
78
.github/workflows/desktop.publish.yml
vendored
78
.github/workflows/desktop.publish.yml
vendored
@@ -45,7 +45,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -107,7 +107,8 @@ jobs:
|
||||
name: Notesnook Desktop v${{ steps.app_metadata.outputs.app_version }}
|
||||
tag_name: v${{ steps.app_metadata.outputs.app_version }}
|
||||
files: ./notesnook_build_v${{ steps.app_metadata.outputs.app_version }}.zip
|
||||
prerelease: ${{ endsWith(steps.app_metadata.outputs.app_version, '-beta') }}
|
||||
prerelease: ${{ inputs.release-track == 'beta' }}
|
||||
target_commitish: ${{ github.ref }}
|
||||
|
||||
- name: Generate flatpak sources
|
||||
if: inputs.publish-github && inputs.build-linux
|
||||
@@ -232,8 +233,8 @@ jobs:
|
||||
xcrun altool --upload-package $package -t osx --apiKey $API_KEY_ID --apiIssuer $API_KEY_ISSUER_ID --apple-id ${{ steps.app_metadata.outputs.apple_app_id }} --bundle-id ${{ steps.app_metadata.outputs.app_bundle_id }} --bundle-short-version-string ${{ steps.app_metadata.outputs.app_version }} --bundle-version ${{ steps.app_metadata.outputs.bundle_version }}
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
build-linux:
|
||||
name: Build for Linux
|
||||
build-linux-x64:
|
||||
name: Build for Linux x64
|
||||
needs: build
|
||||
if: inputs.build-linux
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -266,7 +267,6 @@ jobs:
|
||||
|
||||
- name: Install sqlite-better-trigram for all arch
|
||||
run: |
|
||||
npm i --cpu arm64 sqlite-better-trigram
|
||||
npm i --cpu x64 sqlite-better-trigram
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
@@ -285,9 +285,9 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
if [ ${{ inputs.publish-github }} == true ]; then
|
||||
yarn electron-builder --config=electron-builder.config.js --linux AppImage:x64 AppImage:arm64 -p always
|
||||
yarn electron-builder --config=electron-builder.config.js --linux AppImage:x64 -p always
|
||||
else
|
||||
yarn electron-builder --config=electron-builder.config.js --linux AppImage:x64 AppImage:arm64 -p never
|
||||
yarn electron-builder --config=electron-builder.config.js --linux AppImage:x64 -p never
|
||||
fi
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
@@ -297,6 +297,70 @@ jobs:
|
||||
snapcraft upload --release=stable ./output/notesnook_linux_amd64.snap
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
build-linux-arm64:
|
||||
name: Build for Linux arm64
|
||||
needs: build
|
||||
if: inputs.build-linux
|
||||
runs-on: ubuntu-22.04-arm
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: ./.github/actions/setup-node-with-cache
|
||||
|
||||
# - name: Setup Snapcraft Auth
|
||||
# if: inputs.publish-snap
|
||||
# run: echo "SNAPCRAFT_STORE_CREDENTIALS=${{ secrets.snapcraft_token }}" >> $GITHUB_ENV
|
||||
|
||||
# - name: Install Snapcraft
|
||||
# uses: samuelmeuli/action-snapcraft@v1
|
||||
# if: inputs.publish-snap
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: build
|
||||
path: ./apps/web/build
|
||||
|
||||
- name: Install packages
|
||||
run: |
|
||||
npm ci --ignore-scripts --prefer-offline --no-audit
|
||||
npm run bootstrap -- --scope=desktop
|
||||
|
||||
- name: Install sqlite-better-trigram for all arch
|
||||
run: |
|
||||
npm i --cpu arm64 sqlite-better-trigram
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
# - name: Build snap
|
||||
# if: inputs.publish-snap
|
||||
# run: |
|
||||
# yarn electron-builder --config=electron-builder.config.js --linux snap:arm64 -p never
|
||||
# working-directory: ./apps/desktop
|
||||
|
||||
- name: Build AppImage
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
if [ ${{ inputs.publish-github }} == true ]; then
|
||||
yarn electron-builder --config=electron-builder.config.js --linux AppImage:arm64 -p always
|
||||
else
|
||||
yarn electron-builder --config=electron-builder.config.js --linux AppImage:arm64 -p never
|
||||
fi
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
# - name: Publish on Snapcraft
|
||||
# if: inputs.publish-snap
|
||||
# run: |
|
||||
# snapcraft upload --release=stable ./output/notesnook_linux_arm64.snap
|
||||
# working-directory: ./apps/desktop
|
||||
|
||||
build-windows:
|
||||
name: Build for Windows
|
||||
needs: build
|
||||
|
||||
12
.github/workflows/ios.publish.yml
vendored
12
.github/workflows/ios.publish.yml
vendored
@@ -4,7 +4,7 @@ on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
runs-on: macos-14
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
@@ -14,6 +14,11 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: ./.github/actions/setup-node-with-cache
|
||||
|
||||
- name: Setup Xcode
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: "16.1"
|
||||
|
||||
- name: Install node modules
|
||||
run: |
|
||||
npm ci --ignore-scripts --prefer-offline --no-audit
|
||||
@@ -54,7 +59,10 @@ jobs:
|
||||
key: ${{ runner.os }}-pods-${{ hashFiles('apps/mobile/native/ios/Podfile.lock') }}
|
||||
|
||||
- name: Install Pods
|
||||
run: npm run prepare:ios
|
||||
run: |
|
||||
cd apps/mobile/native/ios
|
||||
bundle install
|
||||
RCT_NEW_ARCH_ENABLED=0 bundle exec pod install
|
||||
|
||||
- name: CCache Stats Before Build
|
||||
run: ccache -sv
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,4 +11,4 @@ nx-cloud.env
|
||||
site
|
||||
node_modules.backup
|
||||
.nx
|
||||
*.patch
|
||||
/*.patch
|
||||
|
||||
@@ -58,10 +58,10 @@ This will compile and run the app in production mode but it won't generate any p
|
||||
npm run release -- --rebuild
|
||||
|
||||
# For macOS
|
||||
npx electron-builder --config=electron-builder.config.js --mac dmg --arm64 --x64 -publish never
|
||||
npx electron-builder --config=electron-builder.config.js --mac dmg --arm64 --x64 --publish never
|
||||
|
||||
# For Linux (AppImage)
|
||||
npx electron-builder --config=electron-builder.config.js --linux AppImage:x64 AppImage:arm64 -publish never
|
||||
npx electron-builder --config=electron-builder.config.js --linux AppImage:x64 AppImage:arm64 --publish never
|
||||
|
||||
# For Windows
|
||||
npx electron-builder --config=electron-builder.config.js --win --publish never
|
||||
|
||||
@@ -57,6 +57,7 @@ module.exports = {
|
||||
"node_modules/bindings",
|
||||
"node_modules/node-gyp-build",
|
||||
"node_modules/sqlite-better-trigram",
|
||||
"node_modules/sqlite3-fts5-html",
|
||||
"node_modules/sodium-native/prebuilds/${platform}-${arch}",
|
||||
{
|
||||
from: "node_modules/sqlite-better-trigram-linux-${arch}",
|
||||
@@ -70,6 +71,20 @@ module.exports = {
|
||||
from: "node_modules/sqlite-better-trigram-windows-${arch}",
|
||||
to: "node_modules/sqlite-better-trigram-windows-${arch}"
|
||||
},
|
||||
|
||||
{
|
||||
from: "node_modules/sqlite3-fts5-html-linux-${arch}",
|
||||
to: "node_modules/sqlite3-fts5-html-linux-${arch}"
|
||||
},
|
||||
{
|
||||
from: "node_modules/sqlite3-fts5-html-darwin-${arch}",
|
||||
to: "node_modules/sqlite3-fts5-html-darwin-${arch}"
|
||||
},
|
||||
{
|
||||
from: "node_modules/sqlite3-fts5-html-windows-${arch}",
|
||||
to: "node_modules/sqlite3-fts5-html-windows-${arch}"
|
||||
},
|
||||
|
||||
"node_modules/sodium-native/index.js",
|
||||
"node_modules/sodium-native/package.json"
|
||||
],
|
||||
@@ -160,23 +175,20 @@ module.exports = {
|
||||
description: "Your private note taking space",
|
||||
executableName: linuxExecutableName,
|
||||
desktop: {
|
||||
actions: [
|
||||
{
|
||||
id: "new-note",
|
||||
name: "New note",
|
||||
args: "new note"
|
||||
desktopActions: {
|
||||
"new-note": {
|
||||
Name: "New note",
|
||||
Exec: `${linuxExecutableName} new note`
|
||||
},
|
||||
{
|
||||
id: "new-notebook",
|
||||
name: "New notebook",
|
||||
args: "new notebook"
|
||||
"new-notebook": {
|
||||
Name: "New notebook",
|
||||
Exec: `${linuxExecutableName} new notebook`
|
||||
},
|
||||
{
|
||||
id: "new-reminder",
|
||||
name: "New reminder",
|
||||
args: "new reminder"
|
||||
"new-reminder": {
|
||||
Name: "New reminder",
|
||||
Exec: `${linuxExecutableName} new reminder`
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
snap: {
|
||||
|
||||
1570
apps/desktop/package-lock.json
generated
1570
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": "3.1.0",
|
||||
"version": "3.2.0",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./dist/cjs/index.js",
|
||||
@@ -27,37 +27,42 @@
|
||||
"dependencies": {
|
||||
"@lingui/core": "5.1.2",
|
||||
"@notesnook/intl": "file:../../packages/intl",
|
||||
"@notesnook/ui": "file:../../packages/ui",
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/server": "10.45.2",
|
||||
"better-sqlite3-multiple-ciphers": "11.5.0",
|
||||
"better-sqlite3-multiple-ciphers": "11.3.0",
|
||||
"electron-trpc": "0.7.1",
|
||||
"electron-updater": "^6.3.4",
|
||||
"icojs": "^0.19.4",
|
||||
"sqlite-better-trigram": "0.0.2",
|
||||
"electron-updater": "^6.6.2",
|
||||
"icojs": "^0.19.5",
|
||||
"sqlite-better-trigram": "0.0.3",
|
||||
"sqlite3-fts5-html": "^0.0.3",
|
||||
"typed-emitter": "^2.1.0",
|
||||
"yargs": "^17.7.2",
|
||||
"zod": "3.23.8"
|
||||
"zod": "3.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@streetwriters/kysely": "^0.27.4",
|
||||
"@types/node": "22.7.0",
|
||||
"@types/node": "22.15.3",
|
||||
"@types/yargs": "^17.0.33",
|
||||
"chokidar": "^4.0.1",
|
||||
"electron": "^31.7.4",
|
||||
"electron-builder": "^25.1.8",
|
||||
"chokidar": "^4.0.3",
|
||||
"electron": "^34.0.0",
|
||||
"electron-builder": "^26.0.12",
|
||||
"esbuild": "0.21.5",
|
||||
"node-abi": "^3.68.0",
|
||||
"node-gyp-build": "^4.8.2",
|
||||
"playwright": "^1.48.2",
|
||||
"node-abi": "^4.5.0",
|
||||
"node-gyp-build": "^4.8.4",
|
||||
"playwright": "1.48.2",
|
||||
"prebuildify": "^6.0.1",
|
||||
"slugify": "1.6.6",
|
||||
"tree-kill": "^1.2.2",
|
||||
"undici": "^6.19.8",
|
||||
"vitest": "^2.1.8"
|
||||
"undici": "^7.8.0",
|
||||
"vitest": "2.1.8"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"dmg-license": "^1.0.11"
|
||||
},
|
||||
"overrides": {
|
||||
"@electron/node-gyp": "^10.2.0-electron.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node scripts/dev.mjs",
|
||||
"staging": "node scripts/build.mjs --run",
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
diff --git a/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js b/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js
|
||||
index 739a48c..7a7b4af 100644
|
||||
--- a/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js
|
||||
+++ b/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js
|
||||
@@ -117,6 +117,7 @@ class LinuxTargetHelper {
|
||||
StartupWMClass: appInfo.productName,
|
||||
...extra,
|
||||
...targetSpecificOptions.desktop,
|
||||
+ actions: undefined
|
||||
};
|
||||
const description = this.getDescription(targetSpecificOptions);
|
||||
if (!(0, builder_util_1.isEmptyOrSpaces)(description)) {
|
||||
@@ -160,6 +161,23 @@ class LinuxTargetHelper {
|
||||
data += `\n${name}=${desktopMeta[name]}`;
|
||||
}
|
||||
data += "\n";
|
||||
+
|
||||
+ if (targetSpecificOptions.desktop.actions) {
|
||||
+ let actionsData = "";
|
||||
+ const validActions = [];
|
||||
+ for (const action of targetSpecificOptions.desktop.actions) {
|
||||
+ if (!action.id || !action.name || !action.args) continue;
|
||||
+ actionsData += "\n";
|
||||
+ actionsData += `[Desktop Action ${action.id}]
|
||||
+Name=${action.name}
|
||||
+Exec=${desktopMeta.Exec} ${action.args}`;
|
||||
+ actionsData += "\n";
|
||||
+
|
||||
+ validActions.push(action.id);
|
||||
+ }
|
||||
+
|
||||
+ data += `Actions=${validActions.join(";")};\n${actionsData}`
|
||||
+ }
|
||||
return Promise.resolve(data);
|
||||
}
|
||||
}
|
||||
13
apps/desktop/patches/app-builder-lib+26.0.12.patch
Normal file
13
apps/desktop/patches/app-builder-lib+26.0.12.patch
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/node_modules/app-builder-lib/out/targets/snap.js b/node_modules/app-builder-lib/out/targets/snap.js
|
||||
index 0b5405e..753f6c6 100644
|
||||
--- a/node_modules/app-builder-lib/out/targets/snap.js
|
||||
+++ b/node_modules/app-builder-lib/out/targets/snap.js
|
||||
@@ -115,7 +115,7 @@ class SnapTarget extends core_1.Target {
|
||||
else {
|
||||
const archTriplet = archNameToTriplet(arch);
|
||||
appDescriptor.environment = {
|
||||
- DISABLE_WAYLAND: options.allowNativeWayland ? "" : "1",
|
||||
+ DISABLE_WAYLAND: options.allowNativeWayland ? "0" : "1",
|
||||
PATH: "$SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/sbin:$SNAP/bin:$PATH",
|
||||
SNAP_DESKTOP_RUNTIME: "$SNAP/gnome-platform",
|
||||
LD_LIBRARY_PATH: [
|
||||
@@ -0,0 +1,11 @@
|
||||
diff --git a/node_modules/better-sqlite3-multiple-ciphers/deps/defines.gypi b/node_modules/better-sqlite3-multiple-ciphers/deps/defines.gypi
|
||||
index 1a14ecd..dabcce2 100644
|
||||
--- a/node_modules/better-sqlite3-multiple-ciphers/deps/defines.gypi
|
||||
+++ b/node_modules/better-sqlite3-multiple-ciphers/deps/defines.gypi
|
||||
@@ -38,5 +38,6 @@
|
||||
'SQLITE_TRACE_SIZE_LIMIT=32',
|
||||
'SQLITE_USER_AUTHENTICATION=0',
|
||||
'SQLITE_USE_URI=0',
|
||||
+ 'SQLITE_ENABLE_REGEXP',
|
||||
],
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
diff --git a/node_modules/electron-trpc/dist/main.mjs b/node_modules/electron-trpc/dist/main.mjs
|
||||
index 07971db..b67a3cf 100644
|
||||
--- a/node_modules/electron-trpc/dist/main.mjs
|
||||
+++ b/node_modules/electron-trpc/dist/main.mjs
|
||||
@@ -537,8 +537,15 @@ class be {
|
||||
attachWindow(r) {
|
||||
F(this, w).includes(r) || (y("Attaching window", r.id), F(this, w).push(r), v(this, N, Z).call(this, r));
|
||||
}
|
||||
- detachWindow(r) {
|
||||
- y("Detaching window", r.id), L(this, w, F(this, w).filter((e) => e !== r)), v(this, R, M).call(this, { webContentsId: r.webContents.id });
|
||||
+ detachWindow(r, webContentsId) {
|
||||
+ y("Detaching window", r.id);
|
||||
+
|
||||
+ if (r.isDestroyed() && webContentsId === undefined) {
|
||||
+ throw new Error('webContentsId is required when calling detachWindow on a destroyed window');
|
||||
+ }
|
||||
+
|
||||
+ L(this, w, F(this, w).filter((e) => e !== r));
|
||||
+ v(this, R, M).call(this, { webContentsId: webContentsId ?? r.webContents.id });
|
||||
}
|
||||
}
|
||||
w = new WeakMap(), E = new WeakMap(), R = new WeakSet(), M = function({
|
||||
@@ -548,6 +555,7 @@ w = new WeakMap(), E = new WeakMap(), R = new WeakSet(), M = function({
|
||||
for (const [i, a] of F(this, E).entries())
|
||||
i.startsWith(`${r}-${e ?? ""}`) && (y("Closing subscription", i), a.unsubscribe(), F(this, E).delete(i));
|
||||
}, N = new WeakSet(), Z = function(r) {
|
||||
+ const webContentsId = r.webContents.id;
|
||||
r.webContents.on("did-start-navigation", ({ frame: e }) => {
|
||||
y(
|
||||
"Handling webContents `did-start-navigation` event",
|
||||
@@ -558,7 +566,7 @@ w = new WeakMap(), E = new WeakMap(), R = new WeakSet(), M = function({
|
||||
frameRoutingId: e.routingId
|
||||
});
|
||||
}), r.webContents.on("destroyed", () => {
|
||||
- y("Handling webContents `destroyed` event"), this.detachWindow(r);
|
||||
+ y("Handling webContents `destroyed` event"), this.detachWindow(r, webContentsId);
|
||||
});
|
||||
};
|
||||
const me = ({
|
||||
@@ -43,8 +43,7 @@ if (args.rebuild || !existsSync(path.join(webAppPath, "build"))) {
|
||||
);
|
||||
}
|
||||
|
||||
// temporary until there's support for prebuilt binaries for linux ARM
|
||||
if (os.platform() === "linux") await patchBetterSQLite3();
|
||||
await patchBetterSQLite3();
|
||||
|
||||
await fs.cp(path.join(webAppPath, "build"), path.join(root, "build"), {
|
||||
recursive: true,
|
||||
|
||||
@@ -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 { readFile, writeFile } from "fs/promises";
|
||||
import { readFile, rm, writeFile } from "fs/promises";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
@@ -25,6 +25,8 @@ const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
export async function patchBetterSQLite3() {
|
||||
console.log("Patching better-sqlite3");
|
||||
|
||||
const jsonPath = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
@@ -34,15 +36,23 @@ export async function patchBetterSQLite3() {
|
||||
);
|
||||
const json = JSON.parse(await readFile(jsonPath, "utf-8"));
|
||||
|
||||
json.version = "11.5.1";
|
||||
json.homepage = "https://github.com/thecodrr/better-sqlite3-multiple-ciphers";
|
||||
json.repository.url =
|
||||
"git://github.com/thecodrr/better-sqlite3-multiple-ciphers.git";
|
||||
delete json.homepage;
|
||||
delete json.repository;
|
||||
|
||||
await writeFile(jsonPath, JSON.stringify(json));
|
||||
|
||||
await rm(
|
||||
path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"node_modules",
|
||||
"better-sqlite3-multiple-ciphers",
|
||||
"build"
|
||||
),
|
||||
{ force: true, recursive: true }
|
||||
);
|
||||
}
|
||||
|
||||
if (process.argv[1] === __filename) {
|
||||
console.log("Patching better-sqlite3");
|
||||
patchBetterSQLite3();
|
||||
}
|
||||
|
||||
@@ -19,7 +19,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { initTRPC } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { app, dialog, nativeTheme, Notification, shell } from "electron";
|
||||
import {
|
||||
app,
|
||||
dialog,
|
||||
Menu,
|
||||
MenuItem,
|
||||
nativeImage,
|
||||
nativeTheme,
|
||||
Notification,
|
||||
shell
|
||||
} from "electron";
|
||||
import { AutoLaunch } from "../utils/autolaunch";
|
||||
import { config, DesktopIntegration } from "../utils/config";
|
||||
import { bringToFront } from "../utils/bring-to-front";
|
||||
@@ -33,6 +42,7 @@ import { isFlatpak, isSnap } from "../utils";
|
||||
import { setupDesktopIntegration } from "../utils/desktop-integration";
|
||||
import { rm } from "fs/promises";
|
||||
import { disableCustomDns, enableCustomDns } from "../utils/custom-dns";
|
||||
import type { MenuItem as NNMenuItem } from "@notesnook/ui";
|
||||
|
||||
const t = initTRPC.create();
|
||||
|
||||
@@ -225,5 +235,63 @@ export const osIntegrationRouter = t.router({
|
||||
nativeTheme.off("updated", updated);
|
||||
};
|
||||
})
|
||||
)
|
||||
),
|
||||
|
||||
showMenu: t.procedure
|
||||
.input(
|
||||
z.object({
|
||||
menuItems: z.array(z.any())
|
||||
})
|
||||
)
|
||||
.subscription(({ input: { menuItems } }) =>
|
||||
observable<string[]>((emit) => {
|
||||
const items = menuItems as NNMenuItem[];
|
||||
const menu = new Menu();
|
||||
for (const item of items) {
|
||||
const menuItem = toMenuItem(item, (id) => emit.next(id));
|
||||
if (menuItem) menu.append(menuItem);
|
||||
}
|
||||
if (menu.items.length > 0) menu.popup();
|
||||
return () => {
|
||||
menu.removeAllListeners();
|
||||
menu.closePopup();
|
||||
};
|
||||
})
|
||||
)
|
||||
});
|
||||
|
||||
function toMenuItem(
|
||||
item: NNMenuItem,
|
||||
onClick: (id: string[]) => void,
|
||||
parentKey?: string
|
||||
): MenuItem | undefined {
|
||||
switch (item.type) {
|
||||
case "lazy-loader":
|
||||
return undefined;
|
||||
case "separator":
|
||||
return new MenuItem({ type: "separator" });
|
||||
case "button": {
|
||||
const submenu = item.menu ? new Menu() : undefined;
|
||||
if (submenu && item.menu) {
|
||||
for (const subitem of item.menu.items) {
|
||||
const subMenuItem = toMenuItem(subitem, onClick, item.key);
|
||||
if (subMenuItem) submenu.append(subMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
return new MenuItem({
|
||||
label: item.title,
|
||||
enabled: !item.isDisabled,
|
||||
visible: !item.isHidden,
|
||||
toolTip: item.tooltip,
|
||||
sublabel: item.tooltip,
|
||||
checked: item.isChecked,
|
||||
type: submenu ? "submenu" : item.isChecked ? "checkbox" : "normal",
|
||||
id: item.key,
|
||||
submenu,
|
||||
click: () => onClick(parentKey ? [parentKey, item.key] : [item.key]),
|
||||
accelerator: item.modifier?.replace("Mod", "CommandOrControl")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ export class SQLite {
|
||||
filePath
|
||||
).unsafeMode(true);
|
||||
const betterTrigram = require("sqlite-better-trigram");
|
||||
const fts5Html = require("sqlite3-fts5-html");
|
||||
betterTrigram.load(this.sqlite);
|
||||
fts5Html.load(this.sqlite);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -143,16 +143,44 @@ function setupMenu() {
|
||||
})
|
||||
);
|
||||
|
||||
if (params.isEditable)
|
||||
if (params.isEditable) {
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
label: strings.paste(),
|
||||
role: "pasteAndMatchStyle",
|
||||
role: "paste",
|
||||
enabled: clipboard.readText("clipboard").length > 0,
|
||||
accelerator: "CommandOrControl+V"
|
||||
})
|
||||
);
|
||||
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
label:
|
||||
process.platform === "darwin"
|
||||
? strings.pasteAndMatchStyle()
|
||||
: strings.pasteWithoutFormatting(),
|
||||
role: "pasteAndMatchStyle",
|
||||
enabled: clipboard.readText("clipboard").length > 0,
|
||||
accelerator:
|
||||
process.platform === "darwin"
|
||||
? "Option+Shift+Command+V"
|
||||
: "Shift+CommandOrControl+V"
|
||||
})
|
||||
);
|
||||
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
type: "separator"
|
||||
})
|
||||
);
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
label: strings.spellCheck(),
|
||||
role: "toggleSpellChecker"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (menu.items.length > 0) menu.popup();
|
||||
});
|
||||
}
|
||||
|
||||
1
apps/mobile/.gitignore
vendored
1
apps/mobile/.gitignore
vendored
@@ -69,6 +69,7 @@ buck-out/
|
||||
*/fastlane/report.xml
|
||||
*/fastlane/Preview.html
|
||||
*/fastlane/screenshots
|
||||
native/vendor
|
||||
|
||||
# Bundle artifact
|
||||
*.jsbundle
|
||||
|
||||
@@ -167,6 +167,7 @@ const Actions = ({
|
||||
setAttachments();
|
||||
eSendEvent(eDBItemUpdate, attachment.id);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
positiveText: strings.rename()
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@ import { notesnook } from "../../../e2e/test.ids";
|
||||
import { getColorLinearShade } from "../../utils/colors";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { Button } from "../ui/button";
|
||||
import { Button, ButtonProps } from "../ui/button";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
|
||||
const DialogButtons = ({
|
||||
@@ -37,6 +37,14 @@ const DialogButtons = ({
|
||||
loading,
|
||||
doneText,
|
||||
positiveType
|
||||
}: {
|
||||
onPressPositive?: () => void;
|
||||
onPressNegative: () => void;
|
||||
positiveTitle: string;
|
||||
negativeTitle?: string;
|
||||
loading?: boolean;
|
||||
doneText?: string;
|
||||
positiveType?: ButtonProps["type"];
|
||||
}) => {
|
||||
const { colors, isDark } = useThemeColors();
|
||||
|
||||
@@ -17,15 +17,17 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { KeyboardTypeOptions } from "react-native";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
import { eCloseSimpleDialog, eOpenSimpleDialog } from "../../utils/events";
|
||||
import { ButtonProps } from "../ui/button";
|
||||
|
||||
type DialogInfo = {
|
||||
export type DialogInfo = {
|
||||
title?: string;
|
||||
paragraph?: string;
|
||||
positiveText?: string;
|
||||
negativeText?: string;
|
||||
positivePress?: (...args: any[]) => void;
|
||||
positiveText: string;
|
||||
negativeText: string;
|
||||
positivePress?: (...args: any[]) => Promise<any>;
|
||||
onClose?: () => void;
|
||||
positiveType?:
|
||||
| "transparent"
|
||||
@@ -44,16 +46,18 @@ type DialogInfo = {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
context: "global" | "local" | (string & {});
|
||||
secureTextEntry?: boolean;
|
||||
keyboardType?: string;
|
||||
keyboardType?: KeyboardTypeOptions;
|
||||
check?: {
|
||||
info: string;
|
||||
type?: string;
|
||||
type?: ButtonProps["type"];
|
||||
defaultValue?: boolean;
|
||||
};
|
||||
notice: {
|
||||
text: string;
|
||||
type: "alert" | "information";
|
||||
};
|
||||
disableBackdropClosing: boolean;
|
||||
component: JSX.Element | ((close?: () => void) => JSX.Element);
|
||||
};
|
||||
|
||||
export function presentDialog(data: Partial<DialogInfo>): void {
|
||||
|
||||
@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { TextInput, View, ViewStyle } from "react-native";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import {
|
||||
eSubscribeEvent,
|
||||
@@ -40,42 +40,26 @@ import Seperator from "../ui/seperator";
|
||||
import BaseDialog from "./base-dialog";
|
||||
import DialogButtons from "./dialog-buttons";
|
||||
import DialogHeader from "./dialog-header";
|
||||
import { DialogInfo } from "./functions";
|
||||
|
||||
export const Dialog = ({ context = "global" }) => {
|
||||
export const Dialog = ({ context = "global" }: { context?: string }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [checked, setChecked] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const values = useRef({
|
||||
const [visible, setVisible] = useState<boolean>();
|
||||
const [checked, setChecked] = useState<boolean>();
|
||||
const [loading, setLoading] = useState<boolean>();
|
||||
const values = useRef<{
|
||||
inputValue?: string;
|
||||
}>({
|
||||
inputValue: undefined
|
||||
});
|
||||
const inputRef = useRef();
|
||||
const [dialogInfo, setDialogInfo] = useState({
|
||||
title: "",
|
||||
paragraph: "",
|
||||
positiveText: strings.done(),
|
||||
negativeText: strings.cancel(),
|
||||
positivePress: () => {},
|
||||
onClose: () => {},
|
||||
positiveType: "transparent",
|
||||
icon: null,
|
||||
paragraphColor: colors.primary.paragraph,
|
||||
input: false,
|
||||
inputPlaceholder: "Enter some text",
|
||||
defaultValue: "",
|
||||
disableBackdropClosing: false,
|
||||
check: {
|
||||
info: "Check",
|
||||
type: "transparent",
|
||||
defaultValue: false
|
||||
}
|
||||
});
|
||||
const inputRef = useRef<TextInput>(null);
|
||||
const [dialogInfo, setDialogInfo] = useState<DialogInfo>();
|
||||
|
||||
const onPressPositive = async () => {
|
||||
if (dialogInfo.positivePress) {
|
||||
if (dialogInfo?.positivePress) {
|
||||
inputRef.current?.blur();
|
||||
setLoading(true);
|
||||
let result;
|
||||
let result = false;
|
||||
try {
|
||||
result = await dialogInfo.positivePress(
|
||||
values.current.inputValue || dialogInfo.defaultValue,
|
||||
@@ -97,7 +81,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
};
|
||||
|
||||
const show = useCallback(
|
||||
(data) => {
|
||||
(data: DialogInfo) => {
|
||||
if (!data.context) data.context = "global";
|
||||
if (data.context !== context) return;
|
||||
setDialogInfo(data);
|
||||
@@ -108,6 +92,14 @@ export const Dialog = ({ context = "global" }) => {
|
||||
[context]
|
||||
);
|
||||
|
||||
const hide = React.useCallback(() => {
|
||||
setChecked(false);
|
||||
values.current.inputValue = undefined;
|
||||
setVisible(false);
|
||||
setDialogInfo(undefined);
|
||||
dialogInfo?.onClose?.();
|
||||
}, [dialogInfo]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eOpenSimpleDialog, show);
|
||||
eSubscribeEvent(eCloseSimpleDialog, hide);
|
||||
@@ -118,21 +110,14 @@ export const Dialog = ({ context = "global" }) => {
|
||||
};
|
||||
}, [hide, show]);
|
||||
|
||||
const hide = React.useCallback(() => {
|
||||
setChecked(false);
|
||||
values.current.inputValue = undefined;
|
||||
setVisible(false);
|
||||
dialogInfo.onClose?.();
|
||||
}, [dialogInfo]);
|
||||
|
||||
const onNegativePress = async () => {
|
||||
if (dialogInfo.onClose) {
|
||||
if (dialogInfo?.onClose) {
|
||||
await dialogInfo.onClose();
|
||||
}
|
||||
hide();
|
||||
};
|
||||
|
||||
const style = {
|
||||
const style: ViewStyle = {
|
||||
...getElevationStyle(5),
|
||||
width: DDS.isTab ? 400 : "85%",
|
||||
maxHeight: 450,
|
||||
@@ -143,7 +128,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
overflow: "hidden"
|
||||
};
|
||||
|
||||
return visible ? (
|
||||
return visible && dialogInfo ? (
|
||||
<BaseDialog
|
||||
statusBarTranslucent={false}
|
||||
bounce={!dialogInfo.input}
|
||||
@@ -160,89 +145,99 @@ export const Dialog = ({ context = "global" }) => {
|
||||
visible={true}
|
||||
onRequestClose={hide}
|
||||
>
|
||||
<View style={style}>
|
||||
<DialogHeader
|
||||
title={dialogInfo.title}
|
||||
icon={dialogInfo.icon}
|
||||
paragraph={dialogInfo.paragraph}
|
||||
paragraphColor={dialogInfo.paragraphColor}
|
||||
padding={12}
|
||||
style={{
|
||||
minHeight: 0
|
||||
}}
|
||||
/>
|
||||
<Seperator half />
|
||||
{typeof dialogInfo.component === "function"
|
||||
? dialogInfo.component(() => hide())
|
||||
: dialogInfo.component}
|
||||
|
||||
{dialogInfo.input ? (
|
||||
<View
|
||||
{dialogInfo.component ? null : (
|
||||
<View style={style}>
|
||||
<DialogHeader
|
||||
title={dialogInfo.title}
|
||||
icon={dialogInfo.icon}
|
||||
paragraph={dialogInfo.paragraph}
|
||||
paragraphColor={dialogInfo.paragraphColor}
|
||||
padding={12}
|
||||
style={{
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
minHeight: 0
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
fwdRef={inputRef}
|
||||
autoCapitalize="none"
|
||||
onChangeText={(value) => {
|
||||
values.current.inputValue = value;
|
||||
}}
|
||||
testID="input-value"
|
||||
secureTextEntry={dialogInfo.secureTextEntry}
|
||||
//defaultValue={dialogInfo.defaultValue}
|
||||
onSubmit={onPressPositive}
|
||||
returnKeyLabel="Done"
|
||||
returnKeyType="done"
|
||||
keyboardType={dialogInfo.keyboardType || "default"}
|
||||
placeholder={dialogInfo.inputPlaceholder}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
/>
|
||||
<Seperator half />
|
||||
|
||||
{dialogInfo?.notice ? (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<Notice
|
||||
type={dialogInfo.notice.type || "information"}
|
||||
text={dialogInfo.notice.text}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{dialogInfo.check ? (
|
||||
<>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setChecked(!checked);
|
||||
}}
|
||||
icon={
|
||||
checked
|
||||
? "check-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
}
|
||||
iconColor={checked ? colors.secondary.icon : colors.primary.icon}
|
||||
{dialogInfo.input ? (
|
||||
<View
|
||||
style={{
|
||||
justifyContent: "flex-start"
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
height={35}
|
||||
iconSize={20}
|
||||
width="100%"
|
||||
title={dialogInfo.check.info}
|
||||
type={checked ? dialogInfo.check.type || "plain" : "plain"}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
>
|
||||
<Input
|
||||
fwdRef={inputRef}
|
||||
autoCapitalize="none"
|
||||
onChangeText={(value) => {
|
||||
values.current.inputValue = value;
|
||||
}}
|
||||
testID="input-value"
|
||||
secureTextEntry={dialogInfo.secureTextEntry}
|
||||
//defaultValue={dialogInfo.defaultValue}
|
||||
onSubmit={() => {
|
||||
onPressPositive();
|
||||
}}
|
||||
returnKeyLabel="Done"
|
||||
returnKeyType="done"
|
||||
keyboardType={dialogInfo.keyboardType || "default"}
|
||||
placeholder={dialogInfo.inputPlaceholder}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
<DialogButtons
|
||||
onPressNegative={onNegativePress}
|
||||
onPressPositive={dialogInfo.positivePress && onPressPositive}
|
||||
loading={loading}
|
||||
positiveTitle={dialogInfo.positiveText}
|
||||
negativeTitle={dialogInfo.negativeText}
|
||||
positiveType={dialogInfo.positiveType}
|
||||
/>
|
||||
</View>
|
||||
{dialogInfo?.notice ? (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<Notice
|
||||
type={dialogInfo.notice.type || "information"}
|
||||
text={dialogInfo.notice.text}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{dialogInfo.check ? (
|
||||
<>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setChecked(!checked);
|
||||
}}
|
||||
icon={
|
||||
checked
|
||||
? "check-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
}
|
||||
iconColor={
|
||||
checked ? colors.secondary.icon : colors.primary.icon
|
||||
}
|
||||
style={{
|
||||
justifyContent: "flex-start"
|
||||
}}
|
||||
height={35}
|
||||
iconSize={20}
|
||||
width="100%"
|
||||
title={dialogInfo.check.info}
|
||||
type={checked ? dialogInfo.check.type || "plain" : "plain"}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<DialogButtons
|
||||
onPressNegative={onNegativePress}
|
||||
onPressPositive={dialogInfo.positivePress && onPressPositive}
|
||||
loading={loading}
|
||||
positiveTitle={dialogInfo.positiveText}
|
||||
negativeTitle={dialogInfo.negativeText}
|
||||
positiveType={dialogInfo.positiveType}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
<Toast context="local" />
|
||||
</BaseDialog>
|
||||
) : null;
|
||||
@@ -133,7 +133,9 @@ export const SectionHeader = React.memo<
|
||||
<Sort
|
||||
screen={screen}
|
||||
type={dataType}
|
||||
hideGroupOptions={screen === "Reminders"}
|
||||
hideGroupOptions={
|
||||
screen === "Reminders" || screen === "Search"
|
||||
}
|
||||
/>
|
||||
)
|
||||
});
|
||||
|
||||
181
apps/mobile/app/components/list-items/search-result/index.tsx
Normal file
181
apps/mobile/app/components/list-items/search-result/index.tsx
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import React from "react";
|
||||
import { HighlightedResult } from "@notesnook/core";
|
||||
import { View } from "react-native";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { Properties } from "../../properties";
|
||||
import { db } from "../../../common/database";
|
||||
import { eSendEvent } from "../../../services/event-manager";
|
||||
import { eOnLoadNote } from "../../../utils/events";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import { fluidTabsRef } from "../../../utils/global-refs";
|
||||
type SearchResultProps = {
|
||||
item: HighlightedResult;
|
||||
};
|
||||
|
||||
export const SearchResult = (props: SearchResultProps) => {
|
||||
const [expanded, setExpanded] = React.useState(true);
|
||||
const { colors } = useThemeColors();
|
||||
|
||||
const openNote = async (index?: number) => {
|
||||
const note = await db.notes.note(props.item.id);
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: {
|
||||
...note,
|
||||
content: props.item.rawContent
|
||||
? {
|
||||
data: props.item.rawContent || "",
|
||||
type: "tiptap"
|
||||
}
|
||||
: undefined
|
||||
},
|
||||
searchResultIndex: index
|
||||
});
|
||||
fluidTabsRef.current?.goToPage("editor");
|
||||
};
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
style={{
|
||||
alignSelf: "flex-start",
|
||||
alignItems: "flex-start",
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
|
||||
borderRadius: 0
|
||||
}}
|
||||
onLongPress={async () => {
|
||||
const note = await db.notes.note(props.item.id);
|
||||
Properties.present(note);
|
||||
}}
|
||||
onPress={async () => openNote()}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: DefaultAppStyles.GAP_SMALL / 2,
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
{props.item.content?.length ? (
|
||||
<IconButton
|
||||
name={!expanded ? "chevron-right" : "chevron-down"}
|
||||
onPress={() => setExpanded((prev) => !prev)}
|
||||
size={AppFontSize.md + 2}
|
||||
color={colors.secondary.icon}
|
||||
style={{
|
||||
width: 23,
|
||||
height: 23
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<Heading
|
||||
size={AppFontSize.sm}
|
||||
style={{
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
{props.item.title.map((title, index) => (
|
||||
<React.Fragment key={props.item.id + index + "-srt"}>
|
||||
{title.prefix}
|
||||
<Heading
|
||||
size={AppFontSize.sm}
|
||||
style={{
|
||||
backgroundColor: colors.secondary.accent,
|
||||
color: colors.secondary.accentForeground
|
||||
}}
|
||||
>
|
||||
{title.match}
|
||||
</Heading>
|
||||
{title.suffix}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</Heading>
|
||||
</View>
|
||||
{props.item.content?.length ? (
|
||||
<Paragraph size={AppFontSize.xxs} color={colors.secondary.paragraph}>
|
||||
{props.item.content.length}
|
||||
</Paragraph>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
{expanded &&
|
||||
props.item.content.map((content, index) => (
|
||||
<Pressable
|
||||
key={props.item.id + index}
|
||||
style={{
|
||||
alignSelf: "flex-start",
|
||||
alignItems: "flex-start",
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
|
||||
borderColor: colors.primary.border,
|
||||
borderWidth: 0,
|
||||
borderRadius: 0,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.primary.border,
|
||||
width: "100%"
|
||||
}}
|
||||
onLongPress={async () => {
|
||||
const note = await db.notes.note(props.item.id);
|
||||
Properties.present(note);
|
||||
}}
|
||||
onPress={() => {
|
||||
let activeIndex = 0;
|
||||
for (let i = 0; i <= index; i++) {
|
||||
activeIndex += props.item.content[i].length;
|
||||
}
|
||||
console.log(activeIndex);
|
||||
openNote(activeIndex);
|
||||
}}
|
||||
>
|
||||
<Paragraph>
|
||||
{content.map((match, index) => (
|
||||
<React.Fragment key={props.item.id + index + "src"}>
|
||||
{match.prefix}
|
||||
<Paragraph
|
||||
size={AppFontSize.sm}
|
||||
style={{
|
||||
backgroundColor: colors.secondary.accent,
|
||||
color: colors.secondary.accentForeground
|
||||
}}
|
||||
>
|
||||
{match.match}
|
||||
</Paragraph>
|
||||
{match.suffix}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</Paragraph>
|
||||
</Pressable>
|
||||
))}
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
@@ -73,7 +73,7 @@ export default function List(props: ListProps) {
|
||||
? "home"
|
||||
: props.renderedInRoute === "Favorites"
|
||||
? "favorites"
|
||||
: props.renderedInRoute === "Trash"
|
||||
: props.renderedInRoute === "Trash" || props.dataType === "trash"
|
||||
? "trash"
|
||||
: `${props.dataType}s`;
|
||||
|
||||
@@ -150,7 +150,7 @@ export default function List(props: ListProps) {
|
||||
flex: 1
|
||||
}}
|
||||
>
|
||||
{props.data?.placeholders?.length === 0 ? (
|
||||
{props.data?.placeholders?.length === 0 || !props.data ? (
|
||||
<>
|
||||
{props.CustomLisHeader ? (
|
||||
props.CustomLisHeader
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
GroupHeader,
|
||||
GroupOptions,
|
||||
GroupingKey,
|
||||
HighlightedResult,
|
||||
Item,
|
||||
ItemType,
|
||||
Note,
|
||||
@@ -49,6 +50,7 @@ import { NoteWrapper } from "../list-items/note/wrapper";
|
||||
import { NotebookWrapper } from "../list-items/notebook/wrapper";
|
||||
import ReminderItem from "../list-items/reminder";
|
||||
import TagItem from "../list-items/tag";
|
||||
import { SearchResult } from "../list-items/search-result";
|
||||
|
||||
type ListItemWrapperProps<TItem = Item> = {
|
||||
group?: GroupingKey;
|
||||
@@ -153,7 +155,9 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
|
||||
},
|
||||
items?.cacheItem(index) ? 100 : 0
|
||||
);
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
/** empty */
|
||||
}
|
||||
})();
|
||||
}, [index, items, refreshItem]);
|
||||
|
||||
@@ -196,7 +200,7 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
|
||||
notebooks={notebooks.current}
|
||||
reminder={reminder.current}
|
||||
attachmentsCount={attachmentsCount.current}
|
||||
date={getDate(item, group)}
|
||||
date={getDate(item as Note, group)}
|
||||
isRenderedInActionSheet={isSheet}
|
||||
index={index}
|
||||
locked={locked.current}
|
||||
@@ -227,7 +231,7 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
|
||||
<NotebookWrapper
|
||||
item={item as Notebook}
|
||||
totalNotes={totalNotes.current}
|
||||
date={getDate(item, group)}
|
||||
date={getDate(item as Notebook, group)}
|
||||
index={index}
|
||||
/>
|
||||
</>
|
||||
@@ -285,12 +289,34 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
|
||||
/>
|
||||
</>
|
||||
);
|
||||
case "searchResult":
|
||||
return (
|
||||
<>
|
||||
{groupHeader && previousIndex.current === index && !isSheet ? (
|
||||
<SectionHeader
|
||||
screen={props.renderedInRoute}
|
||||
item={groupHeader}
|
||||
index={index}
|
||||
dataType={item.type}
|
||||
color={props.customAccentColor}
|
||||
groupOptions={groupOptions}
|
||||
onOpenJumpToDialog={() => {
|
||||
eSendEvent(eOpenJumpToDialog, {
|
||||
ref: props.scrollRef,
|
||||
data: items
|
||||
});
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<SearchResult item={item as HighlightedResult} />
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getDate(item: Item, groupType?: GroupingKey): number {
|
||||
function getDate(item: Notebook | Note, groupType?: GroupingKey): number {
|
||||
return (
|
||||
getSortValue(
|
||||
groupType
|
||||
|
||||
@@ -58,7 +58,6 @@ const Line = ({ top = 6, bottom = 6 }) => {
|
||||
|
||||
export const Properties = ({ close = () => {}, item, buttons = [] }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const isColor = !!ColorValues[item.title];
|
||||
if (!item || !item.id) {
|
||||
return (
|
||||
<Paragraph style={{ marginVertical: 10, alignSelf: "center" }}>
|
||||
|
||||
@@ -36,6 +36,7 @@ import Paragraph from "../ui/typography/paragraph";
|
||||
const TOP_BAR_ITEMS: ActionId[] = [
|
||||
"pin",
|
||||
"favorite",
|
||||
"archive",
|
||||
"lock-unlock",
|
||||
"publish",
|
||||
"local-only",
|
||||
@@ -66,6 +67,7 @@ const COLUMN_BAR_ITEMS: ActionId[] = [
|
||||
"move-notebook",
|
||||
"pin",
|
||||
"default-notebook",
|
||||
"default-tag",
|
||||
"default-homepage",
|
||||
"add-shortcut",
|
||||
"reorder",
|
||||
|
||||
@@ -24,11 +24,11 @@ import { TaggedNotes } from "../../screens/notes/tagged";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import ManageTagsSheet from "../sheets/manage-tags";
|
||||
import { Button } from "../ui/button";
|
||||
import { ColorTags } from "./color-tags";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import ManageTags from "../../screens/manage-tags";
|
||||
|
||||
export const Tags = ({ item, close }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -47,7 +47,8 @@ export const Tags = ({ item, close }) => {
|
||||
>
|
||||
<Button
|
||||
onPress={async () => {
|
||||
ManageTagsSheet.present([item.id]);
|
||||
ManageTags.present([item.id]);
|
||||
close();
|
||||
}}
|
||||
buttonType={{
|
||||
text: colors.primary.accent
|
||||
|
||||
@@ -42,10 +42,11 @@ import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { presentDialog } from "../dialog/functions";
|
||||
import ExportNotesSheet from "../sheets/export-notes";
|
||||
import ManageTagsSheet from "../sheets/manage-tags";
|
||||
|
||||
import { MoveNotebook } from "../../screens/move-notebook";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import NativeTooltip from "../../utils/tooltip";
|
||||
import ManageTags from "../../screens/manage-tags";
|
||||
|
||||
export const SelectionHeader = React.memo(
|
||||
({
|
||||
@@ -209,7 +210,7 @@ export const SelectionHeader = React.memo(
|
||||
{
|
||||
title: strings.manageTags(),
|
||||
onPress: async () => {
|
||||
ManageTagsSheet.present(selectedItemsList);
|
||||
ManageTags.present(selectedItemsList);
|
||||
},
|
||||
visible: type === "note",
|
||||
icon: "pound"
|
||||
|
||||
@@ -24,23 +24,22 @@ import { TextInput, View } from "react-native";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { db } from "../../../common/database";
|
||||
import { DDS } from "../../../services/device-detection";
|
||||
import {
|
||||
ToastManager,
|
||||
eSendEvent,
|
||||
presentSheet
|
||||
} from "../../../services/event-manager";
|
||||
import { ToastManager, eSendEvent } from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import { useMenuStore } from "../../../stores/use-menu-store";
|
||||
import { useNotebookStore } from "../../../stores/use-notebook-store";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { eOnNotebookUpdated } from "../../../utils/events";
|
||||
import { getParentNotebookId } from "../../../utils/notebooks";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { Button } from "../../ui/button";
|
||||
import Input from "../../ui/input";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
import { useSettingStore } from "../../../stores/use-setting-store";
|
||||
import DialogHeader from "../../dialog/dialog-header";
|
||||
import DialogButtons from "../../dialog/dialog-buttons";
|
||||
import { presentDialog } from "../../dialog/functions";
|
||||
import { getElevationStyle } from "../../../utils/elevation";
|
||||
import { defaultBorderRadius } from "../../../utils/size";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { getContainerBorder } from "../../../utils/colors";
|
||||
|
||||
export const AddNotebookSheet = ({
|
||||
notebook,
|
||||
@@ -55,6 +54,7 @@ export const AddNotebookSheet = ({
|
||||
showMoveNotesOnComplete: boolean;
|
||||
defaultTitle?: string;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const title = useRef(notebook?.title || defaultTitle);
|
||||
const description = useRef(notebook?.description);
|
||||
const titleInput = useRef<TextInput>(null);
|
||||
@@ -124,57 +124,66 @@ export const AddNotebookSheet = ({
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
maxHeight: DDS.isTab ? "90%" : "97%",
|
||||
borderRadius: DDS.isTab ? 5 : 0,
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
...getElevationStyle(5),
|
||||
width: DDS.isTab ? 400 : "85%",
|
||||
maxHeight: 450,
|
||||
borderRadius: defaultBorderRadius,
|
||||
backgroundColor: colors.primary.background,
|
||||
paddingTop: 12,
|
||||
...getContainerBorder(colors.primary.border, 0.5),
|
||||
overflow: "hidden"
|
||||
}}
|
||||
>
|
||||
<Heading size={AppFontSize.lg}>
|
||||
{notebook ? strings.editNotebook() : strings.newNotebook()}
|
||||
</Heading>
|
||||
|
||||
<Seperator />
|
||||
|
||||
<Input
|
||||
fwdRef={titleInput}
|
||||
testID={notesnook.ids.dialogs.notebook.inputs.title}
|
||||
onChangeText={(value) => {
|
||||
title.current = value;
|
||||
}}
|
||||
onLayout={() => {
|
||||
setImmediate(() => {
|
||||
titleInput?.current?.focus();
|
||||
});
|
||||
}}
|
||||
placeholder={strings.enterNotebookTitle()}
|
||||
onSubmit={() => {
|
||||
descriptionInput.current?.focus();
|
||||
}}
|
||||
returnKeyLabel="Next"
|
||||
returnKeyType="next"
|
||||
defaultValue={notebook ? notebook.title : title.current}
|
||||
/>
|
||||
|
||||
<Input
|
||||
fwdRef={descriptionInput}
|
||||
testID={notesnook.ids.dialogs.notebook.inputs.description}
|
||||
onChangeText={(value) => {
|
||||
description.current = value;
|
||||
}}
|
||||
placeholder={strings.enterNotebookDescription()}
|
||||
returnKeyLabel={strings.next()}
|
||||
returnKeyType="next"
|
||||
defaultValue={notebook ? notebook.description : ""}
|
||||
/>
|
||||
|
||||
<Button
|
||||
title={notebook ? strings.save() : strings.add()}
|
||||
type="accent"
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: DefaultAppStyles.GAP * 2,
|
||||
width: "100%"
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
onPress={onSaveChanges}
|
||||
>
|
||||
<DialogHeader
|
||||
title={notebook ? strings.editNotebook() : strings.newNotebook()}
|
||||
/>
|
||||
|
||||
<Input
|
||||
fwdRef={titleInput}
|
||||
testID={notesnook.ids.dialogs.notebook.inputs.title}
|
||||
onChangeText={(value) => {
|
||||
title.current = value;
|
||||
}}
|
||||
onLayout={() => {
|
||||
setTimeout(() => {
|
||||
titleInput?.current?.focus();
|
||||
}, 300);
|
||||
}}
|
||||
placeholder={strings.enterNotebookTitle()}
|
||||
onSubmit={() => {
|
||||
descriptionInput.current?.focus();
|
||||
}}
|
||||
returnKeyLabel="Next"
|
||||
returnKeyType="next"
|
||||
defaultValue={notebook ? notebook.title : title.current}
|
||||
/>
|
||||
|
||||
<Input
|
||||
fwdRef={descriptionInput}
|
||||
testID={notesnook.ids.dialogs.notebook.inputs.description}
|
||||
onChangeText={(value) => {
|
||||
description.current = value;
|
||||
}}
|
||||
placeholder={strings.enterNotebookDescription()}
|
||||
returnKeyLabel={strings.next()}
|
||||
returnKeyType="next"
|
||||
defaultValue={notebook ? notebook.description : ""}
|
||||
/>
|
||||
</View>
|
||||
<DialogButtons
|
||||
onPressNegative={() => {
|
||||
title.current = undefined;
|
||||
close?.(false);
|
||||
useSettingStore.getState().setSheetKeyboardHandler(true);
|
||||
}}
|
||||
positiveTitle={notebook ? strings.save() : strings.add()}
|
||||
negativeTitle={strings.cancel()}
|
||||
onPressPositive={onSaveChanges}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -188,9 +197,9 @@ AddNotebookSheet.present = (
|
||||
showMoveNotesOnComplete = true,
|
||||
defaultTitle?: string
|
||||
) => {
|
||||
presentSheet({
|
||||
presentDialog({
|
||||
context: context,
|
||||
component: (ref, close) => (
|
||||
component: (close) => (
|
||||
<AddNotebookSheet
|
||||
notebook={notebook}
|
||||
parentNotebook={parentNotebook}
|
||||
|
||||
@@ -283,7 +283,14 @@ export default function LinkNote(props: {
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<Paragraph numberOfLines={1}>{selectedNote?.title}</Paragraph>
|
||||
<Paragraph
|
||||
style={{
|
||||
flexShrink: 1
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{selectedNote?.title}
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph
|
||||
color={colors.secondary.paragraph}
|
||||
|
||||
@@ -48,7 +48,7 @@ import { Dialog } from "../../dialog";
|
||||
import { ReminderTime } from "../../ui/reminder-time";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { ItemReference, Note, Reminder } from "@notesnook/core";
|
||||
import { Note, Reminder } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
@@ -57,7 +57,7 @@ type ReminderSheetProps = {
|
||||
close?: (ctx?: string) => void;
|
||||
update?: (options: PresentSheetOptions) => void;
|
||||
reminder?: Reminder;
|
||||
reference?: ItemReference;
|
||||
reference?: Note;
|
||||
};
|
||||
|
||||
const ReminderModes =
|
||||
@@ -612,7 +612,7 @@ export default function ReminderSheet({
|
||||
|
||||
ReminderSheet.present = (
|
||||
reminder?: Reminder,
|
||||
reference?: ItemReference,
|
||||
reference?: Note,
|
||||
isSheet?: boolean
|
||||
) => {
|
||||
presentSheet({
|
||||
|
||||
@@ -52,23 +52,42 @@ const Sort = ({
|
||||
hideGroupOptions?: boolean;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
|
||||
const groupType =
|
||||
screen === "Archive"
|
||||
? "archive"
|
||||
: screen === "Search"
|
||||
? "search"
|
||||
: screen === "Notes"
|
||||
? "home"
|
||||
: screen === "Trash" || type === "trash"
|
||||
? "trash"
|
||||
: ((type + "s") as GroupingKey);
|
||||
|
||||
const [groupOptions, setGroupOptions] = useState(
|
||||
db.settings.getGroupOptions(
|
||||
screen === "Notes"
|
||||
? "home"
|
||||
: screen === "Trash"
|
||||
? "trash"
|
||||
: ((type + "s") as GroupingKey)
|
||||
)
|
||||
db.settings.getGroupOptions(groupType)
|
||||
);
|
||||
|
||||
const getSortButtonTitle = () => {
|
||||
const { sortDirection, groupBy, sortBy } = groupOptions || {};
|
||||
const isAlphabetical = groupBy === "abc" || sortBy === "title";
|
||||
const isDueDate = sortBy === "dueDate";
|
||||
const isRelevance = sortBy === "relevance";
|
||||
|
||||
if (sortDirection === "asc") {
|
||||
if (isAlphabetical) return strings.aToZ();
|
||||
if (isDueDate) return strings.earliestFirst();
|
||||
if (isRelevance) return strings.leastRelevantFirst();
|
||||
return strings.oldNew();
|
||||
} else {
|
||||
if (isAlphabetical) return strings.zToA();
|
||||
if (isDueDate) return strings.latestFirst();
|
||||
if (isRelevance) return strings.mostRelevantFirst();
|
||||
return strings.newOld();
|
||||
}
|
||||
};
|
||||
|
||||
const updateGroupOptions = async (_groupOptions: GroupOptions) => {
|
||||
const groupType =
|
||||
screen === "Notes"
|
||||
? "home"
|
||||
: screen === "Trash"
|
||||
? "trash"
|
||||
: ((type + "s") as GroupingKey);
|
||||
console.log("updateGroupOptions for group", groupType, "in", screen);
|
||||
await db.settings.setGroupOptions(groupType, _groupOptions);
|
||||
setGroupOptions(_groupOptions);
|
||||
setTimeout(() => {
|
||||
@@ -109,31 +128,10 @@ const Sort = ({
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
size={AppFontSize.lg}
|
||||
style={{
|
||||
alignSelf: "center"
|
||||
}}
|
||||
>
|
||||
{strings.sortBy()}
|
||||
</Heading>
|
||||
<Heading size={AppFontSize.lg}>{strings.sortBy()}</Heading>
|
||||
|
||||
<Button
|
||||
title={
|
||||
groupOptions?.sortDirection === "asc"
|
||||
? groupOptions?.groupBy === "abc" ||
|
||||
groupOptions?.sortBy === "title"
|
||||
? strings.aToZ()
|
||||
: groupOptions?.sortBy === "dueDate"
|
||||
? strings.earliestFirst()
|
||||
: strings.oldNew()
|
||||
: groupOptions?.groupBy === "abc" ||
|
||||
groupOptions?.sortBy === "title"
|
||||
? strings.zToA()
|
||||
: groupOptions?.sortBy === "dueDate"
|
||||
? strings.latestFirst()
|
||||
: strings.newOld()
|
||||
}
|
||||
title={getSortButtonTitle()}
|
||||
icon={
|
||||
groupOptions?.sortDirection === "asc"
|
||||
? "sort-ascending"
|
||||
@@ -157,13 +155,24 @@ const Sort = ({
|
||||
borderBottomColor: colors.primary.border
|
||||
}}
|
||||
>
|
||||
{Object.keys(SORT).map((item) =>
|
||||
(item === "dueDate" && screen !== "Reminders") ||
|
||||
(screen !== "Tags" &&
|
||||
screen !== "Reminders" &&
|
||||
item === "dateModified") ||
|
||||
((screen === "Tags" || screen === "Reminders") &&
|
||||
item === "dateEdited") ? null : (
|
||||
{Object.keys(SORT).map((item) => {
|
||||
const sortOptionVisibility = {
|
||||
relevance: screen === "Search",
|
||||
dueDate: screen === "Reminders",
|
||||
dateModified: screen === "Tags" || screen === "Reminders",
|
||||
dateEdited: screen !== "Tags" && screen !== "Reminders"
|
||||
};
|
||||
|
||||
// Check if this sort option should be skipped for the current screen
|
||||
const shouldSkip =
|
||||
item in sortOptionVisibility &&
|
||||
!sortOptionVisibility[item as keyof typeof sortOptionVisibility];
|
||||
|
||||
if (shouldSkip) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
key={item}
|
||||
type={groupOptions?.sortBy === item ? "selected" : "plain"}
|
||||
@@ -201,8 +210,8 @@ const Sort = ({
|
||||
/>
|
||||
) : null}
|
||||
</Pressable>
|
||||
)
|
||||
)}
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
|
||||
{!hideGroupOptions ? (
|
||||
|
||||
@@ -80,6 +80,9 @@ function _MenuItem({
|
||||
case "Monographs":
|
||||
setItemCount(await db.monographs.all.count());
|
||||
break;
|
||||
case "Archive":
|
||||
setItemCount(await db.notes.archived.count());
|
||||
break;
|
||||
case "Trash":
|
||||
setItemCount((await db.trash.all()).length);
|
||||
break;
|
||||
|
||||
@@ -93,7 +93,11 @@ export const NotebookItem = ({
|
||||
<View
|
||||
style={{
|
||||
paddingLeft:
|
||||
item.depth > 0 && item.depth < 6 ? 15 * item.depth : undefined,
|
||||
item.depth === 0
|
||||
? undefined
|
||||
: item.depth < 6
|
||||
? 15 * item.depth
|
||||
: 15 * 5,
|
||||
width: "100%",
|
||||
marginTop: 2
|
||||
}}
|
||||
|
||||
@@ -321,6 +321,9 @@ const Input = ({
|
||||
bottom={10}
|
||||
onPress={button.onPress}
|
||||
color={button.color}
|
||||
style={{
|
||||
marginRight: -8
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -21,11 +21,7 @@ import { FeatureType } from "./components/sheets/new-feature";
|
||||
|
||||
export const features: FeatureType[] = [
|
||||
{
|
||||
title: "Notebook Tree View",
|
||||
body: "Notebooks are now displayed in a tree view for better organization and user experience."
|
||||
},
|
||||
{
|
||||
title: "New SideBar",
|
||||
body: "Sidebar now contains tabs for Notebooks and Tags for easy navigation."
|
||||
title: "Improved Search",
|
||||
body: "Improved search results with better relevance and highlighting."
|
||||
}
|
||||
];
|
||||
|
||||
@@ -66,9 +66,11 @@ import { convertNoteToText } from "../utils/note-to-text";
|
||||
import { sleep } from "../utils/time";
|
||||
import SettingsService from "../services/settings";
|
||||
import { useSettingStore } from "../stores/use-setting-store";
|
||||
import { useArchivedStore } from "../stores/use-archived-store";
|
||||
|
||||
export type ActionId =
|
||||
| "select"
|
||||
| "archive"
|
||||
| "restore"
|
||||
| "delete"
|
||||
| "reorder"
|
||||
@@ -108,7 +110,8 @@ export type ActionId =
|
||||
| "favorite"
|
||||
| "remove-from-notebook"
|
||||
| "trash"
|
||||
| "default-homepage";
|
||||
| "default-homepage"
|
||||
| "default-tag";
|
||||
|
||||
export type Action = {
|
||||
id: ActionId;
|
||||
@@ -156,6 +159,8 @@ export const useActions = ({
|
||||
const [defaultNotebook, setDefaultNotebook] = useState(
|
||||
db.settings.getDefaultNotebook()
|
||||
);
|
||||
const [defaultTag, setDefaultTag] = useState(db.settings.getDefaultTag());
|
||||
|
||||
const [noteInCurrentNotebook, setNoteInCurrentNotebook] = useState(false);
|
||||
const [locked, setLocked] = useState(false);
|
||||
const isHomepage = useSettingStore(
|
||||
@@ -467,15 +472,39 @@ export const useActions = ({
|
||||
}
|
||||
|
||||
if (item.type === "tag" || item.type === "notebook") {
|
||||
actions.push({
|
||||
id: "add-shortcut",
|
||||
title: isPinnedToMenu ? strings.removeShortcut() : strings.addShortcut(),
|
||||
icon: isPinnedToMenu ? "link-variant-remove" : "link-variant",
|
||||
onPress: createMenuShortcut,
|
||||
isToggle: true,
|
||||
checked: isPinnedToMenu,
|
||||
activeColor: colors.error.paragraph
|
||||
});
|
||||
actions.push(
|
||||
{
|
||||
id: "add-shortcut",
|
||||
title: isPinnedToMenu
|
||||
? strings.removeShortcut()
|
||||
: strings.addShortcut(),
|
||||
icon: isPinnedToMenu ? "link-variant-remove" : "link-variant",
|
||||
onPress: createMenuShortcut,
|
||||
isToggle: true,
|
||||
checked: isPinnedToMenu,
|
||||
activeColor: colors.error.paragraph
|
||||
},
|
||||
{
|
||||
id: "default-tag",
|
||||
title:
|
||||
defaultTag === item.id
|
||||
? strings.removeAsDefault()
|
||||
: strings.setAsDefault(),
|
||||
hidden: item.type !== "tag",
|
||||
icon: "pound",
|
||||
onPress: async () => {
|
||||
if (defaultTag === item.id) {
|
||||
await db.settings.setDefaultTag(undefined);
|
||||
setDefaultTag(undefined);
|
||||
} else {
|
||||
await db.settings.setDefaultTag(item.id);
|
||||
setDefaultTag(item.id);
|
||||
}
|
||||
close();
|
||||
},
|
||||
checked: defaultTag === item.id
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (item.type === "notebook") {
|
||||
@@ -651,7 +680,8 @@ export const useActions = ({
|
||||
|
||||
async function pinToNotifications() {
|
||||
if (notifPinned) {
|
||||
Notifications.remove(item.id);
|
||||
await Notifications.remove(item.id);
|
||||
await sleep(500);
|
||||
await Notifications.get();
|
||||
setNotifPinned(isNotePinnedInNotifications(item));
|
||||
return;
|
||||
@@ -665,7 +695,8 @@ export const useActions = ({
|
||||
return;
|
||||
}
|
||||
|
||||
Notifications.pinNote(item.id);
|
||||
await Notifications.pinNote(item.id);
|
||||
await sleep(500);
|
||||
await Notifications.get();
|
||||
setNotifPinned(isNotePinnedInNotifications(item));
|
||||
}
|
||||
@@ -926,7 +957,7 @@ export const useActions = ({
|
||||
title: strings.remindMe(),
|
||||
icon: "clock-plus-outline",
|
||||
onPress: () => {
|
||||
ReminderSheet.present(undefined, { id: item.id, type: "note" });
|
||||
ReminderSheet.present(undefined, item);
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -972,6 +1003,19 @@ export const useActions = ({
|
||||
reference: item as ItemReference
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "archive",
|
||||
title: !item.archived ? strings.archive() : strings.unarchive(),
|
||||
icon: "archive",
|
||||
onPress: async () => {
|
||||
db.notes.archive(!item.archived, item.id);
|
||||
setItem((await db.notes.note(item.id)) as Item);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useArchivedStore.getState().refresh();
|
||||
},
|
||||
checked: item.archived,
|
||||
isToggle: true
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -341,8 +341,15 @@ const doAppLoadActions = async () => {
|
||||
};
|
||||
|
||||
const checkAppUpdateAvailable = async () => {
|
||||
if (__DEV__ || Config.isTesting === "true" || Config.FDROID_BUILD || BETA)
|
||||
if (
|
||||
__DEV__ ||
|
||||
Config.isTesting === "true" ||
|
||||
Config.FDROID_BUILD ||
|
||||
BETA ||
|
||||
!SettingsService.getProperty("checkForUpdates")
|
||||
)
|
||||
return;
|
||||
|
||||
try {
|
||||
const version =
|
||||
Config.GITHUB_RELEASE === "true"
|
||||
|
||||
@@ -32,7 +32,7 @@ export function useGroupOptions(type: any) {
|
||||
const onUpdate = (groupType: string) => {
|
||||
if (groupType !== type) return;
|
||||
const options = db.settings?.getGroupOptions(type) as any;
|
||||
|
||||
if (!options) return;
|
||||
if (
|
||||
groupOptions?.groupBy !== options.groupBy ||
|
||||
groupOptions?.sortBy !== options.sortBy ||
|
||||
|
||||
@@ -43,7 +43,7 @@ let Reminders: any = null;
|
||||
let Monographs: any = null;
|
||||
let TaggedNotes: any = null;
|
||||
let ColoredNotes: any = null;
|
||||
|
||||
let Archive: any = null;
|
||||
const AppNavigation = React.memo(
|
||||
() => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -192,6 +192,14 @@ const AppNavigation = React.memo(
|
||||
initialParams={home.name === "ColoredNotes" ? home.params : undefined}
|
||||
/>
|
||||
|
||||
<AppStack.Screen
|
||||
name="Archive"
|
||||
getComponent={() => {
|
||||
Archive = Archive || require("../screens/archive").default;
|
||||
return Archive;
|
||||
}}
|
||||
/>
|
||||
|
||||
<AppStack.Screen
|
||||
name="Reminders"
|
||||
getComponent={() => {
|
||||
@@ -239,6 +247,7 @@ let LinkNotebooks: any = null;
|
||||
let MoveNotebook: any = null;
|
||||
let MoveNotes: any = null;
|
||||
let Settings: any = null;
|
||||
let ManageTags: any = null;
|
||||
|
||||
export const RootNavigation = () => {
|
||||
const introCompleted = useSettingStore(
|
||||
@@ -318,6 +327,15 @@ export const RootNavigation = () => {
|
||||
return Settings;
|
||||
}}
|
||||
/>
|
||||
|
||||
<RootStack.Screen
|
||||
name="ManageTags"
|
||||
getComponent={() => {
|
||||
ManageTags =
|
||||
ManageTags || require("../screens/manage-tags").default;
|
||||
return ManageTags;
|
||||
}}
|
||||
/>
|
||||
</RootStack.Navigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
|
||||
88
apps/mobile/app/screens/archive/index.tsx
Normal file
88
apps/mobile/app/screens/archive/index.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import DelayLayout from "../../components/delay-layout";
|
||||
import { Header } from "../../components/header";
|
||||
import List from "../../components/list";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import SettingsService from "../../services/settings";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { db } from "../../common/database";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useArchived } from "../../stores/use-archived-store";
|
||||
|
||||
export const Archive = ({ navigation, route }: NavigationProps<"Archive">) => {
|
||||
const [archive, loading, refresh] = useArchived();
|
||||
const isFocused = useNavigationFocus(navigation, {
|
||||
onFocus: (prev) => {
|
||||
Navigation.routeNeedsUpdate(
|
||||
route.name,
|
||||
Navigation.routeUpdateFunctions[route.name]
|
||||
);
|
||||
useNavigationStore.getState().setFocusedRouteId(route?.name);
|
||||
return false;
|
||||
},
|
||||
onBlur: () => false,
|
||||
delay: SettingsService.get().homepage === route.name ? 1 : -1
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<SelectionHeader id={route.name} items={archive} type="note" />
|
||||
<Header
|
||||
renderedInRoute={route.name}
|
||||
title={strings.routes[route.name]()}
|
||||
canGoBack={false}
|
||||
hasSearch={true}
|
||||
id={route.name}
|
||||
onSearch={() => {
|
||||
Navigation.push("Search", {
|
||||
placeholder: strings.searchInRoute(route.name),
|
||||
type: "note",
|
||||
title: route.name,
|
||||
route: route.name,
|
||||
items: db.notes.archived
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<DelayLayout wait={loading}>
|
||||
<List
|
||||
data={archive}
|
||||
dataType="note"
|
||||
onRefresh={() => {
|
||||
refresh();
|
||||
}}
|
||||
renderedInRoute="Archive"
|
||||
loading={loading}
|
||||
placeholder={{
|
||||
title: strings.yourArchive(),
|
||||
paragraph: strings.yourArchiveIsEmpty(),
|
||||
loading: strings.loadingArchive()
|
||||
}}
|
||||
headerTitle={strings.routes.Archive()}
|
||||
/>
|
||||
</DelayLayout>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Archive;
|
||||
@@ -236,6 +236,11 @@ class Commands {
|
||||
const tabId = useTabStore.getState().currentTab;
|
||||
return this.sendCommand("scrollIntoViewById", id, tabId);
|
||||
};
|
||||
|
||||
scrollToSearchResult = (index: number) => {
|
||||
const tabId = useTabStore.getState().currentTab;
|
||||
return this.sendCommand("scrollToSearchResult", index, tabId);
|
||||
};
|
||||
}
|
||||
|
||||
export default Commands;
|
||||
|
||||
@@ -41,7 +41,6 @@ import { AuthMode } from "../../../components/auth/common";
|
||||
import EditorTabs from "../../../components/sheets/editor-tabs";
|
||||
import { Issue } from "../../../components/sheets/github/issue";
|
||||
import LinkNote from "../../../components/sheets/link-note";
|
||||
import ManageTagsSheet from "../../../components/sheets/manage-tags";
|
||||
import { RelationsList } from "../../../components/sheets/relations-list";
|
||||
import ReminderSheet from "../../../components/sheets/reminder";
|
||||
import TableOfContents from "../../../components/sheets/toc";
|
||||
@@ -79,6 +78,8 @@ import { EditorMessage, EditorProps, useEditorType } from "./types";
|
||||
import { useTabStore } from "./use-tab-store";
|
||||
import { editorState, openInternalLink } from "./utils";
|
||||
import { Properties } from "../../../components/properties";
|
||||
import { sleep } from "../../../utils/time";
|
||||
import ManageTags from "../../manage-tags";
|
||||
|
||||
const publishNote = async () => {
|
||||
const user = useUserStore.getState().user;
|
||||
@@ -177,7 +178,7 @@ export const useEditorEvents = (
|
||||
useEffect(() => {
|
||||
const handleKeyboardDidShow: KeyboardEventListener = () => {
|
||||
editor.commands.keyboardShown(true);
|
||||
//editor.postMessage(NativeEvents.keyboardShown, undefined);
|
||||
editor.postMessage(NativeEvents.keyboardShown, undefined);
|
||||
};
|
||||
const handleKeyboardDidHide: KeyboardEventListener = () => {
|
||||
editor.commands.keyboardShown(false);
|
||||
@@ -448,7 +449,7 @@ export const useEditorEvents = (
|
||||
});
|
||||
return;
|
||||
}
|
||||
ManageTagsSheet.present([noteId]);
|
||||
ManageTags.present([noteId]);
|
||||
break;
|
||||
case EditorEvents.tag:
|
||||
if (editorMessage.value) {
|
||||
@@ -613,6 +614,10 @@ export const useEditorEvents = (
|
||||
eSendEvent(eEditorTabFocused, editorMessage.tabId);
|
||||
if (!editor.state.current.initialLoadCalled) break;
|
||||
if (editorMessage.noteId) {
|
||||
// Wait for next tick to ensure the tab is not changed.
|
||||
await sleep(1);
|
||||
if (useTabStore.getState().currentTab !== editorMessage.tabId)
|
||||
return;
|
||||
if (!useSettingStore.getState().isAppLoading) {
|
||||
const note = await db.notes.note(editorMessage.noteId);
|
||||
if (note) {
|
||||
|
||||
@@ -352,7 +352,7 @@ export const useEditor = (
|
||||
DatabaseLogger.log(`Note saved: ${id}...`);
|
||||
|
||||
clearTimeout(saveTimer);
|
||||
|
||||
const oldNote = currentNotes.current[id];
|
||||
if (id) {
|
||||
currentNotes.current[id] = await db.notes?.note(id);
|
||||
}
|
||||
@@ -365,22 +365,37 @@ export const useEditor = (
|
||||
}
|
||||
});
|
||||
|
||||
const defaultNotebook = db.settings.getDefaultNotebook();
|
||||
if (!state.current.onNoteCreated && defaultNotebook) {
|
||||
onNoteCreated(id, {
|
||||
type: "notebook",
|
||||
id: defaultNotebook
|
||||
});
|
||||
if (!state.current.onNoteCreated) {
|
||||
const defaultNotebook = db.settings.getDefaultNotebook();
|
||||
if (defaultNotebook) {
|
||||
onNoteCreated(id, {
|
||||
type: "notebook",
|
||||
id: defaultNotebook
|
||||
});
|
||||
}
|
||||
|
||||
const defaultTag = db.settings.getDefaultTag();
|
||||
if (defaultTag) {
|
||||
onNoteCreated(id, {
|
||||
type: "tag",
|
||||
id: defaultTag
|
||||
});
|
||||
}
|
||||
} else {
|
||||
state.current?.onNoteCreated && state.current.onNoteCreated(id);
|
||||
state.current.onNoteCreated(id);
|
||||
}
|
||||
}
|
||||
|
||||
postMessage(
|
||||
NativeEvents.title,
|
||||
currentNotes.current[id]?.title,
|
||||
tabId
|
||||
);
|
||||
if (
|
||||
oldNote?.title !== currentNotes.current[id]?.title &&
|
||||
!noteData.title
|
||||
) {
|
||||
postMessage(
|
||||
NativeEvents.title,
|
||||
currentNotes.current[id]?.title,
|
||||
tabId
|
||||
);
|
||||
}
|
||||
|
||||
if (Notifications.isNotePinned(id as string)) {
|
||||
Notifications.pinNote(id as string);
|
||||
@@ -464,8 +479,7 @@ export const useEditor = (
|
||||
}
|
||||
) => {
|
||||
currentNotes.current[note.id] = note;
|
||||
const locked = note && (await db.vaults.itemExists(note));
|
||||
if ((locked || note.content) && note.content?.data) {
|
||||
if (note.content && note.content?.data) {
|
||||
currentContents.current[note.id] = {
|
||||
data: note.content?.data,
|
||||
type: note.content?.type || "tiptap",
|
||||
@@ -493,6 +507,7 @@ export const useEditor = (
|
||||
session?: TabSessionItem;
|
||||
newTab?: boolean;
|
||||
refresh?: boolean;
|
||||
searchResultIndex?: number;
|
||||
}) => {
|
||||
loadNoteMutex.runExclusive(async () => {
|
||||
if (!event) return;
|
||||
@@ -678,13 +693,17 @@ export const useEditor = (
|
||||
{
|
||||
data: currentContents.current[item.id]?.data || "",
|
||||
scrollTop: tab?.session?.scrollTop,
|
||||
selection: tab?.session?.selection
|
||||
selection: tab?.session?.selection,
|
||||
searchResultIndex: event.searchResultIndex
|
||||
},
|
||||
tabId,
|
||||
10000
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
if (event.searchResultIndex !== undefined) {
|
||||
commands.scrollToSearchResult(event.searchResultIndex);
|
||||
}
|
||||
if (blockIdRef.current) {
|
||||
commands.scrollIntoViewById(blockIdRef.current);
|
||||
blockIdRef.current = undefined;
|
||||
|
||||
@@ -29,27 +29,30 @@ import React, {
|
||||
useRef,
|
||||
useState
|
||||
} from "react";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import { TextInput, View, useWindowDimensions } from "react-native";
|
||||
import { ActionSheetRef } from "react-native-actions-sheet";
|
||||
import { FlashList } from "react-native-actions-sheet/dist/src/views/FlashList";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../../../common/database";
|
||||
import { useDBItem } from "../../../hooks/use-db-item";
|
||||
import { ToastManager, presentSheet } from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import { db } from "../../common/database";
|
||||
import { useDBItem } from "../../hooks/use-db-item";
|
||||
import { ToastManager } from "../../services/event-manager";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import {
|
||||
ItemSelection,
|
||||
createItemSelectionStore
|
||||
} from "../../../stores/item-selection-store";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { useTagStore } from "../../../stores/use-tag-store";
|
||||
import { defaultBorderRadius, AppFontSize } from "../../../utils/size";
|
||||
import Input from "../../ui/input";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
} from "../../stores/item-selection-store";
|
||||
import { useRelationStore } from "../../stores/use-relation-store";
|
||||
import { useTagStore } from "../../stores/use-tag-store";
|
||||
import { defaultBorderRadius, AppFontSize } from "../../utils/size";
|
||||
import Input from "../../components/ui/input";
|
||||
import { Pressable } from "../../components/ui/pressable";
|
||||
import Heading from "../../components/ui/typography/heading";
|
||||
import Paragraph from "../../components/ui/typography/paragraph";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { Header } from "../../components/header";
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
|
||||
async function updateInitialSelectionState(items: string[]) {
|
||||
const relations = await db.relations
|
||||
@@ -85,16 +88,14 @@ async function updateInitialSelectionState(items: string[]) {
|
||||
|
||||
const useTagItemSelection = createItemSelectionStore(true);
|
||||
|
||||
const ManageTagsSheet = (props: {
|
||||
ids?: string[];
|
||||
actionSheetRef: RefObject<ActionSheetRef>;
|
||||
}) => {
|
||||
const ManageTags = (props: NavigationProps<"ManageTags">) => {
|
||||
const { colors } = useThemeColors();
|
||||
const ids = useMemo(() => props.ids || [], [props.ids]);
|
||||
const ids = props.route.params.ids || [];
|
||||
const [tags, setTags] = useState<VirtualizedGrouping<Tag>>();
|
||||
const [query, setQuery] = useState<string>();
|
||||
const inputRef = useRef<TextInput>(null);
|
||||
const [focus, setFocus] = useState(false);
|
||||
useNavigationFocus(props.navigation, { focusOnInit: true });
|
||||
const [queryExists, setQueryExists] = useState(false);
|
||||
const dimensions = useWindowDimensions();
|
||||
const refreshSelection = useCallback(() => {
|
||||
@@ -239,112 +240,117 @@ const ManageTagsSheet = (props: {
|
||||
);
|
||||
|
||||
return (
|
||||
<View
|
||||
<SafeAreaView
|
||||
style={{
|
||||
width: "100%",
|
||||
alignSelf: "center",
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
maxHeight: dimensions.height * 0.85
|
||||
backgroundColor: colors.primary.background,
|
||||
gap: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
button={{
|
||||
icon: "magnify",
|
||||
color: colors.primary.accent,
|
||||
size: AppFontSize.lg,
|
||||
onPress: () => {}
|
||||
}}
|
||||
testID="tag-input"
|
||||
fwdRef={inputRef}
|
||||
autoCapitalize="none"
|
||||
onChangeText={(v) => {
|
||||
setQuery(sanitizeTag(v));
|
||||
checkQueryExists(sanitizeTag(v));
|
||||
}}
|
||||
onFocusInput={() => {
|
||||
setFocus(true);
|
||||
}}
|
||||
onBlurInput={() => {
|
||||
setFocus(false);
|
||||
}}
|
||||
onSubmit={() => {
|
||||
onSubmit();
|
||||
}}
|
||||
placeholder={strings.searchForTags()}
|
||||
/>
|
||||
|
||||
{query && !queryExists ? (
|
||||
<Pressable
|
||||
key={"query_item"}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
marginVertical: 5,
|
||||
justifyContent: "space-between",
|
||||
padding: DefaultAppStyles.GAP
|
||||
}}
|
||||
onPress={onSubmit}
|
||||
type="selected"
|
||||
>
|
||||
<Heading size={AppFontSize.sm} color={colors.selected.heading}>
|
||||
{strings.add()} {'"' + "#" + query + '"'}
|
||||
</Heading>
|
||||
<Icon
|
||||
name="plus"
|
||||
color={colors.selected.icon}
|
||||
size={AppFontSize.lg}
|
||||
/>
|
||||
</Pressable>
|
||||
) : null}
|
||||
|
||||
<Header title={strings.manageTags()} canGoBack />
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
flexGrow: 1,
|
||||
height: "100%"
|
||||
paddingHorizontal: DefaultAppStyles.GAP
|
||||
}}
|
||||
>
|
||||
<FlashList
|
||||
data={tags?.placeholders}
|
||||
keyboardShouldPersistTaps
|
||||
keyboardDismissMode="interactive"
|
||||
estimatedItemSize={50}
|
||||
renderItem={renderTag}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 200,
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Heading size={50} color={colors.secondary.heading}>
|
||||
#
|
||||
</Heading>
|
||||
<Paragraph
|
||||
textBreakStrategy="balanced"
|
||||
color={colors.secondary.paragraph}
|
||||
>
|
||||
{strings.emptyPlaceholders("tag")}
|
||||
</Paragraph>
|
||||
</View>
|
||||
}
|
||||
ListFooterComponent={<View style={{ height: 50 }} />}
|
||||
<Input
|
||||
button={{
|
||||
icon: "magnify",
|
||||
color: colors.primary.accent,
|
||||
size: AppFontSize.lg,
|
||||
onPress: () => {}
|
||||
}}
|
||||
testID="tag-input"
|
||||
fwdRef={inputRef}
|
||||
autoCapitalize="none"
|
||||
onChangeText={(v) => {
|
||||
setQuery(sanitizeTag(v));
|
||||
checkQueryExists(sanitizeTag(v));
|
||||
}}
|
||||
onFocusInput={() => {
|
||||
setFocus(true);
|
||||
}}
|
||||
onBlurInput={() => {
|
||||
setFocus(false);
|
||||
}}
|
||||
onSubmit={() => {
|
||||
onSubmit();
|
||||
}}
|
||||
placeholder={strings.searchForTags()}
|
||||
/>
|
||||
|
||||
{query && !queryExists ? (
|
||||
<Pressable
|
||||
key={"query_item"}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
onPress={onSubmit}
|
||||
type="selected"
|
||||
>
|
||||
<Heading size={AppFontSize.sm} color={colors.selected.heading}>
|
||||
{strings.add()} {'"' + "#" + query + '"'}
|
||||
</Heading>
|
||||
<Icon
|
||||
name="plus"
|
||||
color={colors.selected.icon}
|
||||
size={AppFontSize.lg}
|
||||
/>
|
||||
</Pressable>
|
||||
) : null}
|
||||
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
flexGrow: 1,
|
||||
height: "100%"
|
||||
}}
|
||||
>
|
||||
<FlashList
|
||||
data={tags?.placeholders}
|
||||
keyboardShouldPersistTaps
|
||||
keyboardDismissMode="interactive"
|
||||
estimatedItemSize={50}
|
||||
renderItem={renderTag}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 200,
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Heading size={50} color={colors.secondary.heading}>
|
||||
#
|
||||
</Heading>
|
||||
<Paragraph
|
||||
textBreakStrategy="balanced"
|
||||
color={colors.secondary.paragraph}
|
||||
>
|
||||
{strings.emptyPlaceholders("tag")}
|
||||
</Paragraph>
|
||||
</View>
|
||||
}
|
||||
ListFooterComponent={<View style={{ height: 50 }} />}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
ManageTagsSheet.present = (ids?: string[]) => {
|
||||
presentSheet({
|
||||
component: (ref) => {
|
||||
return <ManageTagsSheet actionSheetRef={ref} ids={ids} />;
|
||||
}
|
||||
ManageTags.present = (ids?: string[]) => {
|
||||
Navigation.push("ManageTags", {
|
||||
ids: ids
|
||||
});
|
||||
};
|
||||
|
||||
export default ManageTagsSheet;
|
||||
export default ManageTags;
|
||||
|
||||
const TagItem = ({
|
||||
id,
|
||||
@@ -248,7 +248,13 @@ const SelectableNoteItem = React.memo(
|
||||
flexGrow: 1
|
||||
}}
|
||||
>
|
||||
<Heading size={AppFontSize.sm} numberOfLines={1}>
|
||||
<Heading
|
||||
size={AppFontSize.sm}
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
maxWidth: "93%"
|
||||
}}
|
||||
>
|
||||
{item?.title}
|
||||
</Heading>
|
||||
{item.type == "note" && item.headline ? (
|
||||
@@ -256,6 +262,9 @@ const SelectableNoteItem = React.memo(
|
||||
numberOfLines={1}
|
||||
color={colors?.secondary.paragraph}
|
||||
size={AppFontSize.sm}
|
||||
style={{
|
||||
maxWidth: "93%"
|
||||
}}
|
||||
>
|
||||
{item.headline}
|
||||
</Paragraph>
|
||||
|
||||
@@ -17,35 +17,37 @@ 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 { Item, Note, VirtualizedGrouping } from "@notesnook/core";
|
||||
import {
|
||||
FilteredSelector,
|
||||
Item,
|
||||
Note,
|
||||
VirtualizedGrouping
|
||||
} from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { DatabaseLogger, db } from "../../common/database";
|
||||
import List from "../../components/list";
|
||||
import SelectionHeader from "../../components/selection-header";
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import {
|
||||
ToastManager,
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent
|
||||
} from "../../services/event-manager";
|
||||
import { ToastManager, eSubscribeEvent } from "../../services/event-manager";
|
||||
import { NavigationProps } from "../../services/navigation";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { eOnRefreshSearch } from "../../utils/events";
|
||||
import { eGroupOptionsUpdated, eOnRefreshSearch } from "../../utils/events";
|
||||
import { SearchBar } from "./search-bar";
|
||||
import { FilteredSelector } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
export const Search = ({ route, navigation }: NavigationProps<"Search">) => {
|
||||
const [results, setResults] = useState<VirtualizedGrouping<Item>>();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchStatus, setSearchStatus] = useState<string>();
|
||||
const currentQuery = useRef<string>();
|
||||
const timer = useRef<NodeJS.Timeout>();
|
||||
const isFocused = useNavigationFocus(navigation, {
|
||||
useNavigationFocus(navigation, {
|
||||
onFocus: (prev) => {
|
||||
useNavigationStore.getState().setFocusedRouteId(route.name);
|
||||
return !prev?.current;
|
||||
},
|
||||
onBlur: () => false
|
||||
onBlur: () => {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
const onSearch = React.useCallback(
|
||||
@@ -60,32 +62,35 @@ export const Search = ({ route, navigation }: NavigationProps<"Search">) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
let results: VirtualizedGrouping<Item> | undefined;
|
||||
|
||||
const groupOptions = db.settings.getGroupOptions("search");
|
||||
switch (route.params.type) {
|
||||
case "note":
|
||||
results = await db.lookup
|
||||
.notes(query, route.params.items as FilteredSelector<Note>)
|
||||
.sorted();
|
||||
results = await db.lookup.notesWithHighlighting(
|
||||
query,
|
||||
route.params.items as FilteredSelector<Note>,
|
||||
groupOptions
|
||||
);
|
||||
|
||||
break;
|
||||
case "notebook":
|
||||
results = await db.lookup.notebooks(query).sorted();
|
||||
results = await db.lookup.notebooks(query).sorted(groupOptions);
|
||||
break;
|
||||
case "tag":
|
||||
results = await db.lookup.tags(query).sorted();
|
||||
results = await db.lookup.tags(query).sorted(groupOptions);
|
||||
break;
|
||||
case "reminder":
|
||||
results = await db.lookup.reminders(query).sorted();
|
||||
results = await db.lookup.reminders(query).sorted(groupOptions);
|
||||
break;
|
||||
case "trash":
|
||||
results = await db.lookup.trash(query).sorted();
|
||||
results = await db.lookup.trash(query).sorted(groupOptions);
|
||||
break;
|
||||
case "attachment":
|
||||
results = await db.lookup.attachments(query).sorted();
|
||||
results = await db.lookup.attachments(query).sorted(groupOptions);
|
||||
break;
|
||||
default:
|
||||
results = undefined;
|
||||
}
|
||||
|
||||
if (currentQuery.current !== query) return;
|
||||
if (!results) {
|
||||
setSearchStatus(strings.noResultsFound(query));
|
||||
setLoading(false);
|
||||
@@ -97,6 +102,7 @@ export const Search = ({ route, navigation }: NavigationProps<"Search">) => {
|
||||
);
|
||||
if (currentQuery.current !== query) return;
|
||||
await results.item(0);
|
||||
if (currentQuery.current !== query) return;
|
||||
setResults(results);
|
||||
if (results.placeholders?.length === 0) {
|
||||
setSearchStatus(strings.noResultsFound(query));
|
||||
@@ -118,9 +124,18 @@ export const Search = ({ route, navigation }: NavigationProps<"Search">) => {
|
||||
onSearch(currentQuery.current);
|
||||
}
|
||||
};
|
||||
eSubscribeEvent(eOnRefreshSearch, onRefreshSearch);
|
||||
|
||||
const subs = [
|
||||
eSubscribeEvent(eGroupOptionsUpdated, (groupType) => {
|
||||
if (groupType === "search") {
|
||||
onSearch(currentQuery.current);
|
||||
}
|
||||
}),
|
||||
eSubscribeEvent(eOnRefreshSearch, onRefreshSearch)
|
||||
];
|
||||
|
||||
return () => {
|
||||
eUnSubscribeEvent(eOnRefreshSearch, onRefreshSearch);
|
||||
subs.forEach((sub) => sub?.unsubscribe());
|
||||
};
|
||||
}, [onSearch, route.params?.type]);
|
||||
|
||||
@@ -137,7 +152,7 @@ export const Search = ({ route, navigation }: NavigationProps<"Search">) => {
|
||||
clearTimeout(timer.current);
|
||||
timer.current = setTimeout(() => {
|
||||
onSearch(query);
|
||||
}, 300);
|
||||
}, 500);
|
||||
}}
|
||||
loading={loading}
|
||||
/>
|
||||
|
||||
@@ -82,7 +82,8 @@ export const settingsGroups: SettingSection[] = [
|
||||
useHook: () => useUserStore((state) => state.user),
|
||||
hidden: (current) => !current,
|
||||
name: (current) => {
|
||||
const user = current as User;
|
||||
const user = (current as User) || useUserStore.getState().user;
|
||||
if (!user) return strings.subscribeToPro();
|
||||
const isBasic = user.subscription?.type === SUBSCRIPTION_STATUS.BASIC;
|
||||
const isTrial = user.subscription?.type === SUBSCRIPTION_STATUS.TRIAL;
|
||||
return isBasic || !user.subscription?.type
|
||||
@@ -96,6 +97,7 @@ export const settingsGroups: SettingSection[] = [
|
||||
icon: "crown",
|
||||
description: (current) => {
|
||||
const user = current as User;
|
||||
if (!user) return strings.neverHesitate();
|
||||
const subscriptionDaysLeft =
|
||||
user &&
|
||||
getTimeLeft(
|
||||
@@ -670,6 +672,13 @@ export const settingsGroups: SettingSection[] = [
|
||||
});
|
||||
},
|
||||
disabled: () => !db.settings.getDefaultNotebook()
|
||||
},
|
||||
{
|
||||
id: "disable-update-check",
|
||||
type: "switch",
|
||||
name: strings.autoUpdateCheck(),
|
||||
description: strings.autoUpdateCheckDesc(),
|
||||
property: "checkForUpdates"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
rootNavigatorRef
|
||||
} from "../utils/global-refs";
|
||||
import { eSendEvent } from "./event-manager";
|
||||
import { useArchivedStore } from "../stores/use-archived-store";
|
||||
|
||||
/**
|
||||
* Routes that should be updated on focus
|
||||
@@ -66,7 +67,9 @@ const routeNames = {
|
||||
Reminders: "Reminders",
|
||||
MoveNotebook: "MoveNotebook",
|
||||
LinkNotebooks: "LinkNotebooks",
|
||||
MoveNotes: "MoveNotes"
|
||||
MoveNotes: "MoveNotes",
|
||||
Archive: "Archive",
|
||||
ManageTags: "ManageTags"
|
||||
};
|
||||
|
||||
export type NavigationProps<T extends RouteName> = NativeStackScreenProps<
|
||||
@@ -92,7 +95,8 @@ const routeUpdateFunctions: {
|
||||
TopicNotes: (params) => eSendEvent("TopicNotes", params),
|
||||
Monographs: (params) => eSendEvent("Monographs", params),
|
||||
Reminders: () => useReminderStore.getState().refresh(),
|
||||
Search: () => eSendEvent(eOnRefreshSearch)
|
||||
Search: () => eSendEvent(eOnRefreshSearch),
|
||||
Archive: () => useArchivedStore.getState().refresh()
|
||||
};
|
||||
|
||||
function clearRouteFromQueue(routeName: RouteName) {
|
||||
|
||||
30
apps/mobile/app/stores/use-archived-store.ts
Normal file
30
apps/mobile/app/stores/use-archived-store.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
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 { db } from "../common/database";
|
||||
import createDBCollectionStore from "./create-db-collection-store";
|
||||
|
||||
const { useStore: useArchivedStore, useCollection: useArchived } =
|
||||
createDBCollectionStore({
|
||||
getCollection: () =>
|
||||
db.notes.archived.grouped(db.settings.getGroupOptions("archive")),
|
||||
eagerlyFetchFirstBatch: true
|
||||
});
|
||||
|
||||
export { useArchivedStore, useArchived };
|
||||
@@ -74,6 +74,7 @@ export interface RouteParams extends ParamListBase {
|
||||
TaggedNotes: NotesScreenParams;
|
||||
ColoredNotes: NotesScreenParams;
|
||||
TopicNotes: NotesScreenParams;
|
||||
Archive: GenericRouteParam;
|
||||
Monographs: NotesScreenParams;
|
||||
Reminders: GenericRouteParam;
|
||||
SettingsGroup: GenericRouteParam;
|
||||
@@ -90,6 +91,9 @@ export interface RouteParams extends ParamListBase {
|
||||
MoveNotes: {
|
||||
notebook: Notebook;
|
||||
};
|
||||
ManageTags: {
|
||||
ids?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export type RouteName = keyof RouteParams;
|
||||
|
||||
@@ -98,6 +98,7 @@ export type Settings = {
|
||||
lastFullBackupDate?: number;
|
||||
serverUrls?: Record<HostId, string>;
|
||||
defaultSidebarTab: number;
|
||||
checkForUpdates?: boolean;
|
||||
};
|
||||
|
||||
type DimensionsType = {
|
||||
@@ -196,7 +197,8 @@ export const defaultSettings: SettingStore["settings"] = {
|
||||
settingsVersion: 0,
|
||||
backupType: "partial",
|
||||
fullBackupReminder: "never",
|
||||
lastFullBackupDate: 0
|
||||
lastFullBackupDate: 0,
|
||||
checkForUpdates: true
|
||||
};
|
||||
|
||||
export const useSettingStore = create<SettingStore>((set, get) => ({
|
||||
|
||||
@@ -45,7 +45,8 @@ export const SORT = {
|
||||
dateEdited: "Date edited",
|
||||
dateCreated: "Date created",
|
||||
title: "Title",
|
||||
dueDate: "Due date"
|
||||
dueDate: "Due date",
|
||||
relevance: "Relevance"
|
||||
};
|
||||
|
||||
export const itemSkus = [
|
||||
|
||||
@@ -77,12 +77,13 @@ export const MenuItemsList: SideMenuItem[] = [
|
||||
},
|
||||
type: "side-menu-item"
|
||||
},
|
||||
// {
|
||||
// dataType: "note",
|
||||
// id: "Archive",
|
||||
// title: "Archive",
|
||||
// icon: "archive"
|
||||
// },
|
||||
{
|
||||
dataType: "note",
|
||||
id: "Archive",
|
||||
title: "Archive",
|
||||
icon: "archive",
|
||||
type: "side-menu-item"
|
||||
},
|
||||
{
|
||||
dataType: "note",
|
||||
id: "Trash",
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
|
||||
ruby ">= 2.6.10"
|
||||
# Cocoapods 1.15 introduced a bug which break the build. We will remove the upper
|
||||
# bound in the template on Cocoapods with next React Native release.
|
||||
gem 'cocoapods', '>= 1.13', '< 1.15'
|
||||
gem 'activesupport', '>= 6.1.7.5', '< 7.1.0'
|
||||
|
||||
# Exclude problematic versions of cocoapods and activesupport that causes build failures.
|
||||
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
|
||||
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
|
||||
gem 'xcodeproj', '< 1.26.0'
|
||||
gem 'concurrent-ruby', '< 1.3.4'
|
||||
|
||||
@@ -1,30 +1,41 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.5)
|
||||
CFPropertyList (3.0.7)
|
||||
base64
|
||||
nkf
|
||||
rexml
|
||||
activesupport (6.1.5)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
activesupport (7.2.2.1)
|
||||
base64
|
||||
benchmark (>= 0.3)
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||
connection_pool (>= 2.2.5)
|
||||
drb
|
||||
i18n (>= 1.6, < 2)
|
||||
logger (>= 1.4.2)
|
||||
minitest (>= 5.1)
|
||||
tzinfo (~> 2.0)
|
||||
zeitwerk (~> 2.3)
|
||||
addressable (2.8.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
securerandom (>= 0.3)
|
||||
tzinfo (~> 2.0, >= 2.0.5)
|
||||
addressable (2.8.7)
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
algoliasearch (1.27.5)
|
||||
httpclient (~> 2.8, >= 2.8.3)
|
||||
json (>= 1.5.1)
|
||||
atomos (0.1.3)
|
||||
base64 (0.3.0)
|
||||
benchmark (0.4.1)
|
||||
bigdecimal (3.2.1)
|
||||
claide (1.1.0)
|
||||
cocoapods (1.11.3)
|
||||
cocoapods (1.15.2)
|
||||
addressable (~> 2.8)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
cocoapods-core (= 1.11.3)
|
||||
cocoapods-core (= 1.15.2)
|
||||
cocoapods-deintegrate (>= 1.0.3, < 2.0)
|
||||
cocoapods-downloader (>= 1.4.0, < 2.0)
|
||||
cocoapods-downloader (>= 2.1, < 3.0)
|
||||
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||
cocoapods-search (>= 1.0.0, < 2.0)
|
||||
cocoapods-trunk (>= 1.4.0, < 2.0)
|
||||
cocoapods-trunk (>= 1.6.0, < 2.0)
|
||||
cocoapods-try (>= 1.1.0, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
escape (~> 0.0.4)
|
||||
@@ -32,10 +43,10 @@ GEM
|
||||
gh_inspector (~> 1.0)
|
||||
molinillo (~> 0.8.0)
|
||||
nap (~> 1.0)
|
||||
ruby-macho (>= 1.0, < 3.0)
|
||||
xcodeproj (>= 1.21.0, < 2.0)
|
||||
cocoapods-core (1.11.3)
|
||||
activesupport (>= 5.0, < 7)
|
||||
ruby-macho (>= 2.3.0, < 3.0)
|
||||
xcodeproj (>= 1.23.0, < 2.0)
|
||||
cocoapods-core (1.15.2)
|
||||
activesupport (>= 5.0, < 8)
|
||||
addressable (~> 2.8)
|
||||
algoliasearch (~> 1.0)
|
||||
concurrent-ruby (~> 1.1)
|
||||
@@ -45,7 +56,7 @@ GEM
|
||||
public_suffix (~> 4.0)
|
||||
typhoeus (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.5)
|
||||
cocoapods-downloader (1.6.3)
|
||||
cocoapods-downloader (2.1)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.1)
|
||||
@@ -54,47 +65,56 @@ GEM
|
||||
netrc (~> 0.11)
|
||||
cocoapods-try (1.2.0)
|
||||
colored2 (3.1.2)
|
||||
concurrent-ruby (1.1.10)
|
||||
concurrent-ruby (1.3.3)
|
||||
connection_pool (2.5.3)
|
||||
drb (2.2.3)
|
||||
escape (0.0.4)
|
||||
ethon (0.15.0)
|
||||
ethon (0.16.0)
|
||||
ffi (>= 1.15.0)
|
||||
ffi (1.15.5)
|
||||
ffi (1.17.2)
|
||||
fourflusher (2.3.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.1.3)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.10.0)
|
||||
httpclient (2.9.0)
|
||||
mutex_m
|
||||
i18n (1.14.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
json (2.6.1)
|
||||
minitest (5.15.0)
|
||||
json (2.12.2)
|
||||
logger (1.7.0)
|
||||
minitest (5.25.5)
|
||||
molinillo (0.8.0)
|
||||
mutex_m (0.3.0)
|
||||
nanaimo (0.3.0)
|
||||
nap (1.1.0)
|
||||
netrc (0.11.0)
|
||||
nkf (0.2.0)
|
||||
public_suffix (4.0.7)
|
||||
rexml (3.2.5)
|
||||
rexml (3.4.1)
|
||||
ruby-macho (2.5.1)
|
||||
typhoeus (1.4.0)
|
||||
securerandom (0.4.1)
|
||||
typhoeus (1.4.1)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (2.0.4)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
xcodeproj (1.21.0)
|
||||
xcodeproj (1.25.1)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.3.0)
|
||||
rexml (~> 3.2.4)
|
||||
zeitwerk (2.5.4)
|
||||
rexml (>= 3.3.6, < 4.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
cocoapods (~> 1.11, >= 1.11.2)
|
||||
activesupport (>= 6.1.7.5, != 7.1.0)
|
||||
cocoapods (>= 1.13, != 1.15.1, != 1.15.0)
|
||||
concurrent-ruby (< 1.3.4)
|
||||
xcodeproj (< 1.26.0)
|
||||
|
||||
RUBY VERSION
|
||||
ruby 2.7.4p191
|
||||
ruby 3.4.1p0
|
||||
|
||||
BUNDLED WITH
|
||||
2.2.27
|
||||
2.6.2
|
||||
|
||||
@@ -48,6 +48,9 @@ react {
|
||||
//
|
||||
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
|
||||
hermesFlags = ["-O", "-output-source-map"]
|
||||
|
||||
/* Autolinking */
|
||||
autolinkLibrariesWithApp()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +124,7 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
multiDexEnabled true
|
||||
versionCode 3049
|
||||
versionCode 3056
|
||||
versionName getNpmVersion()
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
@@ -258,7 +261,3 @@ copyFontFiles.dependsOn(copyEditorBundle);
|
||||
copyPlainEditorBundle.dependsOn(copyFontFiles);
|
||||
preBuild.dependsOn(copyPlainEditorBundle)
|
||||
|
||||
apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove"/>
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" tools:node="remove" />
|
||||
@@ -59,9 +58,8 @@
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:theme="@style/BootTheme"
|
||||
android:largeHeap="true"
|
||||
android:supportsRtl="false"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
tools:replace="android:supportsRtl">
|
||||
android:supportsRtl="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config">
|
||||
|
||||
<receiver android:exported="false" android:label="@string/reminders_title" android:name=".ReminderWidgetProvider">
|
||||
<intent-filter>
|
||||
|
||||
@@ -14,19 +14,21 @@ public class BootRecieverService extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (!isAppOnForeground((context))) {
|
||||
/**
|
||||
We will start our service and send extra info about
|
||||
network connections
|
||||
**/
|
||||
Intent serviceIntent = new Intent(context, BootTaskService.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(serviceIntent);
|
||||
} else {
|
||||
context.startService(serviceIntent);
|
||||
}
|
||||
HeadlessJsTaskService.acquireWakeLockNow(context);
|
||||
}
|
||||
try {
|
||||
if (!isAppOnForeground((context))) {
|
||||
/**
|
||||
We will start our service and send extra info about
|
||||
network connections
|
||||
**/
|
||||
Intent serviceIntent = new Intent(context, BootTaskService.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(serviceIntent);
|
||||
} else {
|
||||
context.startService(serviceIntent);
|
||||
}
|
||||
HeadlessJsTaskService.acquireWakeLockNow(context);
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
private boolean isAppOnForeground(Context context) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
|
||||
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
|
||||
import com.facebook.react.defaults.DefaultReactNativeHost
|
||||
import com.facebook.soloader.SoLoader
|
||||
import com.facebook.react.soloader.OpenSourceMergedSoMapping
|
||||
|
||||
class MainApplication : Application(), ReactApplication {
|
||||
|
||||
@@ -36,7 +37,7 @@ class MainApplication : Application(), ReactApplication {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
SoLoader.init(this, false)
|
||||
SoLoader.init(this, OpenSourceMergedSoMapping)
|
||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||
// If you opted-in for the New Architecture, we load the native entry point for this app.
|
||||
load()
|
||||
|
||||
@@ -3,16 +3,16 @@ import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "34.0.0"
|
||||
minSdkVersion = 23
|
||||
compileSdkVersion = 34
|
||||
targetSdkVersion = 34
|
||||
kotlinVersion = '1.9.22'
|
||||
buildToolsVersion = "35.0.0"
|
||||
minSdkVersion = 24
|
||||
compileSdkVersion = 35
|
||||
targetSdkVersion = 35
|
||||
kotlinVersion = '2.0.21'
|
||||
androidXAnnotation = "1.1.0"
|
||||
androidXCoreVersion = "1.7.0"
|
||||
androidXCore = "1.7.0"
|
||||
androidXBrowser = "1.0.0"
|
||||
ndkVersion = "23.2.8568313"
|
||||
ndkVersion = "27.1.12297006"
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
||||
@@ -23,7 +23,7 @@ org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
# android.enableJetifier=true
|
||||
|
||||
# Use this property to specify which architecture you want to build.
|
||||
# You can also override it from the CLI using
|
||||
@@ -47,4 +47,4 @@ hermesEnabled=true
|
||||
# fdroid
|
||||
fdroidBuild=false
|
||||
# -DSQLITE_USER_AUTHENTICATION=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_OMIT_DEPRECATED=1 -DSQLITE_OMIT_PROGRESS_CALLBACK=1
|
||||
quickSqliteFlags=-DSQLITE3MC_OMIT_AES_HARDWARE_SUPPORT -DHAVE_CIPHER_AES_128_CBC=0 -DHAVE_CIPHER_AES_256_CBC=0 -DHAVE_CIPHER_SQLCIPHER=0 -DHAVE_CIPHER_RC4=0 -DHAVE_CIPHER_CHACHA20=1 -DSQLITE_ENABLE_FTS5 -DSQLITE_OMIT_PROGRESS_CALLBACK=1 -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_OMIT_DEPRECATED=1 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 -DSQLITE_DQS=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_USE_ALLOCA=1
|
||||
quickSqliteFlags=-DSQLITE3MC_OMIT_AES_HARDWARE_SUPPORT -DHAVE_CIPHER_AES_128_CBC=0 -DHAVE_CIPHER_AES_256_CBC=0 -DHAVE_CIPHER_SQLCIPHER=0 -DHAVE_CIPHER_RC4=0 -DHAVE_CIPHER_CHACHA20=1 -DSQLITE_ENABLE_FTS5 -DSQLITE_OMIT_PROGRESS_CALLBACK=1 -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_OMIT_DEPRECATED=1 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 -DSQLITE_DQS=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_USE_ALLOCA=1 -DSQLITE_ENABLE_REGEXP=1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
7
apps/mobile/native/android/gradlew
vendored
7
apps/mobile/native/android/gradlew
vendored
@@ -15,6 +15,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
@@ -55,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -84,7 +86,8 @@ done
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
2
apps/mobile/native/android/gradlew.bat
vendored
2
apps/mobile/native/android/gradlew.bat
vendored
@@ -13,6 +13,8 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
- v3.1.0 brings new features and improvements to enhance your Notesnook experience.
|
||||
- Notebooks and Tags are not located in the Sidebar
|
||||
- Tree view for notebooks
|
||||
- Improved list view UI for better user experience
|
||||
- Improved notebook related actions by integrating tree view in most places
|
||||
- You can set any notebook, tag or colors as home screen
|
||||
- New and improved search with highlighting
|
||||
- Fixed app crashing on android 16 devices
|
||||
- Many bug fixes and improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -1,4 +1,9 @@
|
||||
pluginManagement { includeBuild("../../node_modules/@react-native/gradle-plugin") }
|
||||
plugins { id("com.facebook.react.settings") }
|
||||
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
|
||||
rootProject.name = 'Notesnook'
|
||||
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
|
||||
include ':app'
|
||||
includeBuild('../../node_modules/@react-native/gradle-plugin')
|
||||
|
||||
include ":lazysodium"
|
||||
project(':lazysodium').projectDir = new File(rootProject.projectDir, '../../node_modules/@ammarahmed/react-native-sodium/android/lazysodium')
|
||||
|
||||
@@ -6,7 +6,7 @@ module.exports = function (api, opts) {
|
||||
if (!PROCESS_ENV) PROCESS_ENV = 'production';
|
||||
|
||||
const env = {
|
||||
presets: ['module:metro-react-native-babel-preset'],
|
||||
presets: ['module:@react-native/babel-preset'],
|
||||
plugins: [
|
||||
'@babel/plugin-transform-named-capturing-groups-regex',
|
||||
'react-native-reanimated/plugin',
|
||||
|
||||
@@ -653,15 +653,25 @@
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Notesnook/Pods-Notesnook-resources.sh",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker/QBImagePicker.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RNSVG/RNSVGFilters.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/TOCropViewController/TOCropViewControllerBundle.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/QBImagePicker.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNSVGFilters.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/TOCropViewControllerBundle.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
@@ -810,15 +820,25 @@
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Notesnook-NotesnookTests/Pods-Notesnook-NotesnookTests-resources.sh",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker/QBImagePicker.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RNSVG/RNSVGFilters.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/TOCropViewController/TOCropViewControllerBundle.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/QBImagePicker.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNSVGFilters.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/TOCropViewControllerBundle.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
@@ -854,11 +874,19 @@
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Make Note/Pods-Make Note-resources.sh",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
@@ -1063,7 +1091,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2132;
|
||||
CURRENT_PROJECT_VERSION = 2134;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1137,7 +1165,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.1.0;
|
||||
MARKETING_VERSION = 3.2.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -1168,7 +1196,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 2132;
|
||||
CURRENT_PROJECT_VERSION = 2134;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1242,7 +1270,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.1.0;
|
||||
MARKETING_VERSION = 3.2.0;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -1401,7 +1429,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2132;
|
||||
CURRENT_PROJECT_VERSION = 2134;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1413,7 +1441,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.1.0;
|
||||
MARKETING_VERSION = 3.2.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
@@ -1444,7 +1472,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2132;
|
||||
CURRENT_PROJECT_VERSION = 2134;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
@@ -1457,7 +1485,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.1.0;
|
||||
MARKETING_VERSION = 3.2.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1487,7 +1515,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2132;
|
||||
CURRENT_PROJECT_VERSION = 2134;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1561,7 +1589,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.1.0;
|
||||
MARKETING_VERSION = 3.2.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
@@ -1592,7 +1620,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2132;
|
||||
CURRENT_PROJECT_VERSION = 2134;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
@@ -1667,7 +1695,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.1.0;
|
||||
MARKETING_VERSION = 3.2.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1750,6 +1778,7 @@
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
USE_HERMES = true;
|
||||
};
|
||||
name = Debug;
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
#import <React/RCTLinkingManager.h>
|
||||
#import "RNShortcuts.h"
|
||||
#import "RNBootSplash.h"
|
||||
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
self.dependencyProvider = [RCTAppDependencyProvider new];
|
||||
self.moduleName = @"Notesnook";
|
||||
// You can add your custom initial props in the dictionary below.
|
||||
// They will be passed down to the ViewController used by React Native.
|
||||
|
||||
@@ -114,7 +114,7 @@ post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
if target.name == "react-native-quick-sqlite" then
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = 'SQLITE_CORE=1 SQLITE_ENABLE_FTS5=1 SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT=1 HAVE_CIPHER_AES_128_CBC=0 HAVE_CIPHER_AES_256_CBC=0 HAVE_CIPHER_SQLCIPHER=0 HAVE_CIPHER_RC4=0 HAVE_CIPHER_CHACHA20=1 SQLITE_OMIT_PROGRESS_CALLBACK=1 SQLITE_MAX_EXPR_DEPTH=0 SQLITE_OMIT_DEPRECATED=1 SQLITE_LIKE_DOESNT_MATCH_BLOBS=1 SQLITE_DQS=0 SQLITE_DEFAULT_MEMSTATUS=0 SQLITE_USE_ALLOCA=1'
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = 'SQLITE_CORE=1 SQLITE_ENABLE_FTS5=1 SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT=1 HAVE_CIPHER_AES_128_CBC=0 HAVE_CIPHER_AES_256_CBC=0 HAVE_CIPHER_SQLCIPHER=0 HAVE_CIPHER_RC4=0 HAVE_CIPHER_CHACHA20=1 SQLITE_OMIT_PROGRESS_CALLBACK=1 SQLITE_MAX_EXPR_DEPTH=0 SQLITE_OMIT_DEPRECATED=1 SQLITE_LIKE_DOESNT_MATCH_BLOBS=1 SQLITE_DQS=0 SQLITE_DEFAULT_MEMSTATUS=0 SQLITE_USE_ALLOCA=1 SQLITE_ENABLE_REGEXP=1'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,13 +5,13 @@
|
||||
"main": "index.js",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"overrides": {
|
||||
"react-native": "0.74.5",
|
||||
"react-native": "0.77.2",
|
||||
"react": "18.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ammarahmed/notifee-react-native": "7.4.7",
|
||||
"@callstack/repack": "~5.0.0",
|
||||
"@bam.tech/react-native-image-resizer": "3.0.5",
|
||||
"dependencies": {
|
||||
"@ammarahmed/notifee-react-native": "7.4.9",
|
||||
"@callstack/repack": "~5.1.2",
|
||||
"@bam.tech/react-native-image-resizer": "3.0.11",
|
||||
"@react-native-clipboard/clipboard": "^1.9.0",
|
||||
"@react-native-community/checkbox": "^0.5.8",
|
||||
"@react-native-community/netinfo": "^9.3.7",
|
||||
@@ -20,9 +20,9 @@
|
||||
"@react-navigation/elements": "^1.3.3",
|
||||
"@react-navigation/native": "^6.0.10",
|
||||
"@react-navigation/native-stack": "6.6.2",
|
||||
"@sayem314/react-native-keep-awake": "^1.0.4",
|
||||
"@sayem314/react-native-keep-awake": "^1.3.1",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.74.5",
|
||||
"react-native": "0.77.2",
|
||||
"react-native-actions-shortcuts": "^1.0.1",
|
||||
"react-native-background-actions": "^2.6.6",
|
||||
"react-native-blob-util": "^0.18.3",
|
||||
@@ -33,31 +33,32 @@
|
||||
"react-native-document-picker": "^7.1.1",
|
||||
"@ammarahmed/react-native-eventsource": "1.1.0",
|
||||
"react-native-file-viewer": "^2.1.1",
|
||||
"react-native-gesture-handler": "^2.18.0",
|
||||
"react-native-reanimated": "3.14.0",
|
||||
"react-native-safe-area-context": "^4.10.8",
|
||||
"react-native-screens": "^3.33.0",
|
||||
"react-native-webview": "^13.10.0",
|
||||
"@shopify/flash-list": "1.7.0",
|
||||
"react-native-gesture-handler": "^2.25.0",
|
||||
"react-native-reanimated": "3.17.5",
|
||||
"react-native-safe-area-context": "^5.4.0",
|
||||
"react-native-screens": "^4.10.0",
|
||||
"react-native-vector-icons": "9.2.0",
|
||||
"react-native-get-random-values": "^1.7.0",
|
||||
"react-native-gzip": "1.1.0",
|
||||
"react-native-html-to-pdf-lite": "^0.9.1",
|
||||
"react-native-iap": "12.15.1",
|
||||
"react-native-iap": "12.16.2",
|
||||
"react-native-in-app-review": "4.3.3",
|
||||
"react-native-keychain": "4.0.5",
|
||||
"react-native-modal-datetime-picker": "14.0.0",
|
||||
"react-native-navigation-bar-color": "2.0.2",
|
||||
"react-native-notification-sounds": "0.5.5",
|
||||
"react-native-pdf": "6.6.2",
|
||||
"@shopify/flash-list": "^1.8.0",
|
||||
"react-native-mmkv-storage": "^0.11.2",
|
||||
"react-native-quick-sqlite": "^8.2.7",
|
||||
"react-native-svg": "^15.12.0",
|
||||
"react-native-webview": "^13.13.5",
|
||||
"react-native-pdf": "6.7.7",
|
||||
"react-native-scoped-storage": "^1.9.5",
|
||||
"react-native-securerandom": "^1.0.1",
|
||||
"react-native-share": "^12.0.3",
|
||||
"react-native-svg": "^12.3.0",
|
||||
"react-native-swiper-flatlist": "3.2.2",
|
||||
"react-native-tooltips": "^1.0.3",
|
||||
"react-native-zip-archive": "6.0.9",
|
||||
"react-native-quick-sqlite": "^8.0.6",
|
||||
"react-native-theme-switch-animation": "^0.6.0",
|
||||
"@ammarahmed/react-native-background-fetch": "^4.2.2",
|
||||
"react-native-image-crop-picker": "^0.40.2",
|
||||
@@ -65,8 +66,7 @@
|
||||
"react-native-screenguard": "^1.0.0",
|
||||
"@formatjs/intl-locale": "4.0.0",
|
||||
"@formatjs/intl-pluralrules": "5.2.14",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.1",
|
||||
"react-native-mmkv-storage": "^0.10.2",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.3",
|
||||
"@react-native-community/datetimepicker": "^8.2.0",
|
||||
"react-native-exit-app": "github:ammarahm-ed/react-native-exit-app",
|
||||
"react-native-begin-background-task": "github:blockfirm/react-native-begin-background-task",
|
||||
@@ -78,19 +78,26 @@
|
||||
"react-native-orientation-locker": "^1.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rspack/core": "^1.2.7",
|
||||
"@babel/core": "^7.27.1",
|
||||
"@babel/preset-env": "^7.27.2",
|
||||
"@babel/runtime": "^7.27.1",
|
||||
"@react-native-community/cli": "15.0.1",
|
||||
"@rspack/core": "^1.3.15",
|
||||
"@react-native-community/cli-platform-android": "15.0.1",
|
||||
"@react-native-community/cli-platform-ios": "15.0.1",
|
||||
"@react-native/babel-preset": "0.77.2",
|
||||
"@react-native/eslint-config": "0.77.2",
|
||||
"@react-native/metro-config": "0.77.2",
|
||||
"@react-native/typescript-config": "0.77.2",
|
||||
"@types/jest": "^29.5.13",
|
||||
"react-test-renderer": "18.2.0",
|
||||
"babel-loader": "^10.0.0",
|
||||
"@babel/plugin-transform-unicode-property-regex": "^7.25.9",
|
||||
"@callstack/repack-plugin-reanimated": "^5.0.0",
|
||||
"@callstack/repack-plugin-reanimated": "^5.1.2",
|
||||
"babel-plugin-syntax-hermes-parser": "^0.26.0",
|
||||
"@swc/helpers": "^0.5.15",
|
||||
"detox": "^20.27.6",
|
||||
"@babel/core": "^7.20.0",
|
||||
"@babel/eslint-parser": "^7.16.5",
|
||||
"@babel/preset-env": "^7.20.0",
|
||||
"@babel/runtime": "^7.20.0",
|
||||
"@react-native/eslint-config": "0.74.86",
|
||||
"@react-native/metro-config": "0.74.86",
|
||||
"@tsconfig/react-native": "^3.0.2",
|
||||
"@types/html-to-text": "^8.0.1",
|
||||
"@types/metro-config": "^0.76.3",
|
||||
@@ -98,22 +105,20 @@
|
||||
"@types/react-native": "^0.69.1",
|
||||
"@types/react-native-vector-icons": "^6.4.10",
|
||||
"@types/react-test-renderer": "^18.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
||||
"@typescript-eslint/parser": "^5.14.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
||||
"@typescript-eslint/parser": "^8.32.1",
|
||||
"babel-jest": "^29.6.3",
|
||||
"eslint": "^8.19.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-native": "^4.0.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"@react-native/babel-preset": "0.74.86",
|
||||
"prettier": "2.8.8",
|
||||
"eslint": "^9.27.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-prettier": "^5.4.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-native": "^5.0.0",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"prettier": "3.5.3",
|
||||
"react-native-actions-shortcuts": "^1.0.1",
|
||||
"react-native-bundle-visualizer": "^3.1.1",
|
||||
"react-native-cli-bump-version": "^1.3.0",
|
||||
"react-refresh": "0.14.0",
|
||||
"react-test-renderer": "18.2.0",
|
||||
"metro-react-native-babel-preset": "0.77.0",
|
||||
"acorn-import-attributes": "1.9.5",
|
||||
"expect": "^29.7.0",
|
||||
@@ -122,7 +127,6 @@
|
||||
"jest-image-snapshot": "^6.4.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
"pixelmatch": "^6.0.0",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@messageformat/parser": "^5.1.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,16 +228,6 @@ module.exports = (env) => {
|
||||
* from `Repack.plugins`.
|
||||
*/
|
||||
new Repack.RepackPlugin({
|
||||
logger: {
|
||||
console: false,
|
||||
listener: (e => {
|
||||
if (e.message[0].includes("Bundle built with warnings")) {
|
||||
console.warn(`ℹ ` + e.message[0] + " time: " + e.message[1].time);
|
||||
return;
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
extraChunks: [
|
||||
{
|
||||
type: "local",
|
||||
|
||||
7065
apps/mobile/package-lock.json
generated
7065
apps/mobile/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "3.1.0",
|
||||
"version": "3.2.0",
|
||||
"private": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
@@ -34,7 +34,7 @@
|
||||
"react-refresh": "0.14.0"
|
||||
},
|
||||
"overrides": {
|
||||
"react-native": "0.74.5",
|
||||
"react-native": "0.77.2",
|
||||
"react": "18.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -54,6 +54,7 @@
|
||||
"@types/validator": "^13.12.2",
|
||||
"diffblazer": "^1.0.1",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.74.5"
|
||||
"react-native": "0.77.2",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
14
apps/mobile/patches/@callstack+repack+5.1.2.patch
Normal file
14
apps/mobile/patches/@callstack+repack+5.1.2.patch
Normal file
@@ -0,0 +1,14 @@
|
||||
diff --git a/node_modules/@callstack/repack/android/build.gradle b/node_modules/@callstack/repack/android/build.gradle
|
||||
index b968f5a..62464d8 100644
|
||||
--- a/node_modules/@callstack/repack/android/build.gradle
|
||||
+++ b/node_modules/@callstack/repack/android/build.gradle
|
||||
@@ -106,7 +106,8 @@ android {
|
||||
cmake {
|
||||
cppFlags "-O2 -frtti -fexceptions -Wall -Wno-unused-variable -fstack-protector-all"
|
||||
arguments "-DANDROID_STL=c++_shared",
|
||||
- "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}"
|
||||
+ "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}",
|
||||
+ "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
|
||||
abiFilters(*reactNativeArchitectures())
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/node_modules/@react-native/community-cli-plugin/dist/utils/loadMetroConfig.js b/node_modules/@react-native/community-cli-plugin/dist/utils/loadMetroConfig.js
|
||||
index 636c0d8..87f4ee6 100644
|
||||
index c0749e1..bbcb97e 100644
|
||||
--- a/node_modules/@react-native/community-cli-plugin/dist/utils/loadMetroConfig.js
|
||||
+++ b/node_modules/@react-native/community-cli-plugin/dist/utils/loadMetroConfig.js
|
||||
@@ -105,5 +105,6 @@ This warning will be removed in future (https://github.com/facebook/metro/issues
|
||||
@@ -83,5 +83,6 @@ This warning will be removed in future (https://github.com/facebook/metro/issues
|
||||
...options,
|
||||
});
|
||||
const overrideConfig = getOverrideConfig(ctx, config);
|
||||
14
apps/mobile/patches/react-native-mmkv-storage+0.11.2.patch
Normal file
14
apps/mobile/patches/react-native-mmkv-storage+0.11.2.patch
Normal file
@@ -0,0 +1,14 @@
|
||||
diff --git a/node_modules/react-native-mmkv-storage/android/build.gradle b/node_modules/react-native-mmkv-storage/android/build.gradle
|
||||
index abb696e..ba35baa 100644
|
||||
--- a/node_modules/react-native-mmkv-storage/android/build.gradle
|
||||
+++ b/node_modules/react-native-mmkv-storage/android/build.gradle
|
||||
@@ -98,7 +98,8 @@ android {
|
||||
cmake {
|
||||
cppFlags "-O3 -frtti -fexceptions -Wall -fstack-protector-all"
|
||||
arguments "-DANDROID_STL=c++_shared",
|
||||
- "-DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION}"
|
||||
+ "-DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION}",
|
||||
+ "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
|
||||
abiFilters (*reactNativeArchitectures())
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,70 +0,0 @@
|
||||
diff --git a/node_modules/react-native-svg/__tests__/css.test.tsx b/node_modules/react-native-svg/__tests__/css.test.tsx
|
||||
index 579c357..57acc09 100644
|
||||
--- a/node_modules/react-native-svg/__tests__/css.test.tsx
|
||||
+++ b/node_modules/react-native-svg/__tests__/css.test.tsx
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
-import { SvgCss, parse, inlineStyles } from '../src/ReactNativeSVG';
|
||||
+import { parse } from '../src/ReactNativeSVG';
|
||||
+import { SvgCss, inlineStyles } from '../css';
|
||||
|
||||
const xml = `<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
diff --git a/node_modules/react-native-svg/css/index.ts b/node_modules/react-native-svg/css/index.ts
|
||||
new file mode 100644
|
||||
index 0000000..3b268af
|
||||
--- /dev/null
|
||||
+++ b/node_modules/react-native-svg/css/index.ts
|
||||
@@ -0,0 +1,2 @@
|
||||
+export * from '../src/css';
|
||||
+export { LocalSvg, WithLocalSvg, loadLocalRawResource } from '../src/LocalSvg';
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/react-native-svg/src/LocalSvg.tsx b/node_modules/react-native-svg/src/LocalSvg.tsx
|
||||
index f13c46f..0457159 100644
|
||||
--- a/node_modules/react-native-svg/src/LocalSvg.tsx
|
||||
+++ b/node_modules/react-native-svg/src/LocalSvg.tsx
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from 'react-native';
|
||||
|
||||
import { fetchText } from './xml';
|
||||
-import { SvgCss, SvgWithCss } from './css';
|
||||
+import { SvgCss, SvgWithCss } from '../css';
|
||||
import { SvgProps } from './elements/Svg';
|
||||
|
||||
const { getRawResource } = NativeModules.RNSVGRenderableManager || {};
|
||||
diff --git a/node_modules/react-native-svg/src/ReactNativeSVG.ts b/node_modules/react-native-svg/src/ReactNativeSVG.ts
|
||||
index 6b72423..1daca6c 100644
|
||||
--- a/node_modules/react-native-svg/src/ReactNativeSVG.ts
|
||||
+++ b/node_modules/react-native-svg/src/ReactNativeSVG.ts
|
||||
@@ -25,14 +25,7 @@ import Marker from './elements/Marker';
|
||||
import ForeignObject from './elements/ForeignObject';
|
||||
|
||||
import { parse, SvgAst, SvgFromUri, SvgFromXml, SvgUri, SvgXml } from './xml';
|
||||
-import {
|
||||
- SvgCss,
|
||||
- SvgCssUri,
|
||||
- SvgWithCss,
|
||||
- SvgWithCssUri,
|
||||
- inlineStyles,
|
||||
-} from './css';
|
||||
-import { LocalSvg, WithLocalSvg, loadLocalRawResource } from './LocalSvg';
|
||||
+
|
||||
import {
|
||||
RNSVGCircle,
|
||||
RNSVGClipPath,
|
||||
@@ -116,14 +109,6 @@ export {
|
||||
SvgFromXml,
|
||||
SvgUri,
|
||||
SvgXml,
|
||||
- SvgCss,
|
||||
- SvgCssUri,
|
||||
- SvgWithCss,
|
||||
- SvgWithCssUri,
|
||||
- inlineStyles,
|
||||
- LocalSvg,
|
||||
- WithLocalSvg,
|
||||
- loadLocalRawResource,
|
||||
Shape,
|
||||
RNSVGMarker,
|
||||
RNSVGMask,
|
||||
@@ -307,7 +307,7 @@ const ShareView = () => {
|
||||
|
||||
noteData = {
|
||||
content: {
|
||||
data: (rawContent?.data || "") + noteContent.current,
|
||||
data: (rawContent?.data || "") + "<br/>" + noteContent.current,
|
||||
type: "tiptap"
|
||||
},
|
||||
id: note.id,
|
||||
|
||||
@@ -108,6 +108,12 @@ export class AppModel {
|
||||
return new TrashViewModel(this.page);
|
||||
}
|
||||
|
||||
async goToArchive() {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
await this.navigateTo("Archive");
|
||||
return new NotesViewModel(this.page, "notes", "archive");
|
||||
}
|
||||
|
||||
async goToSettings() {
|
||||
await this.profileDropdown.open(
|
||||
this.page.locator(getTestId("profile-dropdown")),
|
||||
@@ -153,12 +159,8 @@ export class AppModel {
|
||||
|
||||
async search(query: string, type: string) {
|
||||
const searchinput = this.page.locator(getTestId("search-input"));
|
||||
const searchButton = this.page.locator(getTestId("search-button"));
|
||||
const openSearch = this.page.locator(getTestId("open-search"));
|
||||
|
||||
await openSearch.click();
|
||||
await searchinput.fill(query);
|
||||
await searchButton.click();
|
||||
return new SearchViewModel(this.page, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,4 +84,9 @@ export class ItemModel extends BaseItemModel {
|
||||
await this.contextMenu.close();
|
||||
return state;
|
||||
}
|
||||
|
||||
async setAsDefault() {
|
||||
await this.contextMenu.open(this.locator);
|
||||
await this.contextMenu.clickOnItem("set-as-default");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,4 +77,11 @@ export class NoteItemModel extends BaseItemModel {
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
async isLockedNotePasswordFieldVisible() {
|
||||
return this.page
|
||||
.locator(".active")
|
||||
.locator(getTestId("unlock-note-password"))
|
||||
.isVisible();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ abstract class BaseProperties {
|
||||
private readonly pinToggle: ToggleModel;
|
||||
private readonly favoriteToggle: ToggleModel;
|
||||
private readonly lockToggle: ToggleModel;
|
||||
private readonly archiveToggle: ToggleModel;
|
||||
|
||||
constructor(
|
||||
page: Page,
|
||||
@@ -47,6 +48,7 @@ abstract class BaseProperties {
|
||||
this.pinToggle = new ToggleModel(page, `${itemPrefix}-pin`);
|
||||
this.lockToggle = new ToggleModel(page, `${itemPrefix}-lock`);
|
||||
this.favoriteToggle = new ToggleModel(page, `${itemPrefix}-favorite`);
|
||||
this.archiveToggle = new ToggleModel(page, `${itemPrefix}-archive`);
|
||||
}
|
||||
|
||||
async isPinned() {
|
||||
@@ -126,6 +128,25 @@ abstract class BaseProperties {
|
||||
await this.close();
|
||||
}
|
||||
|
||||
async isArchived() {
|
||||
await this.open();
|
||||
const state = await this.archiveToggle.isToggled();
|
||||
await this.close();
|
||||
return state;
|
||||
}
|
||||
|
||||
async archive() {
|
||||
await this.open();
|
||||
await this.archiveToggle.on();
|
||||
await this.close();
|
||||
}
|
||||
|
||||
async unarchive() {
|
||||
await this.open();
|
||||
await this.archiveToggle.off();
|
||||
await this.close();
|
||||
}
|
||||
|
||||
abstract isColored(color: string): Promise<boolean>;
|
||||
abstract color(color: string): Promise<void>;
|
||||
abstract open(): Promise<void>;
|
||||
|
||||
@@ -113,4 +113,11 @@ export class NotebookItemModel extends BaseItemModel {
|
||||
await this.contextMenu.open(this.locator);
|
||||
await new ToggleModel(this.page, "menu-button-set-as-default").on();
|
||||
}
|
||||
|
||||
async isMoveToTopVisible() {
|
||||
await this.contextMenu.open(this.locator);
|
||||
return this.contextMenu.menuContainer
|
||||
.locator(getTestId("menu-button-move-to-top"))
|
||||
.isVisible();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,3 +324,30 @@ test("when default notebook is set, created note in colors context should go to
|
||||
|
||||
expect(await openedNotebook?.findNote(coloredNote)).toBeDefined();
|
||||
});
|
||||
|
||||
test("move to top option should not be available for root notebook", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
|
||||
expect(await notebook?.isMoveToTopVisible()).toBe(false);
|
||||
});
|
||||
|
||||
test("move to top option should be available for sub-notebook", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
const subNotebook = await notebook?.createSubnotebook({
|
||||
title: "Subnotebook 1"
|
||||
});
|
||||
|
||||
expect(await subNotebook?.isMoveToTopVisible()).toBe(true);
|
||||
});
|
||||
|
||||
@@ -201,6 +201,37 @@ for (const actor of actors) {
|
||||
expect(await note?.getDescription()).toContain(NOTE.content);
|
||||
expect(await note?.contextMenu.isLocked()).toBe(false);
|
||||
});
|
||||
|
||||
test(`archive a note using ${actor}`, async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
|
||||
await note?.[actor].archive();
|
||||
|
||||
const archive = await app.goToArchive();
|
||||
const archivedNote = await archive.findNote(NOTE);
|
||||
expect(await archivedNote?.contextMenu.isArchived()).toBe(true);
|
||||
expect(await archivedNote?.properties.isArchived()).toBe(true);
|
||||
});
|
||||
|
||||
test(`unarchive a note using ${actor}`, async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
let notes = await app.goToNotes();
|
||||
let note = await notes.createNote(NOTE);
|
||||
await note?.contextMenu.archive();
|
||||
|
||||
const archive = await app.goToArchive();
|
||||
const archivedNote = await archive.findNote(NOTE);
|
||||
await archivedNote?.[actor].unarchive();
|
||||
|
||||
notes = await app.goToNotes();
|
||||
note = await notes.findNote(NOTE);
|
||||
expect(await note?.contextMenu.isArchived()).toBe(false);
|
||||
expect(await note?.properties.isArchived()).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
test("open a locked note", async ({ page }) => {
|
||||
@@ -339,3 +370,80 @@ test(`sort notes`, async ({ page }, info) => {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("archived favorite note shouldn't be in favorites note list", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
|
||||
await note?.contextMenu.favorite();
|
||||
await note?.contextMenu.archive();
|
||||
|
||||
const favorites = await app.goToFavorites();
|
||||
expect(await favorites.findNote(NOTE)).toBeUndefined();
|
||||
});
|
||||
|
||||
test("archived tag note shouldn't be in tags note list", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const tags = await app.goToTags();
|
||||
const tag = await tags.createItem({ title: "my-tag" });
|
||||
const notes = await tag?.open();
|
||||
|
||||
const note = await notes?.createNote(NOTE);
|
||||
expect(await notes?.findNote(NOTE)).toBeDefined();
|
||||
await note?.contextMenu.archive();
|
||||
|
||||
expect(await notes?.findNote(NOTE)).toBeUndefined();
|
||||
});
|
||||
|
||||
test("archived notebook note shouldn't be in notebooks note list", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({ title: "my-notebook" });
|
||||
const notes = await notebook?.openNotebook();
|
||||
|
||||
const note = await notes?.createNote(NOTE);
|
||||
expect(await notes?.findNote(NOTE)).toBeDefined();
|
||||
await note?.contextMenu.archive();
|
||||
|
||||
expect(await notes?.findNote(NOTE)).toBeUndefined();
|
||||
});
|
||||
|
||||
test("archived colored note shouldn't be in colors note list", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
let note = await notes.createNote(NOTE);
|
||||
await note?.contextMenu.newColor({ title: "red", color: "#ff0000" });
|
||||
const color = await app.goToColor("red");
|
||||
|
||||
note = await color.findNote(NOTE);
|
||||
expect(note).toBeDefined();
|
||||
await note?.contextMenu.archive();
|
||||
|
||||
expect(await color.findNote(NOTE)).toBeUndefined();
|
||||
});
|
||||
|
||||
test("archived note shouldn't appear in search results", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
|
||||
await app.search(NOTE.title, "notes");
|
||||
expect(await notes.findNote(NOTE)).toBeDefined();
|
||||
await note?.contextMenu.archive();
|
||||
|
||||
await app.search(NOTE.title, "notes");
|
||||
const searchedNote = await notes.findNote(NOTE);
|
||||
expect(searchedNote).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { AppModel } from "./models/app.model";
|
||||
import { Item } from "./models/types";
|
||||
import { groupByOptions, NOTE, orderByOptions, sortByOptions } from "./utils";
|
||||
import { NOTE, orderByOptions, sortByOptions } from "./utils";
|
||||
|
||||
const TAG: Item = { title: "hello-world" };
|
||||
const EDITED_TAG: Item = { title: "hello-world-2" };
|
||||
@@ -236,3 +236,84 @@ test("creating more than 5 tags shouldn't be possible on basic plan", async ({
|
||||
]);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test("when default tag is set, created note in notes context should have default tag", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
let tags = await app.goToTags();
|
||||
let tag = await tags.createItem(TAG);
|
||||
await tag?.setAsDefault();
|
||||
|
||||
const notes = await app.goToNotes();
|
||||
await notes?.createNote(NOTE);
|
||||
tags = await app.goToTags();
|
||||
tag = await tags.findItem(TAG);
|
||||
const openedTag = await tag?.open();
|
||||
|
||||
expect(await openedTag?.findNote(NOTE)).toBeDefined();
|
||||
});
|
||||
|
||||
test("when default tag is set, created note in other tag's context should not have default tag", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
let tags = await app.goToTags();
|
||||
let tag = await tags.createItem(TAG);
|
||||
await tag?.setAsDefault();
|
||||
|
||||
const otherTag = await tags.createItem({
|
||||
title: "Other Tag"
|
||||
});
|
||||
const openedOtherTag = await otherTag?.open();
|
||||
await openedOtherTag?.createNote(NOTE);
|
||||
tags = await app.goToTags();
|
||||
tag = await tags.findItem(TAG);
|
||||
const openedTag = await tag?.open();
|
||||
|
||||
expect(await openedTag?.findNote(NOTE)).toBeUndefined();
|
||||
});
|
||||
|
||||
test("when default tag is set, created note in notebooks context should have default tag", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
let tags = await app.goToTags();
|
||||
let tag = await tags.createItem(TAG);
|
||||
await tag?.setAsDefault();
|
||||
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({ title: "Test Notebook" });
|
||||
const openedNotebook = await notebook?.openNotebook();
|
||||
await openedNotebook?.createNote(NOTE);
|
||||
tags = await app.goToTags();
|
||||
tag = await tags.findItem(TAG);
|
||||
const openedTag = await tag?.open();
|
||||
|
||||
expect(await openedTag?.findNote(NOTE)).toBeDefined();
|
||||
});
|
||||
|
||||
test("when default tag is set, created note in colors context should have default tag", async ({
|
||||
page
|
||||
}) => {
|
||||
const coloredNote = { title: "Red note", content: NOTE.content };
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
let tags = await app.goToTags();
|
||||
let tag = await tags.createItem(TAG);
|
||||
await tag?.setAsDefault();
|
||||
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
await note?.contextMenu.newColor({ color: "#ff0000", title: "red" });
|
||||
const color = await app.goToColor("red");
|
||||
await color?.createNote(coloredNote);
|
||||
tags = await app.goToTags();
|
||||
tag = await tags.findItem(TAG);
|
||||
const openedTag = await tag?.open();
|
||||
|
||||
expect(await openedTag?.findNote(coloredNote)).toBeDefined();
|
||||
});
|
||||
|
||||
@@ -86,3 +86,42 @@ test("unlocking a note permanently should not show vault unlocked status", async
|
||||
|
||||
await expect(vaultUnlockedStatus).toBeHidden();
|
||||
});
|
||||
|
||||
test("clicking on vault unlocked status should lock the note", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
await note?.contextMenu.lock(PASSWORD);
|
||||
await note?.openLockedNote(PASSWORD);
|
||||
|
||||
expect(await note?.isLockedNotePasswordFieldVisible()).toBe(false);
|
||||
|
||||
const vaultUnlockedStatus = page.locator(getTestId("vault-unlocked"));
|
||||
await vaultUnlockedStatus.waitFor({ state: "visible" });
|
||||
await vaultUnlockedStatus.click();
|
||||
|
||||
expect(await note?.isLockedNotePasswordFieldVisible()).toBe(true);
|
||||
});
|
||||
|
||||
test("clicking on vault unlocked status should lock the readonly note", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
await note?.properties.readonly();
|
||||
await note?.contextMenu.lock(PASSWORD);
|
||||
await note?.openLockedNote(PASSWORD);
|
||||
|
||||
expect(await note?.isLockedNotePasswordFieldVisible()).toBe(false);
|
||||
|
||||
const vaultUnlockedStatus = page.locator(getTestId("vault-unlocked"));
|
||||
await vaultUnlockedStatus.waitFor({ state: "visible" });
|
||||
await vaultUnlockedStatus.click();
|
||||
|
||||
expect(await note?.isLockedNotePasswordFieldVisible()).toBe(true);
|
||||
});
|
||||
|
||||
3396
apps/web/package-lock.json
generated
3396
apps/web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.1.0",
|
||||
"version": "3.2.0",
|
||||
"private": true,
|
||||
"main": "./src/app.js",
|
||||
"homepage": "https://notesnook.com/",
|
||||
@@ -19,7 +19,7 @@
|
||||
"@lingui/react": "5.1.2",
|
||||
"@mdi/js": "7.4.47",
|
||||
"@mdi/react": "1.6.1",
|
||||
"@notesnook-importer/core": "^2.1.1",
|
||||
"@notesnook-importer/core": "^2.2.2",
|
||||
"@notesnook/common": "file:../../packages/common",
|
||||
"@notesnook/core": "file:../../packages/core",
|
||||
"@notesnook/crypto": "file:../../packages/crypto",
|
||||
@@ -43,7 +43,7 @@
|
||||
"@theme-ui/core": "0.16.1",
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/react-query": "10.45.2",
|
||||
"@zip.js/zip.js": "^2.7.54",
|
||||
"@zip.js/zip.js": "^2.7.62",
|
||||
"async-mutex": "0.5.0",
|
||||
"axios": "^1.7.9",
|
||||
"clipboard-polyfill": "4.1.0",
|
||||
@@ -51,7 +51,7 @@
|
||||
"cronosjs": "^1.7.1",
|
||||
"dayjs": "1.11.13",
|
||||
"diffblazer": "^1.0.1",
|
||||
"electron-trpc": "0.6.1",
|
||||
"electron-trpc": "0.7.1",
|
||||
"event-source-polyfill": "1.0.31",
|
||||
"fflate": "^0.8.0",
|
||||
"file-saver": "^2.0.5",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
.tabsScroll,
|
||||
.titlebarLogo,
|
||||
.theme-scope-titleBar,
|
||||
.navigation-menu-header,
|
||||
.route-container-header {
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
@@ -205,6 +206,10 @@ textarea,
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.flash {
|
||||
animation: flash 1s;
|
||||
}
|
||||
|
||||
@@ -164,8 +164,11 @@ function DesktopAppContents() {
|
||||
|
||||
useEffect(() => {
|
||||
if (isListPaneVisible) {
|
||||
navPane.current?.expand(1);
|
||||
navPane.current?.reset(1);
|
||||
if (navPane.current?.hasExpandedSize(1)) {
|
||||
navPane.current?.expand(1);
|
||||
} else {
|
||||
navPane.current?.reset(1);
|
||||
}
|
||||
} else {
|
||||
navPane.current?.collapse(1);
|
||||
}
|
||||
|
||||
@@ -86,9 +86,12 @@ export async function scheduleFullBackups() {
|
||||
);
|
||||
}
|
||||
|
||||
export function shouldAddAutoBackupsDisabledNotice() {
|
||||
export async function shouldAddAutoBackupsDisabledNotice() {
|
||||
const user = await db.user.getUser();
|
||||
if (!user) return false;
|
||||
|
||||
const backupInterval = Config.get("backupReminderOffset", 0);
|
||||
if (!isUserPremium() && backupInterval) {
|
||||
if (!isUserPremium(user) && backupInterval) {
|
||||
Config.set("backupReminderOffset", 0);
|
||||
return true;
|
||||
}
|
||||
@@ -177,7 +180,7 @@ export const NoticesData: Record<NoticeType, NoticeData> = {
|
||||
export async function resetNotices() {
|
||||
const notices: Notice[] = [];
|
||||
|
||||
if (shouldAddAutoBackupsDisabledNotice()) {
|
||||
if (await shouldAddAutoBackupsDisabledNotice()) {
|
||||
notices.push({ type: "autoBackupsOff", priority: 3 });
|
||||
}
|
||||
if (await shouldAddBackupNotice()) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user