Compare commits
443 Commits
fix-compre
...
v3.0.6-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d546b611b | ||
|
|
1e6d244dfe | ||
|
|
780f18a4fb | ||
|
|
c927fa9728 | ||
|
|
7ec96dd991 | ||
|
|
94d0bbf381 | ||
|
|
6ad074f9dc | ||
|
|
19ed790b32 | ||
|
|
738f6ce1d5 | ||
|
|
06f8c80a80 | ||
|
|
d397e0053d | ||
|
|
4c8a1be00c | ||
|
|
0570e530f3 | ||
|
|
11b220af31 | ||
|
|
386ec60ba0 | ||
|
|
4303b89760 | ||
|
|
bafbc871c1 | ||
|
|
6f797f5b5e | ||
|
|
ab64b4b22d | ||
|
|
70629b3868 | ||
|
|
b808b156f2 | ||
|
|
1077fff7e9 | ||
|
|
03d18e9b13 | ||
|
|
4281fb65e1 | ||
|
|
69add6a536 | ||
|
|
31c6fea321 | ||
|
|
e3b0344f17 | ||
|
|
384f6fc8d9 | ||
|
|
5406448b16 | ||
|
|
19bc8b765d | ||
|
|
f2d0a03651 | ||
|
|
5a30337326 | ||
|
|
43729f188d | ||
|
|
57c6c3e841 | ||
|
|
53ae703029 | ||
|
|
3e9e6b5daf | ||
|
|
2577416edb | ||
|
|
b2d4dd6b3c | ||
|
|
5e9314b5cb | ||
|
|
24f2aa51da | ||
|
|
a4ddbe3f2f | ||
|
|
7f62262eaf | ||
|
|
9e71c5e68a | ||
|
|
c28e81a2c8 | ||
|
|
fc31cc49f6 | ||
|
|
6440db28bd | ||
|
|
c3dae9fa80 | ||
|
|
c721b43bbb | ||
|
|
646d2d6f36 | ||
|
|
a2d0238391 | ||
|
|
c13af2326b | ||
|
|
2b99816e3e | ||
|
|
93332e6345 | ||
|
|
14da470383 | ||
|
|
08356657ae | ||
|
|
3436c6e48a | ||
|
|
d6c3926812 | ||
|
|
e058e3bb44 | ||
|
|
1db4221224 | ||
|
|
08748962fb | ||
|
|
b77d2ae0a3 | ||
|
|
e0346ed902 | ||
|
|
989203dec6 | ||
|
|
d34ff63016 | ||
|
|
2df875a40f | ||
|
|
61007b92a2 | ||
|
|
681681d0ab | ||
|
|
c9a8f36ade | ||
|
|
d2deb1ee7b | ||
|
|
1be9a09d5f | ||
|
|
d0744c298c | ||
|
|
2c2cf2e8bb | ||
|
|
b0d6514a5e | ||
|
|
7f22bedead | ||
|
|
420ed87607 | ||
|
|
8521f9faf2 | ||
|
|
499671180c | ||
|
|
b5786b9239 | ||
|
|
51279b82f6 | ||
|
|
6dc91450da | ||
|
|
8bfb617387 | ||
|
|
c0e79cc65e | ||
|
|
3976086afd | ||
|
|
a4120436be | ||
|
|
f240242217 | ||
|
|
c2737bf0bf | ||
|
|
4d02e6fc20 | ||
|
|
cf4ede7b22 | ||
|
|
1f18827c80 | ||
|
|
7708e5b66e | ||
|
|
e72678c917 | ||
|
|
47f68408b0 | ||
|
|
d3e3a14423 | ||
|
|
565cd8d828 | ||
|
|
2804710a8d | ||
|
|
1c206fb058 | ||
|
|
4848cb9f08 | ||
|
|
4d75da5ee0 | ||
|
|
4079dd079c | ||
|
|
69aa9e284d | ||
|
|
a2dd96d64b | ||
|
|
4444c731f9 | ||
|
|
dd209354d3 | ||
|
|
193d99a9ec | ||
|
|
61e83a999c | ||
|
|
ec846ece9f | ||
|
|
0660f5acf6 | ||
|
|
786d237005 | ||
|
|
a9698916dd | ||
|
|
03380ca9de | ||
|
|
7e886b787e | ||
|
|
55eaebe8a1 | ||
|
|
78248bf8b3 | ||
|
|
1a73d9a888 | ||
|
|
ea35136227 | ||
|
|
ce15ec79fd | ||
|
|
a1dfee8319 | ||
|
|
e4a030c5c9 | ||
|
|
020c5c8f0c | ||
|
|
a546354421 | ||
|
|
eb55d0d7c9 | ||
|
|
1e7c18fff4 | ||
|
|
62861d1ee6 | ||
|
|
32ba0ac2d9 | ||
|
|
23702e4d1e | ||
|
|
da14a77105 | ||
|
|
b127ce17ba | ||
|
|
44ac3732a7 | ||
|
|
ed1c963e6a | ||
|
|
6cc530c452 | ||
|
|
44c38a8598 | ||
|
|
93d55abb1a | ||
|
|
fe02385b52 | ||
|
|
20f322a98d | ||
|
|
f8c8a2b913 | ||
|
|
ee5ebfe7eb | ||
|
|
a04a59ec69 | ||
|
|
7873251d05 | ||
|
|
a409eb3a0f | ||
|
|
861d846720 | ||
|
|
74f52e77ab | ||
|
|
4f09e8bb38 | ||
|
|
8aad4358fb | ||
|
|
cd0a5ae173 | ||
|
|
2677ec4744 | ||
|
|
3202f46ffb | ||
|
|
900f82a991 | ||
|
|
13bbe2149e | ||
|
|
603593a312 | ||
|
|
0bd385395e | ||
|
|
af1312977a | ||
|
|
5002947c27 | ||
|
|
3ed5a031a4 | ||
|
|
5ba87df099 | ||
|
|
a1dd4e7a98 | ||
|
|
21d429f764 | ||
|
|
f6fba20baf | ||
|
|
7542204c6e | ||
|
|
c5527e3893 | ||
|
|
0b221cd900 | ||
|
|
d6830c5488 | ||
|
|
a7ab07d570 | ||
|
|
fec1370239 | ||
|
|
75704a08ea | ||
|
|
081b4d4eb1 | ||
|
|
e1e850f493 | ||
|
|
8e34679fd5 | ||
|
|
c2200ee8e1 | ||
|
|
4c86bac8e0 | ||
|
|
b152fa7463 | ||
|
|
949f6ace54 | ||
|
|
5c6fd953eb | ||
|
|
0326c3fee9 | ||
|
|
d7967d322e | ||
|
|
62d2a4471d | ||
|
|
42df6536c0 | ||
|
|
e9d9252182 | ||
|
|
a400350e48 | ||
|
|
1dcbf93b3a | ||
|
|
620c0b5006 | ||
|
|
d3468401f9 | ||
|
|
a6b83f503e | ||
|
|
e52ad6186f | ||
|
|
59486a7894 | ||
|
|
76fbfd3251 | ||
|
|
804dff4a53 | ||
|
|
a1df8fbf21 | ||
|
|
24c69a8c73 | ||
|
|
16e483954e | ||
|
|
7315192e1a | ||
|
|
f0d3cca188 | ||
|
|
557baf43a3 | ||
|
|
b9c8ac091f | ||
|
|
5add1b1d48 | ||
|
|
2734e50a97 | ||
|
|
ab7814c0cb | ||
|
|
f07269f4ea | ||
|
|
131ed88906 | ||
|
|
d03b46d2c1 | ||
|
|
848c25adeb | ||
|
|
61f5153c9f | ||
|
|
86b6c71501 | ||
|
|
fa11312c46 | ||
|
|
e032852632 | ||
|
|
9a4ebb5662 | ||
|
|
7631612935 | ||
|
|
d5ce877d11 | ||
|
|
446005b8e2 | ||
|
|
dd7765df97 | ||
|
|
b32b3a5af3 | ||
|
|
e3cc211355 | ||
|
|
41fed6e347 | ||
|
|
8766966c27 | ||
|
|
a2972ea9e6 | ||
|
|
99a3f9e779 | ||
|
|
33aad3ec3f | ||
|
|
92c6e9c0bb | ||
|
|
7a0ec7ca11 | ||
|
|
fd1e39cee4 | ||
|
|
bc0f92ea5d | ||
|
|
2b2a9deb71 | ||
|
|
b2ac5965d4 | ||
|
|
7397d5bd01 | ||
|
|
7bca839f6d | ||
|
|
017b466dc0 | ||
|
|
b4f7a7112b | ||
|
|
47c6b80594 | ||
|
|
4e28793c0e | ||
|
|
24f1307955 | ||
|
|
56a9b5a5d9 | ||
|
|
884fbf65e9 | ||
|
|
bc03ad8339 | ||
|
|
2fca6b2431 | ||
|
|
4067a7f7c7 | ||
|
|
a9179734d0 | ||
|
|
0f2f2f085b | ||
|
|
b9e04b763f | ||
|
|
eb23224687 | ||
|
|
70f39fdc2d | ||
|
|
3eea4f73e4 | ||
|
|
226b9f5892 | ||
|
|
47ef642648 | ||
|
|
35b7ef9204 | ||
|
|
cf024eefd8 | ||
|
|
6bba171df0 | ||
|
|
e52492488f | ||
|
|
bdaa2a5977 | ||
|
|
cd85cc32e2 | ||
|
|
1d7d5fd565 | ||
|
|
4baeee9429 | ||
|
|
667a760c89 | ||
|
|
da3ce62f08 | ||
|
|
b5adf70853 | ||
|
|
973c6e0d6f | ||
|
|
ca15a016fd | ||
|
|
5cce557a14 | ||
|
|
e81ee6e4ce | ||
|
|
339e3444e7 | ||
|
|
a32df1a009 | ||
|
|
cb7e438cd2 | ||
|
|
5cf5c1a7f7 | ||
|
|
35ae19acce | ||
|
|
e4130556e9 | ||
|
|
8dc25e9cac | ||
|
|
90cc89cd6e | ||
|
|
4fc7c49ed5 | ||
|
|
387a05e24e | ||
|
|
0129513ec6 | ||
|
|
20e5f7babb | ||
|
|
12dc4caff3 | ||
|
|
58bab91bc8 | ||
|
|
78a25dccdd | ||
|
|
1ce15d8e50 | ||
|
|
4fb10e3507 | ||
|
|
f5e43f753f | ||
|
|
f088ddf50b | ||
|
|
60974182e5 | ||
|
|
d1c613c2ec | ||
|
|
676ffd1116 | ||
|
|
c759350b4c | ||
|
|
930fadeae4 | ||
|
|
3728179a5b | ||
|
|
0fa9649997 | ||
|
|
c8b2b14412 | ||
|
|
fe6007bc51 | ||
|
|
4df150d8a0 | ||
|
|
d62ee05e4b | ||
|
|
a88d9ee134 | ||
|
|
f77a95ca2b | ||
|
|
5d2c6e0509 | ||
|
|
8064cecc89 | ||
|
|
bf238ea560 | ||
|
|
b0c69b5d5a | ||
|
|
82a0273cac | ||
|
|
28edcadc22 | ||
|
|
6ab5264587 | ||
|
|
b732337ca2 | ||
|
|
c164ec4de7 | ||
|
|
30f4fb3d9a | ||
|
|
aa12f5975f | ||
|
|
f3c2757b2a | ||
|
|
f1f67f871c | ||
|
|
f352b8edec | ||
|
|
a37dababe3 | ||
|
|
fee13715f4 | ||
|
|
b046f17644 | ||
|
|
890bb6e057 | ||
|
|
96ad097434 | ||
|
|
74e921930b | ||
|
|
e8eb0ee598 | ||
|
|
9fc7d644fc | ||
|
|
2c6c7f7774 | ||
|
|
e9f5f22601 | ||
|
|
2db4bd99b6 | ||
|
|
65edcf8e6c | ||
|
|
8b927ca94f | ||
|
|
81fe67253a | ||
|
|
4cb418ff75 | ||
|
|
4cf281da08 | ||
|
|
0682345db8 | ||
|
|
f5613bd7ae | ||
|
|
b121f75548 | ||
|
|
1c837f5fc2 | ||
|
|
255bda8e61 | ||
|
|
c8c1871906 | ||
|
|
d56916fc33 | ||
|
|
a3fab3b5ca | ||
|
|
321bd2aa93 | ||
|
|
05ccfcd9fb | ||
|
|
159c4454a3 | ||
|
|
371d7e527f | ||
|
|
5de4e16b12 | ||
|
|
bba809cef9 | ||
|
|
384db9d27e | ||
|
|
b236e7c9b8 | ||
|
|
fceb8a29c7 | ||
|
|
c2791f2bbf | ||
|
|
4a7d3f5caf | ||
|
|
e11fea58f6 | ||
|
|
ff33ced879 | ||
|
|
5f7068c376 | ||
|
|
c988c510ba | ||
|
|
4917a888f1 | ||
|
|
3ba5250d59 | ||
|
|
d595913722 | ||
|
|
1f94c47880 | ||
|
|
c1b7c66e81 | ||
|
|
8712dd286f | ||
|
|
d836170b6f | ||
|
|
0f2122bc41 | ||
|
|
77a5f83a84 | ||
|
|
f618f97845 | ||
|
|
26bdab05dd | ||
|
|
ccd078f660 | ||
|
|
74c4fdac21 | ||
|
|
fc270459b0 | ||
|
|
a51f84c1f4 | ||
|
|
c452e1524d | ||
|
|
bc428dd11f | ||
|
|
8311db0572 | ||
|
|
26d08615a7 | ||
|
|
130f39ef8a | ||
|
|
4b83e7319b | ||
|
|
96f45bf61e | ||
|
|
ebf20c31c8 | ||
|
|
9c858c0037 | ||
|
|
16b68aae4f | ||
|
|
3179c0ca2a | ||
|
|
905c7cdf31 | ||
|
|
dbeb6f7835 | ||
|
|
72015fcbeb | ||
|
|
d32f3994e8 | ||
|
|
eb9f99dc4b | ||
|
|
803ef1ca36 | ||
|
|
9b420c200a | ||
|
|
204d8f37fd | ||
|
|
3d202c834a | ||
|
|
d5adb0c195 | ||
|
|
fd4174d8d5 | ||
|
|
cb376a6144 | ||
|
|
254db0fb49 | ||
|
|
34ec5c0eaa | ||
|
|
9b31bb8598 | ||
|
|
9f33de94cb | ||
|
|
f3cbcf47a5 | ||
|
|
ec7e81d5e8 | ||
|
|
200547415c | ||
|
|
4322559680 | ||
|
|
de187ec433 | ||
|
|
9e9a25861d | ||
|
|
3ecf9eab3b | ||
|
|
a0f8666b7a | ||
|
|
7cf8895b4d | ||
|
|
84b786b5a3 | ||
|
|
b28ab28f57 | ||
|
|
70ef954de5 | ||
|
|
608761ee0d | ||
|
|
a70b309df8 | ||
|
|
58ef5050c4 | ||
|
|
c1594c1687 | ||
|
|
bcb8c14abf | ||
|
|
adb325af4d | ||
|
|
315961eaae | ||
|
|
65d3ef87d2 | ||
|
|
d4d9ebf378 | ||
|
|
d90fa07ed8 | ||
|
|
adae1b6187 | ||
|
|
b40f52b12b | ||
|
|
0b8e0f9848 | ||
|
|
8cbb7f88d6 | ||
|
|
17201979ba | ||
|
|
0bcd162559 | ||
|
|
fe2fc26bc0 | ||
|
|
7b13d064e7 | ||
|
|
cad18cb9e8 | ||
|
|
fa45ead4cb | ||
|
|
e781273345 | ||
|
|
d28179e0cd | ||
|
|
ee6a515683 | ||
|
|
37263304fa | ||
|
|
e96ba80583 | ||
|
|
cfd80d2008 | ||
|
|
288226a3af | ||
|
|
4d2c9cfd4e | ||
|
|
fe52ce38e1 | ||
|
|
46acdf4279 | ||
|
|
1f698280df | ||
|
|
94babf2a97 | ||
|
|
b19be80738 | ||
|
|
f77746cf0e | ||
|
|
d3c033faf2 | ||
|
|
b9f22e1dd0 | ||
|
|
b0dd1c2095 | ||
|
|
0beffd5165 | ||
|
|
a1c0a834ee | ||
|
|
27dc19cb58 | ||
|
|
896884ff59 | ||
|
|
97cb724bc1 | ||
|
|
f08e372bcf | ||
|
|
0aecb2d27a | ||
|
|
3735d9ee18 | ||
|
|
3d4264257e | ||
|
|
96b97c4bec |
19
.github/workflows/desktop.publish.yml
vendored
@@ -97,9 +97,6 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: ./.github/actions/setup-node-with-cache
|
||||
|
||||
- name: Install setuptools
|
||||
run: brew install python-setuptools
|
||||
|
||||
- name: Setup notarization
|
||||
run: |
|
||||
mkdir -p ~/private_keys/
|
||||
@@ -147,7 +144,7 @@ jobs:
|
||||
CSC_KEY_PASSWORD: ${{ secrets.mac_certs_password }}
|
||||
run: |
|
||||
npx nx run release --project @notesnook/desktop -- --variant=mas
|
||||
yarn electron-builder --mac mas --universal -p never
|
||||
npx electron-builder --mac mas --universal -p never
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build zip and dmg
|
||||
@@ -161,9 +158,9 @@ jobs:
|
||||
run: |
|
||||
npx nx run release --project @notesnook/desktop
|
||||
if [ ${{ inputs.publish-github }} == true ]; then
|
||||
yarn electron-builder --mac zip dmg --arm64 --x64 -p always
|
||||
npx electron-builder --mac zip dmg --arm64 --x64 -p always
|
||||
else
|
||||
yarn electron-builder --mac zip dmg --arm64 --x64 -p never
|
||||
npx electron-builder --mac zip dmg --arm64 --x64 -p never
|
||||
fi
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
@@ -219,7 +216,7 @@ jobs:
|
||||
- name: Build snap
|
||||
if: inputs.publish-snap
|
||||
run: |
|
||||
yarn electron-builder --linux snap:x64 -p never
|
||||
npx electron-builder --linux snap:x64 -p never
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build AppImage
|
||||
@@ -227,9 +224,9 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
if [ ${{ inputs.publish-github }} == true ]; then
|
||||
yarn electron-builder --linux AppImage:x64 AppImage:arm64 -p always
|
||||
npx electron-builder --linux AppImage:x64 AppImage:arm64 -p always
|
||||
else
|
||||
yarn electron-builder --linux AppImage:x64 AppImage:arm64 -p never
|
||||
npx electron-builder --linux AppImage:x64 AppImage:arm64 -p never
|
||||
fi
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
@@ -254,8 +251,8 @@ jobs:
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
|
||||
- name: Install TrustedSigning
|
||||
run: Install-Module -Name TrustedSigning -RequiredVersion 0.3.15 -Force -Repository PSGallery
|
||||
- name: Install AzureCodeSigning
|
||||
run: Install-Module -Name AzureCodeSigning -RequiredVersion 0.3.0 -Force -Repository PSGallery
|
||||
shell: pwsh
|
||||
|
||||
- name: Setup Node
|
||||
|
||||
2
.github/workflows/web.tests.yml
vendored
@@ -67,7 +67,7 @@ jobs:
|
||||
- name: Install packages
|
||||
run: |
|
||||
npm ci --ignore-scripts --prefer-offline --no-audit
|
||||
npm install -D @playwright/test otplib dayjs @zip.js/zip.js
|
||||
npm install -D @playwright/test otplib
|
||||
|
||||
- name: Validate build extraction
|
||||
run: ls -ld ./apps/web/build/index.html
|
||||
|
||||
2
.gitignore
vendored
@@ -10,4 +10,4 @@ nx-cloud.env
|
||||
.nyc_output
|
||||
site
|
||||
node_modules.backup
|
||||
.nx
|
||||
.nx/cache
|
||||
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 401 B After Width: | Height: | Size: 520 B |
|
Before Width: | Height: | Size: 543 B After Width: | Height: | Size: 917 B |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 763 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 353 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 36 KiB |
570
apps/desktop/package-lock.json
generated
@@ -1,23 +1,23 @@
|
||||
{
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.6-beta",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.6-beta",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@notesnook/crypto": "file:../../packages/crypto",
|
||||
"@trpc/client": "10.38.3",
|
||||
"@trpc/server": "10.38.3",
|
||||
"better-sqlite3-multiple-ciphers": "^9.5.0",
|
||||
"better-sqlite3-multiple-ciphers": "^9.4.0",
|
||||
"electron-trpc": "0.5.2",
|
||||
"electron-updater": "6.1.4",
|
||||
"icojs": "^0.17.1",
|
||||
"sodium-native": "^4.1.1",
|
||||
"sodium-native": "^4.0.6",
|
||||
"typed-emitter": "^2.1.0",
|
||||
"yargs": "^17.6.2",
|
||||
"zod": "^3.21.4"
|
||||
@@ -26,13 +26,11 @@
|
||||
"@types/node": "18.16.1",
|
||||
"@types/yargs": "^17.0.24",
|
||||
"chokidar": "^3.5.3",
|
||||
"electron": "^29.3.1",
|
||||
"electron-builder": "^24.13.3",
|
||||
"electron": "^28.2.1",
|
||||
"electron-builder": "^24.9.1",
|
||||
"esbuild": "^0.20.0",
|
||||
"node-gyp-build": "^4.8.0",
|
||||
"prebuildify": "^6.0.1",
|
||||
"tree-kill": "^1.2.2",
|
||||
"undici": "^6.14.1"
|
||||
"undici": "^6.6.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"dmg-license": "^1.0.11"
|
||||
@@ -70,9 +68,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/asar": {
|
||||
"version": "3.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.9.tgz",
|
||||
"integrity": "sha512-Vu2P3X2gcZ3MY9W7yH72X9+AMXwUQZEJBrsPIbX0JsdllLtoh62/Q8Wg370/DawIEVKOyfD6KtTLo645ezqxUA==",
|
||||
"version": "3.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.8.tgz",
|
||||
"integrity": "sha512-cmskk5M06ewHMZAplSiF4AlME3IrnnZhKnWbtwKVLRkdJkKyUVjMLhDIiPIx/+6zQWVlKX/LtmK9xDme7540Sg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"commander": "^5.0.0",
|
||||
@@ -171,9 +169,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/notarize": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.2.1.tgz",
|
||||
"integrity": "sha512-aL+bFMIkpR0cmmj5Zgy0LMKEpgy43/hw5zadEArgmAMWWlKc5buwFvFT9G/o/YJkvXAJm5q3iuTuLaiaXW39sg==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.1.0.tgz",
|
||||
"integrity": "sha512-Q02xem1D0sg4v437xHgmBLxI2iz/fc0D4K7fiVWHa/AnW8o7D751xyKNXgziA6HrTOme9ul1JfWN5ark8WH1xA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
@@ -233,9 +231,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/universal": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.5.1.tgz",
|
||||
"integrity": "sha512-kbgXxyEauPJiQQUNG2VgUeyfQNFk6hBF11ISN2PNI6agUgPl55pv4eQmaqHzTAzchBvqZ2tQuRVaPStGf0mxGw==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.4.1.tgz",
|
||||
"integrity": "sha512-lE/U3UNw1YHuowNbTmKNs9UlS3En3cPgwM5MI+agIgr/B1hSze9NdOP0qn7boZaI9Lph8IDv3/24g9IxnJP7aQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@electron/asar": "^3.2.1",
|
||||
@@ -655,100 +653,13 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"string-width": "^5.1.2",
|
||||
"string-width-cjs": "npm:string-width@^4.2.0",
|
||||
"strip-ansi": "^7.0.1",
|
||||
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
|
||||
"wrap-ansi": "^8.1.0",
|
||||
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui/node_modules/ansi-regex": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
|
||||
"node_modules/@fastify/busboy": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
|
||||
"integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui/node_modules/ansi-styles": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui/node_modules/emoji-regex": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@isaacs/cliui/node_modules/string-width": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"eastasianwidth": "^0.2.0",
|
||||
"emoji-regex": "^9.2.2",
|
||||
"strip-ansi": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui/node_modules/strip-ansi": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
||||
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.1.0",
|
||||
"string-width": "^5.0.1",
|
||||
"strip-ansi": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@malept/cross-spawn-promise": {
|
||||
@@ -807,16 +718,6 @@
|
||||
"resolved": "../../packages/crypto",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@sindresorhus/is": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
|
||||
@@ -1066,25 +967,26 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/app-builder-lib": {
|
||||
"version": "24.13.3",
|
||||
"resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-24.13.3.tgz",
|
||||
"integrity": "sha512-FAzX6IBit2POXYGnTCT8YHFO/lr5AapAII6zzhQO3Rw4cEDOgK+t1xhLc5tNcKlicTHlo9zxIwnYCX9X2DLkig==",
|
||||
"version": "24.9.1",
|
||||
"resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-24.9.1.tgz",
|
||||
"integrity": "sha512-Q1nYxZcio4r+W72cnIRVYofEAyjBd3mG47o+zms8HlD51zWtA/YxJb01Jei5F+jkWhge/PTQK+uldsPh6d0/4g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@develar/schema-utils": "~2.6.5",
|
||||
"@electron/notarize": "2.2.1",
|
||||
"@electron/notarize": "2.1.0",
|
||||
"@electron/osx-sign": "1.0.5",
|
||||
"@electron/universal": "1.5.1",
|
||||
"@electron/universal": "1.4.1",
|
||||
"@malept/flatpak-bundler": "^0.4.0",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
"7zip-bin": "~5.2.0",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"bluebird-lst": "^1.0.9",
|
||||
"builder-util": "24.13.1",
|
||||
"builder-util-runtime": "9.2.4",
|
||||
"builder-util": "24.8.1",
|
||||
"builder-util-runtime": "9.2.3",
|
||||
"chromium-pickle-js": "^0.2.0",
|
||||
"debug": "^4.3.4",
|
||||
"ejs": "^3.1.8",
|
||||
"electron-publish": "24.13.1",
|
||||
"electron-publish": "24.8.1",
|
||||
"form-data": "^4.0.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"hosted-git-info": "^4.1.0",
|
||||
@@ -1101,16 +1003,12 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"dmg-builder": "24.13.3",
|
||||
"electron-builder-squirrel-windows": "24.13.3"
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/builder-util-runtime": {
|
||||
"version": "9.2.4",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.4.tgz",
|
||||
"integrity": "sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==",
|
||||
"version": "9.2.3",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.3.tgz",
|
||||
"integrity": "sha512-FGhkqXdFFZ5dNC4C+yuQB9ak311rpGAw+/ASz8ZdxwODCv1GGMWgLDeofRkdi0F3VCHQEWy/aXcJQozx2nOPiw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
@@ -1199,9 +1097,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/better-sqlite3-multiple-ciphers": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/better-sqlite3-multiple-ciphers/-/better-sqlite3-multiple-ciphers-9.5.0.tgz",
|
||||
"integrity": "sha512-6A9xBRvssONJW07Lur6pmkaUwlCGz1bnjFmXrrAR3qXETUBk92OI4C/+LhMOatn5wQ8AQzLScFZC/CKUpxkTaw==",
|
||||
"version": "9.4.0",
|
||||
"resolved": "https://registry.npmjs.org/better-sqlite3-multiple-ciphers/-/better-sqlite3-multiple-ciphers-9.4.0.tgz",
|
||||
"integrity": "sha512-uQoBdShnpCdAPUmCPuLSrHtfSHAxjIFQvLnMbXHsvbWkfBP3sPfnnIaUTz7KHYRqgWNLlcQfs+9F9uqvMqau6Q==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"bindings": "^1.5.0",
|
||||
@@ -1334,16 +1232,16 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/builder-util": {
|
||||
"version": "24.13.1",
|
||||
"resolved": "https://registry.npmjs.org/builder-util/-/builder-util-24.13.1.tgz",
|
||||
"integrity": "sha512-NhbCSIntruNDTOVI9fdXz0dihaqX2YuE1D6zZMrwiErzH4ELZHE6mdiB40wEgZNprDia+FghRFgKoAqMZRRjSA==",
|
||||
"version": "24.8.1",
|
||||
"resolved": "https://registry.npmjs.org/builder-util/-/builder-util-24.8.1.tgz",
|
||||
"integrity": "sha512-ibmQ4BnnqCnJTNrdmdNlnhF48kfqhNzSeqFMXHLIl+o9/yhn6QfOaVrloZ9YUu3m0k3rexvlT5wcki6LWpjTZw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/debug": "^4.1.6",
|
||||
"7zip-bin": "~5.2.0",
|
||||
"app-builder-bin": "4.0.0",
|
||||
"bluebird-lst": "^1.0.9",
|
||||
"builder-util-runtime": "9.2.4",
|
||||
"builder-util-runtime": "9.2.3",
|
||||
"chalk": "^4.1.2",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"debug": "^4.3.4",
|
||||
@@ -1370,9 +1268,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/builder-util/node_modules/builder-util-runtime": {
|
||||
"version": "9.2.4",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.4.tgz",
|
||||
"integrity": "sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==",
|
||||
"version": "9.2.3",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.3.tgz",
|
||||
"integrity": "sha512-FGhkqXdFFZ5dNC4C+yuQB9ak311rpGAw+/ASz8ZdxwODCv1GGMWgLDeofRkdi0F3VCHQEWy/aXcJQozx2nOPiw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
@@ -1576,59 +1474,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/config-file-ts": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.6.tgz",
|
||||
"integrity": "sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w==",
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.4.tgz",
|
||||
"integrity": "sha512-cKSW0BfrSaAUnxpgvpXPLaaW/umg4bqg4k3GO1JqlRfpx+d5W0GDXznCMkWotJQek5Mmz1MJVChQnz3IVaeMZQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"glob": "^10.3.10",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/config-file-ts/node_modules/glob": {
|
||||
"version": "10.3.12",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz",
|
||||
"integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^2.3.6",
|
||||
"minimatch": "^9.0.1",
|
||||
"minipass": "^7.0.4",
|
||||
"path-scurry": "^1.10.2"
|
||||
},
|
||||
"bin": {
|
||||
"glob": "dist/esm/bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/config-file-ts/node_modules/minimatch": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/config-file-ts/node_modules/minipass": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
|
||||
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
"glob": "^7.1.6",
|
||||
"typescript": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
@@ -1817,14 +1669,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dmg-builder": {
|
||||
"version": "24.13.3",
|
||||
"resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-24.13.3.tgz",
|
||||
"integrity": "sha512-rcJUkMfnJpfCboZoOOPf4L29TRtEieHNOeAbYPWPxlaBw/Z1RKrRA86dOI9rwaI4tQSc/RD82zTNHprfUHXsoQ==",
|
||||
"version": "24.9.1",
|
||||
"resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-24.9.1.tgz",
|
||||
"integrity": "sha512-huC+O6hvHd24Ubj3cy2GMiGLe2xGFKN3klqVMLAdcbB6SWMd1yPSdZvV8W1O01ICzCCRlZDHiv4VrNUgnPUfbQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"app-builder-lib": "24.13.3",
|
||||
"builder-util": "24.13.1",
|
||||
"builder-util-runtime": "9.2.4",
|
||||
"app-builder-lib": "24.9.1",
|
||||
"builder-util": "24.8.1",
|
||||
"builder-util-runtime": "9.2.3",
|
||||
"fs-extra": "^10.1.0",
|
||||
"iconv-lite": "^0.6.2",
|
||||
"js-yaml": "^4.1.0"
|
||||
@@ -1834,9 +1686,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dmg-builder/node_modules/builder-util-runtime": {
|
||||
"version": "9.2.4",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.4.tgz",
|
||||
"integrity": "sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==",
|
||||
"version": "9.2.3",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.3.tgz",
|
||||
"integrity": "sha512-FGhkqXdFFZ5dNC4C+yuQB9ak311rpGAw+/ASz8ZdxwODCv1GGMWgLDeofRkdi0F3VCHQEWy/aXcJQozx2nOPiw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
@@ -1871,31 +1723,16 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz",
|
||||
"integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv-expand": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
|
||||
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/eastasianwidth": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ejs": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
|
||||
"integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
|
||||
"version": "3.1.9",
|
||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
|
||||
"integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"jake": "^10.8.5"
|
||||
@@ -1908,14 +1745,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron": {
|
||||
"version": "29.3.1",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-29.3.1.tgz",
|
||||
"integrity": "sha512-auge1/6RVqgUd6TgIq88wKdUCJi2cjESi3jy7d+6X4JzvBGprKBqMJ8JSSFpu/Px1YJrFUKAxfy6SC+TQf1uLw==",
|
||||
"version": "28.2.1",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-28.2.1.tgz",
|
||||
"integrity": "sha512-wlzXf+OvOiVlBf9dcSeMMf7Q+N6DG+wtgFbMK0sA/JpIJcdosRbLMQwLg/LTwNVKIbmayqFLDp4FmmFkEMhbYA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@electron/get": "^2.0.0",
|
||||
"@types/node": "^20.9.0",
|
||||
"@types/node": "^18.11.18",
|
||||
"extract-zip": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
@@ -1926,16 +1763,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-builder": {
|
||||
"version": "24.13.3",
|
||||
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-24.13.3.tgz",
|
||||
"integrity": "sha512-yZSgVHft5dNVlo31qmJAe4BVKQfFdwpRw7sFp1iQglDRCDD6r22zfRJuZlhtB5gp9FHUxCMEoWGq10SkCnMAIg==",
|
||||
"version": "24.9.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-24.9.1.tgz",
|
||||
"integrity": "sha512-v7BuakDuY6sKMUYM8mfQGrwyjBpZ/ObaqnenU0H+igEL10nc6ht049rsCw2HghRBdEwJxGIBuzs3jbEhNaMDmg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"app-builder-lib": "24.13.3",
|
||||
"builder-util": "24.13.1",
|
||||
"builder-util-runtime": "9.2.4",
|
||||
"app-builder-lib": "24.9.1",
|
||||
"builder-util": "24.8.1",
|
||||
"builder-util-runtime": "9.2.3",
|
||||
"chalk": "^4.1.2",
|
||||
"dmg-builder": "24.13.3",
|
||||
"dmg-builder": "24.9.1",
|
||||
"fs-extra": "^10.1.0",
|
||||
"is-ci": "^3.0.0",
|
||||
"lazy-val": "^1.0.5",
|
||||
@@ -1952,9 +1789,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-builder/node_modules/builder-util-runtime": {
|
||||
"version": "9.2.4",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.4.tgz",
|
||||
"integrity": "sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==",
|
||||
"version": "9.2.3",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.3.tgz",
|
||||
"integrity": "sha512-FGhkqXdFFZ5dNC4C+yuQB9ak311rpGAw+/ASz8ZdxwODCv1GGMWgLDeofRkdi0F3VCHQEWy/aXcJQozx2nOPiw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
@@ -1965,14 +1802,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-publish": {
|
||||
"version": "24.13.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-24.13.1.tgz",
|
||||
"integrity": "sha512-2ZgdEqJ8e9D17Hwp5LEq5mLQPjqU3lv/IALvgp+4W8VeNhryfGhYEQC/PgDPMrnWUp+l60Ou5SJLsu+k4mhQ8A==",
|
||||
"version": "24.8.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-24.8.1.tgz",
|
||||
"integrity": "sha512-IFNXkdxMVzUdweoLJNXSupXkqnvgbrn3J4vognuOY06LaS/m0xvfFYIf+o1CM8if6DuWYWoQFKPcWZt/FUjZPw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/fs-extra": "^9.0.11",
|
||||
"builder-util": "24.13.1",
|
||||
"builder-util-runtime": "9.2.4",
|
||||
"builder-util": "24.8.1",
|
||||
"builder-util-runtime": "9.2.3",
|
||||
"chalk": "^4.1.2",
|
||||
"fs-extra": "^10.1.0",
|
||||
"lazy-val": "^1.0.5",
|
||||
@@ -1980,9 +1817,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-publish/node_modules/builder-util-runtime": {
|
||||
"version": "9.2.4",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.4.tgz",
|
||||
"integrity": "sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==",
|
||||
"version": "9.2.3",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.3.tgz",
|
||||
"integrity": "sha512-FGhkqXdFFZ5dNC4C+yuQB9ak311rpGAw+/ASz8ZdxwODCv1GGMWgLDeofRkdi0F3VCHQEWy/aXcJQozx2nOPiw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
@@ -2020,15 +1857,6 @@
|
||||
"tiny-typed-emitter": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/electron/node_modules/@types/node": {
|
||||
"version": "20.12.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
|
||||
"integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
@@ -2223,22 +2051,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
|
||||
"integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.0",
|
||||
"signal-exit": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
@@ -2749,12 +2561,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/isbinaryfile": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.2.tgz",
|
||||
"integrity": "sha512-GvcjojwonMjWbTkfMpnVHVqXW/wKMYDfEpY94/8zy8HFMOqb/VL6oeONq9v87q4ttVlaTLnGXnJD4B5B1OTGIg==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.0.tgz",
|
||||
"integrity": "sha512-UDdnyGvMajJUWCkib7Cei/dvyJrrvo4FIrsvSFWdPpXSUorzXrDJ0S+X5Q4ZlasfPjca4yqCNNsjbCeiy8FFeg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 18.0.0"
|
||||
"node": ">= 14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/gjtorikian/"
|
||||
@@ -2766,24 +2578,6 @@
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/jackspeak": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
|
||||
"integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@isaacs/cliui": "^8.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jake": {
|
||||
"version": "10.8.7",
|
||||
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
|
||||
@@ -3116,18 +2910,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz",
|
||||
"integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"path-key": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
@@ -3173,31 +2955,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/path-scurry": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz",
|
||||
"integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^10.2.0",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/path-scurry/node_modules/lru-cache": {
|
||||
"version": "10.2.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz",
|
||||
"integrity": "sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "14 || >=16.14"
|
||||
}
|
||||
},
|
||||
"node_modules/peek-readable": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
|
||||
@@ -3274,23 +3031,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/prebuildify": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/prebuildify/-/prebuildify-6.0.1.tgz",
|
||||
"integrity": "sha512-8Y2oOOateom/s8dNBsGIcnm6AxPmLH4/nanQzL5lQMU+sC0CMhzARZHizwr36pUPLdvBnOkCNQzxg4djuFSgIw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.5",
|
||||
"mkdirp-classic": "^0.5.3",
|
||||
"node-abi": "^3.3.0",
|
||||
"npm-run-path": "^3.1.0",
|
||||
"pump": "^3.0.0",
|
||||
"tar-fs": "^2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"prebuildify": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/progress": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||
@@ -3374,6 +3114,15 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/read-config-file/node_modules/dotenv": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz",
|
||||
"integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
@@ -3449,6 +3198,21 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/rimraf": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
"bin": {
|
||||
"rimraf": "bin.js"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/roarr": {
|
||||
"version": "2.15.4",
|
||||
"resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
|
||||
@@ -3586,18 +3350,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-concat": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||
@@ -3678,12 +3430,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sodium-native": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.1.1.tgz",
|
||||
"integrity": "sha512-LXkAfRd4FHtkQS4X6g+nRcVaN7mWVNepV06phIsC6+IZFvGh1voW5TNQiQp2twVaMf05gZqQjuS+uWLM6gHhNQ==",
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.0.6.tgz",
|
||||
"integrity": "sha512-uYsyycwcz9kYDwpXxJmL2YZosynsxcP6RPySbARVJdC9uNDa2CMjzJ7/WsMMvThKgvAYsBWdZc7L/WSVj9lTcA==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build": "^4.8.0"
|
||||
"node-gyp-build": "^4.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
@@ -3706,9 +3458,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sprintf-js": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
|
||||
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
|
||||
"integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@@ -3742,21 +3494,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width-cjs": {
|
||||
"name": "string-width",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
@@ -3768,19 +3505,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi-cjs": {
|
||||
"name": "strip-ansi",
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
@@ -3830,9 +3554,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
|
||||
"integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chownr": "^2.0.0",
|
||||
@@ -3893,12 +3617,15 @@
|
||||
"integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA=="
|
||||
},
|
||||
"node_modules/tmp": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
|
||||
"integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
|
||||
"integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"rimraf": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.14"
|
||||
"node": ">=8.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tmp-promise": {
|
||||
@@ -3987,33 +3714,30 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.4.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
||||
"version": "4.9.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
"node": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.14.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.14.1.tgz",
|
||||
"integrity": "sha512-mAel3i4BsYhkeVPXeIPXVGPJKeBzqCieZYoFsbWfUzd68JmHByhc1Plit5WlylxXFaGpgkZB8mExlxnt+Q1p7A==",
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.6.1.tgz",
|
||||
"integrity": "sha512-J0GaEp0ztu/grIE2Uq57AbK6TRb+bWbOlxu0POCzhFKA6LKbwSAev+hDQaQcgUUA9CPs8Ky+cauzTHnQrtAQEA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@fastify/busboy": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.17"
|
||||
"node": ">=18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
@@ -4087,24 +3811,6 @@
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs": {
|
||||
"name": "wrap-ansi",
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.6-beta",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./dist/index.js",
|
||||
@@ -14,11 +14,11 @@
|
||||
"@notesnook/crypto": "file:../../packages/crypto",
|
||||
"@trpc/client": "10.38.3",
|
||||
"@trpc/server": "10.38.3",
|
||||
"better-sqlite3-multiple-ciphers": "^9.5.0",
|
||||
"better-sqlite3-multiple-ciphers": "^9.4.0",
|
||||
"electron-trpc": "0.5.2",
|
||||
"electron-updater": "6.1.4",
|
||||
"icojs": "^0.17.1",
|
||||
"sodium-native": "^4.1.1",
|
||||
"sodium-native": "^4.0.6",
|
||||
"typed-emitter": "^2.1.0",
|
||||
"yargs": "^17.6.2",
|
||||
"zod": "^3.21.4"
|
||||
@@ -27,13 +27,11 @@
|
||||
"@types/node": "18.16.1",
|
||||
"@types/yargs": "^17.0.24",
|
||||
"chokidar": "^3.5.3",
|
||||
"electron": "^29.3.1",
|
||||
"electron-builder": "^24.13.3",
|
||||
"electron": "^28.2.1",
|
||||
"electron-builder": "^24.9.1",
|
||||
"esbuild": "^0.20.0",
|
||||
"node-gyp-build": "^4.8.0",
|
||||
"prebuildify": "^6.0.1",
|
||||
"tree-kill": "^1.2.2",
|
||||
"undici": "^6.14.1"
|
||||
"undici": "^6.6.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"dmg-license": "^1.0.11"
|
||||
@@ -57,8 +55,8 @@
|
||||
"productName": "Notesnook",
|
||||
"copyright": "Copyright © 2023 Streetwriters (Private) Limited",
|
||||
"artifactName": "notesnook_${os}_${arch}.${ext}",
|
||||
"generateUpdatesFilesForAllChannels": true,
|
||||
"asar": false,
|
||||
"generateUpdatesFilesForAllChannels": true,
|
||||
"files": [
|
||||
"!*.chunk.js.map",
|
||||
"!*.chunk.js.LICENSE.txt",
|
||||
@@ -221,7 +219,8 @@
|
||||
{
|
||||
"provider": "github",
|
||||
"repo": "notesnook",
|
||||
"owner": "streetwriters"
|
||||
"owner": "streetwriters",
|
||||
"channel": "beta"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
diff --git a/node_modules/node-gyp-build/bin.js b/node_modules/node-gyp-build/bin.js
|
||||
index 3fbcdf0..7ca3ab5 100644
|
||||
--- a/node_modules/node-gyp-build/bin.js
|
||||
+++ b/node_modules/node-gyp-build/bin.js
|
||||
@@ -16,7 +16,8 @@ if (!buildFromSource()) {
|
||||
}
|
||||
|
||||
function build () {
|
||||
- var args = [os.platform() === 'win32' ? 'node-gyp.cmd' : 'node-gyp', 'rebuild']
|
||||
+ var win32 = os.platform() === 'win32'
|
||||
+ var args = [win32 ? 'node-gyp.cmd' : 'node-gyp', 'rebuild']
|
||||
|
||||
try {
|
||||
var pkg = require('node-gyp/package.json')
|
||||
@@ -27,7 +28,7 @@ function build () {
|
||||
]
|
||||
} catch (_) {}
|
||||
|
||||
- proc.spawn(args[0], args.slice(1), { stdio: 'inherit' }).on('exit', function (code) {
|
||||
+ proc.spawn(args[0], args.slice(1), { stdio: 'inherit', shell: win32, windowsHide: true }).on('exit', function (code) {
|
||||
if (code || !process.argv[3]) process.exit(code)
|
||||
exec(process.argv[3]).on('exit', function (code) {
|
||||
process.exit(code)
|
||||
@@ -45,15 +46,18 @@ function preinstall () {
|
||||
|
||||
function exec (cmd) {
|
||||
if (process.platform !== 'win32') {
|
||||
- var shell = os.platform() === 'android' ? 'sh' : '/bin/sh'
|
||||
- return proc.spawn(shell, ['-c', '--', cmd], {
|
||||
+ var shell = os.platform() === 'android' ? 'sh' : true
|
||||
+ return proc.spawn(cmd, [], {
|
||||
+ shell,
|
||||
stdio: 'inherit'
|
||||
})
|
||||
}
|
||||
|
||||
- return proc.spawn(process.env.comspec || 'cmd.exe', ['/s', '/c', '"' + cmd + '"'], {
|
||||
+ return proc.spawn(cmd, [], {
|
||||
windowsVerbatimArguments: true,
|
||||
- stdio: 'inherit'
|
||||
+ stdio: 'inherit',
|
||||
+ shell: true,
|
||||
+ windowsHide: true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import path from "path";
|
||||
import fs, { readFile, writeFile } from "fs/promises";
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import { existsSync } from "fs";
|
||||
import yargs from "yargs-parser";
|
||||
import os from "os";
|
||||
import * as childProcess from "child_process";
|
||||
@@ -28,27 +28,21 @@ import { fileURLToPath } from "url";
|
||||
const args = yargs(process.argv);
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const packageJson = JSON.parse(
|
||||
readFileSync(path.join(__dirname, "..", "package.json"), "utf-8")
|
||||
);
|
||||
|
||||
const webAppPath = path.resolve(path.join(__dirname, "..", "..", "web"));
|
||||
|
||||
await fs.rm("./build/", { force: true, recursive: true });
|
||||
|
||||
if (args.rebuild || !existsSync(path.join(webAppPath, "build"))) {
|
||||
await exec(
|
||||
"npx nx build:desktop @notesnook/web",
|
||||
path.join(__dirname, "..", "..", "..")
|
||||
);
|
||||
await exec(`cd ${webAppPath} && npm run build:desktop`);
|
||||
}
|
||||
|
||||
// temporary until there's support for prebuilt binaries for linux ARM
|
||||
if (os.platform() === "linux") await patchBetterSQLite3();
|
||||
// temporary until there's support for prebuilt binaries for windows ARM & linux ARM
|
||||
await patchBetterSQLite3();
|
||||
|
||||
if (os.platform() === "win32")
|
||||
await exec(
|
||||
`npx prebuildify --arch=arm64 --strip -t electron@${packageJson.devDependencies.electron}`,
|
||||
"npx prebuildify --arch=arm64 --strip",
|
||||
path.join(__dirname, "..", "node_modules", "sodium-native")
|
||||
);
|
||||
|
||||
@@ -70,7 +64,7 @@ if (args.run) {
|
||||
if (process.platform === "win32") {
|
||||
await exec(`.\\output\\win-unpacked\\Notesnook.exe`);
|
||||
} else if (process.platform === "darwin") {
|
||||
await exec(`./output/mac/Notesnook.app/Contents/MacOS/Notesnook`);
|
||||
await exec(`./output/darwin-unpacked/Notesnook`);
|
||||
} else {
|
||||
await exec(`./output/linux-unpacked/Notesnook`);
|
||||
}
|
||||
@@ -94,7 +88,7 @@ async function patchBetterSQLite3() {
|
||||
);
|
||||
const json = JSON.parse(await readFile(jsonPath, "utf-8"));
|
||||
|
||||
json.version = "9.5.1";
|
||||
json.version = "9.4.1";
|
||||
json.homepage = "https://github.com/thecodrr/better-sqlite3-multiple-ciphers";
|
||||
json.repository.url =
|
||||
"git://github.com/thecodrr/better-sqlite3-multiple-ciphers.git";
|
||||
|
||||
@@ -53,7 +53,7 @@ async function onChange(first) {
|
||||
if (first) {
|
||||
await fs.rm("./build/", { force: true, recursive: true });
|
||||
|
||||
await exec("npx electron-builder install-app-deps");
|
||||
await exec("npx electron-rebuild");
|
||||
}
|
||||
|
||||
await exec(`npm run bundle`);
|
||||
|
||||
@@ -33,7 +33,7 @@ module.exports = async function (configuration) {
|
||||
const DescriptionUrl = "https://notesnook.com/";
|
||||
const FilesCatalog = createCatalog(configuration.path);
|
||||
|
||||
const command = `Invoke-TrustedSigning -Endpoint "${Endpoint}" -CodeSigningAccountName "${CodeSigningAccountName}" -CertificateProfileName "${CertificateProfileName}" -FileDigest "${FileDigest}" -TimestampRfc3161 "${TimestampRfc3161}" -TimestampDigest "${TimestampDigest}" -Description "${Description}" -DescriptionUrl "${DescriptionUrl}" -FilesCatalog "${FilesCatalog}"`;
|
||||
const command = `Invoke-AzureCodeSigning -Endpoint "${Endpoint}" -CodeSigningAccountName "${CodeSigningAccountName}" -CertificateProfileName "${CertificateProfileName}" -FileDigest "${FileDigest}" -TimestampRfc3161 "${TimestampRfc3161}" -TimestampDigest "${TimestampDigest}" -Description "${Description}" -DescriptionUrl "${DescriptionUrl}" -FilesCatalog "${FilesCatalog}"`;
|
||||
|
||||
console.debug("Signing", configuration.path, "using command", command);
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import { spellCheckerRouter } from "./spell-checker";
|
||||
import { updaterRouter } from "./updater";
|
||||
import { bridgeRouter } from "./bridge";
|
||||
import { safeStorageRouter } from "./safe-storage";
|
||||
import { windowRouter } from "./window";
|
||||
|
||||
const t = initTRPC.create();
|
||||
|
||||
@@ -34,8 +33,7 @@ export const router = t.router({
|
||||
spellChecker: spellCheckerRouter,
|
||||
updater: updaterRouter,
|
||||
bridge: bridgeRouter,
|
||||
safeStorage: safeStorageRouter,
|
||||
window: windowRouter
|
||||
safeStorage: safeStorageRouter
|
||||
});
|
||||
|
||||
export const api = router.createCaller({});
|
||||
|
||||
@@ -55,14 +55,6 @@ export const osIntegrationRouter = t.router({
|
||||
config.zoomFactor = factor;
|
||||
}),
|
||||
|
||||
proxyRules: t.procedure.query(() => config.proxyRules),
|
||||
setProxyRules: t.procedure
|
||||
.input(z.string().optional())
|
||||
.mutation(({ input: proxyRules }) => {
|
||||
globalThis.window?.webContents.session.setProxy({ proxyRules });
|
||||
config.proxyRules = proxyRules || "";
|
||||
}),
|
||||
|
||||
privacyMode: t.procedure.query(() => config.privacyMode),
|
||||
setPrivacyMode: t.procedure
|
||||
.input(z.object({ enabled: z.boolean() }))
|
||||
@@ -170,42 +162,16 @@ export const osIntegrationRouter = t.router({
|
||||
}),
|
||||
bringToFront: t.procedure.query(() => bringToFront()),
|
||||
changeTheme: t.procedure
|
||||
.input(
|
||||
z.object({
|
||||
theme: Theme,
|
||||
windowControlsIconColor: z.string().optional(),
|
||||
backgroundColor: z.string().optional()
|
||||
})
|
||||
)
|
||||
.mutation(
|
||||
({ input: { theme, windowControlsIconColor, backgroundColor } }) => {
|
||||
if (windowControlsIconColor) {
|
||||
config.windowControlsIconColor = windowControlsIconColor;
|
||||
if (process.platform === "win32")
|
||||
globalThis.window?.setTitleBarOverlay({
|
||||
symbolColor: windowControlsIconColor
|
||||
});
|
||||
}
|
||||
|
||||
if (backgroundColor) {
|
||||
config.backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
setTheme(theme);
|
||||
}
|
||||
),
|
||||
.input(Theme)
|
||||
.mutation(({ input }) => setTheme(input)),
|
||||
|
||||
onThemeChanged: t.procedure.subscription(() =>
|
||||
observable<"dark" | "light">((emit) => {
|
||||
const updated = () => {
|
||||
nativeTheme.on("updated", () => {
|
||||
if (getTheme() === "system") {
|
||||
emit.next(nativeTheme.shouldUseDarkColors ? "dark" : "light");
|
||||
}
|
||||
};
|
||||
nativeTheme.on("updated", updated);
|
||||
return () => {
|
||||
nativeTheme.off("updated", updated);
|
||||
};
|
||||
});
|
||||
})
|
||||
)
|
||||
});
|
||||
|
||||
@@ -118,13 +118,5 @@ export const spellCheckerRouter = t.router({
|
||||
.mutation(({ input: { enabled } }) => {
|
||||
globalThis.window?.webContents.session.setSpellCheckerEnabled(enabled);
|
||||
config.isSpellCheckerEnabled = enabled;
|
||||
}),
|
||||
words: t.procedure.query(() =>
|
||||
globalThis.window?.webContents.session.listWordsInSpellCheckerDictionary()
|
||||
),
|
||||
deleteWord: t.procedure.input(z.string()).mutation(({ input: word }) => {
|
||||
globalThis.window?.webContents.session.removeWordFromSpellCheckerDictionary(
|
||||
word
|
||||
);
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
@@ -28,20 +28,16 @@ type UpdateInfo = { version: string };
|
||||
type Progress = { percent: number };
|
||||
|
||||
const t = initTRPC.create();
|
||||
let cancellationToken: CancellationToken | undefined = undefined;
|
||||
|
||||
export const updaterRouter = t.router({
|
||||
autoUpdates: t.procedure.query(() => config.automaticUpdates),
|
||||
install: t.procedure.query(() => autoUpdater.quitAndInstall()),
|
||||
download: t.procedure.query(async () => {
|
||||
if (cancellationToken) return;
|
||||
cancellationToken = new CancellationToken();
|
||||
await autoUpdater
|
||||
.downloadUpdate(cancellationToken)
|
||||
.finally(() => (cancellationToken = undefined));
|
||||
const cancellationToken = new CancellationToken();
|
||||
await autoUpdater.downloadUpdate(cancellationToken);
|
||||
}),
|
||||
check: t.procedure.query(async () => {
|
||||
await autoUpdater.checkForUpdates().catch(console.error);
|
||||
await autoUpdater.checkForUpdates();
|
||||
}),
|
||||
|
||||
toggleAutoUpdates: t.procedure
|
||||
@@ -75,7 +71,6 @@ function createSubscription<
|
||||
const listener: AppUpdaterEvents[TName] = (...args: any[]) => {
|
||||
emit.next(args[0]);
|
||||
};
|
||||
autoUpdater.removeAllListeners(eventName);
|
||||
autoUpdater.addListener(eventName, listener);
|
||||
return () => {
|
||||
autoUpdater.removeListener(eventName, listener);
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { initTRPC } from "@trpc/server";
|
||||
import { observable } from "@trpc/server/observable";
|
||||
|
||||
const t = initTRPC.create();
|
||||
|
||||
export const windowRouter = t.router({
|
||||
maximize: t.procedure.mutation(() => {
|
||||
globalThis.window?.maximize();
|
||||
}),
|
||||
restore: t.procedure.mutation(() => {
|
||||
globalThis.window?.restore();
|
||||
}),
|
||||
minimze: t.procedure.mutation(() => {
|
||||
globalThis.window?.minimize();
|
||||
}),
|
||||
maximized: t.procedure.query(() => globalThis.window?.isMaximized()),
|
||||
fullscreen: t.procedure.query(() => globalThis.window?.isFullScreen()),
|
||||
onWindowStateChanged: t.procedure.subscription(() => {
|
||||
return observable<{ maximized: boolean; fullscreen: boolean }>((emit) => {
|
||||
function listener() {
|
||||
emit.next({
|
||||
maximized: !!globalThis.window?.isMaximized(),
|
||||
fullscreen: !!globalThis.window?.isFullScreen()
|
||||
});
|
||||
}
|
||||
function enterFullscreen() {
|
||||
emit.next({
|
||||
maximized: !!globalThis.window?.isMaximized(),
|
||||
fullscreen: true
|
||||
});
|
||||
}
|
||||
function leaveFullscreen() {
|
||||
emit.next({
|
||||
maximized: !!globalThis.window?.isMaximized(),
|
||||
fullscreen: false
|
||||
});
|
||||
}
|
||||
globalThis.window?.addListener("maximize", listener);
|
||||
globalThis.window?.addListener("minimize", listener);
|
||||
globalThis.window?.addListener("unmaximize", listener);
|
||||
globalThis.window?.addListener("restore", listener);
|
||||
globalThis.window?.addListener("enter-full-screen", enterFullscreen);
|
||||
globalThis.window?.addListener("leave-full-screen", leaveFullscreen);
|
||||
globalThis.window?.addListener("leave-html-full-screen", leaveFullscreen);
|
||||
globalThis.window?.addListener("enter-html-full-screen", enterFullscreen);
|
||||
return () => {
|
||||
globalThis.window?.removeListener("maximize", listener);
|
||||
globalThis.window?.removeListener("minimize", listener);
|
||||
globalThis.window?.removeListener("unmaximize", listener);
|
||||
globalThis.window?.removeListener("restore", listener);
|
||||
globalThis.window?.removeListener("enter-full-screen", enterFullscreen);
|
||||
globalThis.window?.removeListener("leave-full-screen", leaveFullscreen);
|
||||
globalThis.window?.removeListener(
|
||||
"leave-html-full-screen",
|
||||
leaveFullscreen
|
||||
);
|
||||
globalThis.window?.removeListener(
|
||||
"enter-html-full-screen",
|
||||
enterFullscreen
|
||||
);
|
||||
};
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -82,19 +82,6 @@ async function createWindow() {
|
||||
size: 512,
|
||||
format: process.platform === "win32" ? "ico" : "png"
|
||||
}),
|
||||
|
||||
titleBarStyle: "hidden",
|
||||
frame: process.platform === "win32" || process.platform === "darwin",
|
||||
titleBarOverlay: {
|
||||
height: 37,
|
||||
color: "#00000000",
|
||||
symbolColor: config.windowControlsIconColor
|
||||
},
|
||||
trafficLightPosition: {
|
||||
x: 16,
|
||||
y: 12
|
||||
},
|
||||
|
||||
webPreferences: {
|
||||
zoomFactor: config.zoomFactor,
|
||||
nodeIntegration: true,
|
||||
@@ -125,7 +112,6 @@ async function createWindow() {
|
||||
mainWindow.webContents.session.setSpellCheckerDictionaryDownloadURL(
|
||||
"http://dictionaries.notesnook.com/"
|
||||
);
|
||||
mainWindow.webContents.session.setProxy({ proxyRules: config.proxyRules });
|
||||
|
||||
mainWindow.once("closed", () => {
|
||||
globalThis.window = null;
|
||||
@@ -135,7 +121,7 @@ async function createWindow() {
|
||||
setupJumplist();
|
||||
|
||||
if (isDevelopment())
|
||||
mainWindow.webContents.openDevTools({ mode: "bottom", activate: true });
|
||||
mainWindow.webContents.openDevTools({ mode: "right", activate: true });
|
||||
|
||||
mainWindow.webContents.setWindowOpenHandler((details) => {
|
||||
shell.openExternal(details.url);
|
||||
@@ -151,15 +137,6 @@ async function createWindow() {
|
||||
app.once("ready", async () => {
|
||||
console.info("App ready. Opening window.");
|
||||
|
||||
app.configureHostResolver({
|
||||
secureDnsServers: [
|
||||
"https://mozilla.cloudflare-dns.com/dns-query",
|
||||
"https://dns.quad9.net/dns-query"
|
||||
],
|
||||
enableBuiltInResolver: true,
|
||||
secureDnsMode: "automatic"
|
||||
});
|
||||
|
||||
if (!isDevelopment()) registerProtocol();
|
||||
await createWindow();
|
||||
configureAutoUpdater();
|
||||
|
||||
@@ -25,11 +25,7 @@ Type=Application
|
||||
Version=${app.getVersion()}
|
||||
Name=${app.getName()}
|
||||
Comment=${app.getName()} startup script
|
||||
Exec=${
|
||||
process.env.APPIMAGE
|
||||
? `${process.env.APPIMAGE}${hidden ? " --hidden" : ""}`
|
||||
: `${process.execPath}${hidden ? " --hidden" : ""}`
|
||||
}
|
||||
Exec=${process.execPath}${hidden ? " --hidden" : ""}
|
||||
StartupNotify=false
|
||||
Terminal=false`;
|
||||
|
||||
|
||||
@@ -41,12 +41,7 @@ export const config = {
|
||||
isSpellCheckerEnabled: true,
|
||||
zoomFactor: 1,
|
||||
theme: nativeTheme.themeSource,
|
||||
automaticUpdates: true,
|
||||
proxyRules: "",
|
||||
|
||||
backgroundColor: nativeTheme.themeSource === "dark" ? "#0f0f0f" : "#ffffff",
|
||||
windowControlsIconColor:
|
||||
nativeTheme.themeSource === "dark" ? "#ffffff" : "#000000"
|
||||
automaticUpdates: true
|
||||
};
|
||||
|
||||
type ConfigKey = keyof typeof config;
|
||||
|
||||
@@ -131,17 +131,6 @@ function setupMenu() {
|
||||
);
|
||||
}
|
||||
|
||||
if (params.mediaType === "image")
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
id: "copy-image",
|
||||
label: "Copy Image",
|
||||
click() {
|
||||
globalThis.window?.webContents.copyImageAt(params.x, params.y);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if (params.isEditable)
|
||||
menu.append(
|
||||
new MenuItem({
|
||||
|
||||
@@ -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 { net, protocol } from "electron";
|
||||
import { protocol } from "electron";
|
||||
import { isDevelopment } from "./index";
|
||||
import { createReadStream } from "fs";
|
||||
import { extname, normalize } from "path";
|
||||
@@ -62,7 +62,26 @@ function registerProtocol() {
|
||||
headers: { "Content-Type": extensionToMimeType[fileExtension] }
|
||||
});
|
||||
} else {
|
||||
return net.fetch(request, { bypassCustomProtocolHandlers: true });
|
||||
if (request.headers.has("X-Content-Length")) {
|
||||
request.headers.set(
|
||||
"Content-Length",
|
||||
request.headers.get("X-Content-Length") || "0"
|
||||
);
|
||||
request.headers.delete("X-Content-Length");
|
||||
}
|
||||
const headers = Object.fromEntries(request.headers.entries());
|
||||
|
||||
return await fetch(request.url, {
|
||||
signal: request.signal,
|
||||
mode: request.mode,
|
||||
headers,
|
||||
method: request.method,
|
||||
body: request.body,
|
||||
credentials: request.credentials,
|
||||
referrer: (request as any).referrer,
|
||||
duplex: "half",
|
||||
redirect: "manual"
|
||||
});
|
||||
}
|
||||
});
|
||||
console.info(`${SCHEME} protocol inteception "successful"`);
|
||||
|
||||
@@ -41,10 +41,7 @@ function setTheme(theme: Theme) {
|
||||
}
|
||||
|
||||
function getBackgroundColor() {
|
||||
return (
|
||||
config.backgroundColor ||
|
||||
(nativeTheme.shouldUseDarkColors ? "#0f0f0f" : "#ffffff")
|
||||
);
|
||||
return nativeTheme.shouldUseDarkColors ? "#0f0f0f" : "#ffffff";
|
||||
}
|
||||
|
||||
function getSystemTheme() {
|
||||
|
||||
@@ -16,6 +16,7 @@ GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import "@azure/core-asynciterator-polyfill";
|
||||
import "react-native-gesture-handler";
|
||||
import {
|
||||
THEME_COMPATIBILITY_VERSION,
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
} from "@notesnook/theme";
|
||||
import React, { useEffect } from "react";
|
||||
import { I18nManager, View } from "react-native";
|
||||
import "react-native-gesture-handler";
|
||||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||
import { SafeAreaProvider } from "react-native-safe-area-context";
|
||||
import AppLockedOverlay from "./components/app-lock-overlay";
|
||||
@@ -41,6 +43,18 @@ I18nManager.allowRTL(false);
|
||||
I18nManager.forceRTL(false);
|
||||
I18nManager.swapLeftAndRightInRTL(false);
|
||||
|
||||
// How app lock works
|
||||
// 1. User goes to settings and setup app lock with a Pin/Password.
|
||||
// 2. The Pin/Password is used to encrypt a random value or user's encryption key.
|
||||
// 3. The encrypted value is stored in MMKV
|
||||
// 4. When the app launches, the same value is decrypted with user provided key, if it works, we launch the app otherwise it remains locked.
|
||||
// 5. If Biometrics are enabled, the app lock pin/password is stored in keychain. the value can be accessed if fingerprint auth works ONLY.
|
||||
// 6. User can manually enter the pin if biometrics fails.
|
||||
// 7. There is no way to enter the app if user forgets the PIN. The only way is to reset app data and start fresh again.
|
||||
|
||||
// How to handle app lock for existing users...
|
||||
// 1.
|
||||
|
||||
const App = () => {
|
||||
const init = useAppEvents();
|
||||
useEffect(() => {
|
||||
|
||||
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 28 KiB |
@@ -136,10 +136,11 @@ export async function validateAppLockPassword(appLockPassword) {
|
||||
const appLockCipher = CipherStorage.getMap(APPLOCK_CIPHER);
|
||||
if (!appLockCipher) return true;
|
||||
const decrypted = await decrypt(
|
||||
await Sodium.deriveKey(appLockPassword, NOTESNOOK_APPLOCK_KEY_SALT),
|
||||
{
|
||||
password: appLockPassword
|
||||
},
|
||||
appLockCipher
|
||||
);
|
||||
|
||||
DatabaseLogger.info(
|
||||
`validateAppLockPassword: ${typeof decrypted === "string"}`
|
||||
);
|
||||
@@ -318,6 +319,7 @@ export async function decrypt(password, data) {
|
||||
_data.output = "plain";
|
||||
|
||||
if (!password.salt) password.salt = data.salt;
|
||||
|
||||
return await Sodium.decrypt(password, _data);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import RNFetchBlob from "react-native-blob-util";
|
||||
import { ShareComponent } from "../../components/sheets/export-notes/share";
|
||||
import { ToastManager, presentSheet } from "../../services/event-manager";
|
||||
import { useAttachmentStore } from "../../stores/use-attachment-store";
|
||||
import { DatabaseLogger, db } from "../database";
|
||||
import { db } from "../database";
|
||||
import Storage from "../database/storage";
|
||||
import { cacheDir, copyFileAsync, releasePermissions } from "./utils";
|
||||
import { createCacheDir, exists } from "./io";
|
||||
@@ -84,10 +84,8 @@ export async function downloadAttachments(
|
||||
Platform.OS === "ios"
|
||||
? `${outputFolder}/notesnook-attachments-${Date.now()}.zip`
|
||||
: `${cacheDir}/notesnook-attachments.zip`;
|
||||
if (await RNFetchBlob.fs.exists(zipSourceFolder)) {
|
||||
if (await RNFetchBlob.fs.exists(zipSourceFolder))
|
||||
await RNFetchBlob.fs.unlink(zipSourceFolder);
|
||||
}
|
||||
|
||||
await RNFetchBlob.fs.mkdir(zipSourceFolder);
|
||||
|
||||
for (let i = 0; i < attachments.length; i++) {
|
||||
@@ -129,7 +127,7 @@ export async function downloadAttachments(
|
||||
status: FileDownloadStatus.Fail,
|
||||
reason: e
|
||||
});
|
||||
ToastManager.error(e, "Error downloading attachment");
|
||||
console.log("Error downloading attachment", e);
|
||||
}
|
||||
}
|
||||
if (canceled.current) {
|
||||
@@ -166,7 +164,7 @@ export async function downloadAttachments(
|
||||
} catch (e) {
|
||||
releasePermissions(outputFolder);
|
||||
sub?.remove();
|
||||
ToastManager.error(e, "Error zipping attachments");
|
||||
console.log("Error zipping attachments", e);
|
||||
}
|
||||
// Remove source & zip file from cache.
|
||||
RNFetchBlob.fs.unlink(zipSourceFolder).catch(console.log);
|
||||
@@ -194,7 +192,7 @@ export default async function downloadAttachment(
|
||||
|
||||
let attachment = await db.attachments.attachment(hash);
|
||||
if (!attachment) {
|
||||
DatabaseLogger.log("Attachment not found");
|
||||
console.log("attachment not found");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -209,21 +207,19 @@ export default async function downloadAttachment(
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(
|
||||
"starting download attachment",
|
||||
attachment.hash,
|
||||
options.groupId
|
||||
);
|
||||
await db
|
||||
.fs()
|
||||
.downloadFile(options.groupId || attachment.hash, attachment.hash);
|
||||
if (!(await exists(attachment.hash))) {
|
||||
DatabaseLogger.log("Attachment does not exist after download.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.base64 || options.text) {
|
||||
console.log(
|
||||
"starting decrypt base64 file...",
|
||||
options.base64,
|
||||
options.text,
|
||||
attachment.hash
|
||||
);
|
||||
return await db.attachments.read(
|
||||
attachment.hash,
|
||||
options.base64 ? "base64" : "text"
|
||||
@@ -236,7 +232,6 @@ export default async function downloadAttachment(
|
||||
);
|
||||
|
||||
let key = await db.attachments.decryptKey(attachment.key);
|
||||
|
||||
let info = {
|
||||
iv: attachment.iv,
|
||||
salt: attachment.salt,
|
||||
@@ -250,6 +245,7 @@ export default async function downloadAttachment(
|
||||
chunkSize: attachment.chunkSize,
|
||||
appGroupId: IOS_APPGROUPID
|
||||
};
|
||||
|
||||
let fileUri = await Sodium.decryptFile(
|
||||
key,
|
||||
info,
|
||||
|
||||
@@ -29,14 +29,13 @@ import { createCacheDir, exists } from "./io";
|
||||
export async function downloadFile(filename, data, cancelToken) {
|
||||
if (!data) return false;
|
||||
|
||||
console.log("Downloading", filename);
|
||||
await createCacheDir();
|
||||
|
||||
let { url, headers } = data;
|
||||
let path = `${cacheDir}/${filename}`;
|
||||
|
||||
try {
|
||||
if (await exists(filename)) {
|
||||
console.log("Exists already", filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ export async function hashBase64(data) {
|
||||
};
|
||||
}
|
||||
|
||||
export async function writeEncryptedBase64(data, key) {
|
||||
export async function writeEncryptedBase64({ data, key }) {
|
||||
await createCacheDir();
|
||||
let filepath = cacheDir + `/${getRandomId("imagecache_")}`;
|
||||
await RNFetchBlob.fs.writeFile(filepath, data, "base64");
|
||||
@@ -77,8 +77,6 @@ export async function writeEncryptedBase64(data, key) {
|
||||
});
|
||||
RNFetchBlob.fs.unlink(filepath).catch(console.log);
|
||||
console.log("encrypted file output: ", output);
|
||||
output.size = output.length;
|
||||
delete output.length;
|
||||
return {
|
||||
...output,
|
||||
alg: "xcha-stream"
|
||||
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useRef } from "react";
|
||||
import { AppStateStatus, Platform, TextInput, View } from "react-native";
|
||||
import { Platform, TextInput, View } from "react-native";
|
||||
//@ts-ignore
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { enabled } from "react-native-privacy-snapshot";
|
||||
@@ -74,7 +74,6 @@ const verifyUserPassword = async (password: string) => {
|
||||
};
|
||||
|
||||
const AppLockedOverlay = () => {
|
||||
const initialLaunchBiometricRequest = useRef(true);
|
||||
const { colors } = useThemeColors();
|
||||
const user = getUser();
|
||||
const appLocked = useUserStore((state) => state.appLocked);
|
||||
@@ -83,7 +82,6 @@ const AppLockedOverlay = () => {
|
||||
const passwordInputRef = useRef<TextInput>(null);
|
||||
const password = useRef<string>();
|
||||
const appState = useAppState();
|
||||
const lastAppState = useRef<AppStateStatus>(appState);
|
||||
const biometricUnlockAwaitingUserInput = useRef(false);
|
||||
const keyboardType = useSettingStore(
|
||||
(state) => state.settings.applockKeyboardType
|
||||
@@ -133,8 +131,9 @@ const AppLockedOverlay = () => {
|
||||
if (!password.current) return;
|
||||
try {
|
||||
const unlocked = appLockHasPasswordSecurity
|
||||
? await validateAppLockPassword(password.current)
|
||||
? validateAppLockPassword(password.current)
|
||||
: await verifyUserPassword(password.current);
|
||||
|
||||
if (unlocked) {
|
||||
if (!appLockHasPasswordSecurity) {
|
||||
await setAppLockVerificationCipher(password.current);
|
||||
@@ -155,46 +154,18 @@ const AppLockedOverlay = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (appState === "active") {
|
||||
enabled(false);
|
||||
}
|
||||
|
||||
const prevState = lastAppState.current;
|
||||
lastAppState.current = appState;
|
||||
|
||||
if (
|
||||
biometricUnlockAwaitingUserInput.current ||
|
||||
useUserStore.getState().disableAppLockRequests
|
||||
)
|
||||
return;
|
||||
if (
|
||||
appLocked &&
|
||||
appState === "active" &&
|
||||
(prevState === "background" || initialLaunchBiometricRequest.current)
|
||||
!useSettingStore.getState().requestBiometrics
|
||||
) {
|
||||
if (SettingsService.shouldLockAppOnEnterForeground()) {
|
||||
DatabaseLogger.info("Locking app on entering foreground");
|
||||
useUserStore.getState().lockApp(true);
|
||||
}
|
||||
|
||||
if (
|
||||
!(
|
||||
biometricUnlockAwaitingUserInput.current ||
|
||||
useUserStore.getState().disableAppLockRequests ||
|
||||
!appLocked ||
|
||||
useSettingStore.getState().requestBiometrics ||
|
||||
useSettingStore.getState().appDidEnterBackgroundForAction
|
||||
)
|
||||
) {
|
||||
initialLaunchBiometricRequest.current = false;
|
||||
DatabaseLogger.info("Biometric unlock request");
|
||||
onUnlockAppRequested();
|
||||
}
|
||||
|
||||
enabled(false);
|
||||
} else {
|
||||
SettingsService.appEnteredBackground();
|
||||
|
||||
if (
|
||||
SettingsService.get().privacyScreen ||
|
||||
SettingsService.getProperty("appLockEnabled")
|
||||
) {
|
||||
enabled(true);
|
||||
}
|
||||
biometricUnlockAwaitingUserInput.current = true;
|
||||
onUnlockAppRequested();
|
||||
}
|
||||
}, [appState, onUnlockAppRequested, appLocked]);
|
||||
|
||||
|
||||
@@ -40,8 +40,7 @@ import { useAttachmentStore } from "../../stores/use-attachment-store";
|
||||
import {
|
||||
eCloseAttachmentDialog,
|
||||
eCloseSheet,
|
||||
eDBItemUpdate,
|
||||
eOnLoadNote
|
||||
eDBItemUpdate
|
||||
} from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
@@ -54,8 +53,6 @@ import { Notice } from "../ui/notice";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useTabStore } from "../../screens/editor/tiptap/use-tab-store";
|
||||
import { editorController } from "../../screens/editor/tiptap/utils";
|
||||
|
||||
const Actions = ({
|
||||
attachment,
|
||||
@@ -65,7 +62,7 @@ const Actions = ({
|
||||
}: {
|
||||
attachment: Attachment;
|
||||
setAttachments: (attachments?: VirtualizedGrouping<Attachment>) => void;
|
||||
close?: () => void;
|
||||
close: () => void;
|
||||
fwdRef: RefObject<ActionSheetRef>;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -106,7 +103,7 @@ const Actions = ({
|
||||
reupload: true,
|
||||
hash: attachment.hash,
|
||||
context: contextId,
|
||||
type: attachment.mimeType.startsWith("image") ? "image" : "file"
|
||||
type: attachment.type
|
||||
});
|
||||
},
|
||||
icon: "upload"
|
||||
@@ -172,27 +169,10 @@ const Actions = ({
|
||||
{
|
||||
name: "Delete",
|
||||
onPress: async () => {
|
||||
const relations = await db.relations.to(attachment, "note").get();
|
||||
await db.attachments.remove(attachment.hash, false);
|
||||
setAttachments();
|
||||
eSendEvent(eDBItemUpdate, attachment.id);
|
||||
relations
|
||||
.map((relation) => relation.fromId)
|
||||
.forEach(async (id) => {
|
||||
const tab = useTabStore.getState().getTabForNote(id);
|
||||
if (tab !== undefined) {
|
||||
const isFocused = useTabStore.getState().currentTab === tab;
|
||||
if (isFocused) {
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: await db.notes.note(id),
|
||||
forced: true
|
||||
});
|
||||
} else {
|
||||
editorController.current.commands.setLoading(true, tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
close?.();
|
||||
close();
|
||||
},
|
||||
icon: "delete-outline"
|
||||
}
|
||||
@@ -221,7 +201,7 @@ const Actions = ({
|
||||
<View
|
||||
style={{
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.primary.border,
|
||||
borderBottomColor: colors.secondary.background,
|
||||
marginBottom: notes && notes.length > 0 ? 0 : 12
|
||||
}}
|
||||
>
|
||||
@@ -295,7 +275,7 @@ const Actions = ({
|
||||
<View
|
||||
style={{
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.primary.border,
|
||||
borderBottomColor: colors.secondary.background,
|
||||
marginBottom: 12,
|
||||
paddingVertical: 12
|
||||
}}
|
||||
|
||||
@@ -84,9 +84,8 @@ const DownloadAttachments = ({
|
||||
canceled.current = true;
|
||||
if (!groupId.current) return;
|
||||
console.log(groupId.current, "canceling groupId downloads");
|
||||
await db.fs().cancel(groupId.current);
|
||||
await db.fs().cancel(groupId.current, "download");
|
||||
setDownloading(false);
|
||||
setResult(new Map());
|
||||
groupId.current = undefined;
|
||||
};
|
||||
|
||||
@@ -202,7 +201,7 @@ const DownloadAttachments = ({
|
||||
</Paragraph>
|
||||
</View>
|
||||
}
|
||||
keyExtractor={(index) => "attachment_download" + index}
|
||||
keyExtractor={(index) => "attachment" + index}
|
||||
renderItem={({ index }) => {
|
||||
return (
|
||||
<AttachmentItem
|
||||
|
||||
@@ -61,15 +61,10 @@ export const AttachmentDialog = ({ note }: { note?: Note }) => {
|
||||
|
||||
const refresh = React.useCallback(() => {
|
||||
if (note) {
|
||||
db.attachments
|
||||
.ofNote(note.id, "all")
|
||||
.sorted({
|
||||
...DEFAULT_SORTING,
|
||||
sortBy: "dateModified"
|
||||
})
|
||||
.then((attachments) => {
|
||||
setAttachments(attachments);
|
||||
});
|
||||
db.attachments.ofNote(note.id, "all").sorted({
|
||||
...DEFAULT_SORTING,
|
||||
sortBy: "dateModified"
|
||||
});
|
||||
} else {
|
||||
db.attachments.all
|
||||
.sorted({
|
||||
@@ -160,9 +155,7 @@ export const AttachmentDialog = ({ note }: { note?: Note }) => {
|
||||
|
||||
switch (type) {
|
||||
case "all":
|
||||
items = note
|
||||
? db.attachments.ofNote(note.id, "all")
|
||||
: db.attachments.all;
|
||||
items = db.attachments.all;
|
||||
break;
|
||||
case "images":
|
||||
items = note
|
||||
@@ -171,17 +164,15 @@ export const AttachmentDialog = ({ note }: { note?: Note }) => {
|
||||
break;
|
||||
case "video":
|
||||
items = items = note
|
||||
? db.attachments.ofNote(note.id, "videos")
|
||||
? db.attachments.ofNote(note.id, "all")
|
||||
: db.attachments.videos;
|
||||
break;
|
||||
case "audio":
|
||||
items = note
|
||||
? db.attachments.ofNote(note.id, "audio")
|
||||
: db.attachments.all;
|
||||
items = db.attachments.all;
|
||||
break;
|
||||
case "documents":
|
||||
items = note
|
||||
? db.attachments.ofNote(note.id, "documents")
|
||||
? db.attachments.ofNote(note.id, "all")
|
||||
: db.attachments.documents;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,15 +26,12 @@ import {
|
||||
ToastManager
|
||||
} from "../../services/event-manager";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { eCloseSheet, eOpenRecoveryKeyDialog } from "../../utils/events";
|
||||
import { eCloseSheet } from "../../utils/events";
|
||||
import DialogHeader from "../dialog/dialog-header";
|
||||
import { Button } from "../ui/button";
|
||||
import Input from "../ui/input";
|
||||
import { Notice } from "../ui/notice";
|
||||
import Seperator from "../ui/seperator";
|
||||
import { Dialog } from "../dialog";
|
||||
import BackupService from "../../services/backup";
|
||||
import { sleep } from "../../utils/time";
|
||||
|
||||
export const ChangePassword = () => {
|
||||
const passwordInputRef = useRef();
|
||||
@@ -67,9 +64,6 @@ export const ChangePassword = () => {
|
||||
}
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await BackupService.run(false, "change-password-dialog");
|
||||
if (!result) throw new Error("Failed to create backup");
|
||||
|
||||
await db.user.clearSessions();
|
||||
await db.user.changePassword(oldPassword.current, password.current);
|
||||
ToastManager.show({
|
||||
@@ -79,8 +73,6 @@ export const ChangePassword = () => {
|
||||
});
|
||||
setLoading(false);
|
||||
eSendEvent(eCloseSheet);
|
||||
await sleep(300);
|
||||
eSendEvent(eOpenRecoveryKeyDialog);
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
ToastManager.show({
|
||||
@@ -100,7 +92,6 @@ export const ChangePassword = () => {
|
||||
padding: 12
|
||||
}}
|
||||
>
|
||||
<Dialog context="change-password-dialog" />
|
||||
<DialogHeader
|
||||
title="Change password"
|
||||
paragraph="Enter your old and new passwords"
|
||||
@@ -138,14 +129,7 @@ export const ChangePassword = () => {
|
||||
/>
|
||||
|
||||
<Notice
|
||||
text={`Changing password is an irreversible process. You will be logged out from all your devices. Please make sure you do not close the app while your password is changing and have good internet connection.`}
|
||||
type="alert"
|
||||
/>
|
||||
|
||||
<View style={{ height: 10 }} />
|
||||
|
||||
<Notice
|
||||
text={`Once your password is changed, please make sure to save the new account recovery key.`}
|
||||
text="Changing password is a non-undoable process. You will be logged out from all your devices. Please make sure you do not close the app while your password is changing and have good internet connection."
|
||||
type="alert"
|
||||
/>
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { eUserLoggedIn } from "../../utils/events";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import Sync from "../../services/sync";
|
||||
import { Notice } from "../ui/notice";
|
||||
|
||||
const LoginSteps = {
|
||||
emailAuth: 1,
|
||||
|
||||
@@ -69,9 +69,6 @@ export const SessionExpired = () => {
|
||||
eSendEvent(eUserLoggedIn, true);
|
||||
setVisible(false);
|
||||
setFocused(false);
|
||||
useUserStore.setState({
|
||||
disableAppLockRequests: false
|
||||
});
|
||||
},
|
||||
true
|
||||
);
|
||||
@@ -87,9 +84,6 @@ export const SessionExpired = () => {
|
||||
MMKV.clearStore();
|
||||
clearAllStores();
|
||||
setVisible(false);
|
||||
useUserStore.setState({
|
||||
disableAppLockRequests: false
|
||||
});
|
||||
} catch (e) {
|
||||
ToastManager.show({
|
||||
heading: e.message,
|
||||
@@ -133,9 +127,6 @@ export const SessionExpired = () => {
|
||||
email.current = user.email;
|
||||
setFocused(false);
|
||||
setVisible(true);
|
||||
useUserStore.setState({
|
||||
disableAppLockRequests: true
|
||||
});
|
||||
}
|
||||
}, [email]);
|
||||
|
||||
@@ -148,15 +139,9 @@ export const SessionExpired = () => {
|
||||
animated={false}
|
||||
centered={false}
|
||||
onShow={async () => {
|
||||
useUserStore.setState({
|
||||
disableAppLockRequests: true
|
||||
});
|
||||
await sleep(300);
|
||||
passwordInputRef.current?.focus();
|
||||
setFocused(true);
|
||||
useUserStore.setState({
|
||||
disableAppLockRequests: true
|
||||
});
|
||||
}}
|
||||
enableSheetKeyboardHandler={true}
|
||||
visible={true}
|
||||
|
||||
@@ -18,7 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { useRoute } from "@react-navigation/native";
|
||||
import React, { useCallback, useEffect } from "react";
|
||||
import { Keyboard, View } from "react-native";
|
||||
import Animated, {
|
||||
@@ -55,7 +54,6 @@ const FloatingButton = ({
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
const selectionMode = useSelectionStore((state) => state.selectionMode);
|
||||
const translate = useSharedValue(0);
|
||||
const route = useRoute();
|
||||
|
||||
const animatedStyle = useAnimatedStyle(() => {
|
||||
return {
|
||||
@@ -142,13 +140,7 @@ const FloatingButton = ({
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name={
|
||||
route.name === "Notebooks"
|
||||
? "notebook-plus"
|
||||
: route.name === "Trash"
|
||||
? "delete"
|
||||
: "plus"
|
||||
}
|
||||
name={title === "Clear all trash" ? "delete" : "plus"}
|
||||
color={colors.primary.accentForeground}
|
||||
size={SIZE.xxl}
|
||||
/>
|
||||
|
||||
@@ -21,16 +21,14 @@ import React, { PropsWithChildren, useEffect, useRef, useState } from "react";
|
||||
import { Dimensions, Platform, View, useWindowDimensions } from "react-native";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import useKeyboard from "../../hooks/use-keyboard";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
|
||||
export const Container = ({ children }: PropsWithChildren) => {
|
||||
const { colors } = useThemeColors();
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
const keyboard = useKeyboard();
|
||||
const [height, setHeight] = useState(0);
|
||||
const windowHeightRef = useRef(Dimensions.get("window").height);
|
||||
const { height: windowHeight } = useWindowDimensions();
|
||||
const timerRef = useRef<NodeJS.Timeout>();
|
||||
|
||||
useEffect(() => {
|
||||
if (windowHeight !== windowHeightRef.current) {
|
||||
setHeight(0);
|
||||
@@ -45,17 +43,12 @@ export const Container = ({ children }: PropsWithChildren) => {
|
||||
paddingTop: Platform.OS === "android" ? 0 : insets.top,
|
||||
paddingBottom: Platform.OS === "android" ? 0 : insets.bottom,
|
||||
height: height || "100%",
|
||||
width: "100%",
|
||||
backgroundColor: colors.primary.background
|
||||
width: "100%"
|
||||
}}
|
||||
onLayout={(event) => {
|
||||
const height = event.nativeEvent.layout.height;
|
||||
clearTimeout(timerRef.current);
|
||||
timerRef.current = setTimeout(() => {
|
||||
if (!keyboard.keyboardShown) {
|
||||
setHeight(height);
|
||||
}
|
||||
}, 500);
|
||||
if (!keyboard.keyboardShown) {
|
||||
setHeight(event.nativeEvent.layout.height);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -45,8 +45,8 @@ const DialogButtons = ({
|
||||
{
|
||||
backgroundColor: colors.secondary.background,
|
||||
height: 60,
|
||||
borderBottomRightRadius: 5,
|
||||
borderBottomLeftRadius: 5,
|
||||
borderBottomRightRadius: 10,
|
||||
borderBottomLeftRadius: 10,
|
||||
paddingHorizontal: 12,
|
||||
borderTopWidth: 0.7,
|
||||
borderTopColor: getColorLinearShade(
|
||||
|
||||
@@ -104,7 +104,7 @@ const DialogHeader = ({
|
||||
title={button.title}
|
||||
icon={button.icon}
|
||||
type={button.type || "secondary"}
|
||||
height={30}
|
||||
height={25}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
@@ -36,15 +36,11 @@ import DialogButtons from "./dialog-buttons";
|
||||
import DialogHeader from "./dialog-header";
|
||||
import { useCallback } from "react";
|
||||
import { Button } from "../ui/button";
|
||||
import { getContainerBorder } from "../../utils/colors";
|
||||
|
||||
export const Dialog = ({ context = "global" }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [checked, setChecked] = useState(false);
|
||||
const values = useRef({
|
||||
inputValue: undefined
|
||||
});
|
||||
const [inputValue, setInputValue] = useState(null);
|
||||
const inputRef = useRef();
|
||||
const [dialogInfo, setDialogInfo] = useState({
|
||||
title: "",
|
||||
@@ -70,8 +66,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
if (dialogInfo.positivePress) {
|
||||
inputRef.current?.blur();
|
||||
let result = await dialogInfo.positivePress(
|
||||
values.current.inputValue || dialogInfo.defaultValue,
|
||||
checked
|
||||
inputValue || dialogInfo.defaultValue
|
||||
);
|
||||
if (result === false) {
|
||||
return;
|
||||
@@ -86,9 +81,8 @@ export const Dialog = ({ context = "global" }) => {
|
||||
if (!data.context) data.context = "global";
|
||||
if (data.context !== context) return;
|
||||
setDialogInfo(data);
|
||||
setChecked(false);
|
||||
values.current.inputValue = data.defaultValue;
|
||||
setVisible(true);
|
||||
setInputValue(data.defaultValue);
|
||||
},
|
||||
[context]
|
||||
);
|
||||
@@ -104,8 +98,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
}, [show]);
|
||||
|
||||
const hide = () => {
|
||||
setChecked(false);
|
||||
values.current.inputValue = undefined;
|
||||
setInputValue(null);
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
@@ -113,6 +106,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
if (dialogInfo.onClose) {
|
||||
await dialogInfo.onClose();
|
||||
}
|
||||
|
||||
hide();
|
||||
};
|
||||
|
||||
@@ -122,8 +116,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
maxHeight: 450,
|
||||
borderRadius: 5,
|
||||
backgroundColor: colors.primary.background,
|
||||
paddingTop: 12,
|
||||
...getContainerBorder(colors.primary.border, 0.5)
|
||||
paddingTop: 12
|
||||
};
|
||||
|
||||
return visible ? (
|
||||
@@ -166,7 +159,7 @@ export const Dialog = ({ context = "global" }) => {
|
||||
fwdRef={inputRef}
|
||||
autoCapitalize="none"
|
||||
onChangeText={(value) => {
|
||||
values.current.inputValue = value;
|
||||
setInputValue(value);
|
||||
}}
|
||||
testID="input-value"
|
||||
secureTextEntry={dialogInfo.secureTextEntry}
|
||||
@@ -183,10 +176,10 @@ export const Dialog = ({ context = "global" }) => {
|
||||
<>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setChecked(!checked);
|
||||
setInputValue(!inputValue);
|
||||
}}
|
||||
icon={
|
||||
checked
|
||||
inputValue
|
||||
? "check-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
}
|
||||
@@ -194,10 +187,9 @@ export const Dialog = ({ context = "global" }) => {
|
||||
justifyContent: "flex-start"
|
||||
}}
|
||||
height={35}
|
||||
iconSize={20}
|
||||
width="100%"
|
||||
title={dialogInfo.check.info}
|
||||
type={checked ? dialogInfo.check.type || "selected" : "plain"}
|
||||
type={inputValue ? dialogInfo.check.type : "plain"}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
@@ -314,7 +314,6 @@ export const AppLockPassword = () => {
|
||||
new Error(
|
||||
`${keyboardType === "pin" ? "Pin" : "Password"} incorrect`
|
||||
),
|
||||
undefined,
|
||||
"local"
|
||||
);
|
||||
return;
|
||||
@@ -327,7 +326,6 @@ export const AppLockPassword = () => {
|
||||
SettingsService.getProperty("biometricsAuthEnabled") === false
|
||||
) {
|
||||
SettingsService.setProperty("appLockEnabled", false);
|
||||
SettingsService.setPrivacyScreen(SettingsService.get());
|
||||
ToastManager.show({
|
||||
message: "App lock disabled",
|
||||
type: "success"
|
||||
|
||||
@@ -75,7 +75,7 @@ const ColorPicker = ({
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 250,
|
||||
backgroundColor: colors.primary.background,
|
||||
backgroundColor: selectedColor,
|
||||
borderRadius: 10
|
||||
}}
|
||||
>
|
||||
@@ -146,16 +146,12 @@ const ColorPicker = ({
|
||||
onChangeText={(value) => {
|
||||
title.current = value;
|
||||
}}
|
||||
testID="color-title-input"
|
||||
defaultValue={title.current}
|
||||
placeholder={title.current || "Color title"}
|
||||
/>
|
||||
|
||||
<Button
|
||||
title="Add color"
|
||||
style={{
|
||||
marginBottom: 10
|
||||
}}
|
||||
onPress={async () => {
|
||||
if (!selectedColor)
|
||||
return ToastManager.error(
|
||||
@@ -174,6 +170,7 @@ const ColorPicker = ({
|
||||
return ToastManager.error(
|
||||
new Error(`Color #${selectedColor} already exists`)
|
||||
);
|
||||
|
||||
const id = await db.colors.add({
|
||||
title: title.current,
|
||||
colorCode: selectedColor
|
||||
|
||||
@@ -23,6 +23,7 @@ import { InteractionManager, View } from "react-native";
|
||||
import Share from "react-native-share";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { db } from "../../../common/database";
|
||||
import { editorController } from "../../../screens/editor/tiptap/utils";
|
||||
import BiometricService from "../../../services/biometrics";
|
||||
import { DDS } from "../../../services/device-detection";
|
||||
import {
|
||||
@@ -34,11 +35,11 @@ import {
|
||||
import Navigation from "../../../services/navigation";
|
||||
import { getElevationStyle } from "../../../utils/elevation";
|
||||
import {
|
||||
eClearEditor,
|
||||
eCloseActionSheet,
|
||||
eCloseVaultDialog,
|
||||
eOnLoadNote,
|
||||
eOpenVaultDialog,
|
||||
eUpdateNoteInEditor
|
||||
eOpenVaultDialog
|
||||
} from "../../../utils/events";
|
||||
import { deleteItems } from "../../../utils/functions";
|
||||
import { tabBarRef } from "../../../utils/global-refs";
|
||||
@@ -337,26 +338,7 @@ export class VaultDialog extends Component {
|
||||
let verified = await db.user.verifyPassword(this.password);
|
||||
if (!(await db.user.getUser())) verified = true;
|
||||
if (verified) {
|
||||
let noteIds = [];
|
||||
if (this.state.deleteAll) {
|
||||
const vault = await db.vaults.default();
|
||||
const relations = await db.relations.from(vault, "note").get();
|
||||
noteIds = relations.map((item) => item.toId);
|
||||
}
|
||||
|
||||
await db.vault.delete(this.state.deleteAll);
|
||||
|
||||
noteIds.forEach((id) => {
|
||||
eSendEvent(
|
||||
eUpdateNoteInEditor,
|
||||
{
|
||||
id: id,
|
||||
deleted: true
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
eSendEvent("vaultUpdated");
|
||||
this.setState({
|
||||
loading: false
|
||||
@@ -383,22 +365,7 @@ export class VaultDialog extends Component {
|
||||
loading: true
|
||||
});
|
||||
try {
|
||||
const vault = await db.vaults.default();
|
||||
const relations = await db.relations.from(vault, "note").get();
|
||||
const noteIds = relations.map((item) => item.toId);
|
||||
|
||||
await db.vault.clear(this.password);
|
||||
|
||||
noteIds.forEach((id) => {
|
||||
eSendEvent(
|
||||
eUpdateNoteInEditor,
|
||||
{
|
||||
id: id,
|
||||
deleted: true
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
||||
this.setState({
|
||||
loading: false
|
||||
});
|
||||
@@ -427,10 +394,9 @@ export class VaultDialog extends Component {
|
||||
return;
|
||||
} else {
|
||||
await db.vault.add(this.state.note.id);
|
||||
|
||||
console.log("update note event...");
|
||||
eSendEvent(eUpdateNoteInEditor, this.state.note, true);
|
||||
|
||||
if (this.state.note.id === editorController.current?.note?.id) {
|
||||
eSendEvent(eClearEditor);
|
||||
}
|
||||
this.close();
|
||||
ToastManager.show({
|
||||
message: "Note locked successfully",
|
||||
@@ -535,7 +501,9 @@ export class VaultDialog extends Component {
|
||||
}
|
||||
if (this.state.note?.id) {
|
||||
await db.vault.add(this.state.note.id);
|
||||
eSendEvent(eUpdateNoteInEditor, this.state.note, true);
|
||||
if (this.state.note.id === editorController.current?.note?.id) {
|
||||
eSendEvent(eClearEditor);
|
||||
}
|
||||
this.setState({
|
||||
loading: false
|
||||
});
|
||||
@@ -565,7 +533,6 @@ export class VaultDialog extends Component {
|
||||
type: "success",
|
||||
context: "global"
|
||||
});
|
||||
eSendEvent(eUpdateNoteInEditor, this.state.note, true);
|
||||
this.close();
|
||||
})
|
||||
.catch((e) => {
|
||||
|
||||
@@ -71,7 +71,7 @@ export const RightMenus = ({
|
||||
testID={notesnook.ids.default.addBtn}
|
||||
icon={renderedInRoute === "Trash" ? "delete" : "plus"}
|
||||
iconSize={SIZE.xl}
|
||||
type="accent"
|
||||
type="shade"
|
||||
hitSlop={{
|
||||
top: 10,
|
||||
right: 10,
|
||||
@@ -82,7 +82,7 @@ export const RightMenus = ({
|
||||
marginLeft: 10,
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 100,
|
||||
borderRadius: 5,
|
||||
paddingHorizontal: 0,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.accent
|
||||
|
||||
@@ -148,6 +148,10 @@ export const NotebookHeader = ({
|
||||
size={SIZE.xs}
|
||||
color={colors.secondary.paragraph}
|
||||
>
|
||||
{/* {notebook.topics.length === 1
|
||||
? "1 topic"
|
||||
: `${notebook.topics.length} topics`}
|
||||
,{" "} */}
|
||||
{notebook && totalNotes > 1
|
||||
? totalNotes + " notes"
|
||||
: totalNotes === 1
|
||||
|
||||
@@ -25,7 +25,7 @@ import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enab
|
||||
import { presentSheet } from "../../../services/event-manager";
|
||||
import SettingsService from "../../../services/settings";
|
||||
import { RouteName } from "../../../stores/use-navigation-store";
|
||||
import { getContainerBorder } from "../../../utils/colors";
|
||||
import { ColorValues, getContainerBorder } from "../../../utils/colors";
|
||||
import { GROUP } from "../../../utils/constants";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import Sort from "../../sheets/sort";
|
||||
@@ -96,9 +96,13 @@ export const SectionHeader = React.memo<
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
color={color || colors.primary.accent}
|
||||
color={
|
||||
ColorValues[color?.toLowerCase() as keyof typeof ColorValues] ||
|
||||
colors.primary.accent
|
||||
}
|
||||
size={SIZE.sm}
|
||||
style={{
|
||||
minWidth: 60,
|
||||
alignSelf: "center",
|
||||
textAlignVertical: "center"
|
||||
}}
|
||||
@@ -113,7 +117,7 @@ export const SectionHeader = React.memo<
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
{index === 0 ? (
|
||||
{index === 0 && (
|
||||
<>
|
||||
<Button
|
||||
onPress={() => {
|
||||
@@ -122,6 +126,7 @@ export const SectionHeader = React.memo<
|
||||
component: <Sort screen={screen} type={dataType} />
|
||||
});
|
||||
}}
|
||||
hidden={screen === "Reminders"}
|
||||
tooltipText="Change sorting of items in list"
|
||||
title={groupBy}
|
||||
icon={
|
||||
@@ -175,7 +180,7 @@ export const SectionHeader = React.memo<
|
||||
size={SIZE.lg - 2}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -33,12 +33,11 @@ import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
|
||||
import NotebookScreen from "../../../screens/notebook";
|
||||
import { TaggedNotes } from "../../../screens/notes/tagged";
|
||||
import { useEditorStore } from "../../../stores/use-editor-store";
|
||||
import useNavigationStore from "../../../stores/use-navigation-store";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
|
||||
import { useTabStore } from "../../../screens/editor/tiptap/use-tab-store";
|
||||
import { NotebooksWithDateEdited, TagsWithDateEdited } from "@notesnook/common";
|
||||
import { Properties } from "../../properties";
|
||||
import { Button } from "../../ui/button";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
@@ -46,6 +45,7 @@ import { ReminderTime } from "../../ui/reminder-time";
|
||||
import { TimeSince } from "../../ui/time-since";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { NotebooksWithDateEdited, TagsWithDateEdited } from "@notesnook/common";
|
||||
|
||||
type NoteItemProps = {
|
||||
item: Note | BaseTrashItem<Note>;
|
||||
@@ -73,9 +73,8 @@ const NoteItem = ({
|
||||
locked,
|
||||
noOpen = false
|
||||
}: NoteItemProps) => {
|
||||
const isEditingNote = useTabStore(
|
||||
(state) =>
|
||||
state.tabs.find((t) => t.id === state.currentTab)?.noteId === item.id
|
||||
const isEditingNote = useEditorStore(
|
||||
(state) => state.currentEditingNote === item.id
|
||||
);
|
||||
const { colors } = useThemeColors();
|
||||
const compactMode = useIsCompactModeEnabled(
|
||||
@@ -211,31 +210,6 @@ const NoteItem = ({
|
||||
color={colors.error.accent}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{item.localOnly ? (
|
||||
<Icon
|
||||
testID="sync-off"
|
||||
name="sync-off"
|
||||
size={SIZE.sm}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
color={primaryColors.icon}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{item.readonly ? (
|
||||
<Icon
|
||||
testID="pencil-lock"
|
||||
name="pencil-lock"
|
||||
size={SIZE.sm}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
color={primaryColors.icon}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<TimeSince
|
||||
style={{
|
||||
fontSize: SIZE.xs,
|
||||
@@ -251,13 +225,12 @@ const NoteItem = ({
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
marginRight: 6,
|
||||
gap: 2
|
||||
marginRight: 6
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name="attachment"
|
||||
size={SIZE.sm}
|
||||
size={SIZE.md}
|
||||
color={primaryColors.icon}
|
||||
/>
|
||||
<Paragraph
|
||||
@@ -297,7 +270,7 @@ const NoteItem = ({
|
||||
<Icon
|
||||
testID="icon-star"
|
||||
name="star-outline"
|
||||
size={SIZE.sm}
|
||||
size={SIZE.md}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
@@ -314,8 +287,7 @@ const NoteItem = ({
|
||||
height={23}
|
||||
type="plain"
|
||||
textStyle={{
|
||||
textDecorationLine: "underline",
|
||||
color: colors.secondary.paragraph
|
||||
textDecorationLine: "underline"
|
||||
}}
|
||||
hitSlop={{ top: 8, bottom: 12, left: 0, right: 0 }}
|
||||
fontSize={SIZE.xs}
|
||||
@@ -397,7 +369,7 @@ const NoteItem = ({
|
||||
<Icon
|
||||
testID="icon-star"
|
||||
name="star-outline"
|
||||
size={SIZE.sm}
|
||||
size={SIZE.md}
|
||||
style={{
|
||||
marginRight: 6
|
||||
}}
|
||||
|
||||
@@ -26,14 +26,17 @@ import { DDS } from "../../../services/device-detection";
|
||||
import {
|
||||
eSendEvent,
|
||||
hideSheet,
|
||||
openVault,
|
||||
presentSheet
|
||||
} from "../../../services/event-manager";
|
||||
import { useEditorStore } from "../../../stores/use-editor-store";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { eOnLoadNote, eShowMergeDialog } from "../../../utils/events";
|
||||
import { tabBarRef } from "../../../utils/global-refs";
|
||||
|
||||
import { NotebooksWithDateEdited, TagsWithDateEdited } from "@notesnook/common";
|
||||
import NotePreview from "../../note-history/preview";
|
||||
import SelectionWrapper, { selectItem } from "../selection-wrapper";
|
||||
import SelectionWrapper from "../selection-wrapper";
|
||||
import { NotebooksWithDateEdited, TagsWithDateEdited } from "@notesnook/common";
|
||||
|
||||
export const openNote = async (
|
||||
item: Note,
|
||||
@@ -46,22 +49,51 @@ export const openNote = async (
|
||||
if (!isTrash) {
|
||||
note = (await db.notes.note(item.id)) as Note;
|
||||
}
|
||||
if (useSelectionStore.getState().selectionMode === item.type) {
|
||||
const {
|
||||
selectedItemsList,
|
||||
selectionMode,
|
||||
clearSelection,
|
||||
setSelectedItem
|
||||
} = useSelectionStore.getState();
|
||||
|
||||
if (selectItem(item)) return;
|
||||
if (selectedItemsList.length > 0 && selectionMode === item.type) {
|
||||
setSelectedItem(note.id);
|
||||
} else {
|
||||
clearSelection();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (note.conflicted) {
|
||||
eSendEvent(eShowMergeDialog, note);
|
||||
return;
|
||||
}
|
||||
|
||||
if (await db.vaults.itemExists(note)) {
|
||||
openVault({
|
||||
item: note,
|
||||
novault: true,
|
||||
locked: true,
|
||||
goToEditor: true,
|
||||
title: "Open note",
|
||||
description: "Unlock note to open it in editor."
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (isTrash) {
|
||||
if (!note.contentId) return;
|
||||
|
||||
const content = await db.content.get(note.contentId as string);
|
||||
presentSheet({
|
||||
component: <NotePreview note={item} content={content} />
|
||||
component: (
|
||||
<NotePreview note={item} content={{ type: "tiptap", data: content }} />
|
||||
)
|
||||
});
|
||||
} else {
|
||||
if (note?.readonly) {
|
||||
useEditorStore.getState().setReadonly(note?.readonly);
|
||||
}
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: note
|
||||
});
|
||||
|
||||
@@ -27,12 +27,18 @@ import Navigation from "../../../services/navigation";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { useTrashStore } from "../../../stores/use-trash-store";
|
||||
import { presentDialog } from "../../dialog/functions";
|
||||
import SelectionWrapper, { selectItem } from "../selection-wrapper";
|
||||
import SelectionWrapper from "../selection-wrapper";
|
||||
|
||||
export const openNotebook = (item: Notebook | BaseTrashItem<Notebook>) => {
|
||||
const isTrash = item.type === "trash";
|
||||
|
||||
if (selectItem(item)) return;
|
||||
const { selectedItemsList, setSelectedItem, selectionMode, clearSelection } =
|
||||
useSelectionStore.getState();
|
||||
if (selectedItemsList.length > 0 && selectionMode === item.type) {
|
||||
setSelectedItem(item.id);
|
||||
return;
|
||||
} else {
|
||||
clearSelection();
|
||||
}
|
||||
|
||||
if (isTrash) {
|
||||
presentDialog({
|
||||
|
||||
@@ -22,6 +22,7 @@ import React from "react";
|
||||
import { View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { Properties } from "../../properties";
|
||||
import ReminderSheet from "../../sheets/reminder";
|
||||
@@ -29,7 +30,7 @@ import { IconButton } from "../../ui/icon-button";
|
||||
import { ReminderTime } from "../../ui/reminder-time";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import SelectionWrapper, { selectItem } from "../selection-wrapper";
|
||||
import SelectionWrapper from "../selection-wrapper";
|
||||
|
||||
const ReminderItem = React.memo(
|
||||
({
|
||||
@@ -43,7 +44,18 @@ const ReminderItem = React.memo(
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const openReminder = () => {
|
||||
if (selectItem(item)) return;
|
||||
const {
|
||||
selectedItemsList,
|
||||
setSelectedItem,
|
||||
selectionMode,
|
||||
clearSelection
|
||||
} = useSelectionStore.getState();
|
||||
if (selectedItemsList.length > 0 && selectionMode === item.type) {
|
||||
setSelectedItem(item.id);
|
||||
return;
|
||||
} else {
|
||||
clearSelection();
|
||||
}
|
||||
|
||||
ReminderSheet.present(item, undefined, isSheet);
|
||||
};
|
||||
|
||||
@@ -17,18 +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 { Item } from "@notesnook/core";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import useIsSelected from "../../../hooks/use-selected";
|
||||
import { useTabStore } from "../../../screens/editor/tiptap/use-tab-store";
|
||||
import { useEditorStore } from "../../../stores/use-editor-store";
|
||||
import { Item } from "@notesnook/core";
|
||||
|
||||
export const Filler = ({ item, color }: { item: Item; color?: string }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const isEditingNote = useTabStore(
|
||||
(state) =>
|
||||
state.tabs.find((t) => t.id === state.currentTab)?.noteId === item.id
|
||||
const isEditingNote = useEditorStore(
|
||||
(state) => state.currentEditingNote === item.id
|
||||
);
|
||||
|
||||
const [selected] = useIsSelected(item);
|
||||
@@ -42,8 +41,8 @@ export const Filler = ({ item, color }: { item: Item; color?: string }) => {
|
||||
backgroundColor: colors.selected.background,
|
||||
borderLeftWidth: 5,
|
||||
borderLeftColor: isEditingNote
|
||||
? color
|
||||
? color
|
||||
? item.color
|
||||
? colors.static[item.color]
|
||||
: colors.selected.accent
|
||||
: "transparent"
|
||||
}}
|
||||
|
||||
@@ -26,23 +26,6 @@ import { Filler } from "./back-fill";
|
||||
import { SelectionIcon } from "./selection";
|
||||
import { Item, TrashItem } from "@notesnook/core";
|
||||
|
||||
export function selectItem(item: Item) {
|
||||
if (useSelectionStore.getState().selectionMode === item.type) {
|
||||
const { selectionMode, clearSelection, setSelectedItem } =
|
||||
useSelectionStore.getState();
|
||||
|
||||
if (selectionMode === item.type) {
|
||||
setSelectedItem(item.id);
|
||||
}
|
||||
|
||||
if (useSelectionStore.getState().selectedItemsList.length === 0) {
|
||||
clearSelection();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
type SelectionWrapperProps = PropsWithChildren<{
|
||||
item: Item;
|
||||
onPress: () => void;
|
||||
|
||||
@@ -23,12 +23,13 @@ import React from "react";
|
||||
import { View } from "react-native";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { TaggedNotes } from "../../../screens/notes/tagged";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { Properties } from "../../properties";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import SelectionWrapper, { selectItem } from "../selection-wrapper";
|
||||
import SelectionWrapper from "../selection-wrapper";
|
||||
|
||||
const TagItem = React.memo(
|
||||
({
|
||||
@@ -42,7 +43,18 @@ const TagItem = React.memo(
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const onPress = () => {
|
||||
if (selectItem(item)) return;
|
||||
const {
|
||||
selectedItemsList,
|
||||
setSelectedItem,
|
||||
selectionMode,
|
||||
clearSelection
|
||||
} = useSelectionStore.getState();
|
||||
if (selectedItemsList.length > 0 && selectionMode === item.type) {
|
||||
setSelectedItem(item.id);
|
||||
return;
|
||||
} else {
|
||||
clearSelection();
|
||||
}
|
||||
|
||||
TaggedNotes.navigate(item, true);
|
||||
};
|
||||
|
||||
@@ -48,7 +48,6 @@ 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 { useIsCompactModeEnabled } from "../../hooks/use-is-compact-mode-enabled";
|
||||
|
||||
type ListItemWrapperProps<TItem = Item> = {
|
||||
group?: GroupingKey;
|
||||
@@ -76,7 +75,6 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
|
||||
const refreshTimeout = useRef<NodeJS.Timeout>();
|
||||
const currentItemId = useRef<string>();
|
||||
const locked = useRef(false);
|
||||
const compactMode = useIsCompactModeEnabled(props.dataType as ItemType);
|
||||
|
||||
const refreshItem = useCallback((resolvedItem: any) => {
|
||||
if (!resolvedItem || !resolvedItem.data) {
|
||||
@@ -119,24 +117,14 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
|
||||
}
|
||||
currentItemId.current = resolvedItem.item.id;
|
||||
setItem(resolvedItem.item);
|
||||
}
|
||||
|
||||
if (resolvedItem?.group) {
|
||||
setGroupHeader(resolvedItem.group);
|
||||
} else {
|
||||
setGroupHeader(undefined);
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (previousIndex.current !== index) {
|
||||
previousIndex.current = index;
|
||||
const resolvedItem = items?.cacheItem(index);
|
||||
if (resolvedItem) {
|
||||
refreshItem(resolvedItem);
|
||||
} else {
|
||||
setItem(undefined);
|
||||
setGroupHeader(undefined);
|
||||
}
|
||||
refreshItem(resolvedItem);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -144,15 +132,12 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
|
||||
try {
|
||||
clearTimeout(refreshTimeout.current);
|
||||
const idx = index;
|
||||
refreshTimeout.current = setTimeout(
|
||||
async () => {
|
||||
if (idx !== previousIndex.current) return;
|
||||
const resolvedItem = await items?.item(idx, resolveItems);
|
||||
if (idx !== previousIndex.current) return;
|
||||
refreshItem(resolvedItem);
|
||||
},
|
||||
items?.cacheItem(index) ? 100 : 0
|
||||
);
|
||||
refreshTimeout.current = setTimeout(async () => {
|
||||
if (idx !== previousIndex.current) return;
|
||||
const resolvedItem = await items?.item(idx, resolveItems);
|
||||
if (idx !== previousIndex.current) return;
|
||||
refreshItem(resolvedItem);
|
||||
}, 100);
|
||||
} catch (e) {
|
||||
console.log("Error", e);
|
||||
}
|
||||
@@ -163,7 +148,7 @@ export function ListItemWrapper(props: ListItemWrapperProps) {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
height: compactMode ? 50 : 120,
|
||||
height: 120,
|
||||
width: "100%"
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -23,9 +23,9 @@ import { FlatList, StyleSheet, View } from "react-native";
|
||||
import {
|
||||
DraxList,
|
||||
DraxListProps,
|
||||
DraxListRenderItemContent
|
||||
DraxListRenderItemContent,
|
||||
DraxProvider
|
||||
} from "react-native-drax";
|
||||
|
||||
import { tabBarRef } from "../../utils/global-refs";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { useSideBarDraggingStore } from "../side-menu/dragging-store";
|
||||
@@ -74,7 +74,6 @@ function ReorderableList<T extends { id: string }>({
|
||||
const renderItemContent: DraxListRenderItemContent<T> = React.useCallback(
|
||||
(info, props) => {
|
||||
const isHidden = hiddenItemsState.indexOf(info?.item?.id) > -1;
|
||||
|
||||
return isHidden && !dragging ? null : (
|
||||
<View
|
||||
style={{
|
||||
@@ -137,49 +136,53 @@ function ReorderableList<T extends { id: string }>({
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<DraxList
|
||||
{...restProps}
|
||||
ref={listRef}
|
||||
data={getOrderedItems()}
|
||||
renderItemContent={renderItemContent}
|
||||
itemStyles={{
|
||||
hoverDragReleasedStyle: {
|
||||
display: "none"
|
||||
},
|
||||
hoverDraggingWithoutReceiverStyle: {
|
||||
opacity: 0.5
|
||||
},
|
||||
dragReleasedStyle: {
|
||||
opacity: 1
|
||||
},
|
||||
hoverDraggingStyle: {
|
||||
backgroundColor: colors.secondary.background
|
||||
<DraxProvider>
|
||||
<View style={styles.container}>
|
||||
<DraxList
|
||||
{...restProps}
|
||||
ref={listRef}
|
||||
data={getOrderedItems()}
|
||||
renderItemContent={renderItemContent}
|
||||
itemStyles={{
|
||||
hoverDragReleasedStyle: {
|
||||
display: "none"
|
||||
},
|
||||
hoverDraggingWithoutReceiverStyle: {
|
||||
opacity: 0.5
|
||||
},
|
||||
dragReleasedStyle: {
|
||||
opacity: 1
|
||||
},
|
||||
hoverDraggingStyle: {
|
||||
backgroundColor: colors.secondary.background
|
||||
}
|
||||
}}
|
||||
longPressDelay={500}
|
||||
onItemDragStart={() =>
|
||||
useSideBarDraggingStore.setState({
|
||||
dragging: true
|
||||
})
|
||||
}
|
||||
}}
|
||||
longPressDelay={500}
|
||||
onItemDragStart={() =>
|
||||
useSideBarDraggingStore.setState({
|
||||
dragging: true
|
||||
})
|
||||
}
|
||||
disableVirtualization
|
||||
itemsDraggable={disableDefaultDrag ? dragging : true}
|
||||
lockItemDragsToMainAxis
|
||||
onItemReorder={({ fromIndex, fromItem, toIndex, toItem }) => {
|
||||
const newOrder = getOrderedItems().map((item) => item.id);
|
||||
const element = newOrder.splice(fromIndex, 1)[0];
|
||||
if (toIndex === 0) {
|
||||
newOrder.unshift(element);
|
||||
} else {
|
||||
newOrder.splice(toIndex, 0, element);
|
||||
}
|
||||
setItemsOrder(newOrder);
|
||||
onListOrderChanged?.(newOrder);
|
||||
}}
|
||||
keyExtractor={(item) => (item as any).id}
|
||||
/>
|
||||
</View>
|
||||
itemsDraggable={disableDefaultDrag ? dragging : true}
|
||||
lockItemDragsToMainAxis
|
||||
onItemReorder={({ fromIndex, fromItem, toIndex, toItem }) => {
|
||||
const newOrder = getOrderedItems().map((item) => item.id);
|
||||
const element = newOrder.splice(fromIndex, 1)[0];
|
||||
if (toIndex === 0) {
|
||||
newOrder.unshift(element);
|
||||
} else {
|
||||
newOrder.splice(toIndex, 0, element);
|
||||
}
|
||||
setItemsOrder(newOrder);
|
||||
onListOrderChanged?.(newOrder);
|
||||
}}
|
||||
onItemDragEnd={(e) => {
|
||||
console.log(e.receiver?.receiveOffset);
|
||||
}}
|
||||
keyExtractor={(item) => (item as any).id}
|
||||
/>
|
||||
</View>
|
||||
</DraxProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@ import { SafeAreaView, Text, View } from "react-native";
|
||||
import Animated from "react-native-reanimated";
|
||||
import { db } from "../../common/database";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import { ReadonlyEditor } from "../../screens/editor/readonly-editor";
|
||||
import { useTabStore } from "../../screens/editor/tiptap/use-tab-store";
|
||||
import Editor from "../../screens/editor";
|
||||
import { editorController } from "../../screens/editor/tiptap/utils";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import {
|
||||
@@ -39,6 +38,7 @@ import Sync from "../../services/sync";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { eOnLoadNote, eShowMergeDialog } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import BaseDialog from "../dialog/base-dialog";
|
||||
import DialogButtons from "../dialog/dialog-buttons";
|
||||
import DialogContainer from "../dialog/dialog-container";
|
||||
@@ -47,7 +47,6 @@ import { Button } from "../ui/button";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import Seperator from "../ui/seperator";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { diff } from "diffblazer";
|
||||
|
||||
const MergeConflicts = () => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -89,11 +88,10 @@ const MergeConflicts = () => {
|
||||
});
|
||||
}
|
||||
Navigation.queueRoutesForUpdate();
|
||||
|
||||
if (useTabStore.getState().getCurrentNoteId() === note.id) {
|
||||
if (editorController.current?.note?.id === note.id) {
|
||||
// reload the note in editor
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: editorController.current.note.current[note.id],
|
||||
item: editorController.current?.note,
|
||||
forced: true
|
||||
});
|
||||
}
|
||||
@@ -313,20 +311,26 @@ const MergeConflicts = () => {
|
||||
height: height / 2 - (50 + insets.top / 2),
|
||||
backgroundColor: colors.primary.background,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.primary.border
|
||||
borderBottomColor: colors.secondary.background
|
||||
}}
|
||||
>
|
||||
<ReadonlyEditor
|
||||
editorId="conflictPrimary"
|
||||
onLoad={async (loadContent) => {
|
||||
<Editor
|
||||
noHeader
|
||||
noToolbar
|
||||
readonly
|
||||
editorId=":conflictPrimary"
|
||||
onLoad={async () => {
|
||||
const note = await db.notes.note(content.current?.noteId);
|
||||
if (!note) return;
|
||||
loadContent({
|
||||
id: note.id,
|
||||
data: diff(
|
||||
content.current.conflicted.data,
|
||||
content.current.data
|
||||
)
|
||||
await sleep(300);
|
||||
eSendEvent(eOnLoadNote + ":conflictPrimary", {
|
||||
item: {
|
||||
...note,
|
||||
content: {
|
||||
...content.current,
|
||||
isPreview: true
|
||||
}
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@@ -347,14 +351,20 @@ const MergeConflicts = () => {
|
||||
borderRadius: 10
|
||||
}}
|
||||
>
|
||||
<ReadonlyEditor
|
||||
editorId="conflictSecondary"
|
||||
onLoad={async (loadContent) => {
|
||||
<Editor
|
||||
noHeader
|
||||
noToolbar
|
||||
readonly
|
||||
editorId=":conflictSecondary"
|
||||
onLoad={async () => {
|
||||
const note = await db.notes.note(content.current?.noteId);
|
||||
if (!note) return;
|
||||
loadContent({
|
||||
id: note.id,
|
||||
data: content.current.conflicted.data
|
||||
await sleep(300);
|
||||
eSendEvent(eOnLoadNote + ":conflictSecondary", {
|
||||
item: {
|
||||
...note,
|
||||
content: { ...content.current.conflicted, isPreview: true }
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -199,9 +199,7 @@ export default function NoteHistory({
|
||||
Note version history is local only.{" "}
|
||||
<Text
|
||||
onPress={() => {
|
||||
openLinkInBrowser(
|
||||
"https://help.notesnook.com/note-version-history"
|
||||
);
|
||||
openLinkInBrowser("https://docs.notesnook.com/versionhistory");
|
||||
}}
|
||||
style={{
|
||||
color: colors.primary.accent,
|
||||
|
||||
@@ -22,10 +22,10 @@ import React, { useEffect, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
import Editor from "../../screens/editor";
|
||||
import { useTabStore } from "../../screens/editor/tiptap/use-tab-store";
|
||||
import { editorController } from "../../screens/editor/tiptap/utils";
|
||||
import { eSendEvent, ToastManager } from "../../services/event-manager";
|
||||
import Navigation from "../../services/navigation";
|
||||
import { useEditorStore } from "../../stores/use-editor-store";
|
||||
import { useSelectionStore } from "../../stores/use-selection-store";
|
||||
import { useTrashStore } from "../../stores/use-trash-store";
|
||||
import { eCloseSheet, eOnLoadNote } from "../../utils/events";
|
||||
@@ -34,7 +34,6 @@ import DialogHeader from "../dialog/dialog-header";
|
||||
import { presentDialog } from "../dialog/functions";
|
||||
import { Button } from "../ui/button";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { ReadonlyEditor } from "../../screens/editor/readonly-editor";
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -43,6 +42,7 @@ import { ReadonlyEditor } from "../../screens/editor/readonly-editor";
|
||||
*/
|
||||
export default function NotePreview({ session, content, note }) {
|
||||
const { colors } = useThemeColors();
|
||||
const editorId = ":noteHistory";
|
||||
const [locked, setLocked] = useState(false);
|
||||
|
||||
async function restore() {
|
||||
@@ -58,11 +58,10 @@ export default function NotePreview({ session, content, note }) {
|
||||
return;
|
||||
}
|
||||
await db.noteHistory.restore(session.id);
|
||||
if (useTabStore.getState().hasTabForNote(session?.noteId)) {
|
||||
const note = editorController.current.note.current[session?.noteId];
|
||||
if (note) {
|
||||
if (useEditorStore.getState()?.currentEditingNote === session?.noteId) {
|
||||
if (editorController.current?.note) {
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: note,
|
||||
item: editorController.current?.note,
|
||||
forced: true
|
||||
});
|
||||
}
|
||||
@@ -118,16 +117,22 @@ export default function NotePreview({ session, content, note }) {
|
||||
flex: 1
|
||||
}}
|
||||
>
|
||||
<ReadonlyEditor
|
||||
editorId="historyPreview"
|
||||
onLoad={async (loadContent) => {
|
||||
if (content.data) {
|
||||
const _note = note || (await db.notes.note(session?.noteId));
|
||||
loadContent({
|
||||
data: content.data,
|
||||
id: _note.id
|
||||
});
|
||||
}
|
||||
<Editor
|
||||
noHeader
|
||||
noToolbar
|
||||
readonly
|
||||
editorId={editorId}
|
||||
onLoad={async () => {
|
||||
const _note = note || (await db.notes.note(session?.noteId));
|
||||
eSendEvent(eOnLoadNote + editorId, {
|
||||
item: {
|
||||
..._note,
|
||||
content: {
|
||||
...content,
|
||||
isPreview: true
|
||||
}
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -162,7 +162,7 @@ export const features = [
|
||||
platform: "android"
|
||||
}
|
||||
],
|
||||
info: "* Free users are limited to keeping 3 notebooks and 5 tags."
|
||||
info: "* Free users are limited to keeping 3 notebooks (no limit on topics) and 5 tags."
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
@@ -111,7 +111,6 @@ export const ColorTags = ({ item }: { item: Note }) => {
|
||||
visible={visible}
|
||||
setVisible={setVisible}
|
||||
onColorAdded={async (color) => {
|
||||
await db.relations.to(note, "color").unlink();
|
||||
await db.relations.add(color, note);
|
||||
useRelationStore.getState().update();
|
||||
useMenuStore.getState().setColorNotes();
|
||||
|
||||
@@ -22,13 +22,11 @@ import { Platform, View } from "react-native";
|
||||
import { FlatList } from "react-native-actions-sheet";
|
||||
import { db } from "../../common/database";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import { eSendEvent, presentSheet } from "../../services/event-manager";
|
||||
import { presentSheet } from "../../services/event-manager";
|
||||
import { ColorValues } from "../../utils/colors";
|
||||
import { eOnLoadNote } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import SheetProvider from "../sheet-provider";
|
||||
import { useSideBarDraggingStore } from "../side-menu/dragging-store";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import { ReminderTime } from "../ui/reminder-time";
|
||||
import Heading from "../ui/typography/heading";
|
||||
@@ -38,7 +36,6 @@ import { Items } from "./items";
|
||||
import Notebooks from "./notebooks";
|
||||
import { Synced } from "./synced";
|
||||
import { TagStrip, Tags } from "./tags";
|
||||
import { tabBarRef } from "../../utils/global-refs";
|
||||
|
||||
const Line = ({ top = 6, bottom = 6 }) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -77,7 +74,6 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
|
||||
maxHeight: "100%"
|
||||
}}
|
||||
nestedScrollEnabled
|
||||
bounces={false}
|
||||
data={[0]}
|
||||
keyExtractor={() => "properties-scroll-item"}
|
||||
renderItem={() => (
|
||||
@@ -93,61 +89,31 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between"
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
{item.type === "color" ? (
|
||||
<Pressable
|
||||
type="accent"
|
||||
accentColor={item.colorCode}
|
||||
accentText={colors.static.white}
|
||||
style={{
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 100,
|
||||
marginRight: 10
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<Heading size={SIZE.lg}>
|
||||
{item.type === "tag" && !isColor ? (
|
||||
<Heading size={SIZE.xl} color={colors.primary.accent}>
|
||||
#
|
||||
</Heading>
|
||||
) : null}
|
||||
{item.title}
|
||||
</Heading>
|
||||
</View>
|
||||
|
||||
{item.type === "note" ? (
|
||||
<IconButton
|
||||
name="open-in-new"
|
||||
type="plain"
|
||||
color={colors.primary.icon}
|
||||
size={SIZE.lg}
|
||||
{item.type === "color" ? (
|
||||
<Pressable
|
||||
type="accent"
|
||||
accentColor={item.colorCode}
|
||||
accentText={colors.static.white}
|
||||
style={{
|
||||
alignSelf: "flex-start"
|
||||
}}
|
||||
onPress={() => {
|
||||
close();
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: item,
|
||||
presistTab: true
|
||||
});
|
||||
if (!DDS.isTab) {
|
||||
tabBarRef.current?.goToPage(1);
|
||||
}
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 100,
|
||||
marginRight: 10
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<Heading size={SIZE.lg}>
|
||||
{item.type === "tag" && !isColor ? (
|
||||
<Heading size={SIZE.xl} color={colors.primary.accent}>
|
||||
#
|
||||
</Heading>
|
||||
) : null}
|
||||
{item.title}
|
||||
</Heading>
|
||||
</View>
|
||||
|
||||
{item.type === "notebook" && item.description ? (
|
||||
@@ -242,14 +208,13 @@ Properties.present = async (item, buttons = [], isSheet) => {
|
||||
"attachments",
|
||||
"lock-unlock",
|
||||
"trash",
|
||||
"remove-from-topic",
|
||||
"remove-from-notebook",
|
||||
"history",
|
||||
"read-only",
|
||||
"reminders",
|
||||
"local-only",
|
||||
"duplicate",
|
||||
"copy-link",
|
||||
"references",
|
||||
...android,
|
||||
...buttons
|
||||
]);
|
||||
@@ -263,8 +228,7 @@ Properties.present = async (item, buttons = [], isSheet) => {
|
||||
"trash",
|
||||
"default-notebook",
|
||||
"add-notebook",
|
||||
"move-notes",
|
||||
"move-notebook"
|
||||
"move-notes"
|
||||
]);
|
||||
break;
|
||||
case "tag":
|
||||
|
||||
@@ -22,7 +22,6 @@ import React from "react";
|
||||
import { Dimensions, ScrollView, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { useActions } from "../../hooks/use-actions";
|
||||
import { useStoredRef } from "../../hooks/use-stored-ref";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { SIZE } from "../../utils/size";
|
||||
@@ -32,8 +31,6 @@ import Paragraph from "../ui/typography/paragraph";
|
||||
|
||||
export const Items = ({ item, buttons, close }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const topBarSorting = useStoredRef("topbar-sorting-ref", {});
|
||||
|
||||
const dimensions = useSettingStore((state) => state.dimensions);
|
||||
const actions = useActions({ item, close });
|
||||
const data = actions.filter((i) => buttons.indexOf(i.id) > -1 && !i.hidden);
|
||||
@@ -48,6 +45,7 @@ export const Items = ({ item, buttons, close }) => {
|
||||
|
||||
const _renderRowItem = ({ item }) => (
|
||||
<View
|
||||
onPress={item.func}
|
||||
key={item.id}
|
||||
testID={"icon-" + item.id}
|
||||
style={{
|
||||
@@ -73,7 +71,7 @@ export const Items = ({ item, buttons, close }) => {
|
||||
<Icon
|
||||
allowFontScaling
|
||||
name={item.icon}
|
||||
size={DDS.isTab ? SIZE.xxl : shouldShrink ? SIZE.xxl : SIZE.lg}
|
||||
size={DDS.isTab ? SIZE.xxl : SIZE.lg}
|
||||
color={
|
||||
item.on
|
||||
? colors.primary.accent
|
||||
@@ -119,23 +117,16 @@ export const Items = ({ item, buttons, close }) => {
|
||||
);
|
||||
|
||||
const renderTopBarItem = (item, index) => {
|
||||
const isLast = index === topBarItems.length;
|
||||
return (
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
item.func();
|
||||
setImmediate(() => {
|
||||
const currentValue = topBarSorting.current[item.id] || 0;
|
||||
topBarSorting.current = {
|
||||
...topBarSorting.current,
|
||||
[item.id]: currentValue + 1
|
||||
};
|
||||
});
|
||||
}}
|
||||
onPress={item.func}
|
||||
key={item.id}
|
||||
testID={"icon-" + item.id}
|
||||
activeOpacity={1}
|
||||
style={{
|
||||
alignSelf: "flex-start",
|
||||
marginRight: isLast ? 0 : 10,
|
||||
paddingHorizontal: 0,
|
||||
width: topBarItemWidth
|
||||
}}
|
||||
@@ -183,36 +174,34 @@ export const Items = ({ item, buttons, close }) => {
|
||||
"favorite",
|
||||
"copy",
|
||||
"share",
|
||||
"lock-unlock",
|
||||
"publish",
|
||||
"export",
|
||||
"copy-link",
|
||||
"duplicate",
|
||||
"local-only",
|
||||
"read-only"
|
||||
];
|
||||
|
||||
const bottomBarItemsList = [
|
||||
"notebooks",
|
||||
"add-reminder",
|
||||
"pin-to-notifications",
|
||||
"history",
|
||||
"reminders",
|
||||
"attachments",
|
||||
"references",
|
||||
"trash"
|
||||
"lock-unlock"
|
||||
];
|
||||
|
||||
const topBarItems = data
|
||||
.filter((item) => topBarItemsList.indexOf(item.id) > -1)
|
||||
.sort((a, b) =>
|
||||
topBarItemsList.indexOf(a.id) > topBarItemsList.indexOf(b.id) ? 1 : -1
|
||||
)
|
||||
.sort((a, b) => {
|
||||
return (
|
||||
(topBarSorting.current[b.id] || 0) - (topBarSorting.current[a.id] || 0)
|
||||
);
|
||||
});
|
||||
);
|
||||
|
||||
const bottomBarItemsList = [
|
||||
"notebooks",
|
||||
"add-reminder",
|
||||
"pin-to-notifications",
|
||||
"duplicate",
|
||||
"read-only",
|
||||
"local-only",
|
||||
"history",
|
||||
"reminders",
|
||||
"attachments",
|
||||
"trash"
|
||||
];
|
||||
|
||||
if (!shouldShrink) {
|
||||
topBarItemsList.push("publish");
|
||||
} else {
|
||||
bottomBarItemsList.splice(4, 0, "publish");
|
||||
}
|
||||
|
||||
const bottomGridItems = data
|
||||
.filter((item) => bottomBarItemsList.indexOf(item.id) > -1)
|
||||
@@ -226,8 +215,8 @@ export const Items = ({ item, buttons, close }) => {
|
||||
(width - (topBarItems.length * 10 + 14)) / topBarItems.length;
|
||||
topBarItemWidth;
|
||||
|
||||
if (topBarItemWidth < 60) {
|
||||
topBarItemWidth = 60;
|
||||
if (topBarItemWidth < 55) {
|
||||
topBarItemWidth = 55;
|
||||
}
|
||||
|
||||
return item.type === "note" ? (
|
||||
@@ -236,13 +225,7 @@ export const Items = ({ item, buttons, close }) => {
|
||||
horizontal
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
marginTop: 6,
|
||||
marginBottom: 6
|
||||
}}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={{
|
||||
paddingRight: 25,
|
||||
gap: 5
|
||||
marginTop: 6
|
||||
}}
|
||||
>
|
||||
{topBarItems.map(renderTopBarItem)}
|
||||
|
||||
@@ -48,7 +48,7 @@ export const Synced = ({ item, close }) => {
|
||||
paddingTop: 10,
|
||||
marginTop: 10,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: colors.primary.border
|
||||
borderTopColor: colors.secondary.background
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
@@ -92,7 +92,7 @@ export const Synced = ({ item, close }) => {
|
||||
close();
|
||||
await sleep(300);
|
||||
await openLinkInBrowser(
|
||||
"https://help.notesnook.com/how-is-my-data-encrypted",
|
||||
"https://docs.notesnook.com/how-is-my-data-encrypted/",
|
||||
colors
|
||||
);
|
||||
} catch (e) {
|
||||
|
||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
import { TaggedNotes } from "../../screens/notes/tagged";
|
||||
@@ -68,38 +68,26 @@ export const Tags = ({ item, close }) => {
|
||||
};
|
||||
|
||||
export const TagStrip = ({ item, close }) => {
|
||||
const [tags, setTags] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
db.relations
|
||||
.to(item, "tag")
|
||||
.resolve()
|
||||
.then((tags) => {
|
||||
setTags(tags);
|
||||
});
|
||||
});
|
||||
|
||||
return tags?.length > 0 ? (
|
||||
return item.tags?.length > 0 ? (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
alignItems: "center",
|
||||
marginTop: 10,
|
||||
gap: 5
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
{tags?.map((tag) =>
|
||||
tag ? <TagItem key={tag.id} tag={tag} close={close} /> : null
|
||||
{item.tags.map((tag) =>
|
||||
tag ? <TagItem key={tag} tag={tag} close={close} /> : null
|
||||
)}
|
||||
</View>
|
||||
) : null;
|
||||
};
|
||||
|
||||
const TagItem = ({ tag, close }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const onPress = async () => {
|
||||
TaggedNotes.navigate(tag, true);
|
||||
let tags = db.tags.all;
|
||||
let _tag = tags.find((t) => t.title === tag);
|
||||
TaggedNotes.navigate(_tag, true);
|
||||
await sleep(300);
|
||||
close();
|
||||
};
|
||||
@@ -107,19 +95,20 @@ const TagItem = ({ tag, close }) => {
|
||||
const style = {
|
||||
paddingHorizontal: 0,
|
||||
borderRadius: 100,
|
||||
marginRight: 10,
|
||||
marginTop: 0,
|
||||
backgroundColor: "transparent"
|
||||
};
|
||||
return (
|
||||
<Button
|
||||
onPress={onPress}
|
||||
title={"#" + tag.title}
|
||||
type="plain"
|
||||
title={"#" + tag}
|
||||
type="secondary"
|
||||
height={20}
|
||||
fontSize={SIZE.xs}
|
||||
style={style}
|
||||
textStyle={{
|
||||
color: colors.secondary.paragraph
|
||||
textDecorationLine: "underline"
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -44,7 +44,6 @@ import ExportNotesSheet from "../sheets/export-notes";
|
||||
import ManageTagsSheet from "../sheets/manage-tags";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import { MoveNotebookSheet } from "../sheets/move-notebook";
|
||||
|
||||
export const SelectionHeader = React.memo(
|
||||
({
|
||||
@@ -214,24 +213,7 @@ export const SelectionHeader = React.memo(
|
||||
size={SIZE.xl}
|
||||
/>
|
||||
|
||||
{renderedInRoute === "Notebooks" && selectedItemsList.length ? (
|
||||
<IconButton
|
||||
style={{
|
||||
marginLeft: 10
|
||||
}}
|
||||
onPress={async () => {
|
||||
const ids = selectedItemsList;
|
||||
const notebooks = await db.notebooks.all.items(ids);
|
||||
MoveNotebookSheet.present(notebooks);
|
||||
}}
|
||||
tooltipText="Move notebooks"
|
||||
tooltipPosition={1}
|
||||
name="arrow-right-bold-box-outline"
|
||||
size={SIZE.xl}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{type !== "note" || !selectedItemsList.length ? null : (
|
||||
{type !== "note" ? null : (
|
||||
<>
|
||||
<IconButton
|
||||
onPress={async () => {
|
||||
@@ -278,14 +260,16 @@ export const SelectionHeader = React.memo(
|
||||
</>
|
||||
)}
|
||||
|
||||
{renderedInRoute === "Notebook" && selectedItemsList.length ? (
|
||||
{renderedInRoute === "Notebook" ? (
|
||||
<IconButton
|
||||
onPress={async () => {
|
||||
if (!id) return;
|
||||
await db.notes.removeFromNotebook(id, ...selectedItemsList);
|
||||
updateNotebook(id);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
clearSelection();
|
||||
if (selectedItemsList.length > 0) {
|
||||
if (!id) return;
|
||||
await db.notes.removeFromNotebook(id, ...selectedItemsList);
|
||||
updateNotebook(id);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
clearSelection();
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
marginLeft: 10
|
||||
@@ -299,7 +283,7 @@ export const SelectionHeader = React.memo(
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{focusedRouteId === "Favorites" && selectedItemsList.length ? (
|
||||
{focusedRouteId === "Favorites" ? (
|
||||
<IconButton
|
||||
onPress={addToFavorite}
|
||||
style={{
|
||||
@@ -313,7 +297,7 @@ export const SelectionHeader = React.memo(
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{type === "trash" || !selectedItemsList.length ? null : (
|
||||
{type === "trash" ? null : (
|
||||
<IconButton
|
||||
style={{
|
||||
marginLeft: 10
|
||||
@@ -335,7 +319,7 @@ export const SelectionHeader = React.memo(
|
||||
/>
|
||||
)}
|
||||
|
||||
{type === "trash" && selectedItemsList.length ? (
|
||||
{type === "trash" ? (
|
||||
<>
|
||||
<IconButton
|
||||
style={{
|
||||
|
||||
@@ -39,18 +39,15 @@ import Heading from "../../ui/typography/heading";
|
||||
import { MoveNotes } from "../move-notes/movenote";
|
||||
import { eOnNotebookUpdated } from "../../../utils/events";
|
||||
import { getParentNotebookId } from "../../../utils/notebooks";
|
||||
import { useNotebookStore } from "../../../stores/use-notebook-store";
|
||||
|
||||
export const AddNotebookSheet = ({
|
||||
notebook,
|
||||
parentNotebook,
|
||||
close,
|
||||
showMoveNotesOnComplete
|
||||
close
|
||||
}: {
|
||||
notebook?: Notebook;
|
||||
parentNotebook?: Notebook;
|
||||
close?: (didAddNotebook: boolean) => void;
|
||||
showMoveNotesOnComplete: boolean;
|
||||
close: ((context?: string | undefined) => void) | undefined;
|
||||
}) => {
|
||||
const title = useRef(notebook?.title);
|
||||
const description = useRef(notebook?.description);
|
||||
@@ -88,7 +85,6 @@ export const AddNotebookSheet = ({
|
||||
useMenuStore.getState().setMenuPins();
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useRelationStore.getState().update();
|
||||
useNotebookStore.getState().refresh();
|
||||
|
||||
const parent =
|
||||
parentNotebook?.id || (await getParentNotebookId(notebook?.id || id));
|
||||
@@ -101,10 +97,10 @@ export const AddNotebookSheet = ({
|
||||
});
|
||||
}
|
||||
|
||||
if (!notebook && showMoveNotesOnComplete) {
|
||||
if (!notebook) {
|
||||
MoveNotes.present(await db.notebooks.notebook(id));
|
||||
} else {
|
||||
close?.(true);
|
||||
close?.();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -173,8 +169,7 @@ AddNotebookSheet.present = (
|
||||
notebook?: Notebook,
|
||||
parentNotebook?: Notebook,
|
||||
context?: string,
|
||||
onClose?: (didAddNotebook: boolean) => void,
|
||||
showMoveNotesOnComplete = true
|
||||
onClose?: () => void
|
||||
) => {
|
||||
presentSheet({
|
||||
context: context,
|
||||
@@ -182,12 +177,9 @@ AddNotebookSheet.present = (
|
||||
<AddNotebookSheet
|
||||
notebook={notebook}
|
||||
parentNotebook={parentNotebook}
|
||||
close={(didAddNotebook: boolean) => {
|
||||
close?.();
|
||||
onClose?.(didAddNotebook);
|
||||
}}
|
||||
showMoveNotesOnComplete={showMoveNotesOnComplete || false}
|
||||
close={close}
|
||||
/>
|
||||
)
|
||||
),
|
||||
onClose: onClose
|
||||
});
|
||||
};
|
||||
|
||||
@@ -46,7 +46,6 @@ import { IconButton } from "../../ui/icon-button";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { NotebookItem } from "./notebook-item";
|
||||
import { useNotebookItemSelectionStore } from "./store";
|
||||
import { AddNotebookSheet } from "../add-notebook";
|
||||
|
||||
async function updateInitialSelectionState(items: string[]) {
|
||||
const relations = await db.relations
|
||||
@@ -142,11 +141,6 @@ const MoveNoteSheet = ({
|
||||
actionSheetRef.current?.hide();
|
||||
};
|
||||
|
||||
const hasSelected = () => {
|
||||
const selection = useNotebookItemSelectionStore.getState().selection;
|
||||
return Object.keys(selection).some((key) => selection[key] === "selected");
|
||||
};
|
||||
|
||||
const renderNotebook = useCallback(
|
||||
({ index }: { item: boolean; index: number }) => (
|
||||
<NotebookItem items={notebooks} id={index} index={index} />
|
||||
@@ -186,7 +180,7 @@ const MoveNoteSheet = ({
|
||||
paragraph={
|
||||
!multiSelect
|
||||
? "Long press to enable multi-select."
|
||||
: "Select notebooks you want to add note(s) to."
|
||||
: "Select topics you want to add note(s) to."
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -196,21 +190,18 @@ const MoveNoteSheet = ({
|
||||
columnGap: 10
|
||||
}}
|
||||
>
|
||||
{hasSelected() ? (
|
||||
<IconButton
|
||||
name="restore"
|
||||
type="secondaryAccented"
|
||||
color={colors.primary.icon}
|
||||
onPress={() => {
|
||||
const items = note ? [note.id] : selectedItemsList;
|
||||
updateInitialSelectionState(items);
|
||||
}}
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<IconButton
|
||||
name="restore"
|
||||
type="secondaryAccented"
|
||||
onPress={() => {
|
||||
const items = note ? [note.id] : selectedItemsList;
|
||||
updateInitialSelectionState(items);
|
||||
}}
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
height={40}
|
||||
@@ -239,36 +230,6 @@ const MoveNoteSheet = ({
|
||||
style={{
|
||||
width: "100%"
|
||||
}}
|
||||
ListHeaderComponent={
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
title="Add new notebook"
|
||||
style={{
|
||||
alignSelf: "flex-start",
|
||||
paddingHorizontal: 12,
|
||||
justifyContent: "space-between"
|
||||
}}
|
||||
onPress={() => {
|
||||
AddNotebookSheet.present(
|
||||
undefined,
|
||||
undefined,
|
||||
"link-notebooks",
|
||||
undefined,
|
||||
false
|
||||
);
|
||||
}}
|
||||
icon="plus"
|
||||
iconPosition="right"
|
||||
type="secondaryAccented"
|
||||
width="100%"
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
estimatedItemSize={50}
|
||||
renderItem={renderNotebook}
|
||||
ListEmptyComponent={
|
||||
@@ -304,8 +265,7 @@ MoveNoteSheet.present = (note?: Note) => {
|
||||
presentSheet({
|
||||
component: (ref) => <MoveNoteSheet actionSheetRef={ref} note={note} />,
|
||||
enableGesturesInScrollView: false,
|
||||
noBottomPadding: true,
|
||||
keyboardHandlerDisabled: true
|
||||
noBottomPadding: true
|
||||
});
|
||||
};
|
||||
export default MoveNoteSheet;
|
||||
|
||||
@@ -226,13 +226,7 @@ export const NotebookItem = ({
|
||||
testID={notesnook.ids.notebook.menu}
|
||||
onPress={() => {
|
||||
if (!item) return;
|
||||
AddNotebookSheet.present(
|
||||
undefined,
|
||||
item,
|
||||
"link-notebooks",
|
||||
undefined,
|
||||
false
|
||||
);
|
||||
AddNotebookSheet.present(undefined, item, "link-notebooks");
|
||||
}}
|
||||
left={0}
|
||||
right={0}
|
||||
|
||||
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { Note } from "@notesnook/core";
|
||||
import { EVENTS } from "@notesnook/core/dist/common";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useEffect } from "react";
|
||||
import { View } from "react-native";
|
||||
import { FlatList } from "react-native-actions-sheet";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../../../common/database";
|
||||
import { useDBItem } from "../../../hooks/use-db-item";
|
||||
import { useTabStore } from "../../../screens/editor/tiptap/use-tab-store";
|
||||
import { editorController } from "../../../screens/editor/tiptap/utils";
|
||||
import { eSendEvent, presentSheet } from "../../../services/event-manager";
|
||||
import { eUnlockNote } from "../../../utils/events";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { Button } from "../../ui/button";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
|
||||
type TabItem = {
|
||||
id: number;
|
||||
noteId?: string;
|
||||
previewTab?: boolean;
|
||||
locked?: boolean;
|
||||
noteLocked?: boolean;
|
||||
readonly?: boolean;
|
||||
pinned?: boolean;
|
||||
};
|
||||
|
||||
const TabItemComponent = (props: {
|
||||
tab: TabItem;
|
||||
isFocused: boolean;
|
||||
close?: (ctx?: string | undefined) => void;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [item, update] = useDBItem(props.tab.noteId, "note");
|
||||
|
||||
useEffect(() => {
|
||||
const syncCompletedSubscription = db.eventManager?.subscribe(
|
||||
EVENTS.syncItemMerged,
|
||||
(data: Note) => {
|
||||
if (data.type === "note") {
|
||||
const tabId = useTabStore.getState().getTabForNote(data.id);
|
||||
if (tabId !== undefined && item?.title !== data.title) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
return () => {
|
||||
syncCompletedSubscription?.unsubscribe();
|
||||
};
|
||||
}, [update, item]);
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
style={{
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
flexDirection: "row",
|
||||
paddingLeft: 12,
|
||||
minHeight: 45
|
||||
}}
|
||||
type={props.isFocused ? "selected" : "transparent"}
|
||||
onPress={() => {
|
||||
if (!props.isFocused) {
|
||||
useTabStore.getState().focusTab(props.tab.id);
|
||||
if (props.tab.locked) {
|
||||
eSendEvent(eUnlockNote);
|
||||
}
|
||||
|
||||
if (!props.tab.noteId) {
|
||||
setTimeout(() => {
|
||||
editorController?.current?.commands?.focus(props.tab.id);
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
props.close?.();
|
||||
}}
|
||||
onLongPress={() => {
|
||||
useTabStore.getState().updateTab(props.tab.id, {
|
||||
previewTab: false
|
||||
});
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
gap: 10,
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
{props.tab.noteLocked ? (
|
||||
<>
|
||||
{props.tab.locked ? (
|
||||
<Icon size={SIZE.md} name="lock" />
|
||||
) : (
|
||||
<Icon size={SIZE.md} name="lock-open-outline" />
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{props.tab.readonly ? <Icon size={SIZE.md} name="pencil-lock" /> : null}
|
||||
|
||||
<Paragraph
|
||||
color={
|
||||
props.isFocused
|
||||
? colors.selected.paragraph
|
||||
: colors.primary.paragraph
|
||||
}
|
||||
style={{
|
||||
fontFamily: props.tab.previewTab
|
||||
? "OpenSans-Italic"
|
||||
: "OpenSans-Regular"
|
||||
}}
|
||||
numberOfLines={1}
|
||||
size={SIZE.md}
|
||||
>
|
||||
{props.tab.noteId ? item?.title || "Untitled note" : "New note"}
|
||||
</Paragraph>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
gap: 5,
|
||||
paddingRight: 12
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
name="pin"
|
||||
size={SIZE.lg}
|
||||
color={props.tab.pinned ? colors.primary.accent : colors.primary.icon}
|
||||
onPress={() => {
|
||||
useTabStore.getState().updateTab(props.tab.id, {
|
||||
pinned: !props.tab.pinned,
|
||||
previewTab: false
|
||||
});
|
||||
}}
|
||||
top={0}
|
||||
left={0}
|
||||
right={20}
|
||||
bottom={0}
|
||||
/>
|
||||
|
||||
{!props.tab?.pinned ? (
|
||||
<IconButton
|
||||
name="close"
|
||||
size={SIZE.lg}
|
||||
color={colors.primary.icon}
|
||||
onPress={() => {
|
||||
const isLastTab = useTabStore.getState().tabs.length === 1;
|
||||
useTabStore.getState().removeTab(props.tab.id);
|
||||
// The last tab is not actually removed, it is just cleaned up.
|
||||
if (isLastTab) {
|
||||
editorController.current?.reset(props.tab.id, true, true);
|
||||
props.close?.();
|
||||
}
|
||||
}}
|
||||
top={0}
|
||||
left={0}
|
||||
right={20}
|
||||
bottom={0}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
export default function EditorTabs({
|
||||
close
|
||||
}: {
|
||||
close?: (ctx?: string | undefined) => void;
|
||||
}) {
|
||||
const [tabs, currentTab] = useTabStore((state) => [
|
||||
state.tabs,
|
||||
state.currentTab
|
||||
]);
|
||||
|
||||
const renderTabItem = React.useCallback(
|
||||
({ item }: { item: TabItem }) => {
|
||||
return (
|
||||
<TabItemComponent
|
||||
key={item.id}
|
||||
tab={item}
|
||||
isFocused={item.id === currentTab}
|
||||
close={close}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[close, currentTab]
|
||||
);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
gap: 12,
|
||||
maxHeight: "100%"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Heading size={SIZE.lg}>Tabs</Heading>
|
||||
<Button
|
||||
onPress={() => {
|
||||
useTabStore.getState().newTab();
|
||||
setTimeout(() => {
|
||||
editorController?.current?.commands?.focus(
|
||||
useTabStore.getState().currentTab
|
||||
);
|
||||
}, 500);
|
||||
close?.();
|
||||
}}
|
||||
title="New tab"
|
||||
icon="plus"
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-start",
|
||||
borderRadius: 100,
|
||||
height: 35
|
||||
}}
|
||||
iconSize={SIZE.lg}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<FlatList
|
||||
windowSize={3}
|
||||
data={tabs.sort((t1, t2) => {
|
||||
if (t1.pinned && t2.pinned) return 0;
|
||||
if (t1.pinned) return -1;
|
||||
if (t2.pinned) return 1;
|
||||
return 0;
|
||||
})}
|
||||
renderItem={renderTabItem}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
EditorTabs.present = () => {
|
||||
presentSheet({
|
||||
component: (ref, close, update) => <EditorTabs close={close} />
|
||||
});
|
||||
};
|
||||
@@ -39,7 +39,6 @@ import { getElevationStyle } from "../../../utils/elevation";
|
||||
import { eCloseSheet } from "../../../utils/events";
|
||||
import { SIZE, ph, pv } from "../../../utils/size";
|
||||
import { sleep } from "../../../utils/time";
|
||||
import { Dialog } from "../../dialog";
|
||||
import DialogHeader from "../../dialog/dialog-header";
|
||||
import { ProTag } from "../../premium/pro-tag";
|
||||
import { Button } from "../../ui/button";
|
||||
@@ -48,6 +47,7 @@ import { Pressable } from "../../ui/pressable";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { Dialog } from "../../dialog";
|
||||
|
||||
const ExportNotesSheet = ({
|
||||
ids,
|
||||
@@ -71,7 +71,7 @@ const ExportNotesSheet = ({
|
||||
const [status, setStatus] = useState<string>();
|
||||
const premium = useUserStore((state) => state.premium);
|
||||
|
||||
const exportNoteAs = async (
|
||||
const save = async (
|
||||
type: "pdf" | "txt" | "md" | "html" | "md-frontmatter"
|
||||
) => {
|
||||
if (exporting) return;
|
||||
@@ -81,18 +81,9 @@ const ExportNotesSheet = ({
|
||||
setComplete(false);
|
||||
let result;
|
||||
if (ids.length > 1) {
|
||||
result = await Exporter.bulkExport(
|
||||
db.notes.all.where((eb) => eb("id", "in", ids)),
|
||||
type,
|
||||
setStatus
|
||||
);
|
||||
result = await Exporter.bulkExport(ids, type, setStatus);
|
||||
} else {
|
||||
const note = await db.notes.note(ids[0]);
|
||||
if (!note) {
|
||||
setExporting(false);
|
||||
return;
|
||||
}
|
||||
result = await Exporter.exportNote(note, type, setStatus);
|
||||
result = await Exporter.exportNote(ids[0], type);
|
||||
await sleep(1000);
|
||||
}
|
||||
if (!result) {
|
||||
@@ -110,7 +101,7 @@ const ExportNotesSheet = ({
|
||||
{
|
||||
title: "PDF",
|
||||
func: async () => {
|
||||
await exportNoteAs("pdf");
|
||||
await save("pdf");
|
||||
},
|
||||
icon: "file-pdf-box",
|
||||
desc: "View in any pdf reader app",
|
||||
@@ -120,7 +111,7 @@ const ExportNotesSheet = ({
|
||||
{
|
||||
title: "Markdown",
|
||||
func: async () => {
|
||||
await exportNoteAs("md");
|
||||
await save("md");
|
||||
},
|
||||
icon: "language-markdown",
|
||||
desc: "View in any text or markdown editor",
|
||||
@@ -130,7 +121,7 @@ const ExportNotesSheet = ({
|
||||
{
|
||||
title: "Markdown + Frontmatter",
|
||||
func: async () => {
|
||||
await exportNoteAs("md-frontmatter");
|
||||
await save("md-frontmatter");
|
||||
},
|
||||
icon: "language-markdown",
|
||||
desc: "View in any text or markdown editor",
|
||||
@@ -140,7 +131,7 @@ const ExportNotesSheet = ({
|
||||
{
|
||||
title: "Plain Text",
|
||||
func: async () => {
|
||||
await exportNoteAs("txt");
|
||||
await save("txt");
|
||||
},
|
||||
icon: "card-text",
|
||||
desc: "View in any text editor",
|
||||
@@ -150,7 +141,7 @@ const ExportNotesSheet = ({
|
||||
{
|
||||
title: "HTML",
|
||||
func: async () => {
|
||||
await exportNoteAs("html");
|
||||
await save("html");
|
||||
},
|
||||
icon: "language-html5",
|
||||
desc: "View in any web browser & html reader",
|
||||
@@ -259,9 +250,11 @@ const ExportNotesSheet = ({
|
||||
<>
|
||||
<ActivityIndicator />
|
||||
<Paragraph>
|
||||
{`${
|
||||
status ? `${status})` : `Exporting notes`
|
||||
}... Please wait`}
|
||||
{ids.length === 1
|
||||
? "Exporting note... Please wait"
|
||||
: `Exporting notes${
|
||||
status ? ` (${status})` : ``
|
||||
}... Please wait`}
|
||||
</Paragraph>
|
||||
</>
|
||||
) : (
|
||||
|
||||
@@ -141,7 +141,7 @@ Logged in: ${user ? "yes" : "no"}`,
|
||||
defaultValue={title.current}
|
||||
style={{
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.border,
|
||||
borderColor: colors.secondary.background,
|
||||
borderRadius: 5,
|
||||
padding: 12,
|
||||
fontFamily: "OpenSans-Regular",
|
||||
@@ -178,7 +178,7 @@ For example:
|
||||
}}
|
||||
style={{
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.border,
|
||||
borderColor: colors.secondary.background,
|
||||
borderRadius: 5,
|
||||
padding: 12,
|
||||
fontFamily: "OpenSans-Regular",
|
||||
|
||||
@@ -1,375 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {
|
||||
ContentBlock,
|
||||
Note,
|
||||
VirtualizedGrouping,
|
||||
createInternalLink
|
||||
} from "@notesnook/core";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { TextInput, View } from "react-native";
|
||||
import { FlatList } from "react-native-actions-sheet";
|
||||
import { db } from "../../../common/database";
|
||||
import { useDBItem } from "../../../hooks/use-db-item";
|
||||
import { presentSheet } from "../../../services/event-manager";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { Button } from "../../ui/button";
|
||||
import Input from "../../ui/input";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import type { LinkAttributes } from "@notesnook/editor/dist/extensions/link";
|
||||
import { editorController } from "../../../screens/editor/tiptap/utils";
|
||||
|
||||
const ListNoteItem = ({
|
||||
id,
|
||||
items,
|
||||
onSelectNote
|
||||
}: {
|
||||
id: any;
|
||||
items: VirtualizedGrouping<Note> | undefined;
|
||||
onSelectNote: any;
|
||||
}) => {
|
||||
const [item] = useDBItem(id, "note", items);
|
||||
return (
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
if (!item) return;
|
||||
onSelectNote(item as Note);
|
||||
}}
|
||||
type={"transparent"}
|
||||
style={{
|
||||
paddingVertical: 12,
|
||||
flexDirection: "row",
|
||||
width: "100%",
|
||||
justifyContent: "flex-start",
|
||||
height: 50
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
<Paragraph numberOfLines={1}>{item?.title}</Paragraph>
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
const ListBlockItem = ({
|
||||
item,
|
||||
onSelectBlock
|
||||
}: {
|
||||
item: ContentBlock;
|
||||
onSelectBlock: any;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
return (
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
onSelectBlock(item);
|
||||
}}
|
||||
type={"transparent"}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
width: "100%",
|
||||
justifyContent: "flex-start",
|
||||
minHeight: 45
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
width: "100%",
|
||||
columnGap: 10,
|
||||
alignItems: "flex-start",
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.primary.border,
|
||||
paddingVertical: 5,
|
||||
justifyContent: "space-between"
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
style={{
|
||||
flexShrink: 1
|
||||
}}
|
||||
>
|
||||
{item?.content.length > 200
|
||||
? item?.content.slice(0, 200) + "..."
|
||||
: !item.content || item.content.trim() === ""
|
||||
? "(Empty block)"
|
||||
: item.content}
|
||||
</Paragraph>
|
||||
|
||||
<View
|
||||
style={{
|
||||
borderRadius: 5,
|
||||
backgroundColor: colors.secondary.background,
|
||||
height: 25,
|
||||
minWidth: 25,
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<Paragraph color={colors.secondary.paragraph} size={SIZE.xs}>
|
||||
{item.type.toUpperCase()}
|
||||
</Paragraph>
|
||||
</View>
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
export default function LinkNote(props: {
|
||||
attributes: LinkAttributes;
|
||||
resolverId: string;
|
||||
onLinkCreated: () => void;
|
||||
close?: (ctx?: string) => void;
|
||||
}) {
|
||||
const { colors } = useThemeColors();
|
||||
const query = useRef<string>();
|
||||
const [notes, setNotes] = useState<VirtualizedGrouping<Note>>();
|
||||
const nodesRef = useRef<ContentBlock[]>([]);
|
||||
const [nodes, setNodes] = useState<ContentBlock[]>([]);
|
||||
|
||||
const inputRef = useRef<TextInput>();
|
||||
|
||||
const [selectedNote, setSelectedNote] = useState<Note>();
|
||||
const [selectedNodeId, setSelectedNodeId] = useState<string>();
|
||||
|
||||
useEffect(() => {
|
||||
db.notes.all.sorted(db.settings.getGroupOptions("notes")).then((notes) => {
|
||||
setNotes(notes);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onChange = async (value: string) => {
|
||||
query.current = value;
|
||||
if (!selectedNote) {
|
||||
const notes = await db.lookup.notes(value).sorted();
|
||||
setNotes(notes);
|
||||
} else {
|
||||
if (value.startsWith("#")) {
|
||||
const headingNodes = nodesRef.current.filter((n) =>
|
||||
n.type.match(/(h1|h2|h3|h4|h5|h6)/g)
|
||||
);
|
||||
setNodes(
|
||||
headingNodes.filter((n) => n.content.includes(value.slice(1)))
|
||||
);
|
||||
} else {
|
||||
setNodes(nodesRef.current.filter((n) => n.content.includes(value)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onCreateLink = (blockId?: string) => {
|
||||
if (!selectedNote) return;
|
||||
const link = createInternalLink(
|
||||
"note",
|
||||
selectedNote.id,
|
||||
blockId
|
||||
? {
|
||||
blockId: blockId
|
||||
}
|
||||
: undefined
|
||||
);
|
||||
editorController.current.commands.createInternalLink(
|
||||
{
|
||||
href: link,
|
||||
title: selectedNote.title
|
||||
},
|
||||
props.resolverId
|
||||
);
|
||||
};
|
||||
|
||||
const onSelectNote = async (note: Note) => {
|
||||
setSelectedNote(note);
|
||||
inputRef.current?.clear();
|
||||
setTimeout(async () => {
|
||||
nodesRef.current = await db.notes.contentBlocks(note.id);
|
||||
setNodes(nodesRef.current);
|
||||
});
|
||||
// Fetch and set note's nodes.
|
||||
};
|
||||
|
||||
const onSelectBlock = (block: ContentBlock) => {
|
||||
onCreateLink(block.id);
|
||||
props.onLinkCreated();
|
||||
props.close?.();
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
minHeight: 400,
|
||||
maxHeight: "100%"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
alignItems: "flex-start",
|
||||
gap: 10
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
placeholder={
|
||||
selectedNote
|
||||
? "Search a section of a note to link to"
|
||||
: "Search a note to link to"
|
||||
}
|
||||
containerStyle={{
|
||||
width: "100%"
|
||||
}}
|
||||
marginBottom={0}
|
||||
onChangeText={(value) => {
|
||||
onChange(value);
|
||||
}}
|
||||
/>
|
||||
|
||||
{selectedNote ? (
|
||||
<View
|
||||
style={{
|
||||
gap: 10
|
||||
}}
|
||||
>
|
||||
<Paragraph color={colors.secondary.paragraph} size={SIZE.xs}>
|
||||
SELECTED NOTE
|
||||
</Paragraph>
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
setSelectedNote(undefined);
|
||||
setSelectedNodeId(undefined);
|
||||
setNodes([]);
|
||||
}}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
width: "100%",
|
||||
justifyContent: "flex-start",
|
||||
height: 45,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.accent,
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
type="secondaryAccented"
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<Paragraph numberOfLines={1}>{selectedNote?.title}</Paragraph>
|
||||
|
||||
<Paragraph color={colors.secondary.paragraph} size={SIZE.xs}>
|
||||
Tap to deselect
|
||||
</Paragraph>
|
||||
</View>
|
||||
</Pressable>
|
||||
|
||||
{nodes?.length > 0 ? (
|
||||
<Paragraph
|
||||
style={{
|
||||
marginBottom: 12
|
||||
}}
|
||||
color={colors.secondary.paragraph}
|
||||
size={SIZE.xs}
|
||||
>
|
||||
LINK TO A SECTION
|
||||
</Paragraph>
|
||||
) : null}
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
{selectedNote ? (
|
||||
<FlatList
|
||||
renderItem={({ item, index }) => (
|
||||
<ListBlockItem item={item} onSelectBlock={onSelectBlock} />
|
||||
)}
|
||||
style={{
|
||||
marginTop: 10
|
||||
}}
|
||||
windowSize={3}
|
||||
keyExtractor={(item) => item.id}
|
||||
data={nodes}
|
||||
/>
|
||||
) : (
|
||||
<FlatList
|
||||
renderItem={({ item, index }: any) => (
|
||||
<ListNoteItem
|
||||
id={index}
|
||||
items={notes}
|
||||
onSelectNote={onSelectNote}
|
||||
/>
|
||||
)}
|
||||
style={{
|
||||
marginTop: 10
|
||||
}}
|
||||
windowSize={3}
|
||||
data={notes?.placeholders}
|
||||
/>
|
||||
)}
|
||||
|
||||
{selectedNote ? (
|
||||
<Button
|
||||
style={{
|
||||
marginTop: 10
|
||||
}}
|
||||
title="Create link"
|
||||
type="accent"
|
||||
width="100%"
|
||||
onPress={() => {
|
||||
onCreateLink();
|
||||
props.onLinkCreated();
|
||||
props.close?.();
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
LinkNote.present = (attributes: LinkAttributes, resolverId: string) => {
|
||||
let didCreateLink = false;
|
||||
presentSheet({
|
||||
component: (ref, close) => (
|
||||
<LinkNote
|
||||
attributes={attributes}
|
||||
resolverId={resolverId}
|
||||
onLinkCreated={() => {
|
||||
didCreateLink = true;
|
||||
}}
|
||||
close={close}
|
||||
/>
|
||||
),
|
||||
onClose: () => {
|
||||
if (!didCreateLink) {
|
||||
editorController?.current.commands.dismissCreateInternalLinkRequest(
|
||||
resolverId
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -159,14 +159,13 @@ export default function Migrate() {
|
||||
}}
|
||||
>
|
||||
Migrating database{progress ? `(${progress?.collection})` : null}
|
||||
{progress ? `(${progress.current}/${progress.total}) ` : null}
|
||||
... please wait
|
||||
{progress ? `(${progress.current}/${progress.total}) ` : null}...
|
||||
please wait
|
||||
</Paragraph>
|
||||
|
||||
<View
|
||||
style={{
|
||||
width: 200,
|
||||
alignSelf: "center"
|
||||
width: 200
|
||||
}}
|
||||
>
|
||||
<ProgressBarComponent
|
||||
|
||||
@@ -1,344 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { Notebook, VirtualizedGrouping } from "@notesnook/core";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback } from "react";
|
||||
import { Text, View } from "react-native";
|
||||
import { FlatList } from "react-native-actions-sheet";
|
||||
import create from "zustand";
|
||||
import { db } from "../../../common/database";
|
||||
import { useNotebook } from "../../../hooks/use-notebook";
|
||||
import { eSendEvent, presentSheet } from "../../../services/event-manager";
|
||||
import {
|
||||
useNotebookStore,
|
||||
useNotebooks
|
||||
} from "../../../stores/use-notebook-store";
|
||||
import { eOnNotebookUpdated } from "../../../utils/events";
|
||||
import {
|
||||
findRootNotebookId,
|
||||
getParentNotebookId
|
||||
} from "../../../utils/notebooks";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { Dialog } from "../../dialog";
|
||||
import DialogHeader from "../../dialog/dialog-header";
|
||||
import { presentDialog } from "../../dialog/functions";
|
||||
import SheetProvider from "../../sheet-provider";
|
||||
import { Button } from "../../ui/button";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { AddNotebookSheet } from "../add-notebook";
|
||||
|
||||
const useNotebookExpandedStore = create<{
|
||||
expanded: {
|
||||
[id: string]: boolean;
|
||||
};
|
||||
setExpanded: (id: string) => void;
|
||||
}>((set, get) => ({
|
||||
expanded: {},
|
||||
setExpanded(id: string) {
|
||||
set({
|
||||
expanded: {
|
||||
...get().expanded,
|
||||
[id]: !get().expanded[id]
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
export const MoveNotebookSheet = ({
|
||||
selectedNotebooks,
|
||||
close
|
||||
}: {
|
||||
selectedNotebooks: Notebook[];
|
||||
close?: () => void;
|
||||
}) => {
|
||||
const [notebooks] = useNotebooks();
|
||||
const { colors } = useThemeColors();
|
||||
const renderItem = useCallback(
|
||||
({ index }: { index: number }) => {
|
||||
return (
|
||||
<NotebookItem
|
||||
id={index}
|
||||
items={notebooks}
|
||||
level={0}
|
||||
selectedNotebooks={selectedNotebooks}
|
||||
onPress={async (selectedNotebook) => {
|
||||
presentDialog({
|
||||
title: `Move ${
|
||||
selectedNotebooks.length > 1
|
||||
? selectedNotebooks.length + " notebooks"
|
||||
: selectedNotebooks[0].title
|
||||
}`,
|
||||
paragraph: `Are you sure you want to move ${
|
||||
selectedNotebooks.length > 1
|
||||
? selectedNotebooks.length + " notebooks"
|
||||
: selectedNotebooks[0].title
|
||||
} to ${selectedNotebook.title}?`,
|
||||
positiveText: "Move",
|
||||
positivePress: async () => {
|
||||
for (const notebook of selectedNotebooks) {
|
||||
const parent = await getParentNotebookId(notebook.id);
|
||||
const root = await findRootNotebookId(notebook.id);
|
||||
|
||||
if (selectedNotebook.id === notebook.id) continue;
|
||||
|
||||
if (root !== notebook.id) {
|
||||
await db.relations.unlink(
|
||||
{
|
||||
type: "notebook",
|
||||
id: parent
|
||||
},
|
||||
notebook
|
||||
);
|
||||
eSendEvent(eOnNotebookUpdated, parent);
|
||||
}
|
||||
|
||||
await db.relations.add(selectedNotebook, notebook);
|
||||
eSendEvent(eOnNotebookUpdated, selectedNotebook.id);
|
||||
eSendEvent(eOnNotebookUpdated, notebook.id);
|
||||
}
|
||||
useNotebookStore.getState().refresh();
|
||||
close?.();
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[selectedNotebooks, notebooks, close]
|
||||
);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<SheetProvider context="move-notebook" />
|
||||
<Dialog context="move-notebook" />
|
||||
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
<DialogHeader
|
||||
title={`Moving ${
|
||||
selectedNotebooks.length > 1
|
||||
? selectedNotebooks.length + " notebooks"
|
||||
: selectedNotebooks[0].title
|
||||
}`}
|
||||
paragraph={"Select the notebook you want to move this notebook to."}
|
||||
/>
|
||||
</View>
|
||||
<Seperator />
|
||||
|
||||
<FlatList
|
||||
data={notebooks?.placeholders}
|
||||
renderItem={renderItem}
|
||||
windowSize={1}
|
||||
ListHeaderComponent={
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
title="Move to top"
|
||||
style={{
|
||||
alignSelf: "flex-start",
|
||||
width: "100%",
|
||||
justifyContent: "space-between"
|
||||
}}
|
||||
icon="arrow-up-bold"
|
||||
iconPosition="right"
|
||||
type="secondaryAccented"
|
||||
onPress={async () => {
|
||||
for (const notebook of selectedNotebooks) {
|
||||
const parent = await getParentNotebookId(notebook.id);
|
||||
const root = await findRootNotebookId(notebook.id);
|
||||
if (root !== notebook.id) {
|
||||
await db.relations.unlink(
|
||||
{
|
||||
type: "notebook",
|
||||
id: parent
|
||||
},
|
||||
notebook
|
||||
);
|
||||
eSendEvent(eOnNotebookUpdated, parent);
|
||||
eSendEvent(eOnNotebookUpdated, notebook.id);
|
||||
}
|
||||
}
|
||||
useNotebookStore.getState().refresh();
|
||||
close?.();
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: 200
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: colors.secondary.icon
|
||||
}}
|
||||
>
|
||||
No notebooks
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const NotebookItem = ({
|
||||
id,
|
||||
onPress,
|
||||
items,
|
||||
level = 0,
|
||||
selectedNotebooks
|
||||
}: {
|
||||
id: string | number;
|
||||
level?: number;
|
||||
items?: VirtualizedGrouping<Notebook>;
|
||||
onPress: (item: Notebook) => void;
|
||||
selectedNotebooks: Notebook[];
|
||||
}) => {
|
||||
const { nestedNotebooks, notebook } = useNotebook(id, items, true);
|
||||
|
||||
const isExpanded = useNotebookExpandedStore((state) =>
|
||||
!notebook ? false : state.expanded[notebook.id]
|
||||
);
|
||||
const { colors } = useThemeColors();
|
||||
|
||||
return selectedNotebooks.find(
|
||||
(n) => n.id === notebook?.id
|
||||
) ? null : !notebook ? (
|
||||
<View
|
||||
style={{
|
||||
height: 45
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
minHeight: 45,
|
||||
borderRadius: 0
|
||||
}}
|
||||
>
|
||||
<Pressable
|
||||
onPress={() => onPress(notebook)}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
paddingHorizontal: 12,
|
||||
height: 45
|
||||
}}
|
||||
>
|
||||
{nestedNotebooks?.placeholders.length ? (
|
||||
<IconButton
|
||||
name={isExpanded ? "chevron-down" : "chevron-right"}
|
||||
color={colors.primary.icon}
|
||||
size={20}
|
||||
onPress={() => {
|
||||
if (!notebook) return;
|
||||
useNotebookExpandedStore.getState().setExpanded(notebook.id);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
width: 35,
|
||||
height: 30,
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
flexGrow: 1,
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
color: colors.primary.paragraph,
|
||||
fontSize: 15
|
||||
}}
|
||||
>
|
||||
{notebook.title}
|
||||
</Paragraph>
|
||||
|
||||
<IconButton
|
||||
name="plus"
|
||||
onPress={() => {
|
||||
if (!notebook) return;
|
||||
AddNotebookSheet.present(
|
||||
undefined,
|
||||
notebook,
|
||||
"move-notebooks",
|
||||
undefined,
|
||||
false
|
||||
);
|
||||
}}
|
||||
size={SIZE.lg}
|
||||
/>
|
||||
</View>
|
||||
</Pressable>
|
||||
|
||||
{nestedNotebooks?.placeholders?.length && isExpanded ? (
|
||||
<View
|
||||
style={{
|
||||
paddingLeft: level + 1 > 0 && level + 1 < 5 ? 15 : 0,
|
||||
marginTop: 5
|
||||
}}
|
||||
>
|
||||
{nestedNotebooks.placeholders.map((item, index) => (
|
||||
<NotebookItem
|
||||
key={notebook?.id + index}
|
||||
id={index}
|
||||
onPress={onPress}
|
||||
level={level + 1}
|
||||
items={nestedNotebooks}
|
||||
selectedNotebooks={selectedNotebooks}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
MoveNotebookSheet.present = async (notebooks: Notebook[]) => {
|
||||
presentSheet({
|
||||
component: (ref, close) => (
|
||||
<MoveNotebookSheet selectedNotebooks={notebooks} close={close} />
|
||||
),
|
||||
keyboardHandlerDisabled: true
|
||||
});
|
||||
};
|
||||
@@ -20,8 +20,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { VirtualizedGrouping } from "@notesnook/core";
|
||||
import { Note, Notebook } from "@notesnook/core/dist/types";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { RefObject, useEffect, useRef, useState } from "react";
|
||||
import { ActivityIndicator, TextInput, View } from "react-native";
|
||||
import React, { RefObject, useEffect, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { ActionSheetRef } from "react-native-actions-sheet";
|
||||
import { FlashList } from "react-native-actions-sheet/dist/src/views/FlashList";
|
||||
import { db } from "../../../common/database";
|
||||
@@ -35,7 +35,6 @@ import { Dialog } from "../../dialog";
|
||||
import DialogHeader from "../../dialog/dialog-header";
|
||||
import { Button } from "../../ui/button";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import Input from "../../ui/input";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
@@ -51,60 +50,39 @@ export const MoveNotes = ({
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const currentNotebook = notebook;
|
||||
const inputRef = useRef<TextInput>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const selectionCount = useItemSelectionStore(
|
||||
(state) =>
|
||||
Object.keys(state.selection).filter(
|
||||
(k) =>
|
||||
state.selection?.[k] === "selected" ||
|
||||
state.selection[k] === "deselected"
|
||||
state.initialState?.[k] !== "selected" &&
|
||||
state.selection[k] !== "deselected"
|
||||
)?.length > 0
|
||||
);
|
||||
|
||||
const [notes, setNotes] = useState<VirtualizedGrouping<Note>>();
|
||||
|
||||
const loadNotes = React.useCallback(
|
||||
async (query?: string) => {
|
||||
setLoading(true);
|
||||
const notes = query
|
||||
? db.lookup.notes(query).sorted()
|
||||
: db.notes?.all.sorted(db.settings.getGroupOptions("notes") as any);
|
||||
|
||||
notes
|
||||
.then(async (notes) => {
|
||||
await notes.item(0);
|
||||
setNotes(notes);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
|
||||
db.relations
|
||||
.from(currentNotebook, "note")
|
||||
.get()
|
||||
.then((existingNotes) => {
|
||||
const selection: { [name: string]: any } = {};
|
||||
existingNotes.forEach((rel) => {
|
||||
selection[rel.toId] = "selected";
|
||||
});
|
||||
useItemSelectionStore.setState({
|
||||
selection: selection,
|
||||
initialState: selection
|
||||
});
|
||||
});
|
||||
},
|
||||
[currentNotebook]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
loadNotes();
|
||||
db.notes?.all.sorted(db.settings.getGroupOptions("notes")).then((notes) => {
|
||||
setNotes(notes);
|
||||
});
|
||||
db.relations
|
||||
.from(currentNotebook, "note")
|
||||
.get()
|
||||
.then((existingNotes) => {
|
||||
const selection: { [name: string]: any } = {};
|
||||
existingNotes.forEach((rel) => {
|
||||
selection[rel.toId] = "selected";
|
||||
});
|
||||
useItemSelectionStore.setState({
|
||||
selection: selection,
|
||||
initialState: selection
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
useItemSelectionStore.getState().reset();
|
||||
};
|
||||
}, [currentNotebook, loadNotes]);
|
||||
}, [currentNotebook]);
|
||||
|
||||
const renderItem = React.useCallback(
|
||||
({ index }: { item: boolean; index: number }) => {
|
||||
@@ -118,33 +96,19 @@ export const MoveNotes = ({
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
maxHeight: "100%",
|
||||
height: "100%"
|
||||
height: notes?.placeholders.length
|
||||
? 50 * (notes?.placeholders.length + 2)
|
||||
: 300
|
||||
}}
|
||||
>
|
||||
<Dialog context="local" />
|
||||
|
||||
<DialogHeader
|
||||
title={`Add notes to ${currentNotebook.title}`}
|
||||
paragraph={"Select the notes you want to move to this Notebook."}
|
||||
paragraph={"Select the topic in which you would like to move notes."}
|
||||
/>
|
||||
<Seperator />
|
||||
|
||||
<Input
|
||||
button={{
|
||||
icon: "magnify",
|
||||
color: colors.primary.accent,
|
||||
size: SIZE.lg,
|
||||
onPress: () => {}
|
||||
}}
|
||||
testID="search-input"
|
||||
fwdRef={inputRef}
|
||||
autoCapitalize="none"
|
||||
onChangeText={(v) => {
|
||||
loadNotes(v && v.trim() === "" ? undefined : v.trim());
|
||||
}}
|
||||
placeholder="Search a note"
|
||||
/>
|
||||
|
||||
<FlashList
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
@@ -154,17 +118,13 @@ export const MoveNotes = ({
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator size="large" color={colors.primary.accent} />
|
||||
) : (
|
||||
<Paragraph color={colors.secondary.paragraph}>
|
||||
No notes to show
|
||||
</Paragraph>
|
||||
)}
|
||||
<Paragraph color={colors.secondary.paragraph}>
|
||||
No notes to show
|
||||
</Paragraph>
|
||||
</View>
|
||||
}
|
||||
estimatedItemSize={50}
|
||||
data={loading ? [] : notes?.placeholders}
|
||||
data={notes?.placeholders}
|
||||
renderItem={renderItem}
|
||||
/>
|
||||
|
||||
@@ -175,12 +135,6 @@ export const MoveNotes = ({
|
||||
currentNotebook.id,
|
||||
...useItemSelectionStore.getState().getSelectedItemIds()
|
||||
);
|
||||
|
||||
await db.notes?.removeFromNotebook(
|
||||
currentNotebook.id,
|
||||
...useItemSelectionStore.getState().getDeselectedItemIds()
|
||||
);
|
||||
|
||||
updateNotebook(currentNotebook.id);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
fwdRef?.current?.hide();
|
||||
@@ -207,12 +161,11 @@ const SelectableNoteItem = React.memo(
|
||||
const selected = useItemSelectionStore((state) =>
|
||||
item?.id ? state.selection[item.id] === "selected" : false
|
||||
);
|
||||
|
||||
const exists = useItemSelectionStore((state) =>
|
||||
item?.id ? state.initialState[item.id] === "selected" : false
|
||||
);
|
||||
|
||||
return (
|
||||
return exists ? null : (
|
||||
<Pressable
|
||||
testID="listitem.select"
|
||||
onPress={() => {
|
||||
@@ -252,14 +205,8 @@ const SelectableNoteItem = React.memo(
|
||||
? "check-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
}
|
||||
type="plain"
|
||||
color={
|
||||
selected
|
||||
? colors.selected.icon
|
||||
: exists && !selected
|
||||
? colors.static.red
|
||||
: colors.primary.icon
|
||||
}
|
||||
type="selected"
|
||||
color={selected ? colors.selected.icon : colors.primary.icon}
|
||||
/>
|
||||
|
||||
<View
|
||||
|
||||
@@ -17,14 +17,13 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { Platform, View } from "react-native";
|
||||
import { ScrollView } from "react-native-actions-sheet";
|
||||
import { getVersion } from "react-native-device-info";
|
||||
import { features } from "../../../features";
|
||||
import { eSendEvent, presentSheet } from "../../../services/event-manager";
|
||||
import SettingsService from "../../../services/settings";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { eCloseSheet } from "../../../utils/events";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { Button } from "../../ui/button";
|
||||
@@ -37,13 +36,7 @@ export type FeatureType = {
|
||||
platform?: "ios" | "android";
|
||||
};
|
||||
|
||||
const NewFeature = ({
|
||||
features,
|
||||
version
|
||||
}: {
|
||||
features: FeatureType[];
|
||||
version?: string | null;
|
||||
}) => {
|
||||
const NewFeature = ({ features }: { features: FeatureType[] }) => {
|
||||
const { colors } = useThemeColors();
|
||||
|
||||
return (
|
||||
@@ -51,33 +44,30 @@ const NewFeature = ({
|
||||
style={{
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12,
|
||||
paddingTop: 12,
|
||||
maxHeight: "100%"
|
||||
paddingTop: 12
|
||||
}}
|
||||
>
|
||||
<Heading color={colors.secondary.heading} size={SIZE.md}>
|
||||
{!version ? "New version " : `v${version} `}Highlights 🎉
|
||||
New Version Highlights 🎉
|
||||
</Heading>
|
||||
|
||||
<Seperator />
|
||||
|
||||
<ScrollView>
|
||||
{features.map((item) => (
|
||||
<View
|
||||
key={item.title}
|
||||
style={{
|
||||
backgroundColor: colors.secondary.background,
|
||||
padding: 12,
|
||||
borderRadius: 10,
|
||||
width: "100%",
|
||||
marginBottom: 10
|
||||
}}
|
||||
>
|
||||
<Heading size={SIZE.lg - 2}>{item.title}</Heading>
|
||||
<Paragraph selectable>{item.body}</Paragraph>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
{features.map((item) => (
|
||||
<View
|
||||
key={item.title}
|
||||
style={{
|
||||
backgroundColor: colors.secondary.background,
|
||||
padding: 12,
|
||||
borderRadius: 10,
|
||||
width: "100%",
|
||||
marginBottom: 10
|
||||
}}
|
||||
>
|
||||
<Heading size={SIZE.lg - 2}>{item.title}</Heading>
|
||||
<Paragraph>{item.body}</Paragraph>
|
||||
</View>
|
||||
))}
|
||||
<Seperator />
|
||||
|
||||
<Button
|
||||
@@ -118,8 +108,7 @@ NewFeature.present = () => {
|
||||
);
|
||||
if (_features.length === 0) return;
|
||||
presentSheet({
|
||||
component: <NewFeature features={features} version={version} />,
|
||||
disableClosing: true
|
||||
component: <NewFeature features={features} />
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -44,8 +44,6 @@ import { Pressable } from "../../ui/pressable";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { AddNotebookSheet } from "../add-notebook";
|
||||
import Sort from "../sort";
|
||||
import { MoveNotebookSheet } from "../move-notebook";
|
||||
import { db } from "../../../common/database";
|
||||
|
||||
const useItemSelectionStore = createItemSelectionStore(true, false);
|
||||
|
||||
@@ -139,7 +137,7 @@ export const NotebookSheet = () => {
|
||||
currentItem.current = nextRoot;
|
||||
const snapPoint = NotebookSheetConfig.get({
|
||||
type: "notebook",
|
||||
id: focusedRouteId as string
|
||||
id: nextRoot as string
|
||||
});
|
||||
|
||||
if (ref.current?.isOpen()) {
|
||||
@@ -203,47 +201,6 @@ export const NotebookSheet = () => {
|
||||
backgroundInteractionEnabled
|
||||
gestureEnabled
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: 24 + normalize(50),
|
||||
marginTop: -80
|
||||
}}
|
||||
>
|
||||
<Pressable
|
||||
testID={notesnook.buttons.add}
|
||||
type="secondary"
|
||||
onPress={() => {
|
||||
if (!notebook) return;
|
||||
AddNotebookSheet.present(
|
||||
undefined,
|
||||
notebook,
|
||||
undefined,
|
||||
undefined,
|
||||
false
|
||||
);
|
||||
}}
|
||||
style={{
|
||||
borderRadius: 100
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: normalize(50),
|
||||
width: normalize(50)
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name="notebook-plus"
|
||||
color={colors.primary.accent}
|
||||
size={SIZE.xxl}
|
||||
/>
|
||||
</View>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={{
|
||||
position: "absolute",
|
||||
@@ -263,8 +220,8 @@ export const NotebookSheet = () => {
|
||||
style={{
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: normalize(50),
|
||||
width: normalize(50)
|
||||
height: normalize(60),
|
||||
width: normalize(60)
|
||||
}}
|
||||
>
|
||||
<Icon name="plus" color="white" size={SIZE.xxl} />
|
||||
@@ -321,26 +278,6 @@ export const NotebookSheet = () => {
|
||||
size={22}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
style={{
|
||||
marginLeft: 10,
|
||||
width: 40 * fontScale,
|
||||
height: 40 * fontScale
|
||||
}}
|
||||
onPress={async () => {
|
||||
const ids = useItemSelectionStore
|
||||
.getState()
|
||||
.getSelectedItemIds();
|
||||
const notebooks = await db.notebooks.all.items(ids);
|
||||
MoveNotebookSheet.present(notebooks);
|
||||
}}
|
||||
color={colors.primary.icon}
|
||||
tooltipText="Clear selection"
|
||||
tooltipPosition={1}
|
||||
name="arrow-right-bold-box-outline"
|
||||
size={22}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
style={{
|
||||
marginLeft: 10,
|
||||
@@ -382,6 +319,20 @@ export const NotebookSheet = () => {
|
||||
height: 40 * fontScale
|
||||
}}
|
||||
/>
|
||||
<IconButton
|
||||
name="plus"
|
||||
onPress={() => {
|
||||
if (!notebook) return;
|
||||
AddNotebookSheet.present(undefined, notebook, undefined);
|
||||
}}
|
||||
testID="add-notebook-button"
|
||||
color={colors.primary.icon}
|
||||
size={22}
|
||||
style={{
|
||||
width: 40 * fontScale,
|
||||
height: 40 * fontScale
|
||||
}}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
name={collapsed ? "chevron-up" : "chevron-down"}
|
||||
|
||||
@@ -357,9 +357,7 @@ const PublishNoteSheet = ({
|
||||
}}
|
||||
onPress={async () => {
|
||||
try {
|
||||
await openLinkInBrowser(
|
||||
"https://help.notesnook.com/publish-notes-with-monographs"
|
||||
);
|
||||
await openLinkInBrowser("https://docs.notesnook.com/monographs/");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
@@ -1,528 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {
|
||||
InternalLink,
|
||||
TextSlice,
|
||||
VirtualizedGrouping,
|
||||
createInternalLink,
|
||||
highlightInternalLinks
|
||||
} from "@notesnook/core";
|
||||
import { ContentBlock, ItemReference, Note } from "@notesnook/core/dist/types";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||
import { ActivityIndicator, View } from "react-native";
|
||||
import { FlashList } from "react-native-actions-sheet/dist/src/views/FlashList";
|
||||
import create from "zustand";
|
||||
import { db } from "../../../common/database";
|
||||
import { useDBItem, useNoteLocked } from "../../../hooks/use-db-item";
|
||||
import { eSendEvent, presentSheet } from "../../../services/event-manager";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { eOnLoadNote } from "../../../utils/events";
|
||||
import { tabBarRef } from "../../../utils/global-refs";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import SheetProvider from "../../sheet-provider";
|
||||
import { Button } from "../../ui/button";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
|
||||
export const useExpandedStore = create<{
|
||||
expanded: {
|
||||
[id: string]: boolean;
|
||||
};
|
||||
setExpanded: (id: string) => void;
|
||||
}>((set, get) => ({
|
||||
expanded: {},
|
||||
setExpanded(id: string) {
|
||||
set({
|
||||
expanded: {
|
||||
...get().expanded,
|
||||
[id]: !get().expanded[id]
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
const ListBlockItem = ({
|
||||
item,
|
||||
onSelectBlock
|
||||
}: {
|
||||
item: ContentBlock;
|
||||
onSelectBlock: () => void;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
return (
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
onSelectBlock();
|
||||
}}
|
||||
type={"transparent"}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
width: "100%",
|
||||
paddingLeft: 35,
|
||||
justifyContent: "flex-start",
|
||||
minHeight: 45,
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
width: "100%",
|
||||
columnGap: 10,
|
||||
justifyContent: "space-between"
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
style={{
|
||||
flexShrink: 1,
|
||||
marginTop: 2
|
||||
}}
|
||||
>
|
||||
{item?.content.length > 200
|
||||
? item?.content.slice(0, 200) + "..."
|
||||
: !item.content || item.content.trim() === ""
|
||||
? "(Empty block)"
|
||||
: item.content}
|
||||
</Paragraph>
|
||||
|
||||
<View
|
||||
style={{
|
||||
borderRadius: 5,
|
||||
backgroundColor: colors.secondary.background,
|
||||
width: 25,
|
||||
height: 25,
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<Paragraph color={colors.secondary.paragraph} size={SIZE.xs}>
|
||||
{item.type.toUpperCase()}
|
||||
</Paragraph>
|
||||
</View>
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
const ListNoteInternalLink = ({
|
||||
link,
|
||||
onSelect
|
||||
}: {
|
||||
link: {
|
||||
blockId: string;
|
||||
highlightedText: [TextSlice, TextSlice, TextSlice][];
|
||||
};
|
||||
onSelect: () => void;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
return (
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
onSelect();
|
||||
}}
|
||||
type={"transparent"}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
width: "100%",
|
||||
paddingLeft: 35,
|
||||
justifyContent: "flex-start",
|
||||
minHeight: 45
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
rowGap: 10
|
||||
}}
|
||||
>
|
||||
{link.highlightedText.map((text) => (
|
||||
<Paragraph
|
||||
key={`root_${text[0].text}`}
|
||||
style={{
|
||||
flexShrink: 1,
|
||||
marginTop: 2,
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
>
|
||||
{text.map((slice) =>
|
||||
!slice.highlighted ? (
|
||||
slice.text
|
||||
) : (
|
||||
<Paragraph
|
||||
key={slice.text}
|
||||
color={colors.selected.accent}
|
||||
style={{
|
||||
textDecorationLine: "underline",
|
||||
textDecorationColor: colors.selected.accent
|
||||
}}
|
||||
>
|
||||
{slice.text}
|
||||
</Paragraph>
|
||||
)
|
||||
)}
|
||||
</Paragraph>
|
||||
))}
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
const ListNoteItem = ({
|
||||
id,
|
||||
items,
|
||||
onSelect,
|
||||
reference,
|
||||
internalLinks,
|
||||
listType
|
||||
}: {
|
||||
id: number;
|
||||
items: VirtualizedGrouping<Note> | undefined;
|
||||
onSelect: (item: Note, blockId?: string) => void;
|
||||
reference: Note;
|
||||
internalLinks: MutableRefObject<InternalLink<"note">[] | undefined>;
|
||||
listType: "linkedNotes" | "referencedIn";
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [item] = useDBItem(id, "note", items);
|
||||
const expanded = useExpandedStore((state) =>
|
||||
!item ? false : state.expanded[item.id]
|
||||
);
|
||||
const locked = useNoteLocked(item?.id);
|
||||
const [linkedBlocks, setLinkedBlocks] = useState<ContentBlock[]>([]);
|
||||
const [noteInternalLinks, setNoteInternalLinks] = useState<
|
||||
{
|
||||
blockId: string;
|
||||
highlightedText: [TextSlice, TextSlice, TextSlice][];
|
||||
}[]
|
||||
>([]);
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (item?.id && expanded) {
|
||||
(async () => {
|
||||
if (listType === "linkedNotes") {
|
||||
if (linkedBlocks.length) return;
|
||||
setLoading(true);
|
||||
if (!internalLinks.current) {
|
||||
internalLinks.current = await db.notes.internalLinks(reference.id);
|
||||
}
|
||||
const noteLinks = internalLinks.current.filter(
|
||||
(link) => link.id === item.id && link.params?.blockId
|
||||
);
|
||||
|
||||
if (noteLinks.length) {
|
||||
const blocks = await db.notes.contentBlocks(item.id);
|
||||
|
||||
setLinkedBlocks(
|
||||
blocks.filter((block) =>
|
||||
noteLinks.find((link) => block.id === link.params?.blockId)
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (noteInternalLinks.length) return;
|
||||
setLoading(true);
|
||||
|
||||
const blocks = await db.notes.contentBlocksWithLinks(item.id);
|
||||
setNoteInternalLinks(
|
||||
blocks
|
||||
.filter((block) =>
|
||||
block.content.includes(createInternalLink("note", reference.id))
|
||||
)
|
||||
.map((block) => {
|
||||
return {
|
||||
blockId: block?.id as string,
|
||||
highlightedText: highlightInternalLinks(
|
||||
block as ContentBlock,
|
||||
reference.id
|
||||
)
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
})();
|
||||
}
|
||||
}, [
|
||||
item?.id,
|
||||
expanded,
|
||||
linkedBlocks.length,
|
||||
internalLinks,
|
||||
reference.id,
|
||||
listType,
|
||||
noteInternalLinks.length
|
||||
]);
|
||||
console.log(noteInternalLinks);
|
||||
const renderBlock = React.useCallback(
|
||||
(block: ContentBlock) => (
|
||||
<ListBlockItem
|
||||
item={block}
|
||||
onSelectBlock={() => {
|
||||
if (!item) return;
|
||||
onSelect(item, block.id);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
[item, onSelect]
|
||||
);
|
||||
|
||||
const renderInternalLink = React.useCallback(
|
||||
(link: {
|
||||
blockId: string;
|
||||
highlightedText: [TextSlice, TextSlice, TextSlice][];
|
||||
}) => (
|
||||
<ListNoteInternalLink
|
||||
link={link}
|
||||
onSelect={() => {
|
||||
if (!item) return;
|
||||
onSelect(item, link.blockId);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
[item, onSelect]
|
||||
);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Pressable
|
||||
type={"plain"}
|
||||
onPress={() => {
|
||||
if (!item) return;
|
||||
onSelect(item as Note);
|
||||
}}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
width: "100%",
|
||||
height: 45
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
size={SIZE.xl}
|
||||
onPress={() => {
|
||||
if (!item?.id) return;
|
||||
useExpandedStore.getState().setExpanded(item?.id);
|
||||
}}
|
||||
top={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
right={0}
|
||||
style={{
|
||||
width: 35,
|
||||
height: 35
|
||||
}}
|
||||
name={expanded ? "chevron-down" : "chevron-right"}
|
||||
/>
|
||||
<Paragraph numberOfLines={1}>{item?.title}</Paragraph>
|
||||
</Pressable>
|
||||
|
||||
{expanded && !locked ? (
|
||||
<View
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator color={colors.primary.accent} size={SIZE.lg} />
|
||||
) : (
|
||||
<>
|
||||
{listType === "linkedNotes" ? (
|
||||
<>
|
||||
{linkedBlocks.length === 0 ? (
|
||||
<Paragraph color={colors.secondary.paragraph}>
|
||||
No blocks linked
|
||||
</Paragraph>
|
||||
) : (
|
||||
linkedBlocks.map(renderBlock)
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{noteInternalLinks.length === 0 ? (
|
||||
<Paragraph color={colors.secondary.paragraph}>
|
||||
No references found of this note
|
||||
</Paragraph>
|
||||
) : (
|
||||
noteInternalLinks.map(renderInternalLink)
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
type ReferencesListProps = {
|
||||
item: { id: string; type: string };
|
||||
close?: (ctx?: any) => void;
|
||||
};
|
||||
|
||||
export const ReferencesList = ({ item, close }: ReferencesListProps) => {
|
||||
const [tab, setTab] = useState(0);
|
||||
const updater = useRelationStore((state) => state.updater);
|
||||
const { colors } = useThemeColors();
|
||||
const [items, setItems] = useState<VirtualizedGrouping<Note>>();
|
||||
const hasNoRelations = !items || items?.placeholders?.length === 0;
|
||||
const internalLinks = useRef<InternalLink<"note">[]>();
|
||||
|
||||
useEffect(() => {
|
||||
db.relations?.[tab === 0 ? "from" : "to"]?.(
|
||||
{ id: item?.id, type: item?.type } as ItemReference,
|
||||
"note"
|
||||
)
|
||||
.selector.sorted({
|
||||
sortBy: "dateEdited",
|
||||
sortDirection: "desc"
|
||||
})
|
||||
.then((items) => {
|
||||
setItems(items);
|
||||
});
|
||||
}, [item?.id, item?.type, tab]);
|
||||
|
||||
const renderNote = React.useCallback(
|
||||
({ index }: any) => (
|
||||
<ListNoteItem
|
||||
id={index}
|
||||
items={items}
|
||||
onSelect={(note, blockId) => {
|
||||
console.log(note.id, blockId);
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: note,
|
||||
blockId: blockId
|
||||
});
|
||||
tabBarRef.current?.goToPage(1);
|
||||
close?.();
|
||||
}}
|
||||
reference={item as Note}
|
||||
internalLinks={internalLinks}
|
||||
listType={tab === 0 ? "linkedNotes" : "referencedIn"}
|
||||
/>
|
||||
),
|
||||
[items, item, tab, close]
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={{ height: "100%" }}>
|
||||
<SheetProvider context="local" />
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.primary.border
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
type={"plain"}
|
||||
title="Linked notes"
|
||||
style={{
|
||||
borderRadius: 0,
|
||||
borderWidth: 0,
|
||||
borderBottomWidth: 3,
|
||||
borderColor: tab === 0 ? colors.primary.accent : "transparent",
|
||||
height: 40,
|
||||
width: "50%"
|
||||
}}
|
||||
onPress={() => {
|
||||
setTab(0);
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
type={"plain"}
|
||||
title="Referenced in"
|
||||
style={{
|
||||
width: "50%",
|
||||
borderWidth: 0,
|
||||
borderRadius: 0,
|
||||
borderBottomWidth: 3,
|
||||
borderColor: tab === 1 ? colors.primary.accent : "transparent",
|
||||
height: 40
|
||||
}}
|
||||
onPress={() => {
|
||||
setTab(1);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{hasNoRelations ? (
|
||||
<View
|
||||
style={{
|
||||
height: "85%",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Paragraph color={colors.secondary.paragraph}>
|
||||
{tab === 1
|
||||
? "This note is not referenced in other notes."
|
||||
: "This note does not link to other notes."}
|
||||
</Paragraph>
|
||||
</View>
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
flex: 1,
|
||||
marginTop: 10
|
||||
}}
|
||||
>
|
||||
<FlashList
|
||||
bounces={false}
|
||||
data={items.placeholders}
|
||||
renderItem={renderNote}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
ReferencesList.present = ({
|
||||
reference
|
||||
}: {
|
||||
reference: { id: string; type: string };
|
||||
}) => {
|
||||
presentSheet({
|
||||
component: (ref, close, update) => (
|
||||
<ReferencesList item={reference} close={close} />
|
||||
),
|
||||
onClose: () => {
|
||||
useExpandedStore.setState({
|
||||
expanded: {}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -159,7 +159,7 @@ export default function ReminderNotify({
|
||||
? 160 * references?.placeholders?.length
|
||||
: 500,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: colors.primary.border,
|
||||
borderTopColor: colors.secondary.background,
|
||||
marginTop: 5,
|
||||
paddingTop: 5
|
||||
}}
|
||||
|
||||
@@ -48,7 +48,6 @@ import { Button } from "../../ui/button";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import SheetWrapper from "../../ui/sheet";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { useUserStore } from "../../../stores/use-user-store";
|
||||
|
||||
const RestoreDataSheet = () => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
@@ -184,7 +183,7 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
|
||||
title: "Encrypted backup",
|
||||
input: true,
|
||||
inputPlaceholder: "Password",
|
||||
paragraph: "Please enter password of this backup file",
|
||||
paragraph: "Please enter password of this backup file to restore it",
|
||||
positiveText: "Restore",
|
||||
secureTextEntry: true,
|
||||
onClose: () => {
|
||||
@@ -192,17 +191,10 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
|
||||
resolve(undefined);
|
||||
},
|
||||
negativeText: "Cancel",
|
||||
positivePress: async (password, isEncryptionKey) => {
|
||||
resolve({
|
||||
value: password,
|
||||
isEncryptionKey
|
||||
});
|
||||
positivePress: async (password) => {
|
||||
resolve(password);
|
||||
resolved = true;
|
||||
return true;
|
||||
},
|
||||
check: {
|
||||
info: "Use encryption key",
|
||||
type: "transparent"
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -242,11 +234,10 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const restoreBackup = async (backup, password, key) => {
|
||||
const restoreBackup = async (backup, password) => {
|
||||
await db.transaction(async () => {
|
||||
await db.backup.import(backup, password, key);
|
||||
await db.backup.import(backup, password);
|
||||
});
|
||||
await db.initCollections();
|
||||
refreshAllStores();
|
||||
ToastManager.show({
|
||||
heading: "Backup restored successfully.",
|
||||
@@ -291,7 +282,6 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
|
||||
|
||||
await db.transaction(async () => {
|
||||
let password;
|
||||
let key;
|
||||
console.log(
|
||||
`Found ${backupFiles?.length} files to restore from backup`
|
||||
);
|
||||
@@ -303,16 +293,10 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
|
||||
|
||||
if (parsed.encrypted && !password) {
|
||||
console.log("Backup is encrypted...", "requesting password");
|
||||
const { value, isEncryptionKey } = await withPassword();
|
||||
|
||||
if (isEncryptionKey) {
|
||||
key = value;
|
||||
} else {
|
||||
password = value;
|
||||
}
|
||||
if (!password && !key) throw new Error("Failed to decrypt backup");
|
||||
password = await withPassword();
|
||||
if (!password) throw new Error("Failed to decrypt backup");
|
||||
}
|
||||
await db.backup.import(parsed, password, key);
|
||||
await db.backup.import(parsed, password);
|
||||
console.log("Imported", path);
|
||||
}
|
||||
});
|
||||
@@ -344,19 +328,10 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
|
||||
async function restoreFromNNBackup(backup) {
|
||||
try {
|
||||
if (backup.data.iv && backup.data.salt) {
|
||||
const { value, isEncryptionKey } = await withPassword();
|
||||
|
||||
let key;
|
||||
let password;
|
||||
if (isEncryptionKey) {
|
||||
key = value;
|
||||
} else {
|
||||
password = value;
|
||||
}
|
||||
|
||||
if (key || password) {
|
||||
const password = await withPassword();
|
||||
if (password) {
|
||||
try {
|
||||
await restoreBackup(backup, password, key);
|
||||
await restoreBackup(backup, password);
|
||||
close();
|
||||
setRestoring(false);
|
||||
} catch (e) {
|
||||
@@ -384,20 +359,10 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
useUserStore.setState({
|
||||
disableAppLockRequests: true
|
||||
});
|
||||
console.log("disabled...");
|
||||
const file = await DocumentPicker.pickSingle({
|
||||
copyTo: "cachesDirectory"
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
useUserStore.setState({
|
||||
disableAppLockRequests: false
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
if (file.name.endsWith(".nnbackupz")) {
|
||||
setRestoring(true);
|
||||
await restoreFromZip(file.fileCopyUri, true);
|
||||
@@ -409,11 +374,6 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("error", e.stack);
|
||||
setTimeout(() => {
|
||||
useUserStore.setState({
|
||||
disableAppLockRequests: false
|
||||
});
|
||||
}, 1000);
|
||||
setRestoring(false);
|
||||
backupError(e);
|
||||
}
|
||||
@@ -430,7 +390,7 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
|
||||
borderRadius: 0,
|
||||
flexDirection: "row",
|
||||
borderBottomWidth: 0.5,
|
||||
borderBottomColor: colors.primary.border
|
||||
borderBottomColor: colors.secondary.background
|
||||
}}
|
||||
>
|
||||
<View
|
||||
|
||||
@@ -89,14 +89,10 @@ const Sort = ({ type, screen }) => {
|
||||
? groupOptions.groupBy === "abc" ||
|
||||
groupOptions.sortBy === "title"
|
||||
? "A - Z"
|
||||
: groupOptions.sortBy === "dueDate"
|
||||
? "Earliest first"
|
||||
: "Old - New"
|
||||
: groupOptions.groupBy === "abc" ||
|
||||
groupOptions.sortBy === "title"
|
||||
? "Z - A"
|
||||
: groupOptions.sortBy === "dueDate"
|
||||
? "Latest first"
|
||||
: "New - Old"
|
||||
}
|
||||
icon={
|
||||
@@ -127,7 +123,7 @@ const Sort = ({ type, screen }) => {
|
||||
justifyContent: "flex-start",
|
||||
flexWrap: "wrap",
|
||||
borderBottomWidth: isTopicSheet ? 0 : 1,
|
||||
borderBottomColor: colors.primary.border,
|
||||
borderBottomColor: colors.secondary.background,
|
||||
marginBottom: 12,
|
||||
paddingHorizontal: 12,
|
||||
paddingBottom: 12,
|
||||
@@ -147,7 +143,6 @@ const Sort = ({ type, screen }) => {
|
||||
/>
|
||||
) : (
|
||||
Object.keys(SORT).map((item) =>
|
||||
(item === "dueDate" && screen !== "Reminders") ||
|
||||
((screen !== "Tags" || screen !== "Reminders") &&
|
||||
item === "dateModified") ||
|
||||
((screen === "Tags" || screen === "Reminders") &&
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import { Pressable } from "../../ui/pressable";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { presentSheet } from "../../../services/event-manager";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import {
|
||||
editorController,
|
||||
editorState
|
||||
} from "../../../screens/editor/tiptap/utils";
|
||||
import { FlatList } from "react-native-actions-sheet";
|
||||
|
||||
type TableOfContentsItem = {
|
||||
level: number;
|
||||
title: string;
|
||||
id: string;
|
||||
top: number;
|
||||
isFocused?: boolean;
|
||||
};
|
||||
|
||||
interface TableOfContentsProps {
|
||||
toc: TableOfContentsItem[];
|
||||
close?: (ctx?: string | undefined) => void;
|
||||
}
|
||||
|
||||
const TableOfContentsItem: React.FC<{
|
||||
item: TableOfContentsItem;
|
||||
close?: (ctx?: string | undefined) => void;
|
||||
}> = ({ item, close }) => {
|
||||
const { colors } = useThemeColors();
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
style={{
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
flexDirection: "row",
|
||||
paddingLeft: item.level * 12,
|
||||
height: 45
|
||||
}}
|
||||
type={item.isFocused ? "selected" : "transparent"}
|
||||
onPress={() => {
|
||||
editorController.current.commands.scrollIntoViewById(item.id);
|
||||
close?.();
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
gap: 10
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name="checkbox-blank-circle"
|
||||
size={8}
|
||||
allowFontScaling
|
||||
color={colors.primary.icon}
|
||||
/>
|
||||
<Paragraph
|
||||
color={
|
||||
item.isFocused
|
||||
? colors.selected.paragraph
|
||||
: colors.primary.paragraph
|
||||
}
|
||||
size={SIZE.md}
|
||||
>
|
||||
{item?.title || "New note"}
|
||||
</Paragraph>
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
const TableOfContents = ({ toc, close }: TableOfContentsProps) => {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
gap: 12,
|
||||
paddingTop: 12
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Heading size={SIZE.lg}>Table of contents</Heading>
|
||||
</View>
|
||||
|
||||
<FlatList
|
||||
data={toc.map((item, index) => {
|
||||
return {
|
||||
...item,
|
||||
isFocused:
|
||||
(editorState().scrollPosition || 0) > item.top &&
|
||||
(editorState().scrollPosition || 0) < toc[index + 1]?.top
|
||||
};
|
||||
})}
|
||||
renderItem={({ item }) => (
|
||||
<TableOfContentsItem item={item} close={close} />
|
||||
)}
|
||||
keyExtractor={(item) => item.id}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
TableOfContents.present = (toc: TableOfContentsItem[]) => {
|
||||
presentSheet({
|
||||
component: (ref, close, update) => (
|
||||
<TableOfContents toc={toc} close={close} />
|
||||
)
|
||||
});
|
||||
};
|
||||
|
||||
export default TableOfContents;
|
||||
@@ -170,7 +170,6 @@ export const Update = ({ version: appVersion, fwdRef }) => {
|
||||
lineHeight: 20,
|
||||
marginTop: 10
|
||||
}}
|
||||
selectable
|
||||
>
|
||||
{version.body}
|
||||
</Paragraph>
|
||||
@@ -182,7 +181,6 @@ export const Update = ({ version: appVersion, fwdRef }) => {
|
||||
style={{
|
||||
marginBottom: 5
|
||||
}}
|
||||
selectable
|
||||
>
|
||||
• {item}
|
||||
</Paragraph>
|
||||
|
||||
@@ -43,10 +43,6 @@ export const ColorSection = React.memo(
|
||||
]);
|
||||
const loading = useSettingStore((state) => state.isAppLoading);
|
||||
const setColorNotes = useMenuStore((state) => state.setColorNotes);
|
||||
const [order, hiddensItems] = useMenuStore((state) => [
|
||||
state.order["colors"],
|
||||
state.hiddenItems["colors"]
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
@@ -63,8 +59,8 @@ export const ColorSection = React.memo(
|
||||
db.settings.setSideBarHiddenItems("colors", data);
|
||||
}}
|
||||
disableDefaultDrag={true}
|
||||
itemOrder={order}
|
||||
hiddenItems={hiddensItems}
|
||||
itemOrder={db.settings.getSideBarOrder("colors")}
|
||||
hiddenItems={db.settings.getSideBarHiddenItems("colors")}
|
||||
alwaysBounceVertical={false}
|
||||
data={colorNotes}
|
||||
style={{
|
||||
|
||||
@@ -19,15 +19,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback } from "react";
|
||||
import { View } from "react-native";
|
||||
import { DraxProvider, DraxScrollView } from "react-native-drax";
|
||||
import { FlatList, View } from "react-native";
|
||||
import { notesnook } from "../../../e2e/test.ids";
|
||||
import { db } from "../../common/database";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
import Navigation from "../../services/navigation";
|
||||
import { useMenuStore } from "../../stores/use-menu-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
@@ -51,10 +49,6 @@ export const SideMenu = React.memo(
|
||||
);
|
||||
const isAppLoading = useSettingStore((state) => state.isAppLoading);
|
||||
const dragging = useSideBarDraggingStore((state) => state.dragging);
|
||||
const [order, hiddensItems] = useMenuStore((state) => [
|
||||
state.order["routes"],
|
||||
state.hiddenItems["routes"]
|
||||
]);
|
||||
|
||||
const introCompleted = useSettingStore(
|
||||
(state) => state.settings.introCompleted
|
||||
@@ -98,8 +92,8 @@ export const SideMenu = React.memo(
|
||||
onHiddenItemsChanged={(data) => {
|
||||
db.settings.setSideBarHiddenItems("routes", data);
|
||||
}}
|
||||
itemOrder={order}
|
||||
hiddenItems={hiddensItems}
|
||||
itemOrder={db.settings.getSideBarOrder("routes")}
|
||||
hiddenItems={db.settings.getSideBarHiddenItems("routes")}
|
||||
alwaysBounceVertical={false}
|
||||
data={MenuItemsList}
|
||||
style={{
|
||||
@@ -140,12 +134,16 @@ export const SideMenu = React.memo(
|
||||
paddingTop: insets.top
|
||||
}}
|
||||
>
|
||||
<DraxProvider>
|
||||
<DraxScrollView nestedScrollEnabled={false}>
|
||||
{renderItem()}
|
||||
</DraxScrollView>
|
||||
</DraxProvider>
|
||||
|
||||
<FlatList
|
||||
alwaysBounceVertical={false}
|
||||
contentContainerStyle={{
|
||||
flexGrow: 1
|
||||
}}
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={[0]}
|
||||
keyExtractor={() => "mainMenuView"}
|
||||
renderItem={renderItem}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
@@ -155,6 +153,26 @@ export const SideMenu = React.memo(
|
||||
subscriptionType === SUBSCRIPTION_STATUS.BASIC ? (
|
||||
<MenuItem testID={pro.name} key={pro.name} item={pro} index={0} />
|
||||
) : null}
|
||||
|
||||
{BottomItemsList.slice(DDS.isLargeTablet() ? 0 : 1, 3).map(
|
||||
(item, index) => (
|
||||
<MenuItem
|
||||
testID={
|
||||
item.name == "Night mode"
|
||||
? notesnook.ids.menu.nightmode
|
||||
: item.name
|
||||
}
|
||||
key={item.name}
|
||||
item={item}
|
||||
index={index}
|
||||
rightBtn={
|
||||
DDS.isLargeTablet() || item.name === "Notesnook Pro"
|
||||
? undefined
|
||||
: BottomItemsList[0]
|
||||
}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</View>
|
||||
|
||||
{dragging ? (
|
||||
@@ -186,7 +204,14 @@ export const SideMenu = React.memo(
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<UserStatus />
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
paddingHorizontal: 0
|
||||
}}
|
||||
>
|
||||
<UserStatus />
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -44,7 +44,7 @@ export const PinnedSection = React.memo(
|
||||
const menuPins = useMenuStore((state) => state.menuPins);
|
||||
const loading = useSettingStore((state) => state.isAppLoading);
|
||||
const setMenuPins = useMenuStore((state) => state.setMenuPins);
|
||||
const [order] = useMenuStore((state) => [state.order["shortcuts"]]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
setMenuPins();
|
||||
@@ -61,13 +61,7 @@ export const PinnedSection = React.memo(
|
||||
Navigation.closeDrawer();
|
||||
});
|
||||
};
|
||||
const renderItem = ({
|
||||
item,
|
||||
index
|
||||
}: {
|
||||
item: Notebook | Tag;
|
||||
index: number;
|
||||
}) => {
|
||||
const renderItem = ({ item }: { item: Notebook | Tag; index: number }) => {
|
||||
return <PinItem item={item} onPress={onPress} />;
|
||||
};
|
||||
|
||||
@@ -83,7 +77,7 @@ export const PinnedSection = React.memo(
|
||||
}}
|
||||
onHiddenItemsChanged={(data) => {}}
|
||||
canHideItems={false}
|
||||
itemOrder={order}
|
||||
itemOrder={db.settings.getSideBarOrder("shortcuts")}
|
||||
hiddenItems={[]}
|
||||
alwaysBounceVertical={false}
|
||||
data={menuPins}
|
||||
@@ -100,10 +94,7 @@ export const PinnedSection = React.memo(
|
||||
<Notice
|
||||
size="small"
|
||||
type="information"
|
||||
text="Add shortcuts for notebooks and tags here."
|
||||
style={{
|
||||
marginHorizontal: 12
|
||||
}}
|
||||
text="Add shortcuts for notebooks, topics and tags here."
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||