Compare commits

...

120 Commits

Author SHA1 Message Date
Ammar Ahmed
2f66ee04cc mobile: fix notification notes created on every app launch 2025-12-24 10:51:27 +05:00
Ammar Ahmed
ecf75a07e4 mobile: fix loading note in editor from notifications
Fix a race condition where the loading note gets replaced by editor's stored state on app launch
2025-12-23 12:48:29 +05:00
Ammar Ahmed
50d0827972 Merge pull request #9071 from streetwriters/mobile-release/3.3.11
mobile: release 3.3.11
2025-12-19 10:47:24 +05:00
Abdullah Atta
a0d4be2379 Merge pull request #9069 from streetwriters/common/command-palette-web-keybinding
common: add ctrl+shift+: web keybinding for command palette
2025-12-18 11:56:06 +05:00
Ammar Ahmed
e4eb5d1f0f mobile: release 3.3.11 2025-12-18 11:46:32 +05:00
Ammar Ahmed
9ae4d3df55 Merge pull request #9067 from streetwriters/fix-wrapped-background-mobile
Fixed wrapped background in screenshots on mobile
2025-12-18 11:35:31 +05:00
Abdullah Atta
95b6b45cc4 Merge pull request #9068 from streetwriters/editor/fix-scroll-mobile-table
editor: fix scroll for tables in mobile
2025-12-18 11:34:29 +05:00
01zulfi
9280d0ef7e common: add ctrl+shift+: web keybinding for command palette
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-12-18 10:34:39 +05:00
01zulfi
5171b2e5e2 editor: fix scroll for tables in mobile
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-12-18 10:20:10 +05:00
Ammar Ahmed
8455ff876a mobile: fixed wrapped background in screenshots 2025-12-18 09:48:54 +05:00
Ammar Ahmed
0503af6819 Merge pull request #9066 from streetwriters/mobile-release/3.3.10
Mobile release 3.3.10
2025-12-18 09:46:43 +05:00
Abdullah Atta
fbaba8ebe8 Merge pull request #9064 from streetwriters/release/3.3.6
Release v3.3.6
2025-12-18 00:48:11 +05:00
Abdullah Atta
64c70f51c9 web: bump version to 3.3.6 2025-12-17 23:09:20 +05:00
Abdullah Atta
946da6e274 desktop: update sqlite3-fts5-html to 0.0.6
this should fix the `The specified module could not be found` error on Windows
2025-12-17 23:02:46 +05:00
Ammar Ahmed
f42489ecb5 mobile: fix package version is null 2025-12-17 19:06:48 +05:00
Ammar Ahmed
abd5fa00ed mobile: fix ci workflow no space left 2025-12-17 16:28:50 +05:00
Abdullah Atta
9450849b9d web: remove htmlparser2 2025-12-17 16:25:07 +05:00
Ammar Ahmed
d66bda7adc mobile: release 3.3.10 2025-12-17 15:38:37 +05:00
Abdullah Atta
461c4acfb7 ci: use macos-15-intel instead of macos-13 2025-12-17 14:49:46 +05:00
Abdullah Atta
ccb0840771 web: update @playwright/test to 1.57.0 2025-12-17 14:49:22 +05:00
Abdullah Atta
b5a706a6a9 editor: fix TouchEvent is not defined when resizing columns 2025-12-17 14:40:25 +05:00
Abdullah Atta
a45b54dd85 Merge pull request #9041 from streetwriters/fix-subscription-type 2025-12-17 14:22:31 +05:00
01zulfi
a4d29f3e7a editor: hide expand/collapse icon for empty headings (#9063)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-12-17 14:18:30 +05:00
Ammar Ahmed
2a8ec8245f mobile: fix e2e tests 2025-12-17 13:01:33 +05:00
Ammar Ahmed
d85f32e1f2 mobile: fix babel config for reanimated when using metro bundler 2025-12-17 09:02:27 +05:00
Ammar Ahmed
adc7bb1d9e mobile: fix months ordering bug in wrapped 2025-12-17 09:01:58 +05:00
Ammar Ahmed
2dafde0117 mobile: improve navigation performance 2025-12-13 12:39:38 +05:00
Ammar Ahmed
7582a01b3f mobile: remove polkadot background 2025-12-13 12:38:52 +05:00
Ammar Ahmed
9081012673 mobile: fix drawer open animation velocity 2025-12-13 10:31:41 +05:00
Ammar Ahmed
bf83dfbd28 mobile: do not cache wrapped data 2025-12-13 10:20:12 +05:00
01zulfi
903b96e629 web: show spaces in note,notebook,tag,reminder list item titles (#9027)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-12-12 19:19:36 +05:00
Ammar Ahmed
3e9007806e mobile: release 3.3.10-beta.6 2025-12-12 12:00:58 +05:00
Abdullah Atta
b6ec0091f0 web: update lockfile (again) 2025-12-12 11:57:54 +05:00
Ammar Ahmed
726b4f5c0d Merge pull request #9037 from streetwriters/fix-clipper-images
Fix loading images in clipped pages
2025-12-12 11:54:11 +05:00
Abdullah Atta
2fdd3a2a85 web: update lockfile 2025-12-12 11:45:36 +05:00
Ammar Ahmed
4fbb39efd0 Merge pull request #9041 from streetwriters/fix-subscription-type
Fix subscription type
2025-12-12 11:05:45 +05:00
Ammar Ahmed
88ecb58153 mobile: fix wrapped ui on tablets 2025-12-12 10:38:05 +05:00
Abdullah Atta
d084da2914 global: update package lockfiles 2025-12-12 10:33:02 +05:00
Abdullah Atta
716de6f9eb web: bump version to 3.3.6-beta.3 2025-12-12 10:06:04 +05:00
Abdullah Atta
dfc4cbe01f Merge pull request #9042 from streetwriters/editor/fix-callout-heading
editor: fix callout collapse/expand on clicking right after its heading
2025-12-12 09:57:56 +05:00
Abdullah Atta
3a5b4c48f5 Merge branch 'master' into beta 2025-12-12 09:47:50 +05:00
Abdullah Atta
08b0fd498e Merge pull request #9049 from streetwriters/chore/disable-rebase-when-sync
config: disable rebase when sync vscode setting
2025-12-12 09:47:05 +05:00
Abdullah Atta
3f365e7ee1 config: disable rebase when sync vscode setting 2025-12-12 09:46:31 +05:00
Abdullah Atta
ebb5c078c9 Merge pull request #9048 from streetwriters/wrapped-2025
Notesnook Wrapped
2025-12-12 09:37:52 +05:00
Ammar Ahmed
f536def5fa mobile: wrapped 2025 2025-12-12 09:37:20 +05:00
01zulfi
2918b8f04b web: wrapped 2025
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

web: refined wrapped ui

web: make wrapped work automatically for future years

web: fix emoji for colors

web: format word count
2025-12-12 09:37:11 +05:00
01zulfi
bb3b05aab0 web: allow closing file drag overlay by click or esc key (#9044)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-12-11 11:29:28 +05:00
01zulfi
2cdfe2c158 editor: add shortcut to open search and replace (#9043)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-12-11 11:28:15 +05:00
01zulfi
d1dfafe1da editor: fix callout collapse/expand on clicking right after its heading
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-12-10 14:36:50 +05:00
01zulfi
144febb3cc web: handle null productId
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-12-10 13:01:55 +05:00
Ammar Ahmed
22b2d50139 mobile: fix productId usage 2025-12-10 10:11:21 +05:00
01zulfi
121e521eb7 editor: hide horizontal rule if its under a collapsed heading (#9038)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-12-10 10:01:14 +05:00
Ammar Ahmed
7ada9cacda core: fix productId can be null 2025-12-10 09:40:56 +05:00
Ammar Ahmed
5585d69dcf mobile: fix clipper build path 2025-12-09 12:49:37 +05:00
Ammar Ahmed
f5d73a0c8f clipper: set full src url on image.src 2025-12-09 12:49:02 +05:00
Ammar Ahmed
4563739f6e Merge branch 'mobile-release-3.3.10-beta.4' into beta 2025-12-09 10:49:52 +05:00
Abdullah Atta
79ed081c99 desktop: update sqlite-better-trigram to 0.0.5
this should fix the `The specified module could not be found` error on Windows
2025-12-08 15:14:08 +05:00
Ammar Ahmed
dc1c9a9d37 mobile: fix PrivacyInfo.xcprivacy file 2025-12-06 21:15:51 +05:00
Ammar Ahmed
25c90537c8 mobile: fix version code for iOS 2025-12-06 19:54:57 +05:00
Ammar Ahmed
b7aadf4b17 ci: Update iOS Workflow 2025-12-06 18:51:50 +05:00
Ammar Ahmed
b9587e0fd5 mobile: bump version to v3.3.10-beta.5 2025-12-06 18:46:19 +05:00
Ammar Ahmed
38e529f5bf mobile: update libs 2025-12-06 18:42:06 +05:00
Ammar Ahmed
81e2d7738f mobile: enable fade animation for splash screen 2025-12-06 18:41:53 +05:00
Ammar Ahmed
380a681cc1 mobile: fix splash screen in dark mode 2025-12-06 13:28:18 +05:00
Ammar Ahmed
8c2a557618 mobile: fix switching device mode while in fullscreen mode 2025-12-06 12:36:55 +05:00
Ammar Ahmed
7b98d2ede2 mobile: Update lockfile 2025-12-06 11:21:13 +05:00
Ammar Ahmed
64c544a86e mobile: fix notifee lib version 2025-12-06 11:10:31 +05:00
Ammar Ahmed
a048125a14 mobile: release 3.3.10-beta.4 2025-12-06 11:10:31 +05:00
Ammar Ahmed
4c37e16e92 mobile: remove delay when opening settings 2025-12-06 11:10:31 +05:00
Ammar Ahmed
c448bc151b mobile: remove unused hook 2025-12-06 11:10:31 +05:00
Ammar Ahmed
efcbefe1c8 mobile: fix ui shift on focus search 2025-12-06 11:10:31 +05:00
Ammar Ahmed
339a15803c mobile: fix app exits editor on focus keyboard 2025-12-06 11:10:31 +05:00
Ammar Ahmed
582a06c05a mobile: fix biometric unlock not working on iPad and tablet devices 2025-12-06 11:09:39 +05:00
Ammar Ahmed
852f1ec31a Merge pull request #8949 from streetwriters/mobile-fix-ipad-biometric-unlock
mobile: Fix biometric unlock not working on iPad and tablet devices
2025-12-05 14:43:24 +05:00
Ammar Ahmed
2ca142566c Merge branch 'mobile-release-3.3.10-beta.3' into beta 2025-12-04 14:37:27 +05:00
Ammar Ahmed
9a13d112cb mobile: Update Podfile 2025-12-04 14:36:52 +05:00
Abdullah Atta
bc9cbbc1f6 crypto: lazily import sodium 2025-12-03 19:15:31 +05:00
Ammar Ahmed
129bf49204 mobile: release v3.3.10-beta.3 2025-12-03 14:26:57 +05:00
Ammar Ahmed
a29acb6f30 mobile: update notifee to support new architecture 2025-12-03 14:26:57 +05:00
Ammar Ahmed
c957094b1e mobile: fix orientation changing and fullscreen mode on tablets 2025-12-03 14:26:57 +05:00
Ammar Ahmed
8e5743f417 mobile: fix orientation listening events 2025-12-03 14:26:57 +05:00
Ammar Ahmed
4ff42f1ae4 mobile: fix crash on configuration changed on android 2025-12-03 14:26:57 +05:00
Ammar Ahmed
06c8f5367e mobile: fix picking themes from file 2025-12-03 14:26:57 +05:00
Abdullah Atta
f74d7cf37e web: bump version to 3.3.6-beta.2 2025-12-03 14:06:45 +05:00
Abdullah Atta
b971b4d07a Merge pull request #9002 from streetwriters/web/new-note-properties-pane 2025-12-03 14:05:27 +05:00
Abdullah Atta
09fd5d8642 Merge pull request #9002 from streetwriters/web/new-note-properties-pane
web: release space taken by properties pane for new note/tab
2025-12-03 14:01:34 +05:00
Abdullah Atta
97447e8d6c Merge pull request #9016 from NeedsChloesure/patch/erroneous-filesize-check
Fix file size calculation
2025-12-03 14:01:05 +05:00
Abdullah Atta
c388045c68 web: fix file uploading not working in safari 2025-12-03 13:59:55 +05:00
Abdullah Atta
db4d998705 editor: fix TouchEvent is not defined 2025-12-03 13:59:36 +05:00
Chloe Oletto
011cc992e8 mobile: Incorrect math for determining total number of chunks causes erroneous assertation that there is one more chunk in certain conditions.
Signed-off-by: Chloe Oletto <needschloesure@riseup.net>
2025-12-01 02:45:21 -08:00
Chloe Oletto
2c1d8b0eea web: Incorrect math for determining total number of chunks causes erroneous assertation that there is one more chunk in certain conditions.
Signed-off-by: Chloe Oletto <needschloesure@riseup.net>
2025-12-01 02:43:33 -08:00
Ammar Ahmed
65ae22e70e Merge branch 'mobile-release-3.3.10-beta.2' into beta 2025-12-01 10:05:46 +05:00
01zulfi
81da60333d editor: fade all nodes inside a checklist item except for a nested checklist (#9008)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-11-29 12:37:36 +05:00
01zulfi
aa572febd4 editor: add toggle text color keybinding (#9010)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-11-29 12:36:09 +05:00
Ammar Ahmed
6060cb457d mobile: fix failing build errors on android 2025-11-29 00:01:56 +05:00
Ammar Ahmed
6ac0107274 mobile: bump react-native-upload library version 2025-11-28 18:52:12 +05:00
Ammar Ahmed
95de4855c0 mobile: release 3.3.10-beta.2 2025-11-28 14:36:33 +05:00
Ammar Ahmed
bcfff70e78 mobile: improve file uploads in background 2025-11-28 14:34:18 +05:00
Ammar Ahmed
11e7d34961 mobile: update deps 2025-11-28 12:22:16 +05:00
Ammar Ahmed
e48e523b90 mobile: use KeyboardAvoidingView on android 2025-11-28 12:21:42 +05:00
Ammar Ahmed
4689b4290e mobile: patch rn to fix keyboard hiding on android 2025-11-28 12:21:13 +05:00
Ammar Ahmed
f9af8d116c mobile: fix crash on pick image or file 2025-11-28 11:09:31 +05:00
Ammar Ahmed
1f9339e5ab Merge branch 'release-v3.3.10-beta.1' into beta 2025-11-28 09:29:38 +05:00
Ammar Ahmed
4bc9b718cc mobile: delay layout on navigating to settings 2025-11-27 14:14:19 +05:00
Abdullah Atta
eae6b058fc web: bump version to 3.3.6-beta.1 2025-11-27 14:11:19 +05:00
Ammar Ahmed
a29bcf713f mobile: fix loading data in share extension 2025-11-27 14:09:42 +05:00
Ammar Ahmed
6b171f578d mobile: release 3.3.10-beta.1 2025-11-27 13:31:50 +05:00
Ammar Ahmed
3f45c2ebd4 mobile: update react-native-actions-sheet 2025-11-27 13:31:50 +05:00
Ammar Ahmed
883b1a63b2 mobile: improve animation for fluid panels 2025-11-27 13:31:50 +05:00
Ammar Ahmed
4c0efa8b08 mobile: make gradlew executable 2025-11-27 13:31:50 +05:00
01zulfi
ed2a04d590 editor: improve inline code styling (#8987)
* editor: improve inline code styling
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

* editor: remove top&bottom padding from inline code
* it was cutting off a bit of text from top&bottom lines

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

* editor: update text color of inline code
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

* editor: adjust font size and padding of inline code

---------

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2025-11-27 12:05:16 +05:00
01zulfi
52a3d1c373 editor: readonly table fixes (#8997)
* editor: readonly table fixes
* fix tables not hiding under collapsed headings in readonly view
* allow column resizing in readonly view
* fix scrollbar not showing in readonly view

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

* editor: remove table view

---------

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2025-11-27 12:04:23 +05:00
01zulfi
573b24f28f editor: fix heading align (#8996)
this reverts all the custom layout based on divs & spans and moves back to using pseudo element for the expand/collapse icon.

There were a few problems with the previous logic:

1. We had to write custom logic for text alignment (not a huge deal but it could cause bugs down the line)
2. Aligning the icon properly was hit or miss. We were using flex which meant for multi line headings, the icon appeared way to the left instead of right next to the end of the heading.
3. The styling css for the previous logic was MASSIVE and handled lots of cases which meant more maintenance burden for us.

The new logic is simpler:

1. Use `::after` pseudo element for the expand/collapse icon. This works very nicely on Android.
2. Use selection range on the heading to compute bounding rects for each line. It's a bit hacky but works for both LTR & RTL headings.

---------

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
Co-authored-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2025-11-27 11:43:27 +05:00
Abdullah Atta
e68e5bc6fb web: bump version to 3.3.6-beta.0 2025-11-27 11:43:27 +05:00
01zulfi
6473ce4244 editor: unhide children when collapsed heading is changed to non-heading node (#8946)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-11-27 11:43:27 +05:00
01zulfi
82685314f7 editor: improve table cell styling (#8960)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-11-27 11:43:27 +05:00
01zulfi
c1370af395 editor: change heading collapse icon pos (#8953)
* editor: enable heading in table, change collapse icon pos, && disable empty heading collapse
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

* editor: migrate empty collapsed headings in parseHTML instead of plugin
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

* editor: remove migration for empty collapsed headings
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

* editor: fix heading collapse on mobile
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>

* editor: use ontouchend instead of ontouchstart

---------

Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2025-11-27 11:43:27 +05:00
Abdullah Atta
7779a8b752 Merge pull request #9003 from streetwriters/rn-82
Upgrade to React Native 82
2025-11-27 11:34:08 +05:00
01zulfi
f7914c57c7 web: release space taken by properties pane for new note/tab
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
2025-11-26 16:49:17 +05:00
Ammar Ahmed
6dd16f6791 mobile: fix biometric unlock not working on iPad and tablet devices 2025-11-12 12:19:57 +05:00
123 changed files with 66129 additions and 1099 deletions

View File

@@ -55,13 +55,13 @@ jobs:
- name: Detox build
run: |
yarn build:android
ls apps/mobile/native/android/app/build/outputs/apk
ls apps/mobile/native/android/app/build/outputs/apk/release
ls apps/mobile/android/app/build/outputs/apk
ls apps/mobile/android/app/build/outputs/apk/release
- name: Get device name
id: device
run: |
AVD_NAME=$(node -p "require('./apps/mobile/native/.detoxrc.js').devices.emulator.device.avdName")
AVD_NAME=$(node -p "require('./apps/mobile/.detoxrc.js').devices.emulator.device.avdName")
echo "AVD_NAME=$AVD_NAME" >> $GITHUB_OUTPUT
- name: AVD cache

View File

@@ -24,6 +24,22 @@ jobs:
java-version: "17"
architecture: "x64"
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
with:
# this might remove tools that are actually needed,
# if set to "true" but frees about 6 GB
tool-cache: false
# all of these default to true, but feel free to set to
# "false" if necessary for your workflow
android: false
dotnet: true
haskell: true
large-packages: true
docker-images: true
swap-storage: true
- name: Install node modules
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
@@ -124,7 +140,7 @@ jobs:
- name: Get app version
id: package-version
uses: martinbeentjes/npm-get-version-action@master
uses: saionaro/extract-package-version@master
with:
path: apps/mobile
@@ -143,8 +159,8 @@ jobs:
uses: softprops/action-gh-release@v1
with:
draft: true
tag_name: ${{ steps.package-version.outputs.current-version}}-android
name: Notesnook Android v${{ steps.package-version.outputs.current-version}}
tag_name: ${{ steps.package-version.outputs.version}}-android
name: Notesnook Android v${{ steps.package-version.outputs.version}}
repository: streetwriters/notesnook
token: ${{ secrets.GITHUB_TOKEN }}
files: |

View File

@@ -45,7 +45,7 @@ jobs:
test-macos-x64:
name: Test macOS x64
needs: build
runs-on: macos-13
runs-on: macos-15-intel
steps:
- name: Check out Git repository

View File

@@ -4,7 +4,7 @@ on: workflow_dispatch
jobs:
build:
runs-on: macos-14
runs-on: macos-26
timeout-minutes: 60
steps:
@@ -17,7 +17,7 @@ jobs:
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "16.1"
xcode-version: "26.1.1"
- name: Install node modules
run: |
@@ -30,7 +30,7 @@ jobs:
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2.11
with:
key: ${{ runner.os }}-ccache-${{ hashFiles(format('apps/mobile/native/ios/Podfile.lock')) }}
key: ${{ runner.os }}-ccache-${{ hashFiles(format('apps/mobile/ios/Podfile.lock')) }}
max-size: 1500M
restore-keys: |
${{ runner.os }}-ccache-
@@ -55,14 +55,13 @@ jobs:
uses: actions/cache@v3
id: pods-cache
with:
path: apps/mobile/native/ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('apps/mobile/native/ios/Podfile.lock') }}
path: apps/mobile/ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('apps/mobile/ios/Podfile.lock') }}
- name: Install Pods
run: |
cd apps/mobile/native/ios
bundle install
RCT_NEW_ARCH_ENABLED=0 bundle exec pod install
cd apps/mobile/ios
pod install
- name: Check for typescript errors
run: |
@@ -79,9 +78,9 @@ jobs:
bundle-identifier: org.streetwriters.notesnook
scheme: Notesnook
configuration: "Release"
export-options: apps/mobile/native/ios/ExportOptions.plist
project-path: apps/mobile/native/ios/Notesnook.xcodeproj
workspace-path: apps/mobile/native/ios/Notesnook.xcworkspace
export-options: apps/mobile/ios/ExportOptions.plist
project-path: apps/mobile/ios/Notesnook.xcodeproj
workspace-path: apps/mobile/ios/Notesnook.xcworkspace
update-targets: |
Notesnook
Make Note
@@ -117,5 +116,5 @@ jobs:
name: Notesnook.zip
path: |
Notesnook.ipa
apps/mobile/native/ios/**/*.map
apps/mobile/ios/**/*.map
packages/editor-mobile/sourcemaps/*.map

View File

@@ -11,5 +11,5 @@
"cache": true,
"cacheStrategy": "content"
},
"git.rebaseWhenSync": true
"git.rebaseWhenSync": false
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "@notesnook/desktop",
"productName": "Notesnook",
"description": "Your private note taking space",
"version": "3.3.5",
"version": "3.3.6",
"appAppleId": "1544027013",
"private": true,
"main": "./dist/cjs/index.js",
@@ -36,8 +36,8 @@
"electron-trpc": "0.7.1",
"electron-updater": "^6.6.2",
"icojs": "^0.19.5",
"sqlite-better-trigram": "0.0.3",
"sqlite3-fts5-html": "^0.0.4",
"sqlite-better-trigram": "0.0.5",
"sqlite3-fts5-html": "^0.0.6",
"typed-emitter": "^2.1.0",
"yargs": "^17.7.2",
"zod": "3.24.3"

View File

@@ -47,7 +47,7 @@ module.exports = {
simulator: {
type: "ios.simulator",
device: {
type: "iPhone 12"
type: "iPhone 17 Pro Max"
}
},
attached: {
@@ -59,7 +59,7 @@ module.exports = {
emulator: {
type: "android.emulator",
device: {
avdName: "Pixel_5_API_34"
avdName: "Pixel_5_API_36"
}
}
},

View File

@@ -1,6 +1,7 @@
apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
apply plugin: 'kotlin-parcelize'
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
@@ -124,7 +125,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled true
versionCode 3079
versionCode 3087
versionName getNpmVersion()
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'

View File

@@ -63,4 +63,7 @@
-keepattributes Signature
-keep class com.google.gson.reflect.TypeToken { *; }
-keep class * extends com.google.gson.reflect.TypeToken
-keep class com.streetwriters.notesnook.datatypes.* { *; }
-keep class com.streetwriters.notesnook.datatypes.* { *; }
-keep class net.gotev.uploadservice.* { *; }
-keep class kotlinx.parcelize.* { *; }

View File

@@ -20,7 +20,7 @@ import com.zoontek.rnbootsplash.RNBootSplash;
public class MainActivity extends ReactActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
protected void onCreate(Bundle savedInstanceState) {
RNBootSplash.init(this, R.style.BootTheme);
super.onCreate(null);
@@ -32,19 +32,6 @@ public class MainActivity extends ReactActivity {
startService(new Intent(getBaseContext(), OnClearFromRecentService.class));
} catch (Exception ignored) {}
if (Build.VERSION.SDK_INT >= 35) {
final View rootView = findViewById(android.R.id.content);
ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, insets) -> {
Insets innerPadding = insets.getInsets(WindowInsetsCompat.Type.ime());
rootView.setPadding(
innerPadding.left,
innerPadding.top,
innerPadding.right,
innerPadding.bottom
);
return insets;
});
}
}
/**
@@ -60,20 +47,20 @@ public class MainActivity extends ReactActivity {
DefaultNewArchitectureEntryPoint.getFabricEnabled());
}
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getReactInstanceManager().onConfigurationChanged(this, newConfig);
Intent intent = new Intent("onConfigurationChanged");
intent.putExtra("newConfig", newConfig);
this.sendBroadcast(intent);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getReactHost().onConfigurationChanged(this);
Intent intent = new Intent("onConfigurationChanged");
intent.putExtra("newConfig", newConfig);
this.sendBroadcast(intent);
}
@Override
protected String getMainComponentName() {

View File

@@ -6,7 +6,7 @@ import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
import org.wonday.orientation.OrientationActivityLifecycle;
class MainApplication : Application(), ReactApplication {
override val reactHost: ReactHost by lazy {
getDefaultReactHost(
@@ -22,6 +22,7 @@ class MainApplication : Application(), ReactApplication {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(OrientationActivityLifecycle.getInstance());
loadReactNative(this)
}
}

View File

@@ -17,7 +17,7 @@
</style>
<!-- BootTheme should inherit from Theme.SplashScreen -->
<style name="BootTheme" parent="Theme.SplashScreen">
<style name="BootTheme" parent="Theme.BootSplash.EdgeToEdge">
<item name="bootSplashBackground">@color/bootsplash_background</item>
<item name="bootSplashLogo">@mipmap/bootsplash_logo_dark</item>
<item name="android:navigationBarColor">@color/bootsplash_background</item>

0
apps/mobile/android/gradlew vendored Normal file → Executable file
View File

View File

@@ -1,3 +1,6 @@
- Get an overview of your year with Notesnook with Wrapped 2025
- Cell selection and column resizing in tables
- Added support for uploading large files in background
- Bug fixes and minor improvements
Thank you for using Notesnook!
Thank you for using Notesnook!

View File

@@ -51,8 +51,9 @@ const { appLockEnabled, appLockMode } = SettingsService.get();
if (appLockEnabled || appLockMode !== "none") {
useUserStore.getState().lockApp(true);
}
RNBootSplash.hide();
RNBootSplash.hide({
fade: true
});
const App = (props: { configureMode: "note-preview" }) => {
useAppEvents();
//@ts-ignore
@@ -63,7 +64,7 @@ const App = (props: { configureMode: "note-preview" }) => {
setTimeout(async () => {
await Notifications.get();
if (SettingsService.get().notifNotes) {
Notifications.pinQuickNote(true);
Notifications.pinQuickNote();
}
TipManager.init();
}, 100);

View File

@@ -70,7 +70,7 @@ export async function downloadFile(
throw new Error(error);
}
const totalChunks = Math.ceil(size / chunkSize);
const totalChunks = Math.ceil(size / (chunkSize + ABYTES));
const decryptedLength = size - totalChunks * ABYTES;
if (attachment && attachment.size !== decryptedLength) {

View File

@@ -17,8 +17,8 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { RequestOptions } from "@notesnook/core";
import { Platform } from "react-native";
import { isImage, RequestOptions } from "@notesnook/core";
import { PermissionsAndroid, Platform } from "react-native";
import RNFetchBlob from "react-native-blob-util";
import { ToastManager } from "../../services/event-manager";
import { useAttachmentStore } from "../../stores/use-attachment-store";
@@ -31,6 +31,7 @@ import {
FileSizeResult,
getUploadedFileSize
} from "./utils";
import Upload from "@ammarahmed/react-native-upload";
export async function uploadFile(
filename: string,
@@ -64,47 +65,87 @@ export async function uploadFile(
);
}
const fileSize = (await RNFetchBlob.fs.stat(filePath)).size;
const fileInfo = await RNFetchBlob.fs.stat(filePath);
const remoteFileSize = await getUploadedFileSize(filename);
if (remoteFileSize === FileSizeResult.Error) return false;
if (remoteFileSize > FileSizeResult.Empty && remoteFileSize === fileSize) {
if (
remoteFileSize > FileSizeResult.Empty &&
remoteFileSize === fileInfo.size
) {
DatabaseLogger.log(`File ${filename} is already uploaded.`);
return true;
}
DatabaseLogger.info(`Starting upload: ${filename}`);
let attachmentInfo = await db.attachments.attachment(filename);
const uploadRequest = RNFetchBlob.config({
//@ts-ignore
IOSBackgroundTask: !globalThis["IS_SHARE_EXTENSION"]
})
.fetch(
"PUT",
url,
{
...headers,
"content-type": ""
},
RNFetchBlob.wrap(filePath)
)
.uploadProgress((sent, total) => {
useAttachmentStore
.getState()
.setProgress(sent, total, filename, 0, "upload");
DatabaseLogger.info(
`File upload progress: ${filename}, ${sent}/${total}`
);
});
DatabaseLogger.info(
`Starting upload of ${filename} at path: ${fileInfo.path} ${fileInfo.size}`
);
if (Platform.OS === "android") {
const status = await PermissionsAndroid.request(
"android.permission.POST_NOTIFICATIONS"
);
if (status !== "granted") {
ToastManager.show({
message: `The permission to show file upload notification was disallowed by the user.`,
type: "info"
});
}
}
const upload = Upload.create({
customUploadId: filename,
path: Platform.OS === "ios" ? "file://" + fileInfo.path : fileInfo.path,
url: url,
method: "PUT",
headers: {
...headers,
"content-type": "application/octet-stream"
},
appGroup: IOS_APPGROUPID,
notification: {
filename:
attachmentInfo && isImage(attachmentInfo?.mimeType)
? "image"
: attachmentInfo?.filename || "file",
enabled: true,
enableRingTone: true,
autoClear: true
}
}).onChange((event) => {
switch (event.status) {
case "running":
case "pending":
useAttachmentStore
.getState()
.setProgress(
event.uploadedBytes || 0,
event.totalBytes || fileInfo.size,
filename,
0,
"upload"
);
DatabaseLogger.info(
`File upload progress: ${filename}, ${event.uploadedBytes}/${
event.totalBytes || fileInfo.size
}`
);
break;
case "completed":
console.log("Upload completed");
break;
}
});
const result = await upload.start();
cancelToken.cancel = async () => {
useAttachmentStore.getState().remove(filename);
uploadRequest.cancel();
upload.cancel();
};
const uploadResponse = await uploadRequest;
const status = uploadResponse.info().status;
const status = result.responseCode || 0;
const uploaded = status >= 200 && status < 300;
useAttachmentStore.getState().remove(filename);
@@ -114,12 +155,12 @@ export async function uploadFile(
throw new Error(
`${status}, name: ${fileInfo.filename}, length: ${
fileInfo.size
}, info: ${JSON.stringify(uploadResponse.info())}`
}, info: ${JSON.stringify(result.error)}`
);
}
const attachment = await db.attachments.attachment(filename);
if (!attachment) return false;
await checkUpload(filename, requestOptions.chunkSize, attachment.size);
attachmentInfo = await db.attachments.attachment(filename);
if (!attachmentInfo) return false;
await checkUpload(filename, requestOptions.chunkSize, attachmentInfo.size);
DatabaseLogger.info(`File upload status: ${filename}, ${status}`);
return uploaded;
} catch (e) {

View File

@@ -155,7 +155,7 @@ export async function checkUpload(
expectedSize: number
) {
const size = await getUploadedFileSize(filename);
const totalChunks = Math.ceil(size / chunkSize);
const totalChunks = Math.ceil(size / (chunkSize + ABYTES));
const decryptedLength = size - totalChunks * ABYTES;
const error =
size === 0

View File

@@ -324,7 +324,9 @@ export const Signup = ({
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: DefaultAppStyles.GAP,
width: DDS.isTab ? "50%" : "100%",
alignSelf: "center"
}}
>
<Paragraph

View File

@@ -42,9 +42,7 @@ export default function DelayLayout({
...props
}: IDelayLayoutProps) {
const { colors } = useThemeColors();
const loading = useDelayLayout(
!props.delay || props.delay < 300 ? 0 : props.delay
);
const loading = useDelayLayout(props.delay === undefined ? 200 : props.delay);
const Placeholder = placeholder[props.type || "default"];
return loading || props.wait ? (

View File

@@ -136,12 +136,12 @@ const BaseDialog = ({
backgroundColor: background
? background
: transparent
? "transparent"
: "rgba(0,0,0,0.3)"
? "transparent"
: "rgba(0,0,0,0.3)"
}}
>
<KeyboardAvoidingView
enabled={!floating && Platform.OS === "ios" && !avoidKeyboardResize}
enabled={!floating && !avoidKeyboardResize}
behavior="padding"
>
<BouncingView
@@ -155,8 +155,8 @@ const BaseDialog = ({
justifyContent: centered
? "center"
: bottom
? "flex-end"
: "flex-start"
? "flex-end"
: "flex-start"
}
]}
>

View File

@@ -96,22 +96,22 @@ export class VaultDialog extends Component {
this.title = !this.state.novault
? strings.createVault()
: this.state.fingerprintAccess
? strings.vaultFingerprintUnlock()
: this.state.revokeFingerprintAccess
? strings.revokeVaultFingerprintUnlock()
: this.state.changePassword
? strings.changeVaultPassword()
: this.state.noteLocked
? this.state.deleteNote
? strings.deleteNote()
: this.state.share
? strings.shareNote()
: this.state.copyNote
? strings.copyNote()
: this.state.goToEditor
? strings.goToEditor()
: strings.goToEditor()
: strings.lockNote();
? strings.vaultFingerprintUnlock()
: this.state.revokeFingerprintAccess
? strings.revokeVaultFingerprintUnlock()
: this.state.changePassword
? strings.changeVaultPassword()
: this.state.noteLocked
? this.state.deleteNote
? strings.deleteNote()
: this.state.share
? strings.shareNote()
: this.state.copyNote
? strings.copyNote()
: this.state.goToEditor
? strings.goToEditor()
: strings.goToEditor()
: strings.lockNote();
}
componentDidMount() {
@@ -337,12 +337,13 @@ export class VaultDialog extends Component {
);
});
}
eSendEvent("vaultUpdated");
this.setState({
loading: false
});
this.close();
setTimeout(() => {
this.close();
}, 100);
} else {
ToastManager.show({
heading: strings.passwordIncorrect(),
@@ -353,9 +354,6 @@ export class VaultDialog extends Component {
} catch (e) {
console.error(e);
}
this.setState({
loading: false
});
};
clearVault = async () => {
@@ -874,24 +872,24 @@ export class VaultDialog extends Component {
deleteVault
? strings.delete()
: clearVault
? strings.clear()
: fingerprintAccess
? strings.enable()
: this.state.revokeFingerprintAccess
? strings.revoke()
: changePassword
? strings.change()
: this.state.noteLocked
? deleteNote
? strings.delete()
: share
? strings.share()
: goToEditor
? strings.open()
: strings.unlock()
: !note.id
? strings.create()
: strings.lock()
? strings.clear()
: fingerprintAccess
? strings.enable()
: this.state.revokeFingerprintAccess
? strings.revoke()
: changePassword
? strings.change()
: this.state.noteLocked
? deleteNote
? strings.delete()
: share
? strings.share()
: goToEditor
? strings.open()
: strings.unlock()
: !note.id
? strings.create()
: strings.lock()
}
/>
</View>

View File

@@ -31,6 +31,7 @@ import { Gesture, GestureDetector } from "react-native-gesture-handler";
import Animated, {
runOnJS,
SharedValue,
SnappySpringConfig,
useAnimatedReaction,
useAnimatedStyle,
useSharedValue,
@@ -110,7 +111,6 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
const containerWidth = widths
? widths.sidebar + widths.list + widths.editor
: dimensions.width;
const drawerPosition = 0;
const homePosition = widths.sidebar;
const editorPosition = widths.sidebar + widths.list;
@@ -354,13 +354,10 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
const finalValue = isSwipeLeft
? translateX.value - velocityX / 40.0
: translateX.value + velocityX / 40.0;
const velocity = velocityX / 5000;
const animationConfig: WithSpringConfig = {
velocity: velocityX,
mass: 0.5,
overshootClamping: true,
damping: 800,
stiffness: 800
velocity: velocity,
...SnappySpringConfig
};
if (finalValue < homePosition) {
@@ -443,15 +440,7 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
width: containerWidth,
flexDirection: "row"
},
deviceMode === "tablet"
? {
transform: [
{
translateX: 0
}
]
}
: animatedStyles
animatedStyles
]}
>
{children}

View File

@@ -994,7 +994,7 @@ const PricingPlanCard = ({
PremiumService.get() &&
(pricingPlans?.user?.subscription?.productId ===
(product as RNIap.Subscription)?.productId ||
pricingPlans?.user?.subscription?.productId.startsWith(
pricingPlans?.user?.subscription?.productId?.startsWith(
(product as RNIap.Subscription)?.productId
));
pricingPlans?.selectPlan(

View File

@@ -352,7 +352,7 @@ const ProductItem = (props: {
props.pricingPlans.isSubscribed() &&
(props.pricingPlans.user?.subscription?.productId ===
(product as RNIap.Subscription)?.productId ||
props.pricingPlans.user?.subscription?.productId.startsWith(
props.pricingPlans.user?.subscription?.productId?.startsWith(
(product as RNIap.Subscription)?.productId
) ||
props.pricingPlans.user?.subscription?.productId ===

View File

@@ -103,7 +103,7 @@ export function PlanLimits() {
if (
user?.subscription.plan !== SubscriptionPlan.FREE &&
user?.subscription.productId.includes("5year")
user?.subscription.productId?.includes("5year")
) {
ToastManager.show({
message:

View File

@@ -58,6 +58,7 @@ import { Button } from "../ui/button";
import SettingsService from "../../services/settings";
import { isFeatureAvailable } from "@notesnook/common";
import PaywallSheet from "../sheets/paywall";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
const renderScene = SceneMap({
home: SideMenuHome,
notebooks: SideMenuNotebooks,
@@ -68,6 +69,7 @@ const renderScene = SceneMap({
export const SideMenu = React.memo(
function SideMenu() {
const { colors } = useThemeColors();
const insets = useGlobalSafeAreaInsets();
const [index, setIndex] = React.useState(
SettingsService.getProperty("defaultSidebarTab")
);
@@ -87,10 +89,13 @@ export const SideMenu = React.memo(
]);
return (
<SafeAreaView
<View
style={{
flex: 1,
backgroundColor: colors.primary.background
backgroundColor: colors.primary.background,
paddingTop: insets.top,
paddingBottom: insets.bottom,
paddingLeft: insets.left
}}
>
<TabView
@@ -103,7 +108,7 @@ export const SideMenu = React.memo(
animationEnabled={false}
lazy
/>
</SafeAreaView>
</View>
);
},
() => true
@@ -351,9 +356,8 @@ const TabBar = (
color={colors.primary.icon}
onPress={async () => {
if (props.navigationState.index === 1) {
const notebooksFeature = await isFeatureAvailable(
"notebooks"
);
const notebooksFeature =
await isFeatureAvailable("notebooks");
if (!notebooksFeature.isAllowed) {
PaywallSheet.present(notebooksFeature);
return;

View File

@@ -104,15 +104,12 @@ function _MenuItem({
const _onPress = () => {
if (useSideBarDraggingStore.getState().dragging) return;
if (item.onPress) return item.onPress(item);
Navigation.closeDrawer();
if (useNavigationStore.getState().currentRoute !== item.id) {
Navigation.navigate(item.id as keyof RouteParams, {
canGoBack: false
});
}
setImmediate(() => {
Navigation.closeDrawer();
});
};
return (
@@ -154,8 +151,8 @@ function _MenuItem({
item.icon === "crown"
? colors.static.yellow
: isFocused
? colors.selected.icon
: colors.secondary.icon
? colors.selected.icon
: colors.secondary.icon
}
size={AppFontSize.md}
/>

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { SubscriptionPlan } from "@notesnook/core";
import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import dayjs from "dayjs";
import React from "react";
import { FlatList, View } from "react-native";
import { DraxProvider, DraxScrollView } from "react-native-drax";
@@ -140,19 +141,35 @@ export function SideMenuHome() {
paddingVertical: DefaultAppStyles.GAP_VERTICAL
}}
>
{(subscriptionType === SubscriptionPlan.FREE ||
!subscriptionType ||
!user) &&
!SettingsService.getProperty("serverUrls") ? (
{dayjs().month() !== 11 ? (
<>
{(subscriptionType === SubscriptionPlan.FREE ||
!subscriptionType ||
!user) &&
!SettingsService.getProperty("serverUrls") ? (
<Button
title={pro.title}
style={{
width: "100%"
}}
type="accent"
onPress={pro.onPress}
/>
) : null}
</>
) : (
<Button
title={pro.title}
title={`Wrapped ${dayjs().year()} 🎉`}
style={{
width: "100%"
}}
type="accent"
onPress={pro.onPress}
bold
type="secondaryAccented"
onPress={() => {
Navigation.navigate("Wrapped");
}}
/>
) : null}
)}
</View>
</View>
);

View File

@@ -42,7 +42,7 @@ const SheetWrapper = ({
closeOnTouchBackdrop = true,
onHasReachedTop,
overlay,
overlayOpacity = 0.3,
overlayOpacity = 0.7,
enableGesturesInScrollView = false,
bottomPadding = true,
keyboardHandlerDisabled

View File

@@ -176,6 +176,7 @@ const onAppOpenedFromURL = async (event: { url: string }) => {
if (id) {
const note = await db.notes.note(id);
if (note) {
editorState().initialLoadCalled = true;
eSendEvent(eOnLoadNote, {
item: note
});
@@ -454,9 +455,6 @@ const initializeDatabase = async (password?: string) => {
await setAppMessage();
useSettingStore.getState().setAppLoading(false);
Notifications.setupReminders(true);
if (SettingsService.get().notifNotes) {
Notifications.pinQuickNote(false);
}
DatabaseLogger.info("Database initialized");
Notifications.restorePinnedNotes();
}

View File

@@ -660,9 +660,25 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
}
}
function isSubscribedToPlan(planId: string) {
if (!PremiumService.get()) return false;
return user?.subscription?.productId?.includes(planId);
}
function isSubscribedToProduct(productId: string) {
if (!PremiumService.get()) return false;
return (
user?.subscription?.productId &&
(user?.subscription?.productId === productId ||
user?.subscription?.productId?.startsWith(productId))
);
}
return {
currentPlan: pricingPlans.find((p) => p.id === currentPlan),
pricingPlans: plans,
isSubscribedToPlan,
isSubscribedToProduct,
getStandardPrice: getLocalizedPrice,
loadingPlans,
loading,

View File

@@ -29,7 +29,7 @@ import React, {
useRef,
useState
} from "react";
import { Dimensions, LayoutChangeEvent, Platform, View } from "react-native";
import { LayoutChangeEvent, View } from "react-native";
import Orientation, {
OrientationType,
useDeviceOrientationChange
@@ -39,7 +39,6 @@ import Animated, {
useSharedValue,
withTiming
} from "react-native-reanimated";
import { SafeAreaView } from "react-native-safe-area-context";
import { notesnook } from "../../e2e/test.ids";
import { db } from "../common/database";
import { FluidPanels } from "../components/fluid-panels";
@@ -69,15 +68,13 @@ import {
eOpenFullscreenEditor,
eUnlockNote
} from "../utils/events";
import { editorRef, fluidTabsRef } from "../utils/global-refs";
import { valueLimiter } from "../utils/functions";
import { fluidTabsRef } from "../utils/global-refs";
import { AppNavigationStack } from "./navigation-stack";
import type { PaneWidths } from "../screens/editor/wrapper";
const MOBILE_SIDEBAR_SIZE = 0.85;
const valueLimiter = (value: number, min: number, max: number) => {
return value < min ? min : value > max ? max : value;
};
let SideMenu: any = null;
let EditorWrapper: any = null;
@@ -93,7 +90,6 @@ export const FluidPanelsView = React.memo(
const insets = useGlobalSafeAreaInsets();
const animatedOpacity = useSharedValue(0);
const animatedTranslateY = useSharedValue(-9999);
const overlayRef = useRef<Animated.View>(null);
const [orientation, setOrientation] = useState<OrientationType>(
Orientation.getInitialOrientation()
@@ -102,16 +98,21 @@ export const FluidPanelsView = React.memo(
const [isLoading, setIsLoading] = useState(false);
useDeviceOrientationChange((o) => {
setOrientation(o);
if (
o !== OrientationType.UNKNOWN &&
o !== OrientationType["FACE-UP"] &&
o !== OrientationType["FACE-DOWN"] &&
o !== OrientationType["PORTRAIT-UPSIDEDOWN"]
) {
setOrientation(o);
}
});
const isLandscape = orientation.includes("LANDSCAPE");
useEffect(() => {
if (!appLoading) {
setTimeout(() => {
setIsLoading(false);
}, 500);
}, 200);
}
}, [appLoading]);
@@ -147,16 +148,6 @@ export const FluidPanelsView = React.memo(
if (deviceMode === "smallTablet") {
fluidTabsRef.current?.openDrawer(false);
}
editorRef.current?.setNativeProps({
style: {
width: dimensions.width,
zIndex: 999,
paddingHorizontal:
deviceMode === "smallTablet"
? dimensions.width * 0
: dimensions.width * 0.15
}
});
}, [deviceMode, dimensions.width, setFullscreen]);
const closeFullScreenEditor = useCallback(
@@ -169,17 +160,6 @@ export const FluidPanelsView = React.memo(
editorController.current?.commands.updateSettings({
fullscreen: false
});
editorRef.current?.setNativeProps({
style: {
width:
_deviceMode === "smallTablet"
? dimensions.width -
valueLimiter(dimensions.width * 0.4, 300, 450)
: dimensions.width * 0.48,
zIndex: null,
paddingHorizontal: 0
}
});
if (_deviceMode === "smallTablet") {
fluidTabsRef.current?.goToIndex(1, false);
}
@@ -221,38 +201,8 @@ export const FluidPanelsView = React.memo(
(current: string | null, size: { width: number; height: number }) => {
setDeviceModeState(current);
const needsLayout = current !== deviceMode;
if (fullscreen && current !== "mobile") {
// Runs after size is set via state.
setTimeout(() => {
editorRef.current?.setNativeProps({
style: {
width: size.width,
zIndex: 999,
paddingHorizontal:
current === "smallTablet" ? size.width * 0 : size.width * 0.15
}
});
}, 1);
} else {
if (fullscreen) eSendEvent(eCloseFullscreenEditor, current);
editorRef.current?.setNativeProps({
style: {
position: "relative",
width:
current === "tablet"
? size.width * 0.48
: current === "smallTablet"
? size.width - valueLimiter(size.width * 0.4, 300, 450)
: size.width,
zIndex: null,
paddingHorizontal: 0
}
});
}
if (!needsLayout) {
return;
if (fullscreen && current === "mobile") {
eSendEvent(eCloseFullscreenEditor, current);
}
const state = getAppState();
@@ -264,8 +214,6 @@ export const FluidPanelsView = React.memo(
case "smallTablet":
if (!fullscreen) {
fluidTabsRef.current?.closeDrawer(false);
} else {
fluidTabsRef.current?.openDrawer(false);
}
break;
case "mobile":
@@ -274,46 +222,52 @@ export const FluidPanelsView = React.memo(
editorState().movedAway === false &&
useTabStore.getState().getCurrentNoteId()
) {
fluidTabsRef.current?.goToIndex(2, false);
fluidTabsRef.current?.goToPage("editor", false);
} else {
fluidTabsRef.current?.goToIndex(1, false);
fluidTabsRef.current?.goToPage(
fluidTabsRef.current?.page(),
false
);
}
break;
}
}, 32);
}, 0);
},
[deviceMode, fullscreen, setDeviceModeState]
);
const checkDeviceType = React.useCallback(
(size: { width: number; height: number }) => {
setDimensions({
width: size.width,
height: size.height
});
if (DDS.width === size.width && orientation === DDS.orientation) return;
DDS.setSize(size, orientation);
const nextDeviceMode = DDS.isLargeTablet()
? "tablet"
: DDS.isSmallTab
? "smallTablet"
: "mobile";
setDeviceMode(nextDeviceMode, size);
},
[orientation, setDeviceMode, setDimensions]
);
useEffect(() => {
if (orientation !== "UNKNOWN") {
checkDeviceType(dimensions);
}
}, [orientation, dimensions]);
const _onLayout = React.useCallback(
(event: LayoutChangeEvent) => {
const size = event?.nativeEvent?.layout;
if (!size || (size.width === dimensions.width && deviceMode !== null)) {
DDS.setSize(size, orientation);
setDeviceMode(deviceMode, size);
checkDeviceType(size);
return;
setDimensions({
width: size.width,
height: size.height
});
if (size.width > size.height) {
setOrientation(OrientationType["LANDSCAPE-RIGHT"]);
} else {
setOrientation(OrientationType["PORTRAIT"]);
}
checkDeviceType(size);
},
[
checkDeviceType,
@@ -324,11 +278,6 @@ export const FluidPanelsView = React.memo(
]
);
if (!deviceMode) {
const size = Dimensions.get("window");
checkDeviceType(size);
}
const PANE_OFFSET = useMemo(
() => ({
mobile: {
@@ -356,7 +305,7 @@ export const FluidPanelsView = React.memo(
[dimensions.width, fullscreen]
);
const PANE_WIDTHS = useMemo(
const PANE_WIDTHS: PaneWidths = useMemo(
() => ({
mobile: {
sidebar: dimensions.width * MOBILE_SIDEBAR_SIZE,
@@ -382,6 +331,7 @@ export const FluidPanelsView = React.memo(
(scrollOffset: number) => {
if (!deviceMode) return;
hideAllTooltips();
if (
scrollOffset >
PANE_OFFSET[deviceMode as keyof typeof PANE_OFFSET].sidebar - 10
@@ -409,7 +359,7 @@ export const FluidPanelsView = React.memo(
};
}, []);
if (!isLoading) {
if (!isLoading && !SideMenu && !EditorWrapper) {
SideMenu = require("../components/side-menu").SideMenu;
EditorWrapper = require("../screens/editor/wrapper").EditorWrapper;
}
@@ -421,15 +371,7 @@ export const FluidPanelsView = React.memo(
style={{
height: "100%",
width: "100%",
backgroundColor: colors.primary.background,
marginRight:
orientation === "LANDSCAPE-RIGHT" && Platform.OS === "ios"
? insets.right
: 0,
marginLeft:
orientation === "LANDSCAPE-LEFT" && Platform.OS === "ios"
? insets.left
: 0
backgroundColor: colors.primary.background
}}
>
{deviceMode && PANE_WIDTHS[deviceMode as keyof typeof PANE_WIDTHS] ? (
@@ -503,9 +445,7 @@ export const FluidPanelsView = React.memo(
style={{
flex: 1,
paddingTop: insets.top,
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right
paddingBottom: insets.bottom
}}
>
<AppNavigationStack />

View File

@@ -273,6 +273,7 @@ let Settings: any = null;
let ManageTags: any = null;
let AddReminder: any = null;
let PayWall: any = null;
let Wrapped: any = null;
export const RootNavigation = () => {
const introCompleted = useSettingStore(
(state) => state.settings.introCompleted
@@ -384,6 +385,14 @@ export const RootNavigation = () => {
return PayWall;
}}
/>
<RootStack.Screen
name="Wrapped"
getComponent={() => {
Wrapped = Wrapped || require("../screens/wrapped").default;
return Wrapped;
}}
/>
</RootStack.Navigator>
</NavigationContainer>
);

View File

@@ -62,6 +62,7 @@ import { fluidTabsRef } from "../../utils/global-refs";
import { strings } from "@notesnook/intl";
import { i18n } from "@lingui/core";
import { useVaultStatus } from "../../hooks/use-vault-status";
import { useSettingStore } from "../../stores/use-setting-store";
const style: ViewStyle = {
height: "100%",
@@ -231,7 +232,6 @@ const useLockedNoteHandler = () => {
const unlockWithBiometrics = async () => {
try {
if (!tabRef.current?.session?.noteLocked || !tabRef.current) return;
console.log("Trying to unlock with biometrics...");
const credentials = await BiometricService.getCredentials(
"Unlock note",
"Unlock note to open it in editor."
@@ -320,12 +320,16 @@ const useLockedNoteHandler = () => {
}
};
const unlock = () => {
const unlock = (forced?: boolean) => {
const isMovedAway =
useSettingStore.getState().deviceMode !== "mobile"
? false
: editorState().movedAway;
if (
(tabRef.current?.session?.locked,
tabRef.current?.session?.locked &&
useTabStore.getState().biometryAvailable &&
useTabStore.getState().biometryEnrolled &&
!editorState().movedAway)
useTabStore.getState().biometryEnrolled &&
(!isMovedAway || forced)
) {
setTimeout(() => {
unlockWithBiometrics();
@@ -344,13 +348,15 @@ const useLockedNoteHandler = () => {
const subs = [
eSubscribeEvent(eUnlockNote, unlock),
eSubscribeEvent(eUnlockWithBiometrics, () => {
unlock();
unlock(true);
}),
eSubscribeEvent(eUnlockWithPassword, onSubmit)
];
if (
tabRef.current?.session?.locked &&
fluidTabsRef.current?.page() === "editor"
(fluidTabsRef.current?.page() === "editor" ||
useSettingStore.getState().deviceMode !== "mobile")
) {
unlock();
}

View File

@@ -205,7 +205,9 @@ const camera = async (options: PickerOptions) => {
options
);
})
.catch((e) => {});
.catch((e) => {
console.log(e);
});
} catch (e) {
ToastManager.show({
heading: (e as Error).message,

View File

@@ -664,7 +664,8 @@ export const useEditorEvents = (
if (note) {
eSendEvent(eOnLoadNote, {
item: note,
tabId: editorMessage.tabId
tabId: editorMessage.tabId,
loadedFromEditor: true
});
}
} else {
@@ -675,7 +676,8 @@ export const useEditorEvents = (
if (note) {
eSendEvent(eOnLoadNote, {
item: note,
tabId: editorMessage.tabId
tabId: editorMessage.tabId,
loadedFromEditor: true
});
}
}

View File

@@ -508,9 +508,17 @@ export const useEditor = (
newTab?: boolean;
refresh?: boolean;
searchResultIndex?: number;
loadedFromEditor?: boolean;
}) => {
loadNoteMutex.runExclusive(async () => {
if (!event) return;
if (
!event ||
(event.loadedFromEditor &&
event.item &&
event.item?.id !== useTabStore.getState().getCurrentNoteId())
) {
return;
}
if (event.blockId) {
blockIdRef.current = event.blockId;
}
@@ -719,6 +727,7 @@ export const useEditor = (
}, 300);
}
postMessage(NativeEvents.theme, theme);
console.log("load finished", event.item?.id);
});
},
[

View File

@@ -23,21 +23,36 @@ import {
AppState,
AppStateStatus,
KeyboardAvoidingView,
Platform,
TextInput,
View
} from "react-native";
import Editor from ".";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import useIsFloatingKeyboard from "../../hooks/use-is-floating-keyboard";
import useKeyboard from "../../hooks/use-keyboard";
import { DDS } from "../../services/device-detection";
import { useSettingStore } from "../../stores/use-setting-store";
import { editorRef } from "../../utils/global-refs";
import { editorController, textInput } from "./tiptap/utils";
import deviceInfo from "react-native-device-info";
export const EditorWrapper = ({ widths }: { widths: any }) => {
export type PaneWidths = {
mobile: {
sidebar: number;
list: number;
editor: number;
};
smallTablet: {
sidebar: number;
list: number;
editor: number;
};
tablet: {
sidebar: number;
list: number;
editor: number;
};
};
export const EditorWrapper = ({ widths }: { widths: PaneWidths }) => {
const { colors } = useThemeColors();
const { colors: toolBarColors } = useThemeColors("editorToolbar");
const deviceMode = useSettingStore((state) => state.deviceMode);
@@ -47,8 +62,9 @@ export const EditorWrapper = ({ widths }: { widths: any }) => {
const introCompleted = useSettingStore(
(state) => state.settings.introCompleted
);
const keyboard = useKeyboard();
const prevState = useRef<AppStateStatus>(undefined);
const isFullscreen = useSettingStore((state) => state.fullscreen);
const dimensions = useSettingStore((state) => state.dimensions);
const onAppStateChanged = async (state: AppStateStatus) => {
if (!prevState.current) {
@@ -72,37 +88,40 @@ export const EditorWrapper = ({ widths }: { widths: any }) => {
};
}, [loading]);
const getMarginBottom = () => {
const bottomInsets =
Platform.OS === "android" ? 12 : insets.bottom + 16 || 14;
if (!keyboard.keyboardShown) return bottomInsets / 1.5;
if (deviceInfo.isTablet() && Platform.OS === "ios" && !floating)
return bottomInsets;
if (Platform.OS === "ios") return bottomInsets / 1.5;
return 0;
};
const KeyboardAvoidingViewIOS =
Platform.OS === "ios" ? KeyboardAvoidingView : View;
return (
<View
testID="editor-wrapper"
ref={editorRef}
style={{
width: widths[!introCompleted ? "mobile" : (deviceMode as any)]?.editor,
height: "100%",
minHeight: "100%",
backgroundColor: toolBarColors.primary.background,
borderLeftWidth: DDS.isTab ? 1 : 0,
borderLeftColor: DDS.isTab
? colors.secondary.background
: "transparent",
paddingBottom: insets.bottom
}}
style={[
{
width: isFullscreen
? dimensions.width
: widths[
!introCompleted ? "mobile" : (deviceMode as keyof PaneWidths)
]?.editor,
height: "100%",
minHeight: "100%",
backgroundColor: toolBarColors.primary.background,
paddingLeft: isFullscreen
? deviceMode === "smallTablet"
? 0
: dimensions.width * 0.15
: null,
paddingRight: isFullscreen
? deviceMode === "smallTablet"
? 0
: dimensions.width * 0.15
: insets.right,
borderLeftWidth: DDS.isTab ? 1 : 0,
borderLeftColor: DDS.isTab
? colors.secondary.background
: "transparent",
paddingBottom: insets.bottom
}
]}
>
{loading || !introCompleted ? null : (
<KeyboardAvoidingViewIOS
<KeyboardAvoidingView
behavior="padding"
style={{
backgroundColor: colors.primary.background,
@@ -118,7 +137,7 @@ export const EditorWrapper = ({ widths }: { widths: any }) => {
blurOnSubmit={false}
/>
<Editor key="editor" withController={true} />
</KeyboardAvoidingViewIOS>
</KeyboardAvoidingView>
)}
</View>
);

View File

@@ -217,12 +217,12 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
position: "absolute",
bottom: 20,
right: 20,
gap: DefaultAppStyles.GAP_VERTICAL,
alignItems: "center"
}}
>
<FloatingButton
icon="file-tree"
testID="notebookTreeSheet"
size="small"
onPress={() => {
Notebooks.present(params.current.item);
@@ -230,7 +230,8 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
style={{
position: "relative",
right: 0,
bottom: 5
bottom: 0,
paddingBottom: 10
}}
/>
<FloatingButton
@@ -238,6 +239,7 @@ const NotebookScreen = ({ route, navigation }: NavigationProps<"Notebook">) => {
alwaysVisible
style={{
position: "relative",
paddingTop: 10,
right: 0,
bottom: 0
}}

View File

@@ -23,7 +23,6 @@ import React, { useRef, useState } from "react";
import { View } from "react-native";
import { TextInput } from "react-native-gesture-handler";
import { IconButton } from "../../components/ui/icon-button";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import Navigation from "../../services/navigation";
import useNavigationStore from "../../stores/use-navigation-store";
import { useSelectionStore } from "../../stores/use-selection-store";
@@ -41,7 +40,6 @@ export const SearchBar = ({
const isFocused = useNavigationStore(
(state) => state.focusedRouteId === "Search"
);
const insets = useGlobalSafeAreaInsets();
const { colors } = useThemeColors();
const inputRef = useRef<TextInput>(null);
const _onChangeText = (value: string) => {
@@ -58,7 +56,6 @@ export const SearchBar = ({
>
<View
style={{
marginTop: DefaultAppStyles.GAP_SMALL,
flexDirection: "row",
alignItems: "center",
width: "100%",

View File

@@ -59,7 +59,7 @@ const Group = ({
id="Settings"
/>
)}
<DelayLayout type="settings" delay={0}>
<DelayLayout type="settings">
<View
style={{
flex: 1

View File

@@ -59,7 +59,7 @@ const Home = ({
hasSearch={false}
id="Settings"
/>
<DelayLayout delay={0} type="settings">
<DelayLayout type="settings">
<LegendList
data={settingsGroups}
keyExtractor={keyExtractor}

View File

@@ -17,23 +17,29 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ScopedThemeProvider, useThemeColors } from "@notesnook/theme";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import React from "react";
import { View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import useNavigationStore from "../../stores/use-navigation-store";
import { ScopedThemeProvider, useThemeColors } from "@notesnook/theme";
import Group from "./group";
import Home from "./home";
import { RouteParams } from "./types";
import { SafeAreaView } from "react-native-safe-area-context";
const SettingsStack = createNativeStackNavigator<RouteParams>();
export const Settings = () => {
const { colors } = useThemeColors();
const insets = useSafeAreaInsets();
return (
<SafeAreaView
<View
style={{
flex: 1,
backgroundColor: colors.primary.background
backgroundColor: colors.primary.background,
paddingTop: insets.top,
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right
}}
>
<ScopedThemeProvider value="list">
@@ -58,7 +64,7 @@ export const Settings = () => {
<SettingsStack.Screen name="SettingsGroup" component={Group} />
</SettingsStack.Navigator>
</ScopedThemeProvider>
</SafeAreaView>
</View>
);
};

View File

@@ -118,7 +118,8 @@ export const settingsGroups: SettingSection[] = [
if (
(user.subscription?.provider === SubscriptionProvider.GOOGLE ||
user.subscription?.provider === SubscriptionProvider.APPLE) &&
isCurrentPlatform
isCurrentPlatform &&
user?.subscription?.productId
) {
RNIap.deepLinkToSubscriptions({
sku: user?.subscription.productId
@@ -142,13 +143,18 @@ export const settingsGroups: SettingSection[] = [
"dddd, MMMM D, YYYY h:mm A"
);
if (user.subscription?.plan !== SubscriptionPlan.FREE) {
if (
user.subscription?.plan !== SubscriptionPlan.FREE &&
user.subscription?.productId
) {
const status = user.subscription?.status;
return status === SubscriptionStatus.TRIAL
? strings.trialEndsOn(
dayjs(user?.subscription?.start)
.add(
user?.subscription?.productId.includes("monthly") ? 7 : 14
user?.subscription?.productId?.includes("monthly")
? 7
: 14
)
.format("dddd, MMMM D, YYYY h:mm A")
)
@@ -1323,7 +1329,7 @@ export const settingsGroups: SettingSection[] = [
if (settings.notifNotes) {
Notifications.unpinQuickNote();
} else {
Notifications.pinQuickNote(false);
Notifications.pinQuickNote();
}
SettingsService.set({
notifNotes: !settings.notifNotes

View File

@@ -28,7 +28,7 @@ import type {
ThemeMetadata,
ThemesRouter
} from "@notesnook/themes-server";
import { pick } from "@react-native-documents/picker";
import { keepLocalCopy, pick } from "@react-native-documents/picker";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { createTRPCProxyClient, httpBatchLink } from "@trpc/client";
@@ -57,6 +57,7 @@ import { getColorLinearShade } from "../../utils/colors";
import { strings } from "@notesnook/intl";
import { DefaultAppStyles } from "../../utils/styles";
import { LegendList } from "@legendapp/list";
import ReactNativeBlobUtil from "react-native-blob-util";
const THEME_SERVER_URL = "https://themes-api.notesnook.com";
//@ts-ignore
@@ -412,20 +413,39 @@ function ThemeSelector() {
type={"secondaryAccented"}
icon="folder"
fontSize={AppFontSize.xs}
onPress={() => {
pick({
allowMultiSelection: false
}).then((r) => {
fetch(r[0].uri).then(async (response) => {
const json = await response.json();
const result = validateTheme(json);
if (result.error) {
ToastManager.error(new Error(result.error));
return;
}
select(json, true);
onPress={async () => {
try {
const pickResponse = await pick({
allowMultiSelection: false
});
});
const copiedFile = await keepLocalCopy({
destination: "cachesDirectory",
files: [
{
uri: pickResponse[0].uri,
fileName: pickResponse[0].name || "theme.json"
}
]
});
if (copiedFile[0].status !== "success") return;
const themeJson = await ReactNativeBlobUtil.fs.readFile(
copiedFile[0].localUri,
"utf8"
);
ReactNativeBlobUtil.fs
.unlink(copiedFile[0].localUri)
.catch(() => {});
const json = JSON.parse(themeJson);
const result = validateTheme(json);
if (result.error) {
ToastManager.error(new Error(result.error));
return;
}
select(json, true);
} catch (e) {
ToastManager.error(e as Error);
}
}}
/>
</View>

File diff suppressed because it is too large Load Diff

View File

@@ -114,7 +114,7 @@ async function onBackgroundSyncStarted() {
}
await Notifications.setupReminders();
if (SettingsService.get().notifNotes) {
Notifications.pinQuickNote(false);
Notifications.pinQuickNote();
}
Notifications.restorePinnedNotes();
NotePreviewWidget.updateNotes();
@@ -142,7 +142,7 @@ const onBoot = async () => {
await Notifications.setupReminders();
if (SettingsService.get().notifNotes) {
Notifications.pinQuickNote(false);
Notifications.pinQuickNote();
}
Notifications.restorePinnedNotes();
NotePreviewWidget.updateNotes();

View File

@@ -50,6 +50,7 @@ export class DeviceDetectionService {
windowSize = size || windowSize;
this.width = windowSize.width;
this.height = windowSize.height;
this.orientation = orientation;
this.adjustedWidth = this.width * this.pixelDensity;
this.adjustedHeight = this.height * this.pixelDensity;
screenSize = Dimensions.get("screen");

View File

@@ -71,7 +71,8 @@ const routeNames = {
Archive: "Archive",
ManageTags: "ManageTags",
AddReminder: "AddReminder",
PayWall: "PayWall"
PayWall: "PayWall",
Wrapped: "Wrapped"
};
export type NavigationProps<T extends RouteName> = NativeStackScreenProps<

View File

@@ -109,6 +109,15 @@ async function initDatabase() {
const onEvent = async ({ type, detail }: Event) => {
await initDatabase();
const { notification, pressAction, input } = detail;
if (
type === EventType.DISMISSED &&
Platform.OS === "android" &&
notification?.id === "notesnook_note_input" &&
SettingsService.getProperty("notifNotes")
) {
pinQuickNote();
}
if (type === EventType.DELIVERED && Platform.OS === "android") {
if (notification?.id) {
const reminder = await db.reminders?.reminder(
@@ -438,6 +447,7 @@ async function scheduleNotification(
async function loadNote(id: string, jump: boolean) {
if (!id || id === "notesnook_note_input") return;
editorState().initialLoadCalled = true;
const note = await db.notes.note(id);
if (!note) return;
if (!DDS.isTab && jump) {
@@ -502,7 +512,8 @@ async function displayNotification({
ongoing,
reply_placeholder_text,
reply_button_text,
id
id,
channelId = "default"
}: {
title?: string;
message: string;
@@ -513,6 +524,7 @@ async function displayNotification({
reply_placeholder_text?: string;
reply_button_text?: string;
id?: string;
channelId?: "silent" | "vibrate" | "urgent" | "default";
}) {
useUserStore.setState({
disableAppLockRequests: true
@@ -537,7 +549,7 @@ async function displayNotification({
ongoing: ongoing,
smallIcon: "ic_stat_name",
localOnly: true,
channelId: await getChannelId("default"),
channelId: await getChannelId(channelId),
autoCancel: false,
pressAction: {
id: "default",
@@ -884,7 +896,7 @@ function init() {
notifee.onForegroundEvent(onEvent);
}
async function pinQuickNote(launch: boolean) {
async function pinQuickNote() {
useUserStore.setState({
disableAppLockRequests: true
});
@@ -896,14 +908,13 @@ async function pinQuickNote(launch: boolean) {
return;
}
get().then((items) => {
const notification = items.filter((n) => n.id === "notesnook_note_input");
if (notification && launch) {
return;
}
const notification = items.find((n) => n.id === "notesnook_note_input");
if (notification) return;
displayNotification({
title: strings.quickNoteTitle(),
message: strings.quickNoteContent(),
ongoing: true,
channelId: "silent",
actions: ["ReplyInput", strings.hide()],
reply_button_text: strings.takeNote(),
reply_placeholder_text: strings.quickNotePlaceholder(),
@@ -1030,6 +1041,7 @@ async function pinNote(id: string) {
subtitle: "",
bigText: html,
ongoing: true,
channelId: "silent",
actions: [strings.unpin()],
id: note.id
});
@@ -1040,9 +1052,13 @@ async function pinNote(id: string) {
async function restorePinnedNotes() {
const pinnedNotes = PinnedNotesStorage.get();
for (const id of pinnedNotes) {
pinNote(id);
}
Notifications.get().then(() => {
for (const id of pinnedNotes) {
if (!isNotePinned(id)) {
pinNote(id);
}
}
});
}
async function clearPinnedNotes() {

View File

@@ -251,6 +251,7 @@ const ShareView = () => {
setRawData(item);
if (isURL(item.value)) {
note = await showLinkPreview(note, item.value);
noteTitle.current = note.title;
} else {
note.content.data = makeHtmlFromPlainText(item.value);
}
@@ -261,9 +262,6 @@ const ShareView = () => {
if (key.includes("TITLE") || key.includes("SUBJECT")) {
note.title = item[key];
noteTitle.current = note.title;
inputRef.current?.setNativeProps?.({
text: noteTitle.current
});
}
if (key.includes("TEXT") && !note.content.data) {
note.content.data = item[key];
@@ -294,6 +292,10 @@ const ShareView = () => {
}
}
}
inputRef.current?.setNativeProps?.({
text: noteTitle.current
});
onLoad();
setNote({ ...note });
} catch (e) {
@@ -308,7 +310,6 @@ const ShareView = () => {
try {
await initDatabase();
setLoadingExtension(false);
loadData(false);
useShareStore.getState().restore();
} catch (e) {
DatabaseLogger.error(e);

View File

@@ -112,6 +112,7 @@ export interface RouteParams extends ParamListBase {
context: "signup" | "logged-in" | "logged-out" | "subscribed";
state?: BillingState;
};
Wrapped: GenericRouteParam;
}
export type RouteName = keyof RouteParams;

View File

@@ -35,6 +35,10 @@ import { useTagStore } from "../stores/use-tag-store";
import { eUpdateNoteInEditor } from "./events";
import { unlockVault } from "./unlock-vault";
export const valueLimiter = (value: number, min: number, max: number) => {
return value < min ? min : value > max ? max : value;
};
export function getObfuscatedEmail(email: string) {
if (!email) return "";
const [username, provider] = email.split("@");

View File

@@ -23,7 +23,7 @@ module.exports = function (api, opts) {
});
}
env.plugins.push("react-native-reanimated/plugin");
env.plugins.push("react-native-worklets/plugin");
api.cache(true);
return env;

View File

@@ -134,7 +134,7 @@ describe("NOTE TESTS", () => {
.run();
});
it("Assign colors to a note", async () => {
it.only("Assign colors to a note", async () => {
await TestBuilder.create()
.prepare()
.createNote()

View File

@@ -121,7 +121,7 @@ describe("NOTEBOOKS", () => {
.run();
});
it.only("Remove note from notebook", async () => {
it("Remove note from notebook", async () => {
await TestBuilder.create()
.prepare()
.openSideMenu()
@@ -138,7 +138,8 @@ describe("NOTEBOOKS", () => {
.longPressByText(note.body)
.wait(500)
.waitAndTapById("select-minus")
.isNotVisibleById(note.title)
.wait(500)
.isNotVisibleByText(note.body)
.run();
})
.run();
@@ -199,6 +200,7 @@ describe("NOTEBOOKS", () => {
.longPressByText("Notebook 1")
.wait(500)
.waitAndTapByText("Move to trash")
.wait(500)
.waitAndTapByText("Delete")
.waitAndTapById("tab-home")
.waitAndTapByText("Trash")

View File

@@ -34,7 +34,7 @@ describe("Sort & filter", () => {
.element(by.web.className("ProseMirror"))
.typeText("Edited ", true);
})
.pressBack()
.pressBack(2)
.waitAndTapById("icon-sort")
.wait(500)
.waitAndTapByText("Date created")

View File

@@ -32,7 +32,10 @@ const testvars = {
class Element {
element: Detox.NativeElement;
constructor(public type: "id" | "text", public value: string) {
constructor(
public type: "id" | "text",
public value: string
) {
if (type == "id") {
this.element = element(by.id(value)).atIndex(0);
} else {
@@ -135,6 +138,7 @@ const Tests = {
);
await titleInput.isVisible();
await titleInput.element.typeText(title);
await Tests.sleep(1000);
if (description) {
await Tests.fromId(
notesnook.ids.dialogs.notebook.inputs.description

View File

@@ -84,7 +84,7 @@ describe("VAULT", () => {
.run();
});
it.only("Change vault password", async () => {
it("Change vault password", async () => {
await TestBuilder.create()
.prepare()
.createNote()
@@ -94,7 +94,7 @@ describe("VAULT", () => {
.typeTextById(notesnook.ids.dialogs.vault.pwd, "1234")
.typeTextById(notesnook.ids.dialogs.vault.changePwd, "2362")
.waitAndTapByText("Change")
.pressBack(3)
.pressBack(4)
.addStep(async () => await openLockedNote("2362"))
.run();
});

View File

@@ -1029,7 +1029,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2158;
CURRENT_PROJECT_VERSION = 2167;
DEVELOPMENT_TEAM = 53CWBG3QUC;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1104,7 +1104,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.3.10;
MARKETING_VERSION = 3.3.11;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1135,7 +1135,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2158;
CURRENT_PROJECT_VERSION = 2167;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1210,7 +1210,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.3.10;
MARKETING_VERSION = 3.3.11;
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"$(inherited)",
@@ -1367,7 +1367,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2158;
CURRENT_PROJECT_VERSION = 2167;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1379,7 +1379,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 3.3.10;
MARKETING_VERSION = 3.3.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
@@ -1410,7 +1410,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2158;
CURRENT_PROJECT_VERSION = 2167;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
@@ -1423,7 +1423,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 3.3.10;
MARKETING_VERSION = 3.3.11;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1453,7 +1453,7 @@
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2158;
CURRENT_PROJECT_VERSION = 2167;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1534,7 +1534,7 @@
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
MARKETING_VERSION = 3.3.10;
MARKETING_VERSION = 3.3.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
@@ -1565,7 +1565,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2158;
CURRENT_PROJECT_VERSION = 2167;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
@@ -1647,7 +1647,7 @@
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
MARKETING_VERSION = 3.3.10;
MARKETING_VERSION = 3.3.11;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -4,6 +4,7 @@
#import "RNShortcuts.h"
#import "RNBootSplash.h"
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
#import "RNFileUploader.h"
@interface ReactNativeDelegate : RCTDefaultReactNativeFactoryDelegate
@end
@@ -79,4 +80,8 @@
[RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView]; // ⬅️ initialize the splash screen
}
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
[RNFileUploader setCompletionHandlerWithIdentifier:identifier completionHandler:completionHandler];
}
@end

View File

@@ -10,8 +10,6 @@
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
<string>3B52.1</string>
<string>C617.1</string>
</array>
</dict>
<dict>

View File

@@ -1887,7 +1887,7 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-document-picker (10.1.7):
- react-native-document-picker (11.0.1):
- boost
- DoubleConversion
- fast_float
@@ -1969,14 +1969,14 @@ PODS:
- React-Core
- React-RCTFabric
- ReactCommon/turbomodule/core
- react-native-mmkv-storage (0.11.2):
- react-native-mmkv-storage (12.0.1):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- MMKV (~> 1.3.9)
- MMKV (~> 1.3.14)
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
@@ -2244,6 +2244,36 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-upload (6.29.0):
- React
- react-native-view-shot (4.0.3):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-webview (13.16.0):
- boost
- DoubleConversion
@@ -3031,14 +3061,14 @@ PODS:
- Yoga
- RNKeychain (4.0.5):
- React
- RNNotifee (7.4.9):
- RNNotifee (7.4.10):
- React-Core
- RNNotifee/NotifeeCore (= 7.4.9)
- RNNotifee/NotifeeCore (7.4.9):
- RNNotifee/NotifeeCore (= 7.4.10)
- RNNotifee/NotifeeCore (7.4.10):
- React-Core
- RNPrivacySnapshot (1.0.0):
- React-Core
- RNReanimated (4.1.3):
- RNReanimated (4.2.0):
- boost
- DoubleConversion
- fast_float
@@ -3065,11 +3095,11 @@ PODS:
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- RNReanimated/reanimated (= 4.1.3)
- RNReanimated/reanimated (= 4.2.0)
- RNWorklets
- SocketRocket
- Yoga
- RNReanimated/reanimated (4.1.3):
- RNReanimated/reanimated (4.2.0):
- boost
- DoubleConversion
- fast_float
@@ -3096,11 +3126,11 @@ PODS:
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- RNReanimated/reanimated/apple (= 4.1.3)
- RNReanimated/reanimated/apple (= 4.2.0)
- RNWorklets
- SocketRocket
- Yoga
- RNReanimated/reanimated/apple (4.1.3):
- RNReanimated/reanimated/apple (4.2.0):
- boost
- DoubleConversion
- fast_float
@@ -3280,7 +3310,7 @@ PODS:
- pop (~> 1.0)
- React
- SexyTooltip
- RNWorklets (0.6.1):
- RNWorklets (0.7.1):
- boost
- DoubleConversion
- fast_float
@@ -3307,10 +3337,10 @@ PODS:
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- RNWorklets/worklets (= 0.6.1)
- RNWorklets/worklets (= 0.7.1)
- SocketRocket
- Yoga
- RNWorklets/worklets (0.6.1):
- RNWorklets/worklets (0.7.1):
- boost
- DoubleConversion
- fast_float
@@ -3337,10 +3367,10 @@ PODS:
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- RNWorklets/worklets/apple (= 0.6.1)
- RNWorklets/worklets/apple (= 0.7.1)
- SocketRocket
- Yoga
- RNWorklets/worklets/apple (0.6.1):
- RNWorklets/worklets/apple (0.7.1):
- boost
- DoubleConversion
- fast_float
@@ -3462,6 +3492,8 @@ DEPENDENCIES:
- "react-native-share-extension (from `../node_modules/@ammarahmed/react-native-share-extension`)"
- "react-native-sodium (from `../node_modules/@ammarahmed/react-native-sodium`)"
- react-native-theme-switch-animation (from `../node_modules/react-native-theme-switch-animation`)
- "react-native-upload (from `../node_modules/@ammarahmed/react-native-upload`)"
- react-native-view-shot (from `../node_modules/react-native-view-shot`)
- react-native-webview (from `../node_modules/react-native-webview`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`)
@@ -3675,6 +3707,10 @@ EXTERNAL SOURCES:
:path: "../node_modules/@ammarahmed/react-native-sodium"
react-native-theme-switch-animation:
:path: "../node_modules/react-native-theme-switch-animation"
react-native-upload:
:path: "../node_modules/@ammarahmed/react-native-upload"
react-native-view-shot:
:path: "../node_modules/react-native-view-shot"
react-native-webview:
:path: "../node_modules/react-native-webview"
React-NativeModulesApple:
@@ -3855,7 +3891,7 @@ SPEC CHECKSUMS:
react-native-blob-util: 7946b7e13acf0da5e849dc2f73fcfebe1d981699
react-native-config: 963b5efabc864cf69412e54b5de49b6a23e4af03
react-native-date-picker: 4f4f40f6e65798038bb4b1bff47890c2be69c2e6
react-native-document-picker: 1734eb0aa3dbd1cd7bf1b105936f9b55031ae616
react-native-document-picker: 254467fec90f263dfc4828210daf3e8baa4fcb81
react-native-fingerprint-scanner: d5e143a361f3f01858e9c45141ddcabc4fd57055
react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba
react-native-gzip: 794e0e964a0d9e1dfd1773fee938adb4d4310e26
@@ -3863,7 +3899,7 @@ SPEC CHECKSUMS:
react-native-image-resizer: 290b045c34c69db7574e4d08aadfc4abe1ff5a99
react-native-in-app-review: 1516ba69d60d58053b7eb3aaaf8d2a5a74af8b57
react-native-keep-awake: a351e6f67006b47f316ae2b17ee8ee69386167f4
react-native-mmkv-storage: b7ce5a5eb3d3bfddcf2df127671abba6ef3d76ae
react-native-mmkv-storage: e84980084e371a9c2230bbde071536a7e1539406
react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
react-native-notification-sounds: ce106d58df0dd384bccbd2e84fb53accab7cc068
react-native-orientation-locker: cc6f357b289a2e0dd2210fea0c52cb8e0727fdaa
@@ -3875,6 +3911,8 @@ SPEC CHECKSUMS:
react-native-share-extension: fdc6aaab51591a2d445df239c446aaa3a99658ec
react-native-sodium: 066f76e46c9be13e9260521e3fa994937c4cdab4
react-native-theme-switch-animation: 449d6db7a760f55740505e7403ae8061debc9a7e
react-native-upload: 1459a4be625dda39e4364d9e7d859477a3000f2a
react-native-view-shot: 6c008e58f4720de58370848201c5d4a082c6d4ca
react-native-webview: 654f794a7686b47491cf43aa67f7f428bea00eed
React-NativeModulesApple: 46690a0fe94ec28fc6fc686ec797b911d251ded0
React-oscompat: 95875e81f5d4b3c7b2c888d5bd2c9d83450d8bdb
@@ -3921,15 +3959,15 @@ SPEC CHECKSUMS:
RNIap: 61f183ac917792fae42b0326b1bef33598c1adf6
RNImageCropPicker: 5fd4ceaead64d8c53c787e4e559004f97bc76df7
RNKeychain: ffd0513e676445c637410b47249460cbf56bc9cb
RNNotifee: dabf3cdd7bfd9340bb84358cc78f635af4bc80e2
RNNotifee: 3840cc81add9954a5dec040f96442498f3f95d7b
RNPrivacySnapshot: ccad3a548338c2f526bb7b1789af3fb0618b7d1d
RNReanimated: 732e7d1662f8cc0e533fa32791800de5b5934726
RNReanimated: f1868b36f4b2b52a0ed00062cfda69506f75eaee
RNScreens: d821082c6dd1cb397cc0c98b026eeafaa68be479
RNSecureRandom: b64d263529492a6897e236a22a2c4249aa1b53dc
RNShare: 5d39a36f2d3d9a6c9344bfb3232c8ed607924a35
RNSVG: 8c0bbfa480a24b24468f1c76bd852a4aac3178e6
RNTooltips: 50ff94bd2bff84ef74279c9532d008f5fdcddb95
RNWorklets: ab618bf7d1c7fd2cb793b9f0f39c3e29274b3ebf
RNWorklets: d9c050940f140af5d8b611d937eab1cbfce5e9a5
RNZipArchive: 71befbdc20e7fbd4b64552a0b324ad0e8d0efefb
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
SexyTooltip: 5c9b4dec52bfb317938cb0488efd9da3717bb6fd

File diff suppressed because one or more lines are too long

View File

@@ -1,21 +1,22 @@
{
"name": "@notesnook/mobile",
"version": "3.3.10-beta.0",
"version": "3.3.10-beta.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/mobile",
"version": "3.3.10-beta.0",
"version": "3.3.10-beta.6",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
"@ammarahmed/notifee-react-native": "7.4.9",
"@ammarahmed/notifee-react-native": "^7.4.10",
"@ammarahmed/react-native-background-fetch": "^4.2.2",
"@ammarahmed/react-native-eventsource": "1.1.0",
"@ammarahmed/react-native-fingerprint-scanner": "^5.0.1",
"@ammarahmed/react-native-share-extension": "^2.9.5",
"@ammarahmed/react-native-sodium": "^1.6.8",
"@ammarahmed/react-native-upload": "^6.29.0",
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bam.tech/react-native-image-resizer": "3.0.11",
"@callstack/repack": "~5.2.1",
@@ -41,7 +42,7 @@
"@react-native-community/datetimepicker": "^8.4.5",
"@react-native-community/netinfo": "^11.4.1",
"@react-native-community/toolbar-android": "^0.2.1",
"@react-native-documents/picker": "^10.1.7",
"@react-native-documents/picker": "^11.0.1",
"@react-native-masked-view/masked-view": "^0.3.2",
"@react-navigation/elements": "^1.3.3",
"@react-navigation/native": "^6.0.10",
@@ -71,7 +72,7 @@
"react": "19.1.1",
"react-async-hook": "^4.0.0",
"react-native": "0.82.1",
"react-native-actions-sheet": "10.0.0-alpha.8",
"react-native-actions-sheet": "^10.1.0",
"react-native-actions-shortcuts": "^1.0.1",
"react-native-background-actions": "^2.6.6",
"react-native-begin-background-task": "github:blockfirm/react-native-begin-background-task",
@@ -96,7 +97,7 @@
"react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-keychain": "4.0.5",
"react-native-material-menu": "^2.0.0",
"react-native-mmkv-storage": "^12.0.0",
"react-native-mmkv-storage": "^12.0.1",
"react-native-modal-datetime-picker": "14.0.0",
"react-native-navigation-bar-color": "2.0.2",
"react-native-notification-sounds": "0.5.5",
@@ -107,7 +108,7 @@
"react-native-progress": "5.0.0",
"react-native-qrcode-svg": "^6.0.6",
"react-native-quick-sqlite": "^8.2.7",
"react-native-reanimated": "^4.1.3",
"react-native-reanimated": "^4.2.0",
"react-native-reanimated-progress-bar": "1.0.1",
"react-native-safe-area-context": "^5.6.1",
"react-native-scoped-storage": "^1.9.5",
@@ -122,9 +123,10 @@
"react-native-tooltips": "^1.0.3",
"react-native-url-polyfill": "^2.0.0",
"react-native-vector-icons": "10.3.0",
"react-native-view-shot": "^4.0.3",
"react-native-webview": "^13.13.5",
"react-native-wheel-color-picker": "^1.3.1",
"react-native-worklets": "^0.6.1",
"react-native-worklets": "^0.7.1",
"react-native-zip-archive": "6.0.9",
"timeago.js": "4.0.2",
"toggle-switch-react-native": "3.2.0",
@@ -227,6 +229,7 @@
"@streetwriters/kysely": "^0.27.4",
"@streetwriters/showdown": "^3.0.9-alpha",
"@types/mime-db": "^1.43.5",
"alfaaz": "^1.1.0",
"async-mutex": "0.5.0",
"dayjs": "1.11.13",
"dom-serializer": "^2.0.0",
@@ -482,9 +485,9 @@
}
},
"node_modules/@ammarahmed/notifee-react-native": {
"version": "7.4.9",
"resolved": "https://registry.npmjs.org/@ammarahmed/notifee-react-native/-/notifee-react-native-7.4.9.tgz",
"integrity": "sha512-DK4ogXPBnoM8UsDQQLK6AQZUbP9TqOcL3YDEKtXmsWug1hzvcP/AfJ42KUCni/XR5NMI1VWW7a7tEwdbdzmS8g==",
"version": "7.4.10",
"resolved": "https://registry.npmjs.org/@ammarahmed/notifee-react-native/-/notifee-react-native-7.4.10.tgz",
"integrity": "sha512-19t1vhIddFneOI7JVmXghunEt5mEmDBY/G1YVMuRNNT/HFQ1EcArJWuAaFAJrhrl/2CBS7xoPGLusKbkbT/JjA==",
"license": "Apache-2.0",
"peerDependencies": {
"react-native": "*"
@@ -529,6 +532,16 @@
"integrity": "sha512-FbX9fMfqJ3ysd+zkSS5di459tPv5iB0fhmK3dx/xo+l07sf7f1gzJu17mghSGkOKkbjXaoLPcq3XLMwWGpvapQ==",
"license": "ISC"
},
"node_modules/@ammarahmed/react-native-upload": {
"version": "6.29.0",
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-upload/-/react-native-upload-6.29.0.tgz",
"integrity": "sha512-k2FJAVR4Nohx4VhfgHuXzLXQpgEnco/PAv9R080X7oY3O12DTgY0ruDvOFwvQGFW0PDIHlXfLfUiMq2kZc/k1A==",
"license": "BSD-3-Clause",
"peerDependencies": {
"react": "*",
"react-native": ">=0.47.0"
}
},
"node_modules/@azure/core-asynciterator-polyfill": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.2.tgz",
@@ -1990,6 +2003,7 @@
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz",
"integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
@@ -2472,16 +2486,16 @@
}
},
"node_modules/@babel/preset-typescript": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz",
"integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==",
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz",
"integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==",
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/helper-validator-option": "^7.27.1",
"@babel/plugin-syntax-jsx": "^7.27.1",
"@babel/plugin-transform-modules-commonjs": "^7.27.1",
"@babel/plugin-transform-typescript": "^7.28.5"
"@babel/plugin-transform-typescript": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
@@ -4839,13 +4853,13 @@
}
},
"node_modules/@react-native-documents/picker": {
"version": "10.1.7",
"resolved": "https://registry.npmjs.org/@react-native-documents/picker/-/picker-10.1.7.tgz",
"integrity": "sha512-Tb8SPU+pHxrSJmDHBozSUStIPeyFHTHLrU3MW0N3sUAioLd5z+nmUdypfg5fs+Yzp7KTxVW06APe2HLB1ysLww==",
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/@react-native-documents/picker/-/picker-11.0.1.tgz",
"integrity": "sha512-aUq4MHGO/f8BslCFFx9OXz9NLLmcLkYAXp5PAEVau31v7obItPpb71Fe84bxpGV6gALIvGlGgSm6W9kEyU4toA==",
"license": "MIT",
"peerDependencies": {
"react": "*",
"react-native": "*"
"react-native": ">=0.79.0"
}
},
"node_modules/@react-native-masked-view/masked-view": {
@@ -7486,6 +7500,15 @@
"resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
"integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -8542,6 +8565,15 @@
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
"license": "MIT"
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/css-select": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
@@ -11622,6 +11654,19 @@
"entities": "^4.4.0"
}
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"license": "MIT",
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/htmlparser2": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
@@ -17119,9 +17164,9 @@
}
},
"node_modules/react-native-actions-sheet": {
"version": "10.0.0-alpha.8",
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-10.0.0-alpha.8.tgz",
"integrity": "sha512-olKqucpGaxP/kiO2/nw0uPXn69ZdWWhcHFzu2tcv5RBMl+PhRv870HuODbE21X4jXY/fWTG6FwPJqRqWpKkY8A==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-10.1.0.tgz",
"integrity": "sha512-pfbfWs2YqdF3Vo7Cx6LUsDQ/uS3iw8H64iFxZvtLXhZ3cVHWundJ903sZtadzJC+TpQIRV7NQsdnhErhf+wBlg==",
"license": "MIT",
"peerDependencies": {
"react-native": "*",
@@ -17644,13 +17689,10 @@
}
},
"node_modules/react-native-mmkv-storage": {
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/react-native-mmkv-storage/-/react-native-mmkv-storage-12.0.0.tgz",
"integrity": "sha512-sssZInILQBquytDDfjosjEdvevwMPk3fqQQjdjfnH362IcsBsApvtT8yJS406Mz9aJ6VhqVsZw/awltsUuPSYg==",
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-native-mmkv-storage/-/react-native-mmkv-storage-12.0.1.tgz",
"integrity": "sha512-4I4NzjStuCqkeXGfJ7pcACNQ2FlZKlAQqeRvI80iZL7mQcaO5NMO26ILUk2f4LPEvxaT2ns+NcqPMZSj7L83ng==",
"license": "MIT",
"bin": {
"mmkv-link": "autolink/postlink/run.js"
},
"peerDependencies": {
"react-native": "*"
}
@@ -17788,19 +17830,18 @@
}
},
"node_modules/react-native-reanimated": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.3.tgz",
"integrity": "sha512-GP8wsi1u3nqvC1fMab/m8gfFwFyldawElCcUSBJQgfrXeLmsPPUOpDw44lbLeCpcwUuLa05WTVePdTEwCLTUZg==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.2.0.tgz",
"integrity": "sha512-frhu5b8/m/VvaMWz48V8RxcsXnE3hrlErQ5chr21MzAeDCpY4X14sQjvm+jvu3aOI+7Cz2atdRpyhhIuqxVaXg==",
"license": "MIT",
"dependencies": {
"react-native-is-edge-to-edge": "^1.2.1",
"semver": "7.7.2"
"react-native-is-edge-to-edge": "1.2.1",
"semver": "7.7.3"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0",
"react": "*",
"react-native": "*",
"react-native-worklets": ">=0.5.0"
"react-native-worklets": ">=0.7.0"
}
},
"node_modules/react-native-reanimated-progress-bar": {
@@ -17815,9 +17856,9 @@
}
},
"node_modules/react-native-reanimated/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -18058,6 +18099,19 @@
"node": ">=10"
}
},
"node_modules/react-native-view-shot": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/react-native-view-shot/-/react-native-view-shot-4.0.3.tgz",
"integrity": "sha512-USNjYmED7C0me02c1DxKA0074Hw+y/nxo+xJKlffMvfUWWzL5ELh/TJA/pTnVqFurIrzthZDPtDM7aBFJuhrHQ==",
"license": "MIT",
"dependencies": {
"html2canvas": "^1.4.1"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-webview": {
"version": "13.16.0",
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.16.0.tgz",
@@ -18082,33 +18136,49 @@
}
},
"node_modules/react-native-worklets": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.6.1.tgz",
"integrity": "sha512-URca8l7c7Uog7gv4mcg9KILdJlnbvwdS5yfXQYf5TDkD2W1VY1sduEKrD+sA3lUPXH/TG1vmXAvNxCNwPMYgGg==",
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.7.1.tgz",
"integrity": "sha512-KNsvR48ULg73QhTlmwPbdJLPsWcyBotrGPsrDRDswb5FYpQaJEThUKc2ncXE4UM5dn/ewLoQHjSjLaKUVPxPhA==",
"license": "MIT",
"dependencies": {
"@babel/plugin-transform-arrow-functions": "^7.0.0-0",
"@babel/plugin-transform-class-properties": "^7.0.0-0",
"@babel/plugin-transform-classes": "^7.0.0-0",
"@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0",
"@babel/plugin-transform-optional-chaining": "^7.0.0-0",
"@babel/plugin-transform-shorthand-properties": "^7.0.0-0",
"@babel/plugin-transform-template-literals": "^7.0.0-0",
"@babel/plugin-transform-unicode-regex": "^7.0.0-0",
"@babel/preset-typescript": "^7.16.7",
"convert-source-map": "^2.0.0",
"semver": "7.7.2"
"@babel/plugin-transform-arrow-functions": "7.27.1",
"@babel/plugin-transform-class-properties": "7.27.1",
"@babel/plugin-transform-classes": "7.28.4",
"@babel/plugin-transform-nullish-coalescing-operator": "7.27.1",
"@babel/plugin-transform-optional-chaining": "7.27.1",
"@babel/plugin-transform-shorthand-properties": "7.27.1",
"@babel/plugin-transform-template-literals": "7.27.1",
"@babel/plugin-transform-unicode-regex": "7.27.1",
"@babel/preset-typescript": "7.27.1",
"convert-source-map": "2.0.0",
"semver": "7.7.3"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0",
"@babel/core": "*",
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-worklets/node_modules/@babel/plugin-transform-optional-chaining": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz",
"integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==",
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/helper-skip-transparent-expression-wrappers": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/react-native-worklets/node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -20255,6 +20325,15 @@
"dev": true,
"license": "MIT"
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/thingies": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz",
@@ -21066,6 +21145,15 @@
"node": ">= 0.4.0"
}
},
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"license": "MIT",
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/uuid": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "@notesnook/mobile",
"version": "3.3.10-beta.0",
"version": "3.3.11",
"private": true,
"license": "GPL-3.0-or-later",
"scripts": {
@@ -26,12 +26,13 @@
"react": "19.1.1"
},
"dependencies": {
"@ammarahmed/notifee-react-native": "7.4.9",
"@ammarahmed/notifee-react-native": "^7.4.10",
"@ammarahmed/react-native-background-fetch": "^4.2.2",
"@ammarahmed/react-native-eventsource": "1.1.0",
"@ammarahmed/react-native-fingerprint-scanner": "^5.0.1",
"@ammarahmed/react-native-share-extension": "^2.9.5",
"@ammarahmed/react-native-sodium": "^1.6.8",
"@ammarahmed/react-native-upload": "^6.29.0",
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bam.tech/react-native-image-resizer": "3.0.11",
"@callstack/repack": "~5.2.1",
@@ -57,7 +58,7 @@
"@react-native-community/datetimepicker": "^8.4.5",
"@react-native-community/netinfo": "^11.4.1",
"@react-native-community/toolbar-android": "^0.2.1",
"@react-native-documents/picker": "^10.1.7",
"@react-native-documents/picker": "^11.0.1",
"@react-native-masked-view/masked-view": "^0.3.2",
"@react-navigation/elements": "^1.3.3",
"@react-navigation/native": "^6.0.10",
@@ -87,7 +88,7 @@
"react": "19.1.1",
"react-async-hook": "^4.0.0",
"react-native": "0.82.1",
"react-native-actions-sheet": "10.0.0-alpha.8",
"react-native-actions-sheet": "^10.1.0",
"react-native-actions-shortcuts": "^1.0.1",
"react-native-background-actions": "^2.6.6",
"react-native-begin-background-task": "github:blockfirm/react-native-begin-background-task",
@@ -112,7 +113,7 @@
"react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-keychain": "4.0.5",
"react-native-material-menu": "^2.0.0",
"react-native-mmkv-storage": "^12.0.0",
"react-native-mmkv-storage": "^12.0.1",
"react-native-modal-datetime-picker": "14.0.0",
"react-native-navigation-bar-color": "2.0.2",
"react-native-notification-sounds": "0.5.5",
@@ -123,7 +124,7 @@
"react-native-progress": "5.0.0",
"react-native-qrcode-svg": "^6.0.6",
"react-native-quick-sqlite": "^8.2.7",
"react-native-reanimated": "^4.1.3",
"react-native-reanimated": "^4.2.0",
"react-native-reanimated-progress-bar": "1.0.1",
"react-native-safe-area-context": "^5.6.1",
"react-native-scoped-storage": "^1.9.5",
@@ -138,9 +139,10 @@
"react-native-tooltips": "^1.0.3",
"react-native-url-polyfill": "^2.0.0",
"react-native-vector-icons": "10.3.0",
"react-native-view-shot": "^4.0.3",
"react-native-webview": "^13.13.5",
"react-native-wheel-color-picker": "^1.3.1",
"react-native-worklets": "^0.6.1",
"react-native-worklets": "^0.7.1",
"react-native-zip-archive": "6.0.9",
"timeago.js": "4.0.2",
"toggle-switch-react-native": "3.2.0",
@@ -206,4 +208,4 @@
"engines": {
"node": ">=20"
}
}
}

View File

@@ -0,0 +1,13 @@
diff --git a/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js
index 6eca156..5a42107 100644
--- a/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js
+++ b/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js
@@ -208,7 +208,7 @@ class KeyboardAvoidingView extends React.Component<
];
} else {
this._subscriptions = [
- Keyboard.addListener('keyboardDidHide', this._onKeyboardChange),
+ Keyboard.addListener('keyboardDidHide', this._onKeyboardHide),
Keyboard.addListener('keyboardDidShow', this._onKeyboardChange),
];
}

View File

@@ -1,3 +1,22 @@
diff --git a/node_modules/react-native-actions-shortcuts/android/.settings/org.eclipse.buildship.core.prefs b/node_modules/react-native-actions-shortcuts/android/.settings/org.eclipse.buildship.core.prefs
deleted file mode 100644
index 8c253d6..0000000
--- a/node_modules/react-native-actions-shortcuts/android/.settings/org.eclipse.buildship.core.prefs
+++ /dev/null
@@ -1,13 +0,0 @@
-arguments=
-auto.sync=false
-build.scans.enabled=false
-connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.0))
-connection.project.dir=
-eclipse.preferences.version=1
-gradle.user.home=
-java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home
-jvm.arguments=
-offline.mode=false
-override.workspace.settings=true
-show.console.view=true
-show.executions.view=true
diff --git a/node_modules/react-native-actions-shortcuts/android/build.gradle b/node_modules/react-native-actions-shortcuts/android/build.gradle
index 19bd311..642ddbc 100644
--- a/node_modules/react-native-actions-shortcuts/android/build.gradle
@@ -3788,7 +3807,7 @@ index b438823..ba03915 100644
}
diff --git a/node_modules/react-native-actions-shortcuts/android/src/main/java/com/reactnativeshortcuts/ShortcutsModule.kt b/node_modules/react-native-actions-shortcuts/android/src/main/java/com/reactnativeshortcuts/ShortcutsModule.kt
index ec847cc..a4686a0 100644
index ec847cc..f101793 100644
--- a/node_modules/react-native-actions-shortcuts/android/src/main/java/com/reactnativeshortcuts/ShortcutsModule.kt
+++ b/node_modules/react-native-actions-shortcuts/android/src/main/java/com/reactnativeshortcuts/ShortcutsModule.kt
@@ -28,18 +28,18 @@ class ShortcutsModule(reactContext: ReactApplicationContext) :
@@ -3853,7 +3872,7 @@ index ec847cc..a4686a0 100644
shortcutManager?.removeAllDynamicShortcuts()
}
@@ -145,6 +145,19 @@ class ShortcutsModule(reactContext: ReactApplicationContext) :
@@ -145,6 +145,17 @@ class ShortcutsModule(reactContext: ReactApplicationContext) :
fun isSupported(): Boolean {
return Build.VERSION.SDK_INT >= 25
}
@@ -3863,9 +3882,7 @@ index ec847cc..a4686a0 100644
+ requestCode: Int,
+ resultCode: Int,
+ data: Intent?
+ ) {
+ TODO("Not yet implemented")
+ }
+ ) {}
+
+ override fun onNewIntent(intent: Intent) {
+ emitEvent(intent)

View File

@@ -0,0 +1,12 @@
diff --git a/node_modules/react-native-gesture-handler/android/build.gradle b/node_modules/react-native-gesture-handler/android/build.gradle
index ac149a0..37f620c 100644
--- a/node_modules/react-native-gesture-handler/android/build.gradle
+++ b/node_modules/react-native-gesture-handler/android/build.gradle
@@ -187,6 +187,7 @@ android {
exclude "**/libreactnative.so"
exclude "**/libjsi.so"
exclude "**/libc++_shared.so"
+ exclude "**/libfbjni.so"
}
sourceSets.main {

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "@notesnook/web",
"description": "Your private note taking space",
"version": "3.3.5",
"version": "3.3.6",
"private": true,
"main": "./src/app.js",
"homepage": "https://notesnook.com/",
@@ -86,7 +86,7 @@
"devDependencies": {
"@babel/core": "7.22.5",
"@cloudflare/workers-types": "^4.20250224.0",
"@playwright/test": "1.48.2",
"@playwright/test": "1.57.0",
"@swc/plugin-react-remove-properties": "^6.0.2",
"@trpc/server": "10.45.2",
"@types/babel__core": "^7.20.1",

View File

@@ -48,6 +48,7 @@ import { getFontSizes } from "@notesnook/theme/theme/font/fontsize.js";
import { useWindowControls } from "./hooks/use-window-controls";
import { STATUS_BAR_HEIGHT } from "./common/constants";
import { NavigationEvents } from "./navigation";
import { db } from "./common/db";
new WebExtensionRelay();
@@ -143,6 +144,10 @@ function DesktopAppContents() {
const isTablet = useTablet();
const navPane = useRef<SplitPaneImperativeHandle>(null);
useEffect(() => {
(async () => {})();
}, []);
useEffect(() => {
if (isTablet) navPane.current?.collapse(0);
else if (navPane.current?.isCollapsed(0)) navPane.current?.expand(0);

View File

@@ -25,6 +25,7 @@ import {
isFeatureSupported
} from "./utils/feature-check";
import { initializeLogger } from "./utils/logger";
import { shouldShowWrapped } from "./utils/should-show-wrapped";
type Route<TProps = null> = {
component: () => Promise<{
@@ -55,6 +56,9 @@ const routes = {
"/plans": {
component: () => import("./views/plans")
},
"/wrapped": {
component: () => import("./views/wrapped")
},
"/checkout": {
component: () => import("./views/checkout")
},
@@ -122,6 +126,12 @@ function getRoute(): RouteWithPath<AuthProps> | RouteWithPath {
routes[path] ? { route: routes[path], path } : null
) as RouteWithPath<AuthProps> | null;
if (route?.path === "/wrapped" && !shouldShowWrapped())
return {
route: routes.default,
path: "default"
};
return signup || sessionExpired || route || fallback;
}

View File

@@ -226,11 +226,13 @@ export default function TabsView() {
<TableOfContents sessionId={activeSession.id} />
</Pane>
) : null}
{arePropertiesVisible && activeSession && (
<Pane id="properties-pane" initialSize={250} minSize={250}>
<Properties sessionId={activeSession.id} />
</Pane>
)}
{arePropertiesVisible &&
activeSession &&
activeSession.type !== "new" && (
<Pane id="properties-pane" initialSize={250} minSize={250}>
<Properties sessionId={activeSession.id} />
</Pane>
)}
</SplitPane>
<DropZone overlayRef={overlayRef} />
</ScopedThemeProvider>
@@ -848,17 +850,27 @@ function useDragOverlay() {
e.preventDefault();
}
function handleKeyDown(e: KeyboardEvent) {
if (e.key === "Escape") {
hideOverlay();
}
}
dropElement.addEventListener("dragenter", showOverlay);
overlay.addEventListener("drop", hideOverlay);
overlay.addEventListener("dragenter", allowDrag);
overlay.addEventListener("dragover", allowDrag);
overlay.addEventListener("dragleave", hideOverlay);
overlay.addEventListener("click", hideOverlay);
document.addEventListener("keydown", handleKeyDown);
return () => {
dropElement.removeEventListener("dragenter", showOverlay);
overlay.removeEventListener("drop", hideOverlay);
overlay.removeEventListener("dragenter", allowDrag);
overlay.removeEventListener("dragover", allowDrag);
overlay.removeEventListener("dragleave", hideOverlay);
overlay.removeEventListener("click", hideOverlay);
document.removeEventListener("keydown", handleKeyDown);
};
}, []);

View File

@@ -202,7 +202,7 @@ function ListItem<TItem extends Item, TContext>(
data-test-id={`title`}
variant={"body"}
sx={{
whiteSpace: "nowrap",
whiteSpace: "pre",
overflow: "hidden",
textOverflow: "ellipsis",
fontWeight: isCompact ? "body" : "medium",

View File

@@ -0,0 +1,143 @@
/*
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 { Box, Flex, Text } from "@theme-ui/components";
import { SxProp } from "@theme-ui/core";
type MonthlyActivityHeatmapProps = {
monthlyStats: Record<string, number>;
year?: number;
} & SxProp;
const MONTHS = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
];
const MONTHS_SHORT = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
export function MonthlyActivityHeatmap({
monthlyStats
}: MonthlyActivityHeatmapProps) {
// Find max count for bar height calculation
const maxCount = Math.max(...Object.values(monthlyStats), 1);
// Create month data with counts
const monthData = MONTHS.map((month) => ({
month,
count: monthlyStats[month] || 0
}));
return (
<>
{/* Bar chart */}
<Flex
sx={{
alignItems: "flex-end",
justifyContent: "space-between",
gap: 2,
height: "100%",
width: "100%",
position: "relative",
pb: 2
}}
>
{monthData.map((data, index) => {
const barHeight = maxCount > 0 ? (data.count / maxCount) * 100 : 0;
return (
<Flex
key={data.month}
sx={{
flexDirection: "column",
alignItems: "center",
justifyContent: "flex-end",
flex: 1,
gap: 2,
cursor: "pointer",
"&:hover .tooltip": { opacity: 1 },
"&:hover .bar": { bg: "accent" },
height: "100%"
}}
>
<Flex
className="tooltip"
sx={{ opacity: 0, bg: "background", zIndex: 1000 }}
>
<Text variant="body" sx={{ fontWeight: "bold" }}>
{data.count}
</Text>
</Flex>
<Box
className="bar"
sx={{
width: "100%",
height: `${barHeight}%`,
minHeight: data.count > 0 ? "10px" : "5px",
bg: maxCount === data.count ? "accent" : "paragraph",
borderRadius: "4px 4px 0 0",
transition: "all 0.3s ease",
position: "relative",
"&:hover": {
transform: "scaleY(1.05)",
transformOrigin: "bottom"
}
}}
></Box>
<Text
sx={{
fontSize: "11px",
color: "paragraph-secondary",
fontWeight: "normal",
transition: "all 0.3s ease"
}}
>
{MONTHS_SHORT[index]}
</Text>
</Flex>
);
})}
</Flex>
</>
);
}

View File

@@ -97,7 +97,6 @@ import { strings } from "@notesnook/intl";
import Tags from "../../views/tags";
import { Notebooks } from "../../views/notebooks";
import { UserProfile } from "../../dialogs/settings/components/user-profile";
import { SUBSCRIPTION_STATUS } from "../../common/constants";
import {
checkFeature,
createSetDefaultHomepageMenuItem,
@@ -105,7 +104,6 @@ import {
withFeatureCheck
} from "../../common";
import { TabItem } from "./tab-item";
import Notice from "../notice";
import { Freeze } from "react-freeze";
import { CREATE_BUTTON_MAP } from "../../common";
import { useStore as useNotebookStore } from "../../stores/notebook-store";
@@ -118,6 +116,7 @@ import {
useIsFeatureAvailable
} from "@notesnook/common";
import { isUserSubscribed } from "../../hooks/use-is-user-premium";
import { shouldShowWrapped } from "../../utils/should-show-wrapped";
type Route = {
id: "notes" | "favorites" | "reminders" | "monographs" | "trash" | "archive";
@@ -449,7 +448,17 @@ function NavigationMenu({ onExpand }: { onExpand?: () => void }) {
</FlexScrollContainer>
</Freeze>
</Flex>
{currentTab.id === "home" && !isCollapsed ? <Notice /> : null}
{currentTab.id === "home" && !isCollapsed && shouldShowWrapped() ? (
<Button
variant="accent"
sx={{ m: 2 }}
onClick={() => {
hardNavigate("/wrapped");
}}
>
🎉 Wrapped {new Date().getFullYear()}
</Button>
) : null}
</ScopedThemeProvider>
);
}

View File

@@ -153,7 +153,7 @@ export function Notebook(props: NotebookProps) {
variant={"body"}
color={isOpened ? "paragraph-selected" : "paragraph"}
sx={{
whiteSpace: "nowrap",
whiteSpace: "pre",
overflow: "hidden",
textOverflow: "ellipsis",
fontWeight: "body",

View File

@@ -67,7 +67,7 @@ function Tag(props: TagProps) {
variant={"body"}
color={isSelected ? "paragraph-selected" : "paragraph"}
sx={{
whiteSpace: "nowrap",
whiteSpace: "pre",
overflow: "hidden",
textOverflow: "ellipsis",
fontWeight: "body",

View File

@@ -147,7 +147,7 @@ export const BuyDialog = DialogManager.register(function BuyDialog(
</Text>
</Flex>
<PlansList
selectedPlan={user?.subscription.productId}
selectedPlan={user?.subscription?.productId}
recommendedPlan={SubscriptionPlan.PRO}
onPlanSelected={(plan) => selectPlan(plan)}
/>

View File

@@ -42,7 +42,7 @@ import { useStore as useUserStore } from "../../stores/user-store";
import { getCurrencySymbol } from "../../common/currencies";
type PlansListProps = {
selectedPlan?: string;
selectedPlan?: string | null;
loadAllPlans?: boolean;
ignoreTrial?: boolean;
recommendedPlan?: SubscriptionPlan;

View File

@@ -93,14 +93,23 @@ const features: Record<FeatureKeys, Feature> = {
]
: [
{
title: "Notesnook Circle",
title: "Wrapped 2025",
subtitle:
"Notesnook Circle brings together trusted partners who share our commitment to privacy, transparency, and user freedom. As a member you get exclusive discounts and offers from our partners. Check it out in Settings > Notesnook Circle."
"Notesnook Wrapped 2025 is your personal recap of the year you spent with Notesnook. Available throughout December and accessible from the sidebar, it highlights your activity, stats and how you used Notesnook this year."
},
{
title: "Collapsible headings",
title: "Monograph analytics",
subtitle:
"You can now collapse and expand headings in your notes. This makes it easier to manage large notes and focus on specific sections."
"Pro users can now see view count analytics for monographs."
},
{
title: "Twitter/X embed support",
subtitle: "Simply paste the post URL in the Insert Embed dialog."
},
{
title: "New keyboard shortcuts",
subtitle:
"Use Ctrl/Cmd + Alt/Option + F to open search/replace in the editor. We have also added Ctrl/Cmd + Alt/Option + C for toggling text color."
}
],
cta: {

View File

@@ -454,7 +454,7 @@ export async function checkUpload(
expectedSize: number
) {
const size = await getUploadedFileSize(filename);
const totalChunks = Math.ceil(size / chunkSize);
const totalChunks = Math.ceil(size / (chunkSize + ABYTES));
const decryptedLength = size - totalChunks * ABYTES;
const error =
size === 0
@@ -520,7 +520,7 @@ async function downloadFile(
throw new Error(error);
}
const totalChunks = Math.ceil(size / chunkSize);
const totalChunks = Math.ceil(size / (chunkSize + ABYTES));
const decryptedLength = size - totalChunks * ABYTES;
if (attachment && attachment.size !== decryptedLength) {
const error = `File length mismatch. Expected ${attachment.size} but got ${decryptedLength} bytes. Please upload this file again from the attachment manager. (File hash: ${filename})`;

View File

@@ -20,8 +20,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { INNCrypto } from "@notesnook/crypto";
import CryptoWorker from "./nncrypto.worker?worker";
import { wrap } from "comlink";
import { NNCrypto as NNCryptoSync } from "@notesnook/crypto";
import { isTransferableStreamsSupported } from "../utils/feature-check";
export const NNCrypto = wrap<INNCrypto>(new CryptoWorker()) as INNCrypto;
export const NNCrypto = isTransferableStreamsSupported()
? (wrap<INNCrypto>(new CryptoWorker()) as INNCrypto)
: new NNCryptoSync();
// TODO: disable until we fix the `pull failed` errors for good.
// IS_DESKTOP_APP && window.NativeNNCrypto
// ? new window.NativeNNCrypto()

View File

@@ -22,9 +22,28 @@ const FEATURE_CHECKS = {
cache: false,
indexedDB: false,
clonableCryptoKey: false,
applePaySupported: false
applePaySupported: false,
transferableStreams: false
};
export function isTransferableStreamsSupported() {
try {
const readable = new ReadableStream({
pull(controller) {
controller.enqueue(new Uint8Array([1, 2, 3]));
controller.close();
}
});
window.postMessage(readable, [readable]);
FEATURE_CHECKS.transferableStreams = true;
return true;
} catch {
console.log("Transferable streams not supported");
FEATURE_CHECKS.transferableStreams = false;
return false;
}
}
async function isApplePaySupported() {
try {
FEATURE_CHECKS.applePaySupported =
@@ -99,6 +118,7 @@ async function isCryptoKeyClonable() {
export async function initializeFeatureChecks() {
await Promise.allSettled([
isTransferableStreamsSupported(),
isOPFSSupported(),
isCacheSupported(),
isIndexedDBSupported(),

View File

@@ -0,0 +1,23 @@
/*
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/>.
*/
export const shouldShowWrapped = () => {
const now = new Date();
return now.getMonth() === 11;
};

View File

@@ -0,0 +1,776 @@
/*
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 { Button, Flex, Text, Box, FlexProps } from "@theme-ui/components";
import { db } from "../common/db";
import { useState, useEffect, useRef } from "react";
import { NoteStats, WrappedStats } from "@notesnook/core";
import { formatBytes } from "@notesnook/common";
import { ArrowDown, ArrowLeft, Loading } from "../components/icons";
import { hardNavigate } from "../navigation";
import { MonthlyActivityHeatmap } from "../components/monthly-activity-heatmap";
function formatNumber(num: number) {
return num.toLocaleString();
}
function formatCount(num: number) {
return num > 1000 ? `${(num / 1000).toFixed(0)}k` : num.toString();
}
interface SlideProps {
children: React.ReactNode;
pattern?: "dots" | "grid" | "diagonal" | "none";
}
function Slide({
children,
pattern = "none",
sx,
...flexProps
}: SlideProps & FlexProps) {
const slideRef = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
}
},
{ threshold: 0.5 }
);
if (slideRef.current) {
observer.observe(slideRef.current);
}
return () => {
if (slideRef.current) {
observer.unobserve(slideRef.current);
}
};
}, []);
const getBackgroundPattern = () => {
switch (pattern) {
case "dots":
return "radial-gradient(circle, var(--border) 1px, transparent 1px)";
case "grid":
return "linear-gradient(var(--border) 1px, transparent 1px), linear-gradient(90deg, var(--border) 1px, transparent 1px)";
case "diagonal":
return "repeating-linear-gradient(-45deg, transparent, transparent 20px, var(--border) 20px, var(--border) 21px)";
default:
return "none";
}
};
const getBackgroundSize = () => {
switch (pattern) {
case "dots":
return "20px 20px";
case "grid":
return "30px 30px";
case "diagonal":
default:
return "auto";
}
};
return (
<Flex
ref={slideRef}
sx={{
minHeight: "100vh",
minWidth: "100%",
scrollSnapAlign: "start",
scrollSnapStop: "always",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
p: 4,
position: "relative",
backgroundImage: getBackgroundPattern(),
backgroundSize: getBackgroundSize(),
backgroundPosition: "center"
}}
>
<Flex
{...flexProps}
sx={{
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
opacity: isVisible ? 1 : 0,
transform: isVisible ? "translateY(0)" : "translateY(50px)",
transition: "opacity 0.8s ease-out, transform 0.8s ease-out",
...sx
}}
>
{children}
</Flex>
</Flex>
);
}
function WelcomeSlide({ loading }: { loading: boolean }) {
return (
<Slide pattern="dots">
<Text
sx={{
fontSize: "6rem",
fontWeight: "bold",
mb: 3,
textAlign: "center",
background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
animation: "slideUp 1s ease-out"
}}
>
🎉
</Text>
<Text
variant="heading"
sx={{
fontSize: ["2rem", "3rem", "4rem"],
fontWeight: "bold",
mb: 2,
textAlign: "center",
animation: "slideUp 1s ease-out 0.2s both"
}}
>
Your {new Date().getFullYear()} Wrapped
</Text>
{loading ? (
<Loading
sx={{
animation: "fadeIn 1s ease-out 0.4s both"
}}
size={30}
/>
) : (
<>
<Text
sx={{
fontSize: ["1rem", "1.2rem"],
textAlign: "center",
animation: "fadeIn 1s ease-out 0.4s both"
}}
>
Let&apos;s look back at your year in Notesnook
</Text>
<Text
variant="body"
sx={{
mt: 4,
fontSize: "title",
color: "paragraph-secondary",
textAlign: "center",
animation: "fadeIn 1s ease-out 0.4s both"
}}
>
Scroll down to explore
</Text>
<ArrowDown sx={{ mt: 2 }} color="paragraph-secondary" />
</>
)}
</Slide>
);
}
function TotalNotesSlide({ count }: { count: number }) {
return (
<Slide pattern="dots">
<Flex>
<Flex sx={{ flexDirection: "column" }}>
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"],
textAlign: "center",
animation: "fadeIn 0.8s ease-out"
}}
>
You created
</Text>
<Text
variant="heading"
sx={{
fontSize: ["5rem", "7rem", "8rem"],
textAlign: "center",
color: "accent",
animation: "scaleIn 0.8s ease-out 0.2s both"
}}
>
{formatNumber(count)}
</Text>
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"],
textAlign: "center",
animation: "fadeIn 0.8s ease-out 0.4s both"
}}
>
notes this year
</Text>
</Flex>
<Flex
sx={{
flexDirection: "column",
ml: [0, 5],
mt: [4, 0],
borderLeft: ["none", "1px solid var(--border)"],
pl: [0, 5],
borderTop: ["1px solid var(--border)", "none"]
}}
>
<Text
variant="body"
color="paragraph-secondary"
sx={{
fontSize: ["1.2rem", "1.2rem"],
animation: "fadeIn 0.8s ease-out",
lineHeight: 1.8
}}
>
That&apos;s <strong>{formatNumber(count)}</strong>
<br />
ideas
<br />
thoughts
<br />
memories.
<br />
100% encrypted.
<br />
100% yours.
</Text>
</Flex>
</Flex>
</Slide>
);
}
const TOTAL_WORDS_TAGLINES = {
1000: "That's longer than the average blog post on Medium!",
10000: "That's real commitment to your mindspace.",
25000: "That's almost the length of a short novel!",
50000:
"That's the length of The Great Gatsby if you were F. Scott Fitzgerald.",
100000: "You wrote more than many published authors this year.",
250000: "Woah! Your notes could fill a small library.",
500000: "Your vault is becoming a chronicle.",
1000000: "That's longer than the entire Harry Potter series!"
};
function TotalWordsSlide({ count }: { count: number }) {
const tagline = Object.entries(TOTAL_WORDS_TAGLINES)
.sort((a, b) => Number(b[0]) - Number(a[0]))
.find(([threshold]) => count >= Number(threshold))?.[1];
return (
<Slide pattern="dots">
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"],
textAlign: "center",
animation: "fadeIn 0.8s ease-out"
}}
>
You wrote a total of
</Text>
<Text
variant="heading"
sx={{
fontSize: ["5rem", "7rem"],
textAlign: "center",
color: "accent",
animation: "scaleIn 0.8s ease-out 0.2s both"
}}
>
{formatNumber(count)}
</Text>
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"],
textAlign: "center",
animation: "fadeIn 0.8s ease-out 0.4s both"
}}
>
words this year
</Text>
{tagline ? (
<Text
variant="body"
color="paragraph-secondary"
sx={{
fontSize: ["1.2rem", "1.2rem"],
animation: "fadeIn 0.8s ease-out",
borderTop: "1px solid var(--border)",
mt: 3,
pt: 3
}}
>
{tagline}
</Text>
) : null}
</Slide>
);
}
type ActivityStatsSlideProps = {
mostNotesCreatedInMonth: NoteStats["mostNotesCreatedInMonth"];
mostNotesCreatedInDay: NoteStats["mostNotesCreatedInDay"];
};
function ActivityStatsSlide({
mostNotesCreatedInMonth,
mostNotesCreatedInDay
}: ActivityStatsSlideProps) {
if (!mostNotesCreatedInMonth && !mostNotesCreatedInDay) return null;
return (
<Slide pattern="diagonal" sx={{ alignItems: "start" }}>
{mostNotesCreatedInMonth && (
<>
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"]
}}
>
Your most productive month was
</Text>
<Flex
sx={{
alignItems: "center",
justifyContent: "space-between",
width: "100%"
}}
>
<Text
variant="heading"
sx={{
fontSize: ["5rem", "7rem", "3rem"]
}}
>
{mostNotesCreatedInMonth.month}
</Text>
<Text
variant="body"
sx={{ fontSize: "1rem" }}
color="paragraph-secondary"
>
{formatNumber(mostNotesCreatedInMonth.count)} notes
</Text>
</Flex>
</>
)}
{mostNotesCreatedInDay && (
<>
<Text
variant="body"
sx={{
fontSize: ["1.2rem", "1.5rem"],
mt: 5
}}
>
Your favorite day to write was
</Text>
<Flex
sx={{
alignItems: "center",
justifyContent: "space-between",
width: "100%"
}}
>
<Text
variant="heading"
sx={{
fontSize: ["5rem", "7rem", "3rem"]
}}
>
{mostNotesCreatedInDay.day}
</Text>
<Text
variant="body"
sx={{ fontSize: "1rem" }}
color="paragraph-secondary"
>
{formatNumber(mostNotesCreatedInDay.count)} notes
</Text>
</Flex>
</>
)}
</Slide>
);
}
function SummarySlide({ stats }: { stats: WrappedStats }) {
return (
<Slide
pattern="dots"
sx={{
bg: "background-secondary",
border: "1px solid var(--accent)",
borderRadius: "dialog",
boxShadow: "-15px 15px 0px 0px var(--accent)",
p: 5
}}
>
<svg
style={{
height: 20,
width: 20,
position: "absolute",
bottom: "20px",
right: "20px"
}}
>
<use href="#themed-logo" />
</svg>
<Text
variant="heading"
sx={{
fontSize: "1.2rem",
fontWeight: 800,
textAlign: "center",
transform: "skew(-10deg) scaleX(1.5)",
letterSpacing: "-1px",
mb: "25px",
textDecorationLine: "underline",
textDecorationColor: "border"
}}
>
NOTESNOOK WRAPPED {new Date().getFullYear()}
</Text>
<Flex
sx={{
flexDirection: ["column", "row"],
gap: "30px",
justifyContent: "center",
alignItems: "center"
}}
>
<Flex
sx={{
flexDirection: "column",
flex: 1
}}
>
<Box
sx={{
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
gridTemplateRows: "1fr 1fr",
gap: 4,
height: "100%"
}}
>
{[
{
icon: "📝",
count: stats.totalNotes,
label: "Notes"
},
{
icon: "🎨",
count: stats.totalColors,
label: "Colors"
},
{
icon: "📚",
count: stats.totalNotebooks,
label: "Notebooks"
},
{
icon: "🏷️",
count: stats.totalTags,
label: "Tags"
},
{
icon: "📂",
count: stats.totalAttachments,
label: "Files"
},
{
icon: "☁️",
count: stats.totalMonographs,
label: "Monographs"
}
].map(({ icon, count, label }) => (
<Flex
key={label}
sx={{
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
gap: 1
}}
>
<Text sx={{ fontSize: "1.5rem" }}>{icon}</Text>
<Text
sx={{
fontSize: "2rem",
fontWeight: "bold"
}}
>
{formatCount(count)}
</Text>
<Text sx={{ fontSize: "0.85rem", color: "fontTertiary" }}>
{label}
</Text>
</Flex>
))}
</Box>
<Flex
sx={{
flexDirection: "column",
gap: 2,
borderTop: "1px solid var(--border)",
mt: 6,
pt: 3,
"& strong": {
color: "accent"
}
}}
>
<Text sx={{ fontSize: "1rem", fontWeight: "bold" }}>
Fun facts of the year
</Text>
{stats.mostNotesCreatedInMonth && (
<Text sx={{ fontSize: "0.9rem", color: "fontTertiary" }}>
📅 Your most productive month was{" "}
<Text as="strong">{stats.mostNotesCreatedInMonth.month}</Text>
</Text>
)}
{stats.mostNotesCreatedInDay && (
<Text sx={{ fontSize: "0.9rem", color: "fontTertiary" }}>
🗓 Your favorite day to write was{" "}
<Text as="strong">{stats.mostNotesCreatedInDay.day}</Text>
</Text>
)}
{stats.largestNote && (
<Text
sx={{
fontSize: "0.9rem",
color: "fontTertiary",
maxWidth: 340
}}
>
📝 Your longest note was{" "}
<Text as="strong">
{formatNumber(stats.largestNote.length)}
{" words"}
</Text>
</Text>
)}
{stats.largestAttachment && (
<Text
sx={{
fontSize: "0.9rem",
color: "fontTertiary",
maxWidth: 340
}}
>
🔗 Your largest attachment was{" "}
<strong>{formatBytes(stats.largestAttachment.size)}</strong>
</Text>
)}
</Flex>
</Flex>
<Flex
sx={{
flexDirection: "column",
justifyContent: "stretch",
height: "100%",
flex: 1
}}
>
<Flex
sx={{
flexDirection: "column",
justifyContent: "center",
alignItems: "center"
}}
>
<Text sx={{ fontSize: "2.5rem" }}></Text>
<Text
sx={{
fontSize: "3rem",
fontWeight: "bold",
color: "accent"
}}
>
{formatNumber(stats.totalWords)}
</Text>
<Text sx={{ fontSize: "1rem", color: "fontTertiary" }}>
Words Written
</Text>
</Flex>
<Flex
sx={{
flexDirection: "column",
borderTop: "1px solid var(--border)",
mt: 6,
pt: 2,
flex: 1
}}
>
<MonthlyActivityHeatmap monthlyStats={stats.monthlyStats} />
<Text
sx={{
fontSize: "1rem",
color: "fontTertiary",
textAlign: "center"
}}
>
Notes per month
</Text>
</Flex>
</Flex>
</Flex>
<Text
variant="body"
color="paragraph-secondary"
sx={{ mt: 2, borderTop: "1px solid var(--border)", pt: 2 }}
>
Generated 100% locally on your device.
</Text>
</Slide>
);
}
export default function Wrapped() {
const [loading, setLoading] = useState(false);
const [stats, setStats] = useState<WrappedStats>();
useEffect(() => {
async function loadWrapped() {
setLoading(true);
try {
console.time("wrapped - getting from core");
const wrapped = await db.wrapped.get();
console.timeEnd("wrapped - getting from core");
setStats(wrapped);
} finally {
setLoading(false);
}
}
loadWrapped();
}, []);
return (
<>
<style>
{`
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}
`}
</style>
<Flex
sx={{
position: "fixed",
top: 0,
left: 0,
right: 0,
bottom: 0,
flexDirection: "column",
overflowY: "scroll",
overflowX: "hidden",
scrollSnapType: "y mandatory",
scrollBehavior: "smooth",
"&::-webkit-scrollbar": {
display: "none"
},
msOverflowStyle: "none",
scrollbarWidth: "none"
}}
>
<WelcomeSlide loading={loading} />
{stats ? (
<>
<TotalNotesSlide count={stats.totalNotes} />
{stats.totalWords > 0 && (
<TotalWordsSlide count={stats.totalWords} />
)}
{(stats.mostNotesCreatedInMonth || stats.mostNotesCreatedInDay) && (
<ActivityStatsSlide
mostNotesCreatedInMonth={stats.mostNotesCreatedInMonth}
mostNotesCreatedInDay={stats.mostNotesCreatedInDay}
/>
)}
<SummarySlide stats={stats} />
</>
) : null}
</Flex>
<Button
onClick={() => hardNavigate("/")}
variant="secondary"
sx={{
position: "fixed",
top: 3,
left: 3,
zIndex: 1000
}}
>
<Flex sx={{ alignItems: "center", gap: 1, justifyContent: "center" }}>
<ArrowLeft size={16} />
<Text variant="body">Go back to app</Text>
</Flex>
</Button>
</>
);
}

View File

@@ -9,71 +9,73 @@ The following keyboard shortcuts will help you navigate Notesnook faster.
### General
| Description | Web | Windows/Linux | Mac |
| -------------------------------------------------- | ------ | ------------- | --- |
| Search in notes list view if editor is not focused | Ctrl F | Ctrl F | ⌘ F |
| Settings | Ctrl , | Ctrl , | ⌘ , |
| Keyboard shortcuts | Ctrl / | Ctrl / | ⌘ / |
| New note | - | Ctrl N | ⌘ N |
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| Search in notes list view if editor is not focused | Ctrl F | Ctrl F | ⌘ F |
| Settings | Ctrl , | Ctrl , | ⌘ , |
| Keyboard shortcuts | Ctrl / | Ctrl / | ⌘ / |
| New note | - | Ctrl N | ⌘ N |
### Navigation
| Description | Web | Windows/Linux | Mac |
| ---------------- | ------------------------- | ------------- | ------- |
| Next tab | Ctrl Alt → / Ctrl Alt ⇧ → | Ctrl tab | ⌘ tab |
| Previous tab | Ctrl Alt ← / Ctrl Alt ⇧ ← | Ctrl ⇧ tab | ⌘ ⇧ tab |
| Command palette | Ctrl ⇧ P | Ctrl ⇧ P | ⌘ ⇧ P |
| Quick open | Ctrl P | Ctrl P | ⌘ P |
| New tab | - | Ctrl T | ⌘ T |
| Close active tab | - | Ctrl W | ⌘ W |
| Close all tabs | - | Ctrl ⇧ W | ⌘ ⇧ W |
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| Next tab | Ctrl Alt → / Ctrl Alt ⇧ → | Ctrl tab | ⌘ tab |
| Previous tab | Ctrl Alt ← / Ctrl Alt ⇧ ← | Ctrl ⇧ tab | ⌘ ⇧ tab |
| Command palette | Ctrl ⇧ P / Ctrl ⇧ : | Ctrl ⇧ P | ⌘ ⇧ P |
| Quick open | Ctrl P | Ctrl P | ⌘ P |
| New tab | - | Ctrl T | ⌘ T |
| Close active tab | - | Ctrl W | ⌘ W |
| Close all tabs | - | Ctrl ⇧ W | ⌘ ⇧ W |
### Editor
| Description | Web | Windows/Linux | Mac |
| ---------------------------------- | ----------------- | ----------------- | ----------- |
| Add attachment | Ctrl ⇧ A | Ctrl ⇧ A | ⌘ ⇧ A |
| Insert blockquote | Ctrl ⇧ B | Ctrl ⇧ B | ⌘ ⇧ B |
| Toggle bold | Ctrl B | Ctrl B | ⌘ B |
| Toggle bullet list | Ctrl ⇧ 8 | Ctrl ⇧ 8 | ⌘ ⇧ 8 |
| Toggle check list | Ctrl ⇧ 9 | Ctrl ⇧ 9 | ⌘ ⇧ 9 |
| Split list item | ↵ | ↵ | ↵ |
| Lift list item | ⇧ Tab | ⇧ Tab | ⇧ Tab |
| Sink list item | Ctrl ⇧ Down | Ctrl ⇧ Down | ⌘ ⇧ Down |
| Toggle code | Ctrl E | Ctrl E | ⌘ E |
| Toggle code block | Ctrl ⇧ C | Ctrl ⇧ C | ⌘ ⇧ C |
| Insert date | Alt D | Alt D | ⌥ D |
| Insert time | Alt T | Alt T | ⌥ T |
| Insert date and time | Ctrl Alt D | Ctrl Alt D | ⌘ ⌥ D |
| Insert date and time with timezone | Ctrl Alt Z | Ctrl Alt Z | ⌘ ⌥ Z |
| Increase font size | Ctrl [ | Ctrl [ | ⌘ [ |
| Decrease font size | Ctrl ] | Ctrl ] | ⌘ ] |
| Insert paragraph | Ctrl ⇧ 0 | Ctrl ⇧ 0 | ⌘ 0 |
| Insert heading 1 | Ctrl Alt 1 | Ctrl Alt 1 | ⌘ ⌥ 1 |
| Insert heading 2 | Ctrl Alt 2 | Ctrl Alt 2 | ⌘ ⌥ 2 |
| Insert heading 3 | Ctrl Alt 3 | Ctrl Alt 3 | ⌘ ⌥ 3 |
| Insert heading 4 | Ctrl Alt 4 | Ctrl Alt 4 | ⌘ ⌥ 4 |
| Insert heading 5 | Ctrl Alt 5 | Ctrl Alt 5 | ⌘ ⌥ 5 |
| Insert heading 6 | Ctrl Alt 6 | Ctrl Alt 6 | ⌘ ⌥ 6 |
| Undo | Ctrl Z | Ctrl Z | ⌘ Z |
| Redo | Ctrl ⇧ Z / Ctrl Y | Ctrl ⇧ Z / Ctrl Y | ⌘ ⇧ Z / ⌘ Y |
| Add image | Ctrl ⇧ I | Ctrl ⇧ I | ⌘ ⇧ I |
| Toggle italic | Ctrl I | Ctrl I | ⌘ I |
| Remove formatting in selection | Ctrl \ | Ctrl \ | ⌘ \ |
| Insert internal link | Ctrl ⇧ K | Ctrl ⇧ K | ⌘ ⇧ K |
| Insert link | Ctrl K | Ctrl K | ⌘ K |
| Insert math block | Ctrl ⇧ M | Ctrl ⇧ M | ⌘ ⇧ M |
| Toggle ordered list | Ctrl ⇧ 7 | Ctrl ⇧ 7 | ⌘ ⇧ 7 |
| Toggle outline list | Ctrl ⇧ O | Ctrl ⇧ O | ⌘ ⇧ O |
| Toggle outline list expand | Ctrl Space | Ctrl Space | ⌘ Space |
| Open search | Ctrl F | Ctrl F | ⌘ F |
| Toggle strike | Ctrl ⇧ S | Ctrl ⇧ S | ⌘ ⇧ S |
| Toggle subscript | Ctrl , | Ctrl , | ⌘ , |
| Toggle superscript | Ctrl . | Ctrl . | ⌘ . |
| Toggle task list | Ctrl ⇧ T | Ctrl ⇧ T | ⌘ ⇧ T |
| Text align center | Ctrl ⇧ E | Ctrl ⇧ E | ⌘ ⇧ E |
| Text align justify | Ctrl ⇧ J | Ctrl ⇧ J | ⌘ ⇧ J |
| Text align left | Ctrl ⇧ L | Ctrl ⇧ L | ⌘ ⇧ L |
| Text align right | Ctrl ⇧ R | Ctrl ⇧ R | ⌘ ⇧ R |
| Underline | Ctrl U | Ctrl U | ⌘ U |
| Toggle highlight | Ctrl Alt H | Ctrl Alt H | ⌘ ⌥ H |
| Description | Web | Windows/Linux | Mac |
| --- | --- | --- | --- |
| Add attachment | Ctrl ⇧ A | Ctrl ⇧ A | ⌘ ⇧ A |
| Insert blockquote | Ctrl ⇧ B | Ctrl ⇧ B | ⌘ ⇧ B |
| Toggle bold | Ctrl B | Ctrl B | ⌘ B |
| Toggle bullet list | Ctrl ⇧ 8 | Ctrl ⇧ 8 | ⌘ ⇧ 8 |
| Toggle check list | Ctrl ⇧ 9 | Ctrl ⇧ 9 | ⌘ ⇧ 9 |
| Split list item | ↵ | ↵ | ↵ |
| Lift list item | ⇧ Tab | ⇧ Tab | ⇧ Tab |
| Sink list item | Ctrl ⇧ Down | Ctrl ⇧ Down | ⌘ ⇧ Down |
| Toggle code | Ctrl E | Ctrl E | ⌘ E |
| Toggle code block | Ctrl ⇧ C | Ctrl ⇧ C | ⌘ ⇧ C |
| Insert date | Alt D | Alt D | ⌥ D |
| Insert time | Alt T | Alt T | ⌥ T |
| Insert date and time | Ctrl Alt D | Ctrl Alt D | ⌘ ⌥ D |
| Insert date and time with timezone | Ctrl Alt Z | Ctrl Alt Z | ⌘ ⌥ Z |
| Increase font size | Ctrl [ | Ctrl [ | ⌘ [ |
| Decrease font size | Ctrl ] | Ctrl ] | ⌘ ] |
| Insert paragraph | Ctrl Alt 0 | Ctrl Alt 0 | ⌘ 0 |
| Insert heading 1 | Ctrl Alt 1 | Ctrl Alt 1 | ⌘ ⌥ 1 |
| Insert heading 2 | Ctrl Alt 2 | Ctrl Alt 2 | ⌘ ⌥ 2 |
| Insert heading 3 | Ctrl Alt 3 | Ctrl Alt 3 | ⌘ ⌥ 3 |
| Insert heading 4 | Ctrl Alt 4 | Ctrl Alt 4 | ⌘ ⌥ 4 |
| Insert heading 5 | Ctrl Alt 5 | Ctrl Alt 5 | ⌘ ⌥ 5 |
| Insert heading 6 | Ctrl Alt 6 | Ctrl Alt 6 | ⌘ ⌥ 6 |
| Undo | Ctrl Z | Ctrl Z | ⌘ Z |
| Redo | Ctrl ⇧ Z / Ctrl Y | Ctrl ⇧ Z / Ctrl Y | ⌘ ⇧ Z / ⌘ Y |
| Add image | Ctrl ⇧ I | Ctrl ⇧ I | ⌘ ⇧ I |
| Toggle italic | Ctrl I | Ctrl I | ⌘ I |
| Remove formatting in selection | Ctrl \ | Ctrl \ | ⌘ \ |
| Insert internal link | Ctrl ⇧ K | Ctrl ⇧ K | ⌘ ⇧ K |
| Insert link | Ctrl K | Ctrl K | ⌘ K |
| Insert math block | Ctrl ⇧ M | Ctrl ⇧ M | ⌘ ⇧ M |
| Toggle ordered list | Ctrl ⇧ 7 | Ctrl ⇧ 7 | ⌘ ⇧ 7 |
| Toggle outline list | Ctrl ⇧ O | Ctrl ⇧ O | ⌘ ⇧ O |
| Toggle outline list expand | Ctrl Space | Ctrl Space | ⌘ Space |
| Open search | Ctrl F | Ctrl F | ⌘ F |
| Open search and replace | Ctrl Alt F | Ctrl Alt F | ⌘ ⌥ F |
| Toggle strike | Ctrl ⇧ S | Ctrl ⇧ S | ⌘ ⇧ S |
| Toggle subscript | Ctrl , | Ctrl , | ⌘ , |
| Toggle superscript | Ctrl . | Ctrl . | ⌘ . |
| Toggle task list | Ctrl ⇧ T | Ctrl ⇧ T | ⌘ ⇧ T |
| Text align center | Ctrl ⇧ E | Ctrl ⇧ E | ⌘ ⇧ E |
| Text align justify | Ctrl ⇧ J | Ctrl ⇧ J | ⌘ ⇧ J |
| Text align left | Ctrl ⇧ L | Ctrl ⇧ L | ⌘ ⇧ L |
| Text align right | Ctrl ⇧ R | Ctrl ⇧ R | ⌘ ⇧ R |
| Underline | Ctrl U | Ctrl U | ⌘ U |
| Toggle highlight | Ctrl Alt H | Ctrl Alt H | ⌘ ⌥ H |
| Toggle text color | Ctrl Alt C | Ctrl Alt C | ⌘ ⌥ C |

View File

@@ -0,0 +1,5 @@
- Get an overview of your year with Notesnook with Wrapped 2025
- Cell selection and column resizing in tables
- Bug fixes and minor improvements
Thank you for using Notesnook!

View File

@@ -0,0 +1,5 @@
- Get an overview of your year with Notesnook with Wrapped 2025
- Cell selection and column resizing in tables
- Bug fixes and minor improvements
Thank you for using Notesnook!

View File

@@ -34,10 +34,7 @@ export default defineConfig({
js: "clipper.bundle.js"
},
distPath: {
root: path.resolve(
__dirname,
"../../apps/mobile/native/ios/extension.bundle"
)
root: path.resolve(__dirname, "../../apps/mobile/ios/extension.bundle")
}
}
});

View File

@@ -26,9 +26,13 @@ type CloneNodeOptions = {
export function cloneNode(node: HTMLElement, options: CloneNodeOptions) {
node = node.cloneNode(true) as HTMLElement;
const images = node.querySelectorAll("img");
if (!options.images) {
const images = node.getElementsByTagName("img");
for (const image of images) image.remove();
} else {
for (const image of images) {
image.src = image.currentSrc;
}
}
if (!options.styles) {

View File

@@ -41,6 +41,7 @@
"@streetwriters/kysely": "^0.27.4",
"@streetwriters/showdown": "^3.0.9-alpha",
"@types/mime-db": "^1.43.5",
"alfaaz": "^1.1.0",
"async-mutex": "0.5.0",
"dayjs": "1.11.13",
"dom-serializer": "^2.0.0",

View File

@@ -96,7 +96,10 @@ export const hotkeys = {
type: "hotkeys"
},
openCommandPalette: {
keys: normalizeKeys(["ctrl+shift+p"]),
keys: normalizeKeys({
desktop: ["ctrl+shift+p"],
web: ["ctrl+shift+p", "ctrl+shift+:"]
}),
description: "Command palette",
category: "Navigation",
type: "hotkeys"
@@ -335,6 +338,12 @@ export const tiptapKeys = {
category: "Editor",
type: "tiptap"
},
openSearchAndReplace: {
keys: "Mod-Alt-f",
description: "Open search and replace",
category: "Editor",
type: "tiptap"
},
toggleStrike: {
keys: "Mod-Shift-S",
description: "Toggle strike",
@@ -394,6 +403,12 @@ export const tiptapKeys = {
description: "Toggle highlight",
category: "Editor",
type: "tiptap"
},
toggleTextColor: {
keys: "Mod-Alt-c",
description: "Toggle text color",
category: "Editor",
type: "tiptap"
}
} satisfies Record<string, TipTapKey>;

View File

@@ -18,6 +18,7 @@
"@streetwriters/kysely": "^0.27.4",
"@streetwriters/showdown": "^3.0.9-alpha",
"@types/mime-db": "^1.43.5",
"alfaaz": "^1.1.0",
"async-mutex": "0.5.0",
"dayjs": "1.11.13",
"dom-serializer": "^2.0.0",
@@ -1391,6 +1392,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/alfaaz": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/alfaaz/-/alfaaz-1.1.0.tgz",
"integrity": "sha512-J/P07R41APslK7NmD5303bwStN8jpRA4DdvtLeAr1Jhfj6XWGrASUWI0G6jbWjJAZyw3Lu1Pb4J8rsM/cb+xDQ==",
"license": "MIT"
},
"node_modules/ansi-regex": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",

View File

@@ -73,6 +73,7 @@
"@streetwriters/kysely": "^0.27.4",
"@streetwriters/showdown": "^3.0.9-alpha",
"@types/mime-db": "^1.43.5",
"alfaaz": "^1.1.0",
"async-mutex": "0.5.0",
"dayjs": "1.11.13",
"dom-serializer": "^2.0.0",

View File

@@ -83,6 +83,7 @@ import { ConfigStorage } from "../database/config.js";
import { LazyPromise } from "../utils/lazy-promise.js";
import { InboxApiKeys } from "./inbox-api-keys.js";
import { Circle } from "./circle.js";
import { Wrapped } from "./wrapped.js";
type EventSourceConstructor = new (
uri: string,
@@ -224,6 +225,8 @@ class Database {
inboxApiKeys = new InboxApiKeys(this, this.tokenManager);
wrapped = new Wrapped(this);
/**
* @deprecated only kept here for migration purposes
*/

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