Compare commits

..

239 Commits

Author SHA1 Message Date
ammarahm-ed
993b96901c mobile: fix beta tags ui 2023-09-04 15:43:04 +05:00
Abdullah Atta
8c1629f7dd web: ask for password when doing sensitive actions 2023-09-04 15:10:18 +05:00
ammarahm-ed
9a31c07ac5 mobile: add verification prompts 2023-09-04 15:10:18 +05:00
ammarahm-ed
11f39316b5 mobile: fix color scheme 2023-09-04 15:09:03 +05:00
ammarahm-ed
f157229e00 mobile: fix theme gets reset on opening share extension 2023-09-04 15:09:03 +05:00
ammarahm-ed
a0f25c4e6f mobile: fix list not updating on change date sort 2023-09-04 15:07:33 +05:00
Ammar Ahmed
003b3d2a84 Remove hover effect on mobile in editor (#3163)
* editor: remove background on hover on mobile

* editor: fix task item alignment and size on mobile
2023-09-04 15:06:41 +05:00
ammarahm-ed
1775e0bda1 mobile: fix flash on launch on ios 2023-09-04 14:37:24 +05:00
Ammar Ahmed
d5038ac631 mobile: fix quick notes from notifications (#3165)
- Add note to default notebook
- Respect paragraph spacing

Signed-off-by: Ammar Ahmed <40239442+ammarahm-ed@users.noreply.github.com>
2023-09-04 14:36:55 +05:00
ammarahm-ed
7eab77ba01 mobile: fix share sheet sorting 2023-09-04 14:34:53 +05:00
ammarahm-ed
89413c56e2 mobile: auto update pinned note in notif 2023-09-04 14:33:39 +05:00
Muhammad Ali
4d89643203 web: fix multi-select context menu for list items (#3159) 2023-09-04 14:31:00 +05:00
ammarahm-ed
e119590249 mobile: prevent login/signup request when loading 2023-09-04 14:27:35 +05:00
ammarahm-ed
ace2dfac30 core: increase server timeout 2023-09-04 14:27:35 +05:00
Abdullah Atta
5843df0ce8 web: allow encrypted backups for basic users 2023-09-04 14:24:46 +05:00
Abdullah Atta
403ed8adb6 web: do not clear attachment upload status on complete 2023-09-04 14:24:24 +05:00
Abdullah Atta
1eb5c8bc46 core: do not trigger auto sync on settings merge 2023-09-04 14:24:24 +05:00
Abdullah Atta
46f7ec5e00 core: do not trigger autosync on attachment upload 2023-09-04 14:24:24 +05:00
Abdullah Atta
52adece147 web: upload arraybuffer on desktop builds for attachments 2023-09-04 14:24:24 +05:00
Abdullah Atta
de50be9d1b desktop: use net.fetch instead when handling protocol 2023-09-04 14:24:24 +05:00
Abdullah Atta
0f9e32b49f desktop: update electron to 26.1.0 2023-09-04 14:24:24 +05:00
Muhammad Ali
b4c15adf5d editor: fix formatting issues when pasting from ChatGPT (#3217)
Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2023-09-04 14:22:45 +05:00
Abdullah Atta
a3d3886c51 editor: refactor clipboard extension 2023-09-04 14:22:45 +05:00
Abdullah Atta
0cfa7ce774 editor: paste single line of code as inline code 2023-09-04 14:22:45 +05:00
Abdullah Atta
8299ea909e editor: improve code block detection when pasting from vscode 2023-09-04 14:22:45 +05:00
Abdullah Atta
8b056fe610 editor: preserve formatting when pasting text 2023-09-04 14:22:45 +05:00
Abdullah Atta
511c40db5c editor: do not replace newlines with br when pasting 2023-09-04 14:22:45 +05:00
Muhammad Ali
42d0d42188 web: scroll to top when navigating within settings (#3223) 2023-09-04 13:43:07 +05:00
Abdullah Atta
c80a998444 editor: fix image shuffling on real-time editor sync 2023-09-04 13:41:32 +05:00
ammarahm-ed
0a10df75d1 mobile: add encryptMulti 2023-09-04 13:16:22 +05:00
Abdullah Atta
40d755d191 core: fix all tests 2023-09-04 13:16:22 +05:00
Abdullah Atta
0409a610ab core: improve sync status updates 2023-09-04 13:16:22 +05:00
Abdullah Atta
aa9cd23cf3 core: add fix for localOnly items getting deleted on sync 2023-09-04 13:16:22 +05:00
Abdullah Atta
12d89114a4 core: fix tags & colors not resolving on sync 2023-09-04 13:16:22 +05:00
Abdullah Atta
d5b679187a core: send sync completed event udp style 2023-09-04 13:16:22 +05:00
ammarahm-ed
463ba3754a mobile: add encryptMulti function 2023-09-04 13:16:22 +05:00
Abdullah Atta
2fa8fd14e7 core: migrate to sync v2 for data uploads 2023-09-04 13:16:22 +05:00
Abdullah Atta
fac788d2a9 crypto: remove crypto-worker & simplify crypto interface 2023-09-04 13:16:22 +05:00
ammarahm-ed
6554f900d7 mobile: do not start sync if sync is running 2023-09-04 13:16:22 +05:00
Abdullah Atta
81d3ec83d9 core: fix realtime sync 2023-09-04 13:16:22 +05:00
Abdullah Atta
339c5a357b core: update note-storage mock for tests 2023-09-04 13:16:22 +05:00
ammarahm-ed
b484992037 core: remove console.log 2023-09-04 13:16:22 +05:00
ammarahm-ed
87e42e98c6 mobile: fix logout page ui 2023-09-04 13:16:22 +05:00
ammarahm-ed
51bef01609 mobile: fix logout loading ui 2023-09-04 13:16:22 +05:00
ammarahm-ed
6a49244614 core: fix item not loaded on sync 2023-09-04 13:16:22 +05:00
ammarahm-ed
dad2b61a74 mobile: fix crash when logging out user 2023-09-04 13:16:22 +05:00
ammarahm-ed
fabc595f3d mobile: fix storage 2023-09-04 13:16:22 +05:00
Abdullah Atta
a700787cf3 core: make sure all tests are passing 2023-09-04 13:16:22 +05:00
ammarahm-ed
fb26229715 mobile: update libraries 2023-09-04 13:16:22 +05:00
ammarahm-ed
c4f894f8d0 mobile: add async storage & encryption 2023-09-04 13:16:22 +05:00
Abdullah Atta
ddd1c19c64 core: improve merging performance 2023-09-04 13:16:22 +05:00
Abdullah Atta
79cb3bdba4 core: merge vault key on sync 2023-09-04 13:16:22 +05:00
Abdullah Atta
8447c2150b core: improve sync fetch performance 2023-09-04 13:16:22 +05:00
Abdullah Atta
bc465971be web: add support for bulk writes 2023-09-04 13:16:22 +05:00
Abdullah Atta
f8ce23aa11 crypto: add support for bulk decryption 2023-09-04 13:16:22 +05:00
Abdullah Atta
84004c4d73 global: update lockfiles 2023-08-25 14:30:41 +05:00
Muhammad Ali
2b6aa9b89b ui: allow changing menu button icon color (#3170) 2023-08-21 16:38:21 +05:00
ammarahm-ed
54b8a3e789 mobile: refactor to typescript 2023-08-16 10:14:39 +05:00
Abdullah Atta
7ff5f0001c core: tagging an empty note should not create a content item 2023-08-14 13:41:19 +05:00
Abdullah Atta
d384aa9dcf core: use isolated storage for each test for more reliability 2023-08-14 09:54:57 +05:00
Abdullah Atta
1190da7c91 crypto: use buffer from node:buffer 2023-08-14 09:54:57 +05:00
Abdullah Atta
6561791530 setup: remove dist, build & out dirs during cleanup 2023-08-14 09:54:57 +05:00
Abdullah Atta
26e233d3eb global: update lockfiles 2023-08-14 09:54:57 +05:00
Abdullah Atta
0417981538 global: remove maxNodeModuleJsDepth from tsconfig 2023-08-14 09:54:57 +05:00
Abdullah Atta
81fc56937e web: fix syntax errors 2023-08-14 09:54:57 +05:00
Abdullah Atta
cb778d7e35 core: make dateFormat optional 2023-08-14 09:54:57 +05:00
Abdullah Atta
8442b43715 core: don't include tests & unnecessary files during build 2023-08-14 09:54:57 +05:00
Abdullah Atta
28b3306506 core: import isomorphic-fetch 2023-08-14 09:54:57 +05:00
Abdullah Atta
f51f45aeb2 editor: move isomorphic-fetch import 2023-08-14 09:54:57 +05:00
Abdullah Atta
7f1184736c core: use isomorphic-fetch 2023-08-14 09:54:57 +05:00
Abdullah Atta
e4c8e7a0c5 core: download prismjs languages before tests 2023-08-14 09:54:57 +05:00
Abdullah Atta
44e4722de2 global: fix @notesnook/core direct paths 2023-08-14 09:54:57 +05:00
Abdullah Atta
7c2b0c5947 core: start migrating core to typescript & vitest 2023-08-14 09:54:57 +05:00
Abdullah Atta
6ea912ad0e themebuilder: bump version to 1.1.1 2023-08-11 09:54:09 +05:00
Abdullah Atta
124bbb6ac1 web: do not show website link if there's no homepage 2023-08-11 09:53:01 +05:00
Abdullah Atta
30d6345152 theme: make homepage property in themes optional 2023-08-11 09:53:01 +05:00
Abdullah Atta
60ff7b2f97 themebuilder: update themes manually in themebuilder 2023-08-11 09:51:43 +05:00
Abdullah Atta
c6e90142bb themebuilder: bump version to 1.1.0 2023-08-10 07:20:07 +05:00
Abdullah Atta
1289a025a5 web: skip initiation for theme builder 2023-08-10 07:18:49 +05:00
Abdullah Atta
18d0b72785 themebuilder: fix various bugs 2023-08-10 07:18:18 +05:00
Abdullah Atta
0157cf496f themebuilder: add support for loading from pr, url & base64 2023-08-10 07:17:37 +05:00
Abdullah Atta
3450f2d19d setup: support generating flatpak sources from windows 2023-08-09 16:56:29 +05:00
Abdullah Atta
e509c82807 web: bump version to 2.6.1 2023-08-09 16:31:52 +05:00
Abdullah Atta
d5afd6f32e editor: fix recursive loop on loading a code lang that never registered 2023-08-09 16:26:31 +05:00
Abdullah Atta
fb34dd2864 core: do not throw if language grammar is not found on export 2023-08-09 16:26:31 +05:00
Abdullah Atta
0cd1ce3431 core: don't use require in desktop app 2023-08-09 16:26:31 +05:00
Abdullah Atta
a24447d569 web: fix unstyled "0" in theme details dialog 2023-08-09 16:25:43 +05:00
Abdullah Atta
0bf26afa33 web: fix error on installing theme from file 2023-08-09 16:25:43 +05:00
Abdullah Atta
49455e8054 docs: add documentation for custom themes (#3118)
* themebuilder: add docs

* themebuilder: update theme docs

* docs: finalize docs for custom themes

---------

Co-authored-by: ammarahm-ed <ammarahmed6506@gmail.com>
2023-08-09 15:49:33 +05:00
Abdullah Atta
1136e43115 themebuilder: fix layout 2023-08-08 13:54:56 +05:00
Abdullah Atta
4b74cba4e4 themebuilder: fix builder layout with app on the side 2023-08-08 13:42:28 +05:00
Abdullah Atta
c8a77934f2 ci: use themebuilder scope during bootstrap 2023-08-08 13:26:34 +05:00
Abdullah Atta
e1739e04d1 themebuilder: adjust app branding 2023-08-08 13:19:29 +05:00
Abdullah Atta
a5d39a18a7 web: allow custom app title 2023-08-08 13:19:29 +05:00
Abdullah Atta
77eb661b0e themebuilder: update theme builder on theme switch 2023-08-08 13:19:29 +05:00
Abdullah Atta
667d0d16ea themebuilder: finalize 2023-08-08 13:19:29 +05:00
Abdullah Atta
445ea660c3 web: make web app embeddable 2023-08-08 13:19:29 +05:00
ammarahm-ed
7a35640739 themebuilder: add basic search/replace 2023-08-08 13:19:29 +05:00
ammarahm-ed
f1650fd383 themebuilder: fix accordion 2023-08-08 13:19:29 +05:00
ammarahm-ed
5d67a554d6 themebuilder: fix screenshot 2023-08-08 13:19:29 +05:00
ammarahm-ed
380bfba776 theme: add theme builder app 2023-08-08 13:19:29 +05:00
Abdullah Atta
ed6d125391 clipper: publish v0.3.0 2023-08-08 11:07:22 +05:00
Abdullah Atta
adaa5fd56d clipper: bump version to 0.3.0 2023-08-08 10:29:13 +05:00
Abdullah Atta
0a8db237eb clipper: finalize integration with new theming system 2023-08-08 10:29:13 +05:00
ammarahm-ed
6d723e022b mobile: release v2.6.1 2023-08-08 00:49:29 +05:00
ammarahm-ed
dc3b739719 mobile: fix theme reset on app restart 2023-08-08 00:48:28 +05:00
Abdullah Atta
8d67599278 ci: deploy directly using wrangler 2023-08-07 20:11:11 +05:00
Abdullah Atta
c8da5770c8 web: add list of new features 2023-08-07 14:55:00 +05:00
ammarahm-ed
51c11d9d1a mobile: update release notes 2023-08-07 14:52:28 +05:00
ammarahm-ed
414c164100 mobile: enable remove console.log in release 2023-08-07 14:45:10 +05:00
ammarahm-ed
aa5fd6d946 mobile: release v2.6.0 2023-08-07 14:42:12 +05:00
ammarahm-ed
c89f74d35b mobile: fix ui and cleanup 2023-08-07 14:42:12 +05:00
ammarahm-ed
8c2fdf8554 mobile: fix share extension on ios 2023-08-07 14:42:12 +05:00
ammarahm-ed
f2438d9524 mobile: fix loading local theme 2023-08-07 14:42:12 +05:00
ammarahm-ed
54e7b29716 mobile: update fonts 2023-08-07 14:42:12 +05:00
Abdullah Atta
1d7f4036ec theme: do not send scopes when getting all themes 2023-08-07 12:39:36 +05:00
Abdullah Atta
a2d5eda538 web: fix applied theme status not showing on themes 2023-08-07 12:32:52 +05:00
Abdullah Atta
1b6a27376c web: fix editor & toolbar alignment 2023-08-07 12:00:15 +05:00
Abdullah Atta
8431150f0a web: always show currently applied themes in list 2023-08-07 12:00:02 +05:00
ammarahm-ed
ed5107afaa misc: remove notesnook-themes pulled repo 2023-08-07 09:51:10 +05:00
Abdullah Atta
e52bdd7ca5 web: disable sourcemaps even in testing 2023-08-07 09:18:13 +05:00
Abdullah Atta
26e50848da web: set root to src in vitejs for more focused builds 2023-08-07 09:17:04 +05:00
Abdullah Atta
41fa52c9d5 web: adapt dialog announcements to the new theme 2023-08-07 09:02:26 +05:00
Abdullah Atta
885aa3035e editor: show keyboard shortcuts for tools where possible 2023-08-07 08:47:11 +05:00
Abdullah Atta
b20c20983a ui: improve ui for modifiers in menu items 2023-08-07 08:46:45 +05:00
Abdullah Atta
42994847e9 editor: counter in toolbar should have 100% height 2023-08-07 08:46:13 +05:00
Abdullah Atta
b59a12e743 ui: simplify sub-menus markup 2023-08-07 08:45:18 +05:00
Abdullah Atta
f67792cd30 editor: use error color for errors in math blocks 2023-08-07 08:44:45 +05:00
Abdullah Atta
60ba345e6c editor: add font-display: swap to hack fontface 2023-08-07 08:44:27 +05:00
Abdullah Atta
0074548b84 web: fix broken colors in some places 2023-08-07 06:54:33 +05:00
Abdullah Atta
5af5549173 web: introduce "dangerous" variant for menu items 2023-08-07 06:54:11 +05:00
Abdullah Atta
f9f0235d7b editor: replace all old css colors with new ones 2023-08-07 06:03:25 +05:00
Abdullah Atta
cd51420931 web: replace all old css colors with new ones 2023-08-07 06:03:11 +05:00
Abdullah Atta
000d11976b web: update playwright to 1.36.2 2023-08-07 05:49:02 +05:00
Abdullah Atta
392261c208 web: add helper to imperitively match a media query 2023-08-07 05:49:02 +05:00
Abdullah Atta
71aee40f8d web: improve backups test reliability 2023-08-07 05:49:02 +05:00
Abdullah Atta
565ef2c321 web: don't check for notification permission in tests 2023-08-07 05:49:02 +05:00
Abdullah Atta
2d5c8c9e6d web: only allow changing title via event 2023-08-07 05:49:02 +05:00
Abdullah Atta
800f983688 web: show progress when restoring encrypted backups 2023-08-07 05:49:02 +05:00
ammarahm-ed
7291e54db7 mobile: update detox to latest 2023-08-05 16:46:26 +05:00
ammarahm-ed
794b1c70eb mobile: fix editor stuck in loading state 2023-08-05 16:46:26 +05:00
Abdullah Atta
330b227027 web: improve real time sync test reliability 2023-08-05 16:27:42 +05:00
Abdullah Atta
59a66a63c5 web: update all checkout snapshots 2023-08-05 13:52:19 +05:00
Abdullah Atta
ceb28f08c5 web: load paddle checkout in test mode during testing 2023-08-05 12:27:10 +05:00
Abdullah Atta
7287754218 web: bump version to 2.6.0 2023-08-05 12:19:43 +05:00
Abdullah Atta
80d2f64f10 desktop: bring app to front on start of 2nd instance 2023-08-05 12:10:47 +05:00
Abdullah Atta
9951b83539 web: fix navigation menu resizing on tablet mode 2023-08-05 12:01:06 +05:00
Abdullah Atta
66d50be35a theme: improve check for inheriting emotion theme 2023-08-05 11:27:56 +05:00
Abdullah Atta
9eb5a4cee4 web: update all test screenshot snapshots for linux 2023-08-05 11:20:08 +05:00
Abdullah Atta
3c575c01ad web: fix storage for Firefox & Tor private mode 2023-08-05 11:16:18 +05:00
ammarahm-ed
643028f5d8 mobile: update deps 2023-08-05 11:15:06 +05:00
ammarahm-ed
3831b9409e editor: load theme from local storage on init 2023-08-05 11:15:06 +05:00
ammarahm-ed
985ae848d3 mobile: fix tags wrapping in share extension 2023-08-05 11:15:06 +05:00
Abdullah Atta
0c8c8b6040 editor: fix sub toolbar not getting aligned correctly 2023-08-05 11:15:06 +05:00
ammarahm-ed
a01c084045 mobile: fix react-native-html-to-pdf-lite 2023-08-05 11:15:06 +05:00
ammarahm-ed
7577adf09d mobile: ensure that font size is always number 2023-08-05 11:15:06 +05:00
Abdullah Atta
394002eb4c editor(mobile): add theme to global styles 2023-08-05 11:15:06 +05:00
Abdullah Atta
5c386148a4 editor: fix action sheets not opening 2023-08-05 11:15:06 +05:00
Abdullah Atta
3558d3db93 editor: do not try to download image if src is invalid 2023-08-05 11:15:06 +05:00
ammarahm-ed
2bed812df1 mobile: fix editor 2023-08-05 11:15:06 +05:00
ammarahm-ed
c5db2e0ea9 mobile: fix content in share ext editor takes too long to load 2023-08-05 11:15:06 +05:00
ammarahm-ed
6cd1d7c41b mobile: fix webpack build 2023-08-05 11:15:06 +05:00
ammarahm-ed
36662d58da mobile: fix editor when app enter foreground from share ext 2023-08-05 11:15:06 +05:00
ammarahm-ed
e85cc6ac56 mobile: fix ext height behind keyboard on mobile 2023-08-05 11:15:06 +05:00
ammarahm-ed
a17d2d69ef mobile: fix opening search causes crash in share ext 2023-08-05 11:15:06 +05:00
Abdullah Atta
3ec615a6ec web: update export html snapshot for linux 2023-08-05 10:19:48 +05:00
Abdullah Atta
8eadc6aea1 web: do not redirect automatically on login session expire 2023-08-05 09:50:47 +05:00
Abdullah Atta
506678e72c web: format reminder time correctly (fixes #3085) 2023-08-04 20:05:53 +05:00
Abdullah Atta
aa3561555e desktop: fix desktop toggle settings 2023-08-04 19:34:46 +05:00
Abdullah Atta
405a8aaad0 editor: fix embeds in readonly mode are not visible 2023-08-04 19:33:57 +05:00
Abdullah Atta
7edd45419e editor: align outline bullet in the center of item 2023-08-04 19:00:54 +05:00
Abdullah Atta
5af028698c editor: only put bullet before 1st p tag in outline list 2023-08-04 18:27:04 +05:00
Abdullah Atta
ce822e7538 web: fix toggle colors 2023-08-04 16:09:29 +05:00
Abdullah Atta
9936bee8e0 editor: copying 1 nested list item shouldn't copy list meta 2023-08-04 16:07:31 +05:00
Abdullah Atta
b903e8461d web: make monograph password field hidden 2023-08-04 12:58:05 +05:00
ammarahm-ed
4d2c42330e mobile: fix crash on opening sheet with icon 2023-08-04 12:10:58 +05:00
Abdullah Atta
0ea37fdb31 web: improve checkout responsiveness 2023-08-04 10:23:36 +05:00
Abdullah Atta
22bf738d21 web: make sure all tests are passing 2023-08-03 18:48:51 +05:00
Abdullah Atta
922ba7d192 web: fix errored attachment icon color 2023-08-03 15:55:54 +05:00
Abdullah Atta
c38a98c239 web: upload files < 25mb in a single request 2023-08-03 15:55:54 +05:00
Abdullah Atta
0f9452f6ca web: improve handling of errors during upload 2023-08-03 15:55:54 +05:00
Abdullah Atta
5cc9c6e3e4 web: change themes api url to themes-api.notesnook.com 2023-08-03 15:48:42 +05:00
Abdullah Atta
5da30faf71 web: use settings scroller for themes 2023-08-03 15:46:15 +05:00
ammarahm-ed
99d984f516 core: flush once every 10 sec 2023-08-03 15:02:37 +05:00
ammarahm-ed
20f0760f13 core: fix logger performance 2023-08-03 15:02:37 +05:00
ammarahm-ed
20ffa9bee5 mobile: use themes-api server 2023-08-03 13:58:40 +05:00
Abdullah Atta
bdd003f177 web: fix colors in various places 2023-08-03 13:21:59 +05:00
Abdullah Atta
a45a960bfd editor(mobile): do not override background color 2023-08-03 13:21:59 +05:00
ammarahm-ed
fbf56f2663 mobile: fix incorrect colors uage 2023-08-03 12:01:11 +05:00
ammarahm-ed
0e7ac37b9d mobile: remove prism.css 2023-08-03 11:18:22 +05:00
Abdullah Atta
bcf0d86605 web: use new error icon color 2023-08-03 04:12:08 +05:00
Abdullah Atta
954f894738 web: fix crash when opening attachment menu 2023-08-03 01:44:21 +05:00
Abdullah Atta
908def1b69 editor: update lockfile 2023-08-02 19:50:41 +05:00
Abdullah Atta
f26f638ad4 editor: fix action sheet not closing via drag 2023-08-02 19:50:41 +05:00
Abdullah Atta
700f47fd49 web: disable overscroll behavior 2023-08-02 19:50:41 +05:00
Abdullah Atta
3d0eaacaac theme: allow passing ref to emotion theme provider 2023-08-02 19:50:40 +05:00
Abdullah Atta
c76118d9d6 web: load full framer-motion 2023-08-02 19:50:40 +05:00
Abdullah Atta
148c39158b editor: fix crash on action sheet opening 2023-08-02 19:50:40 +05:00
Ammar Ahmed
89c2d45a4b mobile: reduce app size (#3068)
* mobile: reduce app size

* editor: substitute all @mdi/js icons at build time

* mobile: add script to tree shake icon font file

* mobile: fix icon loading

* mobile: remove html-entities dep

* mobile: add missing icon fonts

* mobile: include plain editor

* mobile: add missing fonts

* mobile: use webpack-bundle

* mobile: keep generated fonts in repo

* mobile: update fonts

* mobile: fix duplicate key warning

* mobile: update fonts

* mobile: disable gesure on reminder sheet

* mobile: update fonts

* mobile: reset session correctly on logout

* mobile: update icon fonts

* mobile: set button action on reminder sheet

* mobile: add missing icons

* mobile: fix crash

* mobile: fix right menus

* mobile: remove console.log

* mobile: disable bounce effect

* mobile: update deps

---------

Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2023-08-02 15:35:15 +05:00
Muhammad Ali
c30c54ab97 web: fix cursor jumps on edit in sticky title (#3028)
Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2023-08-02 15:18:52 +05:00
Abdullah Atta
734cfba45d ci: publish preview on PR open 2023-08-02 15:04:27 +05:00
Abdullah Atta
3b363a1b20 web: prevent scroll jump when toggling focus mode 2023-08-02 15:04:27 +05:00
Abdullah Atta
a747bafa69 web: use new editorSidebar 2023-08-02 13:10:23 +05:00
Abdullah Atta
9d0c11b051 web: unlock view should use base theme scope 2023-08-02 13:09:56 +05:00
Abdullah Atta
bd9e997ef1 theme: add new editorSidebar scope 2023-08-02 13:09:30 +05:00
Abdullah Atta
f222327a89 theme: fix menu buttons have no hover 2023-08-02 13:09:09 +05:00
Abdullah Atta
4e5351134f global: update lockfiles 2023-08-02 12:26:35 +05:00
Abdullah Atta
ec1d5cc211 setup: only grab local deps during bootstrap 2023-08-02 12:26:22 +05:00
Abdullah Atta
8f41e25ac1 ci: ignore paths unrelated to web app 2023-08-02 12:12:32 +05:00
Abdullah Atta
2d90caafc6 ci: use unlike-ltd/github-actions-cloudflare-pages for deployment 2023-08-02 12:12:32 +05:00
Abdullah Atta
a9f36076b3 ci: deploy master branch to cloudflare as beta 2023-08-02 11:38:35 +05:00
Abdullah Atta
8365e557d5 editor: do not copy prism-theme during build 2023-08-02 11:37:15 +05:00
Abdullah Atta
080160ca70 vericrypt: use old @notesnook/theme version 2023-08-02 11:28:54 +05:00
Abdullah Atta
e6164b0b3e setup: use 4 threads at the minimum when bootstrapping 2023-08-01 20:45:08 +05:00
Abdullah Atta
26d786a368 editor: fix codeblock tests 2023-08-01 20:45:08 +05:00
Abdullah Atta
c6172644f0 editor: DOMSerializer2 -> ClipboardDOMSerializer 2023-08-01 20:45:08 +05:00
Abdullah Atta
5810947a5d editor: improve copy pasting 2023-08-01 20:45:08 +05:00
Abdullah Atta
708c2d373d editor: remove unnecessary console.logs 2023-08-01 20:45:08 +05:00
Abdullah Atta
d11a9b2219 editor: fix tests 2023-08-01 20:39:16 +05:00
Abdullah Atta
32b8b008f2 web: make export tests pass 2023-08-01 20:39:16 +05:00
Abdullah Atta
e066d1ce8d global: update lockfiles 2023-08-01 20:39:16 +05:00
Abdullah Atta
4f3f19a785 web: extract editor styles into a fixed css file during build 2023-08-01 20:39:16 +05:00
Abdullah Atta
6c3ea4517d core: inline codeblock styles into html template 2023-08-01 20:39:16 +05:00
Abdullah Atta
1e7e3b8c42 core: use explicit import/require for dynamic imports 2023-08-01 20:39:16 +05:00
Abdullah Atta
a54c18e89b web: remove require transform plugin 2023-08-01 20:39:16 +05:00
Abdullah Atta
ed4d5efea6 editor: generate code languages index during build 2023-08-01 20:39:16 +05:00
Abdullah Atta
4bab279345 global: fix conflicting package versions across subprojects 2023-08-01 20:39:16 +05:00
ammarahm-ed
ec32eeba0b mobile: fix pdf exports with codeblock & katex 2023-08-01 20:39:16 +05:00
Abdullah Atta
2b74e2afb2 web: fix Dynamic module import is disabled error 2023-08-01 20:33:37 +05:00
Abdullah Atta
c4a9d244a9 editor: bump katex version to 0.16.4 2023-08-01 18:35:31 +05:00
Abdullah Atta
6643fb0d63 web: fix old usage of hooks/useTheme 2023-08-01 18:32:58 +05:00
Abdullah Atta
b2a3949ad0 web: auto detect text direction where possible 2023-08-01 15:48:52 +05:00
Abdullah Atta
93c1a44285 editor: infer text direction from parent before insertion 2023-08-01 15:48:52 +05:00
Abdullah Atta
62c4fb328c editor: use single input rule for heading 2023-08-01 15:48:52 +05:00
Muhammad Ali
578fb72ddc editor: infer dir from parent when adding heading 2023-08-01 15:48:52 +05:00
Abdullah Atta
19faaea10e editor: do not save note with codeblock on open 2023-08-01 12:36:41 +05:00
Muhammad Ali
9951aae398 web: use current color scheme in all fields (#3039)
Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2023-08-01 12:32:36 +05:00
Abdullah Atta
0963559a5f global: update lockfiles 2023-08-01 12:09:10 +05:00
Ammar Ahmed
622294b807 global: implement the new theme engine (#2196)
* mobile: theme

* theme: add theme engine

* mobile: migrate app colors to new theme engine

* mobile: fixed some colors

* mobile: fix colors

* mobile: store theme info in store

* theme: `ColorsType` -> `Variants`

* theme: use explicit return type for `useThemeColors`

* theme: add `backdrop` color

* mobile: `const colors` -> `const {colors}

* theme: add default pitch-black theme

* mobile: manage theme state via theme-engine

* mobile: add theme scopes

* mobile: commit

* mobile: fix button width on applock screen

* mobile: fix typings

* mobile: fix theme definition

* web: add partial support for custom themes

only context menus & popups are left.

* theme: add dialog & sheet scopes

* global: sync with master branch and make everything work again

* mobile: fix theme-engine usage in editor & app

* mobile: fix colors

* mobile: fix colors

* mobile: cleanup

* mobile: fix status bar color incorrect on entering foreground

* mobile: fix dark color scheme

* web: move emotion theme provider to @notesnook/theme

* editor: add support for theme enging

* web: adjust hover & focus colors on list item

* mobile: migrate share ext to theme engine

* mobile: fix editor theme provider

* clipper: add support for the new theme engine

* mobile: fix statusbar color on switch from bg

* misc: fix build

* mobile: fix build

* misc: fix colors

* mobile: fix theme colors

* mobile: fix bottom padding

* server: add theme server

* theme: add previewColors

* server: support themes query pagination

* mobile: add client from theme server

* server: reset cache on sync repo

* server: fix types

* server: show ip & port on start server

* server: theme updates

* web: finalize new theme engine on web

* editor: fix build

* global: fix @emotion/react version to 11.11.1

* editor: update katex patch

* web: fix imports

* global: fix @trpc/* versions

* global: a huge set of changes

1. get rid of ThemeVariant. All variants can now be accessed anywhere.
2. remove unnecessary button variants
3. make buttons more responsive
4. implement themes server

* web: add support for theme search and theme switching

* global: update lockfiles

* mobile: fix error

* theme: use vite-plugin-react to start theme server

* web: add support for auto updating themes

* mobile: update theme selector

* mobile: update theme if new verison available

* theme: add `isomorphic-fetch` package

* global: update lockfiles

* web: add theme details dialog

* setup: add scope for themes server in bootstrap script

* web: add production server url

* web: update lockfile

* web: update lockfile

* mobile: remove `react-native-blob-util`

* web: add support for endless scrolling in themes

* web: bring back dark/light mode option in settings

* web: fix colors in places

* theme: add selected variant

* global: use single typescript version across the projects

* web: fix sort & group options not having submenus

* web: apply selected variant where appropriate

* ui: use unique id for all menu items

* config: add ui scope for commits

* theme: export button variant creation fn

* web: fix only 1 theme showing in theme selector

* web: fix navigation item hover & other colors

* mobile: update theme

* editor: fix toolbar group alignments

* editor: set theme provider at app level

* theme: use scope name to get current scope

* mobile: fix color usage in message card

* theme: remove caching

* editor: bring back icons in table menus

* theme: use zustand to manage theme engine state

* web: fix login/signup theming

* mobile: fix webpack build

* misc: remove ThemeProvider usage

* editor: adjust theming and styling of editor toolbar

* mobile: refactor

* editor: fix toolbar group padding everywhere

* web: fix settings sidebar is not scrollable

* web: add loading indicator for themes loading

* mobile: fix warning

* mobile: fix ui issues

* web: fix Loader errors on build

* theme: add getPreviewColors & validateTheme

* theme: fix theme validation

* mobile: load theme from file

* mobile: fix share extension crash

* mobile: rename state

* theme: add sourceURL property

* theme: refactor theme-engine

* web: add support for loading theme from file

* web: improve button hover interaction

* mobile: fix floating button color

* mobile: update theme

* mobile: fix border radius of context menu

* mobile: set sheet overlay color to theme backdrop

* mobile: set sidemenu backdrop to theme backdrop

---------

Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
2023-08-01 12:07:21 +05:00
657 changed files with 75888 additions and 77724 deletions

View File

@@ -33,7 +33,8 @@ const SCOPES = [
"misc",
"common",
"global",
"docs"
"docs",
"themebuilder"
];
module.exports = {

View File

@@ -0,0 +1,31 @@
name: Publish @notesnook/theme-builder
on: workflow_dispatch
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node
uses: ./.github/actions/setup-node-with-cache
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=themebuilder
- name: Setup environment
run: |
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
- name: Generate build
run: npm run build:theme-builder
- name: Publish to Cloudflare Pages
run: npx --yes wrangler pages deploy --project-name=notesnook-theme-builder ./apps/theme-builder/build/

View File

@@ -24,8 +24,8 @@ jobs:
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
- name: Generate desktop build
- name: Generate build
run: npm run build:vericrypt
- name: Publish on Cloudflare Pages
run: npx --yes wrangler pages publish --project-name=vericrypt ./apps/vericrypt/build/
run: npx --yes wrangler pages deploy --project-name=vericrypt ./apps/vericrypt/build/

67
.github/workflows/web.beta.publish.yml vendored Normal file
View File

@@ -0,0 +1,67 @@
name: Publish @notesnook/web Beta
on:
workflow_dispatch:
push:
branches:
- master
paths-ignore:
- "apps/mobile/**"
- "packages/editor-mobile/**"
- "apps/desktop/**"
- "apps/vericrypt/**"
- "servers/**"
- "packages/clipper/**"
- "extensions/web-clipper/**"
pull_request:
types:
- closed
- ready_for_review
- reopened
- opened
- synchronize
branches:
- master
paths-ignore:
- "apps/mobile/**"
- "packages/editor-mobile/**"
- "apps/desktop/**"
- "apps/vericrypt/**"
- "servers/**"
- "packages/clipper/**"
- "extensions/web-clipper/**"
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node
uses: ./.github/actions/setup-node-with-cache
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=web
- name: Setup environment
run: |
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
- name: Generate beta build
run: npm run build:beta:web
- name: Publish to Cloudflare Pages
uses: unlike-ltd/github-actions-cloudflare-pages@v0.1.1
id: pages
with:
cloudflare-api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
cloudflare-project-name: notesnook-beta-app
directory: ./apps/web/build
github-token: ${{ secrets.GITHUB_TOKEN }}
github-environment: ${{ (github.ref == 'refs/heads/master' && 'beta') || 'preview' }}

View File

@@ -24,8 +24,8 @@ jobs:
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
- name: Generate desktop build
- name: Generate build
run: npm run build:web
- name: Publish on Cloudflare Pages
run: npx --yes wrangler pages publish --project-name=notesnook-app ./apps/web/build/
- name: Publish to Cloudflare Pages
run: npx --yes wrangler pages deploy --project-name=notesnook-app ./apps/web/build/

View File

@@ -19,9 +19,40 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/* eslint-disable no-var */
import { BrowserWindow } from "electron";
import {
type FormData as FormDataType,
type Headers as HeadersType,
type Request as RequestType,
type Response as ResponseType
} from "undici";
declare global {
var window: BrowserWindow | null;
var RELEASE: boolean;
var MAC_APP_STORE: boolean;
// Re-export undici fetch function and various classes to global scope.
// These are classes and functions expected to be at global scope according to Node.js v18 API
// documentation.
// See: https://nodejs.org/dist/latest-v18.x/docs/api/globals.html
// eslint-disable-next-line no-var
export var {
FormData,
Headers,
Request,
Response,
fetch
}: typeof import("undici");
type FormData = FormDataType;
type Headers = HeadersType;
type Request = RequestType;
type Response = ResponseType;
}
// NOTE: the import in the global block above needs to be a var for this to work properly.
globalThis.fetch = fetch;
globalThis.FormData = FormData;
globalThis.Headers = Headers;
globalThis.Request = Request;
globalThis.Response = Response;

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": "2.5.8",
"version": "2.6.1",
"appAppleId": "1544027013",
"private": true,
"main": "./dist/index.js",
@@ -22,15 +22,15 @@
"zod": "^3.21.4"
},
"devDependencies": {
"@types/node": "^18.15.0",
"@types/node": "18.16.1",
"@types/yargs": "^17.0.24",
"chokidar": "^3.5.3",
"electron": "24.5.1",
"electron-builder": "24.4.0",
"electron": "^26.1.0",
"electron-builder": "^24.6.3",
"electron-builder-notarize": "^1.5.1",
"esbuild": "^0.17.19",
"node-fetch": "^3.3.1",
"tree-kill": "^1.2.2"
"tree-kill": "^1.2.2",
"undici": "^5.23.0"
},
"optionalDependencies": {
"dmg-license": "^1.0.11"

View File

@@ -52,21 +52,21 @@ export const osIntegrationRouter = t.router({
privacyMode: t.procedure.query(() => config.privacyMode),
setPrivacyMode: t.procedure
.input(z.boolean().optional())
.mutation(({ input: privacyMode }) => {
.input(z.object({ enabled: z.boolean() }))
.mutation(({ input: { enabled } }) => {
if (!globalThis.window || !["win32", "darwin"].includes(process.platform))
return;
globalThis.window.setContentProtection(!!privacyMode);
globalThis.window.setContentProtection(enabled);
if (process.platform === "win32") {
globalThis.window.setThumbnailClip(
privacyMode
enabled
? { x: 0, y: 0, width: 1, height: 1 }
: { x: 0, y: 0, width: 0, height: 0 }
);
}
config.privacyMode = !!privacyMode;
config.privacyMode = enabled;
}),
desktopIntegration: t.procedure.query(() => config.desktopSettings),

View File

@@ -114,9 +114,9 @@ export const spellCheckerRouter = t.router({
globalThis.window?.webContents.session.setSpellCheckerLanguages(languages)
),
toggle: t.procedure
.input(z.boolean().optional())
.mutation(({ input: enabled }) => {
globalThis.window?.webContents.session.setSpellCheckerEnabled(!!enabled);
config.isSpellCheckerEnabled = !!enabled;
.input(z.object({ enabled: z.boolean() }))
.mutation(({ input: { enabled } }) => {
globalThis.window?.webContents.session.setSpellCheckerEnabled(enabled);
config.isSpellCheckerEnabled = enabled;
})
});

View File

@@ -41,10 +41,9 @@ export const updaterRouter = t.router({
}),
toggleAutoUpdates: t.procedure
.input(z.boolean().optional())
.mutation(({ input }) => {
config.automaticUpdates =
input === undefined ? !config.automaticUpdates : input;
.input(z.object({ enabled: z.boolean() }))
.mutation(({ input: { enabled } }) => {
config.automaticUpdates = enabled;
}),
onChecking: createSubscription("checking-for-update"),

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { app, BrowserWindow, nativeTheme, session, shell } from "electron";
import { app, BrowserWindow, nativeTheme, shell } from "electron";
import { isDevelopment } from "./utils";
import { registerProtocol, PROTOCOL_URL } from "./utils/protocol";
import { configureAutoUpdater } from "./utils/autoupdater";
@@ -33,6 +33,13 @@ import { createIPCHandler } from "electron-trpc/main";
import { router, api } from "./api";
import { config } from "./utils/config";
import path from "path";
import { bringToFront } from "./utils/bring-to-front";
// only run a single instance
if (!MAC_APP_STORE && !app.requestSingleInstanceLock()) {
console.log("Another instance is already running!");
app.exit();
}
if (process.platform == "win32" && process.env.PORTABLE_EXECUTABLE_DIR) {
console.log("Portable app: true");
@@ -42,11 +49,6 @@ if (process.platform == "win32" && process.env.PORTABLE_EXECUTABLE_DIR) {
app.setPath("userData", path.join(root, "UserData"));
}
// only run a single instance
if (!MAC_APP_STORE && !app.requestSingleInstanceLock()) {
app.exit();
}
if (process.platform === "win32") {
app.setAppUserModelId(app.name);
}
@@ -91,7 +93,7 @@ async function createWindow() {
mainWindow.setOpacity(1);
if (config.privacyMode) {
await api.integration.setPrivacyMode(config.privacyMode);
await api.integration.setPrivacyMode({ enabled: config.privacyMode });
}
await AssetManager.loadIcons();
@@ -137,6 +139,11 @@ app.once("window-all-closed", () => {
}
});
app.on("second-instance", () => {
if (!globalThis.window) return;
bringToFront();
});
app.on("activate", () => {
if (globalThis.window === null) {
createWindow();

View File

@@ -38,8 +38,8 @@ export const config = {
closeToSystemTray: false
},
privacyMode: false,
isSpellCheckerEnabled: false,
zoomFactor: 0,
isSpellCheckerEnabled: true,
zoomFactor: 1,
theme: nativeTheme.themeSource,
automaticUpdates: true
};

View File

@@ -17,16 +17,14 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { protocol, ProtocolRequest } from "electron";
import { protocol, net } from "electron";
import { isDevelopment } from "./index";
import { createReadStream } from "fs";
import { extname, normalize } from "path";
import { URL } from "url";
import fetch, { Response } from "node-fetch";
const BASE_PATH = isDevelopment() ? "../public" : "";
const HOSTNAME = `app.notesnook.com`;
const FILE_NOT_FOUND = -6;
const SCHEME = "https";
const extensionToMimeType: Record<string, string> = {
html: "text/html",
@@ -34,101 +32,47 @@ const extensionToMimeType: Record<string, string> = {
js: "application/javascript",
css: "text/css",
svg: "image/svg+xml",
png: "image/png"
png: "image/png",
jpg: "image/jpg",
ttf: "font/ttf",
woff: "font/woff",
woff2: "font/woff2"
};
function registerProtocol() {
const protocolInterceptionResult = protocol.interceptStreamProtocol(
SCHEME,
async (request, callback) => {
const url = new URL(request.url);
if (shouldInterceptRequest(url)) {
console.info("Intercepting request:", request.url);
const loadIndex = !extname(url.pathname);
const filePath = normalize(
`${__dirname}${
loadIndex
? `${BASE_PATH}/index.html`
: `${BASE_PATH}/${url.pathname}`
}`
);
if (!filePath) {
console.error("Local asset file not found at", filePath);
callback({ error: FILE_NOT_FOUND });
return;
}
const fileExtension = extname(filePath).replace(".", "");
const data = createReadStream(filePath);
callback({
data,
mimeType: extensionToMimeType[fileExtension]
});
} else {
let response: Response;
try {
const body = await getBody(request);
response = await fetch(request.url, {
...request,
body,
headers: {
...request.headers
// origin: `${PROTOCOL}://${HOSTNAME}/`
},
referrer: request.referrer,
redirect: "manual"
});
} catch (e) {
console.error(e);
console.error(`Error sending request to `, request.url, "Error: ", e);
callback({ statusCode: 400 });
return;
}
callback({
statusCode: response.status,
data: response.body || undefined,
headers: Object.fromEntries(response.headers.entries()),
mimeType: response.headers.get("Content-Type") || undefined
protocol.handle(SCHEME, async (request) => {
const url = new URL(request.url);
if (shouldInterceptRequest(url)) {
console.info("Intercepting request:", request.url);
const loadIndex = !extname(url.pathname);
const filePath = normalize(
`${__dirname}${
loadIndex ? `${BASE_PATH}/index.html` : `${BASE_PATH}/${url.pathname}`
}`
);
if (!filePath) {
console.error("Local asset file not found at", filePath);
return new Response(undefined, {
status: 404,
statusText: "FILE_NOT_FOUND"
});
}
const fileExtension = extname(filePath).replace(".", "");
return new Response(createReadStream(filePath), {
headers: { "Content-Type": extensionToMimeType[fileExtension] }
});
} else {
try {
return net.fetch(request, {
bypassCustomProtocolHandlers: true
});
} catch (e) {
console.error(e);
}
return Response.error();
}
);
console.info(
`${SCHEME} protocol inteception ${
protocolInterceptionResult ? "successful" : "failed"
}.`
);
// protocol.handle(SCHEME, (request) => {
// const url = new URL(request.url);
// if (shouldInterceptRequest(url)) {
// console.info("Intercepting request:", request.url);
// const loadIndex = !extname(url.pathname);
// const absoluteFilePath = normalize(
// `${__dirname}${
// loadIndex ? `${BASE_PATH}/index.html` : `${BASE_PATH}/${url.pathname}`
// }`
// );
// const filePath = getPath(absoluteFilePath);
// if (!filePath) {
// console.error("Local asset file not found at", filePath);
// return new Response(undefined, {
// status: 404,
// statusText: "FILE_NOT_FOUND"
// });
// }
// const fileExtension = extname(filePath).replace(".", "");
// const data = createReadStream(filePath);
// return new Response(data, {
// headers: { "Content-Type": extensionToMimeType[fileExtension] }
// });
// } else {
// return net.fetch(request);
// }
// });
// console.info(`${SCHEME} protocol inteception "successful"`);
});
console.info(`${SCHEME} protocol inteception "successful"`);
}
const bypassedRoutes: string[] = [];
@@ -139,22 +83,3 @@ function shouldInterceptRequest(url: URL) {
const PROTOCOL_URL = `${SCHEME}://${HOSTNAME}/`;
export { registerProtocol, PROTOCOL_URL };
async function getBody(request: ProtocolRequest) {
const session = globalThis?.window?.webContents?.session;
const blobParts = [];
if (!request.uploadData || !request.uploadData.length) return null;
for (const data of request.uploadData) {
if (data.bytes) {
blobParts.push(new Uint8Array(data.bytes));
} else if (session && data.blobUUID) {
const buffer = await session.getBlobData(data.blobUUID);
if (!buffer) continue;
blobParts.push(new Uint8Array(buffer));
}
}
const blob = new Blob(blobParts);
return blob;
}

View File

@@ -5,7 +5,6 @@ artifacts/
.DS_Store
native/android/app/src/main/assets/
*Issues.md
build_cache/
#

View File

@@ -16,6 +16,8 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import "@azure/core-asynciterator-polyfill";
import SettingsService from "./services/settings";
import {
THEME_COMPATIBILITY_VERSION,
useThemeEngineStore
@@ -31,13 +33,11 @@ import GlobalSafeAreaProvider from "./components/globalsafearea";
import { useAppEvents } from "./hooks/use-app-events";
import { ApplicationHolder } from "./navigation";
import Notifications from "./services/notifications";
import SettingsService from "./services/settings";
import { TipManager } from "./services/tip-manager";
import { useThemeStore } from "./stores/use-theme-store";
import { useUserStore } from "./stores/use-user-store";
import { themeTrpcClient } from "./screens/settings/theme-selector";
SettingsService.init();
SettingsService.checkOrientation();
const App = () => {
const init = useAppEvents();
@@ -46,6 +46,7 @@ const App = () => {
if (appLockMode && appLockMode !== "none") {
useUserStore.getState().lockApp(true);
}
globalThis["IS_MAIN_APP_RUNNING"] = true;
init();
setTimeout(async () => {
SettingsService.onFirstLaunch();
@@ -93,6 +94,12 @@ const App = () => {
);
};
let currTheme =
useThemeStore.getState().colorScheme === "dark"
? SettingsService.getProperty("darkTheme")
: SettingsService.getProperty("lightTheme");
useThemeEngineStore.getState().setTheme(currTheme);
export const withTheme = (Element) => {
return function AppWithThemeProvider() {
const [colorScheme, darkTheme, lightTheme] = useThemeStore((state) => [
@@ -102,31 +109,35 @@ export const withTheme = (Element) => {
]);
useEffect(() => {
const currentTheme = colorScheme === "dark" ? darkTheme : lightTheme;
if (!currentTheme) return;
themeTrpcClient.updateTheme
.query({
version: currentTheme.version,
compatibilityVersion: THEME_COMPATIBILITY_VERSION,
id: currentTheme.id
})
.then((theme) => {
if (theme) {
console.log(theme.version, "theme updated");
theme.colorScheme === "dark"
? useThemeStore.getState().setDarkTheme(theme)
: useThemeStore.getState().setLightTheme(theme);
}
})
.catch(console.log);
setTimeout(() => {
const currentTheme = colorScheme === "dark" ? darkTheme : lightTheme;
if (!currentTheme) return;
themeTrpcClient.updateTheme
.query({
version: currentTheme.version,
compatibilityVersion: THEME_COMPATIBILITY_VERSION,
id: currentTheme.id
})
.then((theme) => {
if (theme) {
console.log(theme.version, "theme updated");
theme.colorScheme === "dark"
? useThemeStore.getState().setDarkTheme(theme)
: useThemeStore.getState().setLightTheme(theme);
}
})
.catch(console.log);
}, 1000);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
const nextTheme = colorScheme === "dark" ? darkTheme : lightTheme;
if (JSON.stringify(nextTheme) !== JSON.stringify(currTheme)) {
useThemeEngineStore
.getState()
.setTheme(colorScheme === "dark" ? darkTheme : lightTheme);
}, [colorScheme, darkTheme, lightTheme]);
currTheme = nextTheme;
}
return <Element />;
};

View File

@@ -126,6 +126,18 @@ export async function decrypt(password, data) {
return await Sodium.decrypt(password, _data);
}
export async function decryptMulti(password, data) {
if (!password.password && !password.key) return undefined;
if (password.password && password.password === "" && !password.key)
return undefined;
data = data.map((d) => {
d.output = "plain";
return d;
});
return await Sodium.decryptMulti(password, data);
}
export function parseAlgorithm(alg) {
if (!alg) return {};
const [enc, kdf, compressed, compressionAlg, base64variant] = alg.split("-");
@@ -154,3 +166,24 @@ export async function encrypt(password, data) {
alg: getAlgorithm(7)
};
}
export async function encryptMulti(password, data) {
if (!password.password && !password.key) return undefined;
if (password.password && password.password === "" && !password.key)
return undefined;
let results = await Sodium.encryptMulti(
password,
data.map((item) => ({
type: "plain",
data: item
}))
);
return !results
? []
: results.map((result) => ({
...result,
alg: getAlgorithm(7)
}));
}

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { database } from "@notesnook/common";
import { initalize, logger as dbLogger } from "@notesnook/core/logger";
import { initalize, logger as dbLogger } from "@notesnook/core/dist/logger";
import { Platform } from "react-native";
import { MMKVLoader } from "react-native-mmkv-storage";
import filesystem from "../filesystem";
@@ -30,43 +30,40 @@ const LoggerStorage = new MMKVLoader()
.withInstanceID("notesnook_logs")
.initialize();
database.host(
__DEV__
? {
API_HOST: "https://api.notesnook.com",
AUTH_HOST: "https://auth.streetwriters.co",
SSE_HOST: "https://events.streetwriters.co",
SUBSCRIPTIONS_HOST: "https://subscriptions.streetwriters.co",
ISSUES_HOST: "https://issues.streetwriters.co"
// API_HOST: "http://192.168.8.101:5264",
// AUTH_HOST: "http://192.168.8.101:8264",
// SSE_HOST: "http://192.168.8.101:7264",
// SUBSCRIPTIONS_HOST: "http://192.168.8.101:9264",
// ISSUES_HOST: "http://192.168.8.101:2624"
}
: {
API_HOST: "https://api.notesnook.com",
AUTH_HOST: "https://auth.streetwriters.co",
SSE_HOST: "https://events.streetwriters.co",
SUBSCRIPTIONS_HOST: "https://subscriptions.streetwriters.co",
ISSUES_HOST: "https://issues.streetwriters.co"
}
);
database.host(
__DEV__
? {
API_HOST: "https://api.notesnook.com",
AUTH_HOST: "https://auth.streetwriters.co",
SSE_HOST: "https://events.streetwriters.co",
SUBSCRIPTIONS_HOST: "https://subscriptions.streetwriters.co",
ISSUES_HOST: "https://issues.streetwriters.co"
// API_HOST: "http://192.168.43.108:5264",
// AUTH_HOST: "http://192.168.43.108:8264",
// SSE_HOST: "http://192.168.43.108:7264",
// SUBSCRIPTIONS_HOST: "http://192.168.43.108:9264",
// ISSUES_HOST: "http://192.168.43.108:2624"
}
: {
API_HOST: "https://api.notesnook.com",
AUTH_HOST: "https://auth.streetwriters.co",
SSE_HOST: "https://events.streetwriters.co",
SUBSCRIPTIONS_HOST: "https://subscriptions.streetwriters.co",
ISSUES_HOST: "https://issues.streetwriters.co"
}
);
database.setup(
Storage,
Platform.OS === "ios" ? EventSource : AndroidEventSource,
filesystem,
{
compress: Gzip.deflate,
decompress: Gzip.inflate
}
);
database.setup(
Storage,
Platform.OS === "ios" ? EventSource : AndroidEventSource,
filesystem,
{
compress: Gzip.deflate,
decompress: Gzip.inflate
}
);
initalize(new KV(LoggerStorage), true);
initalize(new KV(LoggerStorage));
export const db = database;
export const DatabaseLogger = dbLogger;

View File

@@ -18,9 +18,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Platform } from "react-native";
import MMKVStorage, { ProcessingModes } from "react-native-mmkv-storage";
import { ProcessingModes, MMKVLoader } from "react-native-mmkv-storage";
export const MMKV = new MMKVStorage.Loader()
export const MMKV = new MMKVLoader()
.setProcessingMode(
Platform.OS === "ios"
? ProcessingModes.MULTI_PROCESS

View File

@@ -27,11 +27,16 @@ import {
getCryptoKey,
getRandomBytes,
hash,
removeCryptoKey
removeCryptoKey,
decryptMulti,
encryptMulti
} from "./encryption";
import { MMKV } from "./mmkv";
export class KV {
/**
* @type {typeof MMKV}
*/
storage = null;
constructor(storage) {
this.storage = storage;
@@ -53,6 +58,7 @@ export class KV {
key,
typeof data === "string" ? data : JSON.stringify(data)
);
return true;
}
@@ -60,27 +66,32 @@ export class KV {
if (keys.length <= 0) {
return [];
} else {
let data = await this.storage.getMultipleItemsAsync(keys.slice());
return data.map(([key, value]) => {
let obj;
try {
obj = JSON.parse(value);
} catch (e) {
obj = value;
}
return [key, obj];
});
try {
let data = await this.storage.getMultipleItemsAsync(
keys.slice(),
"string"
);
return data.map(([key, value]) => {
let obj;
try {
obj = JSON.parse(value);
} catch (e) {
obj = value;
}
return [key, obj];
});
} catch (e) {
console.log(e);
}
}
}
async remove(key) {
return await this.storage.removeItem(key);
return this.storage.removeItem(key);
}
async clear() {
return await this.storage.clearStore();
return this.storage.clearStore();
}
async getAllKeys() {
@@ -96,6 +107,10 @@ export class KV {
);
return keys;
}
async writeMulti(items) {
return this.storage.setMultipleItemsAsync(items, "object");
}
}
const DefaultStorage = new KV(MMKV);
@@ -129,8 +144,10 @@ export default {
remove: (key) => DefaultStorage.remove(key),
clear: () => DefaultStorage.clear(),
getAllKeys: () => DefaultStorage.getAllKeys(),
writeMulti: (items) => DefaultStorage.writeMulti(items),
encrypt,
decrypt,
decryptMulti,
getRandomBytes,
checkAndCreateDir,
requestPermission,
@@ -138,5 +155,6 @@ export default {
getCryptoKey,
removeCryptoKey,
hash,
generateCryptoKey
generateCryptoKey,
encryptMulti
};

View File

@@ -22,7 +22,7 @@ import {
getFileNameWithExtension,
isImage,
isDocument
} from "@notesnook/core/utils/filename";
} from "@notesnook/core/dist/utils/filename";
import React from "react";
import { Platform } from "react-native";
import * as ScopedStorage from "react-native-scoped-storage";

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import hosts from "@notesnook/core/utils/constants";
import hosts from "@notesnook/core/dist/utils/constants";
import NetInfo from "@react-native-community/netinfo";
import RNFetchBlob from "react-native-blob-util";
import { ToastEvent } from "../../services/event-manager";

View File

@@ -21,7 +21,7 @@ import RNFetchBlob from "react-native-blob-util";
import { useAttachmentStore } from "../../stores/use-attachment-store";
import { DatabaseLogger, db } from "../database";
import { cacheDir } from "./utils";
import { isImage, isDocument } from "@notesnook/core/utils/filename";
import { isImage, isDocument } from "@notesnook/core/dist/utils/filename";
import { Platform } from "react-native";
import { IOS_APPGROUPID } from "../../utils/constants";

View File

@@ -100,7 +100,7 @@ const AppLockedOverlay = () => {
appLocked && (
<View
style={{
backgroundColor: colors.bg,
backgroundColor: colors.primary.background,
width: "100%",
height: "100%",
position: "absolute",
@@ -160,7 +160,7 @@ const AppLockedOverlay = () => {
style={{
width: "100%",
padding: 12,
backgroundColor: colors.bg
backgroundColor: colors.primary.background
}}
>
{user ? (

View File

@@ -40,7 +40,7 @@ import {
isDocument,
isImage,
isVideo
} from "@notesnook/core/utils/filename";
} from "@notesnook/core/dist/utils/filename";
import { useSettingStore } from "../../stores/use-setting-store";
import { FlashList } from "react-native-actions-sheet/dist/src/views/FlashList";
@@ -241,7 +241,7 @@ export const AttachmentDialog = ({ note }) => {
width: "100%",
height: 50,
flexDirection: "row",
backgroundColor: colors.bg
backgroundColor: colors.primary.background
}}
contentContainerStyle={{
minWidth: "100%",

View File

@@ -17,18 +17,22 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useState } from "react";
import { Modal, View } from "react-native";
import { db } from "../../common/database";
import { MMKV } from "../../common/database/mmkv";
import BiometricService from "../../services/biometrics";
import {
ToastEvent,
eSendEvent,
eSubscribeEvent
} from "../../services/event-manager";
import { setLoginMessage } from "../../services/message";
import SettingsService from "../../services/settings";
import Sync from "../../services/sync";
import { useThemeColors } from "@notesnook/theme";
import { clearAllStores } from "../../stores";
import { useUserStore } from "../../stores/use-user-store";
import { eLoginSessionExpired, eUserLoggedIn } from "../../utils/events";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
@@ -71,9 +75,12 @@ export const SessionExpired = () => {
try {
await db.user.logout();
await BiometricService.resetCredentials();
SettingsService.set({
introCompleted: true
});
setLoginMessage();
SettingsService.resetSettings();
useUserStore.getState().setUser(null);
useUserStore.getState().setSyncing(false);
MMKV.clearStore();
clearAllStores();
setVisible(false);
} catch (e) {
ToastEvent.show({

View File

@@ -67,6 +67,7 @@ export const Signup = ({ changeMode, trial }) => {
const signup = async () => {
if (!validateInfo() || error) return;
if (loading) return;
setLoading(true);
try {
await db.user.signup(email.current.toLowerCase(), password.current);

View File

@@ -64,6 +64,7 @@ export const useLogin = (onFinishLogin) => {
const login = async () => {
if (!validateInfo() || error) return;
try {
if (loading) return;
setLoading(true);
switch (step) {
case LoginSteps.emailAuth: {

View File

@@ -17,12 +17,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import React, { PropsWithChildren } from "react";
import { View } from "react-native";
import { useSelectionStore } from "../../stores/use-selection-store";
import { useThemeColors } from "@notesnook/theme";
export const ContainerHeader = ({ children }) => {
export const ContainerHeader = (props: PropsWithChildren) => {
const { colors } = useThemeColors();
const selectionMode = useSelectionStore((state) => state.selectionMode);
@@ -34,7 +34,7 @@ export const ContainerHeader = ({ children }) => {
overflow: "hidden"
}}
>
{children}
{props.children}
</View>
) : null;
};

View File

@@ -17,8 +17,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useThemeColors } from "@notesnook/theme";
import React, { useCallback, useEffect } from "react";
import { Keyboard, Platform, View } from "react-native";
import { Keyboard, View } from "react-native";
import Animated, {
Easing,
useAnimatedStyle,
@@ -34,14 +35,20 @@ import { getElevationStyle } from "../../utils/elevation";
import { SIZE, normalize } from "../../utils/size";
import NativeTooltip from "../../utils/tooltip";
import { PressableButton } from "../ui/pressable";
import { useThemeColors } from "@notesnook/theme";
export const FloatingButton = ({
interface FloatingButton {
title?: string;
onPress: () => void;
color?: string;
alwaysVisible?: boolean;
}
const FloatingButton = ({
title,
onPress,
color,
shouldShow = false
}) => {
alwaysVisible = false
}: FloatingButton) => {
const { colors } = useThemeColors();
const deviceMode = useSettingStore((state) => state.deviceMode);
const selectionMode = useSelectionStore((state) => state.selectionMode);
@@ -60,12 +67,8 @@ export const FloatingButton = ({
};
});
useEffect(() => {
animate(selectionMode ? 150 : 0);
}, [animate, selectionMode]);
const animate = useCallback(
(toValue) => {
(toValue: number) => {
translate.value = withTiming(toValue, {
duration: 250,
easing: Easing.elastic(1)
@@ -74,39 +77,39 @@ export const FloatingButton = ({
[translate]
);
const onKeyboardHide = useCallback(async () => {
editorState().keyboardState = false;
if (deviceMode !== "mobile") return;
animate(0);
}, [animate, deviceMode]);
const onKeyboardShow = useCallback(async () => {
editorState().keyboardState = true;
if (deviceMode !== "mobile") return;
animate(150);
}, [animate, deviceMode]);
useEffect(() => {
animate(selectionMode ? 150 : 0);
}, [animate, selectionMode]);
useEffect(() => {
let sub1 = Keyboard.addListener("keyboardDidShow", onKeyboardShow);
let sub2 = Keyboard.addListener("keyboardDidHide", onKeyboardHide);
return () => {
sub1?.remove();
sub2?.remove();
const onKeyboardHide = () => {
editorState().keyboardState = false;
if (deviceMode !== "mobile") return;
animate(0);
};
}, [deviceMode, onKeyboardHide, onKeyboardShow]);
const paddings = {
ios: 20,
android: 20,
iPad: 20
};
return deviceMode !== "mobile" && !shouldShow ? null : (
const onKeyboardShow = () => {
editorState().keyboardState = true;
if (deviceMode !== "mobile") return;
animate(150);
};
const sub = [
Keyboard.addListener("keyboardDidShow", onKeyboardShow),
Keyboard.addListener("keyboardDidHide", onKeyboardHide)
];
return () => {
sub.forEach((sub) => sub?.remove?.());
};
}, [deviceMode, animate]);
return deviceMode !== "mobile" && !alwaysVisible ? null : (
<Animated.View
style={[
{
position: "absolute",
right: 12,
bottom: paddings[Platform.isPad ? "iPad" : Platform.OS],
bottom: 20,
zIndex: 10
},
animatedStyle
@@ -115,16 +118,15 @@ export const FloatingButton = ({
<PressableButton
testID={notesnook.buttons.add}
type="accent"
buttonType={{
color: colors.static[color],
text: colors.static.white
}}
accentColor={colors.static[color as keyof typeof colors.static]}
customStyle={{
...getElevationStyle(5),
borderRadius: 100
}}
onLongPress={(event) => {
NativeTooltip.show(event, title, NativeTooltip.POSITIONS.LEFT);
if (title) {
NativeTooltip.show(event, title, NativeTooltip.POSITIONS.LEFT);
}
}}
onPress={onPress}
>
@@ -146,3 +148,5 @@ export const FloatingButton = ({
</Animated.View>
);
};
export { FloatingButton };

View File

@@ -17,44 +17,40 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { KeyboardAvoidingView, Platform, View } from "react-native";
import React, { PropsWithChildren } from "react";
import { KeyboardAvoidingView, Platform } from "react-native";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import useIsFloatingKeyboard from "../../hooks/use-is-floating-keyboard";
import { useSettingStore } from "../../stores/use-setting-store";
import { Header } from "../header";
import SelectionHeader from "../selection-header";
export const Container = ({ children }) => {
export const Container = ({ children }: PropsWithChildren) => {
const floating = useIsFloatingKeyboard();
const introCompleted = useSettingStore(
(state) => state.settings.introCompleted
);
const insets = useGlobalSafeAreaInsets();
return (
<KeyboardAvoidingView
behavior="padding"
enabled={Platform.OS === "ios" && !floating}
style={{
flex: 1
flex: 1,
overflow: "hidden",
paddingTop: Platform.OS === "android" ? 0 : insets.top,
paddingBottom: Platform.OS === "android" ? 0 : insets.bottom
}}
>
<View
style={{
flex: 1,
overflow: "hidden",
paddingTop: Platform.OS === "android" ? 0 : insets.top,
paddingBottom: Platform.OS === "android" ? 0 : insets.bottom
}}
>
{!introCompleted ? null : (
<>
<SelectionHeader />
<Header title="Header" screen="Header" />
</>
)}
{!introCompleted ? null : (
<>
<SelectionHeader />
<Header />
</>
)}
{children}
</View>
{children}
</KeyboardAvoidingView>
);
};

View File

@@ -43,7 +43,7 @@ const _Header = () => {
);
const onScroll = useCallback(
(data) => {
(data: { x: number; y: number }) => {
if (data.y > 150) {
if (!hide) return;
setHide(false);

View File

@@ -43,12 +43,6 @@ export const LeftMenus = () => {
return;
}
Navigation.goBack();
if (
useNavigationStore.getState().currentScreen.name === "Signup" ||
useNavigationStore.getState().currentScreen.name === "Login"
) {
tabBarRef.current.unlock();
}
};
return isTablet && !canGoBack ? null : (

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useRef } from "react";
import { Platform, StyleSheet, View } from "react-native";
//@ts-ignore
import Menu from "react-native-reanimated-material-menu";
import { notesnook } from "../../../e2e/test.ids";
import Navigation from "../../services/navigation";
@@ -33,12 +34,15 @@ import { IconButton } from "../ui/icon-button";
export const RightMenus = () => {
const { colors } = useThemeColors();
const { contextMenuColors } = useThemeColors("contextMenu");
const { colors: contextMenuColors } = useThemeColors("contextMenu");
const deviceMode = useSettingStore((state) => state.deviceMode);
const rightButtons = useNavigationStore((state) => state.headerRightButtons);
const buttons = useNavigationStore((state) => state.headerRightButtons);
const currentScreen = useNavigationStore((state) => state.currentScreen.name);
const buttonAction = useNavigationStore((state) => state.buttonAction);
const menuRef = useRef();
const menuRef = useRef<{
show: () => void;
hide: () => void;
}>();
return (
<View style={styles.rightBtnContainer}>
@@ -46,9 +50,12 @@ export const RightMenus = () => {
<IconButton
onPress={async () => {
SearchService.prepareSearch();
Navigation.navigate({
name: "Search"
});
Navigation.navigate(
{
name: "Search"
},
{}
);
}}
testID="icon-search"
name="magnify"
@@ -82,7 +89,7 @@ export const RightMenus = () => {
/>
) : null}
{rightButtons && rightButtons.length > 0 ? (
{buttons && buttons.length > 0 ? (
<Menu
ref={menuRef}
animationDuration={200}
@@ -93,7 +100,7 @@ export const RightMenus = () => {
onRequestClose={() => {
menuRef.current?.hide();
}}
button={
anchor={
<IconButton
onPress={() => {
menuRef.current?.show();
@@ -104,7 +111,7 @@ export const RightMenus = () => {
/>
}
>
{rightButtons.map((item) => (
{buttons.map((item) => (
<Button
style={{
width: 150,
@@ -113,7 +120,7 @@ export const RightMenus = () => {
}}
type="gray"
buttonType={{
text: colors.primary.paragraph
text: contextMenuColors.primary.paragraph
}}
key={item.title}
title={item.title}

View File

@@ -17,8 +17,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useEffect, useState } from "react";
import { Platform, View } from "react-native";
import { useThemeColors } from "@notesnook/theme";
import React, { useCallback, useEffect, useState } from "react";
import { Platform } from "react-native";
import { db } from "../../common/database";
import Notebook from "../../screens/notebook";
import {
@@ -26,14 +27,12 @@ import {
eUnSubscribeEvent
} from "../../services/event-manager";
import useNavigationStore from "../../stores/use-navigation-store";
import { useThemeColors } from "@notesnook/theme";
import { eScrollEvent } from "../../utils/events";
import { SIZE } from "../../utils/size";
import Heading from "../ui/typography/heading";
import { useCallback } from "react";
import Tag from "../ui/tag";
import Heading from "../ui/typography/heading";
const titleState = {};
const titleState: { [name: string]: boolean } = {};
export const Title = () => {
const { colors } = useThemeColors();
@@ -42,12 +41,12 @@ export const Title = () => {
const isTopic = currentScreen?.name === "TopicNotes";
const [hide, setHide] = useState(
isNotebook
? typeof titleState[currentScreen.id] === "boolean"
? titleState[currentScreen.id]
? typeof titleState[currentScreen.id as string] === "boolean"
? titleState[currentScreen.id as string]
: true
: false
);
const isHidden = titleState[currentScreen.id];
const isHidden = titleState[currentScreen.id as string];
const notebook =
isTopic && currentScreen.notebookId
? db.notebooks?.notebook(currentScreen.notebookId)?.data
@@ -56,18 +55,18 @@ export const Title = () => {
const isTag = currentScreen?.name === "TaggedNotes";
const onScroll = useCallback(
(data) => {
(data: { x: number; y: number }) => {
if (currentScreen.name !== "Notebook") {
setHide(false);
return;
}
if (data.y > 150) {
if (!hide) return;
titleState[currentScreen.id] = false;
titleState[currentScreen.id as string] = false;
setHide(false);
} else {
if (hide) return;
titleState[currentScreen.id] = true;
titleState[currentScreen.id as string] = true;
setHide(true);
}
},
@@ -76,13 +75,13 @@ export const Title = () => {
useEffect(() => {
if (currentScreen.name === "Notebook") {
let value =
typeof titleState[currentScreen.id] === "boolean"
? titleState[currentScreen.id]
const value =
typeof titleState[currentScreen.id as string] === "boolean"
? titleState[currentScreen.id as string]
: true;
setHide(value);
} else {
setHide(titleState[currentScreen.id]);
setHide(titleState[currentScreen.id as string]);
}
}, [currentScreen.id, currentScreen.name]);
@@ -98,14 +97,7 @@ export const Title = () => {
Notebook.navigate(notebook, true);
}
return (
<View
style={{
opacity: 1,
flexShrink: 1,
flexDirection: "row",
alignItems: "center"
}}
>
<>
{!hide && !isHidden ? (
<Heading
onPress={navigateToNotebook}
@@ -122,10 +114,17 @@ export const Title = () => {
#
</Heading>
) : null}
{title}
{title}{" "}
<Tag
visible={currentScreen.beta}
text="BETA"
style={{
backgroundColor: "transparent"
}}
textColor={colors.primary.accent}
/>
</Heading>
) : null}
<Tag visible={currentScreen.beta} text="BETA" />
</View>
</>
);
};

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import Sodium from "@ammarahmed/react-native-sodium";
import dataurl from "@notesnook/core/utils/dataurl";
import dataurl from "@notesnook/core/dist/utils/dataurl";
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useState } from "react";
import { Platform, View } from "react-native";

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { getUpcomingReminder } from "@notesnook/core/collections/reminders";
import { getUpcomingReminder } from "@notesnook/core/dist/collections/reminders";
import { decode, EntityLevel } from "entities";
import React from "react";
import { View } from "react-native";

View File

@@ -53,15 +53,10 @@ const renderItems = {
const RenderItem = ({ item, index, type, ...restArgs }) => {
if (!item) return <View />;
const Item = renderItems[item.itemType || item.type] || View;
const groupOptions = db.settings?.getGroupOptions(type);
const dateBy =
groupOptions.sortBy !== "title" ? groupOptions.sortBy : "dateEdited";
const totalNotes = getTotalNotes(item);
return (
<Item
item={item}
dateBy={dateBy}
index={index}
type={type}
totalNotes={totalNotes}
@@ -103,6 +98,12 @@ const List = ({
(type === "notes" && notesListMode === "compact") ||
type === "notebooks" ||
notebooksListMode === "compact";
const groupType =
screen === "Notes" ? "home" : screen === "Favorites" ? "favorites" : type;
const groupOptions = db.settings?.getGroupOptions(groupType);
const dateBy =
groupOptions.sortBy !== "title" ? groupOptions.sortBy : "dateEdited";
const renderItem = React.useCallback(
({ item, index }) => (
@@ -111,6 +112,7 @@ const List = ({
index={index}
color={headerProps?.color}
title={headerProps?.heading}
dateBy={dateBy}
type={
screen === "Notes"
? "home"
@@ -122,7 +124,7 @@ const List = ({
isSheet={isSheet}
/>
),
[headerProps?.color, headerProps?.heading, screen, type, isSheet]
[headerProps?.color, headerProps?.heading, screen, type, isSheet, dateBy]
);
const _onRefresh = async () => {

View File

@@ -109,7 +109,6 @@ export default function NotePreview({ session, content, note }) {
flex: 1
}}
>
<EditorOverlay editorId={editorId} />
<Editor
noHeader
noToolbar
@@ -117,7 +116,6 @@ export default function NotePreview({ session, content, note }) {
editorId={editorId}
onLoad={async () => {
const _note = note || db.notes.note(session?.noteId)?.data;
await sleep(1000);
eSendEvent(eOnLoadNote + editorId, {
..._note,
content: {

View File

@@ -102,7 +102,11 @@ const SheetProvider = ({ context = "global" }) => {
setData(null);
}}
bottomPadding={!data.noBottomPadding}
enableGesturesInScrollView={data.enableGesturesInScrollView}
enableGesturesInScrollView={
typeof data.enableGesturesInScrollView === "undefined"
? true
: data.enableGesturesInScrollView
}
>
<View
style={{
@@ -127,7 +131,7 @@ const SheetProvider = ({ context = "global" }) => {
{data?.icon ? (
<Icon
color={colors[dialogData.iconColor] || colors.primary.accent}
color={colors[data.iconColor] || colors.primary.accent}
name={data.icon}
size={50}
/>

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EVENTS } from "@notesnook/core/common";
import { EVENTS } from "@notesnook/core/dist/common";
import React, { useCallback, useEffect, useState } from "react";
import { Platform, View } from "react-native";
import { db } from "../../../common/database";

View File

@@ -16,6 +16,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useThemeColors } from "@notesnook/theme";
import React, { RefObject, useRef, useState } from "react";
import { Platform, TextInput, View } from "react-native";
import { ActionSheetRef, ScrollView } from "react-native-actions-sheet";
@@ -25,7 +26,6 @@ import {
ToastEvent,
presentSheet
} from "../../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { SIZE } from "../../../utils/size";
import { Button } from "../../ui/button";
import Input from "../../ui/input";
@@ -223,7 +223,7 @@ export default function ReminderSheet({
<View
style={{
paddingHorizontal: 12,
maxHeight: DDS.isTab ? "90%" : "99.99%"
maxHeight: DDS.isTab ? "99.99%" : "99.99%"
}}
>
<View
@@ -247,7 +247,12 @@ export default function ReminderSheet({
/>
</View>
<Dialog context="local" />
<ScrollView>
<ScrollView
bounces={false}
style={{
marginBottom: DDS.isTab ? 25 : undefined
}}
>
<Input
fwdRef={titleRef}
defaultValue={reminder?.title || referencedItem?.title}
@@ -601,7 +606,7 @@ ReminderSheet.present = (
) => {
presentSheet({
context: isSheet ? "local" : undefined,
enableGesturesInScrollView: true,
enableGesturesInScrollView: false,
noBottomPadding: true,
component: (ref, close, update) => (
<ReminderSheet

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EVENTS } from "@notesnook/core/common";
import { EVENTS } from "@notesnook/core/dist/common";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { ActivityIndicator, Platform, View } from "react-native";
import { FlatList } from "react-native-actions-sheet";
@@ -377,7 +377,10 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
height: 100
}}
>
<ActivityIndicator color={colors.primary.accent} size={SIZE.lg} />
<ActivityIndicator
color={colors.primary.accent}
size={SIZE.lg}
/>
</View>
) : (
<View
@@ -434,7 +437,9 @@ const RestoreDataComponent = ({ close, setRestoring, restoring }) => {
</Paragraph>
</>
) : (
<Paragraph color={colors.secondary.paragraph}>No backups found</Paragraph>
<Paragraph color={colors.secondary.paragraph}>
No backups found
</Paragraph>
)}
</View>
)

View File

@@ -54,7 +54,7 @@ import {
import { normalize, SIZE } from "../../../utils/size";
import { GroupHeader, NotebookType, TopicType } from "../../../utils/types";
import { groupArray } from "@notesnook/core/utils/grouping";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import Config from "react-native-config";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { notesnook } from "../../../../e2e/test.ids";

View File

@@ -28,7 +28,8 @@ import { useNoteStore } from "../../stores/use-notes-store";
import { useSettingStore } from "../../stores/use-setting-store";
import { useThemeColors } from "@notesnook/theme";
import { useUserStore } from "../../stores/use-user-store";
import { MenuItemsList, SUBSCRIPTION_STATUS } from "../../utils/constants";
import { MenuItemsList } from "../../utils/menu-items";
import { SUBSCRIPTION_STATUS } from "../../utils/constants";
import { eOpenPremiumDialog } from "../../utils/events";
import { ColorSection } from "./color-section";
import { MenuItem } from "./menu-item";

View File

@@ -128,7 +128,21 @@ export const MenuItem = React.memo(
<Paragraph size={SIZE.md}>{item.name}</Paragraph>
)}
<Tag visible={item.isBeta} text="BETA" />
{item.isBeta ? (
<View
style={{
borderRadius: 100,
backgroundColor: colors.primary.accent,
paddingHorizontal: 4,
marginLeft: 5,
paddingVertical: 2
}}
>
<Paragraph color={colors.static.white} size={SIZE.xxs}>
BETA
</Paragraph>
</View>
) : null}
</View>
{item.switch ? (

View File

@@ -214,6 +214,10 @@ export const FluidTabs = forwardRef<TabsRef, TabProps>(function FluidTabs(
return;
}
translateX.value = animated ? withTiming(homePosition) : homePosition;
if (!animated) {
translateX.value = 299;
translateX.value = 300;
}
onDrawerStateChange(false);
isDrawerOpen.value = false;
},

View File

@@ -16,7 +16,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { isReminderActive } from "@notesnook/core/collections/reminders";
import { isReminderActive } from "@notesnook/core/dist/collections/reminders";
import React from "react";
import { ViewStyle } from "react-native";

View File

@@ -49,7 +49,6 @@ const SheetWrapper = ({
const largeTablet = deviceMode === "tablet";
const smallTablet = deviceMode === "smallTablet";
const dimensions = useSettingStore((state) => state.dimensions);
const pitchBlack = useSettingStore((state) => state.settings.pitchBlack);
const insets = useGlobalSafeAreaInsets();
let width = dimensions.width > 600 ? 600 : 500;
@@ -121,19 +120,17 @@ const SheetWrapper = ({
}
onClose={_onClose}
>
<BouncingView>
{children}
{bottomPadding ? (
<View
style={{
height:
Platform.OS === "ios" && insets.bottom !== 0
? insets.bottom + 5
: 20
}}
/>
) : null}
</BouncingView>
{children}
{bottomPadding ? (
<View
style={{
height:
Platform.OS === "ios" && insets.bottom !== 0
? insets.bottom + 5
: 20
}}
/>
) : null}
</ActionSheet>
</ScopedThemeProvider>
);

View File

@@ -37,7 +37,7 @@ export default function Tag({
}) {
const { colors } = useThemeColors();
return !visible ? null : (
<View
<Paragraph
style={{
backgroundColor: background || colors.primary.accent,
borderRadius: 100,
@@ -46,13 +46,14 @@ export default function Tag({
marginLeft: 2,
marginTop: -10,
height: 20,
justifyContent: "center",
textAlignVertical: "center",
textAlign: "center",
...style
}}
color={textColor || colors.static.white}
size={SIZE.xxs}
>
<Paragraph color={textColor || colors.static.white} size={SIZE.xxs}>
{text}
</Paragraph>
</View>
{text}
</Paragraph>
);
}

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EV, EVENTS, SYNC_CHECK_IDS } from "@notesnook/core/common";
import { EV, EVENTS, SYNC_CHECK_IDS } from "@notesnook/core/dist/common";
import notifee from "@notifee/react-native";
import NetInfo from "@react-native-community/netinfo";
import React, { useCallback, useEffect, useRef } from "react";
@@ -631,6 +631,7 @@ const doAppLoadActions = async () => {
await useMessageStore.getState().setAnnouncement();
if (NewFeature.present()) return;
if (await checkAppUpdateAvailable()) return;
if (!(await db.user.getUser())) {
setLoginMessage();
return;

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EVENTS } from "@notesnook/core/common";
import { EVENTS } from "@notesnook/core/dist/common";
import { useCallback, useEffect, useState } from "react";
import { db } from "../common/database";

View File

@@ -16,7 +16,7 @@
"html-to-text": "9.0.5",
"phone": "^3.1.14",
"qclone": "^1.2.0",
"react-native-actions-sheet": "0.9.0-alpha.21",
"react-native-actions-sheet": "0.9.0-alpha.23",
"react-native-check-version": "https://github.com/flexible-agency/react-native-check-version",
"react-native-drax": "^0.10.2",
"react-native-image-zoom-viewer": "^3.0.1",
@@ -30,7 +30,8 @@
"toggle-switch-react-native": "3.2.0",
"url": "^0.11.0",
"validator": "^13.5.2",
"zustand": "^3.6.0"
"zustand": "^3.6.0",
"katex": "0.16.2"
},
"sideEffects": false
}

View File

@@ -18,35 +18,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* eslint-disable @typescript-eslint/no-var-requires */
import { EV, EVENTS } from "@notesnook/core/common";
import { EV, EVENTS } from "@notesnook/core/dist/common";
import React, {
forwardRef,
useCallback,
useEffect,
useImperativeHandle,
useRef,
useState
useLayoutEffect,
useRef
} from "react";
import { Platform, ViewStyle } from "react-native";
import WebView from "react-native-webview";
import { ShouldStartLoadRequest } from "react-native-webview/lib/WebViewTypes";
import { notesnook } from "../../../e2e/test.ids";
import { db } from "../../common/database";
import {
eSubscribeEvent,
eUnSubscribeEvent
} from "../../services/event-manager";
import { IconButton } from "../../components/ui/icon-button";
import useKeyboard from "../../hooks/use-keyboard";
import { eSubscribeEvent } from "../../services/event-manager";
import { useEditorStore } from "../../stores/use-editor-store";
import { getElevationStyle } from "../../utils/elevation";
import { openLinkInBrowser } from "../../utils/functions";
import { NoteType } from "../../utils/types";
import EditorOverlay from "./loading";
import { EDITOR_URI } from "./source";
import { EditorProps, useEditorType } from "./tiptap/types";
import { useEditor } from "./tiptap/use-editor";
import { useEditorEvents } from "./tiptap/use-editor-events";
import { editorController } from "./tiptap/utils";
import { useLayoutEffect } from "react";
import useKeyboard from "../../hooks/use-keyboard";
const style: ViewStyle = {
height: "100%",
@@ -127,21 +125,26 @@ const Editor = React.memo(
const onError = useCallback(() => {
renderKey.current =
renderKey.current === `editor-0` ? `editor-1` : `editor-0`;
// editor.state.current.ready = false;
//editor.setLoading(true);
editor.state.current.ready = false;
editor.setLoading(true);
}, [editor]);
useEffect(() => {
eSubscribeEvent("webview_reset", onError);
EV.subscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded);
const sub = [
eSubscribeEvent("webview_reset", onError),
EV.subscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded)
];
return () => {
eUnSubscribeEvent("webview_reset", onError);
sub.forEach((s) => s.unsubscribe());
EV.unsubscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded);
};
}, [onError, onMediaDownloaded]);
useLayoutEffect(() => {
onLoad && onLoad();
setImmediate(() => {
onLoad && onLoad();
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [onLoad]);
@@ -193,9 +196,8 @@ const Editor = React.memo(
autoManageStatusBarEnabled={false}
onMessage={onMessage || undefined}
/>
{editorId === "shareEditor" ? null : (
<AppSection editor={editor} editorId={editorId} />
)}
<EditorOverlay editorId={editorId || ""} editor={editor} />
<ReadonlyButton editor={editor} />
</>
);
}
@@ -205,32 +207,6 @@ const Editor = React.memo(
export default Editor;
let EditorOverlay: React.ElementType;
let IconButton: React.ElementType;
const AppSection = ({
editor,
editorId
}: {
editor: useEditorType;
editorId: string;
}) => {
const [loaded, setLoaded] = useState(false);
useEffect(() => {
EditorOverlay = require("./loading.js").default;
IconButton =
require("../../components/ui/icon-button/index.tsx").IconButton;
setLoaded(true);
}, []);
return loaded ? (
<>
{EditorOverlay ? (
<EditorOverlay editorId={editorId || ""} editor={editor} />
) : null}
{editorId === "" ? <ReadonlyButton editor={editor} /> : null}
</>
) : null;
};
const ReadonlyButton = ({ editor }: { editor: useEditorType }) => {
const readonly = useEditorStore((state) => state.readonly);
const keyboard = useKeyboard();
@@ -244,7 +220,7 @@ const ReadonlyButton = ({ editor }: { editor: useEditorType }) => {
}
};
return readonly && IconButton && !keyboard.keyboardShown ? (
return readonly && !keyboard.keyboardShown ? (
<IconButton
name="pencil-lock"
type="grayBg"

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import Sodium from "@ammarahmed/react-native-sodium";
import { isImage } from "@notesnook/core/utils/filename";
import { isImage } from "@notesnook/core/dist/utils/filename";
import { Platform } from "react-native";
import RNFetchBlob from "react-native-blob-util";
import DocumentPicker from "react-native-document-picker";

View File

@@ -48,7 +48,7 @@ export type Settings = {
keyboardShown?: boolean;
doubleSpacedLines?: boolean;
corsProxy: string;
fontSize: string;
fontSize: number;
fontFamily: string;
dateFormat: string;
timeFormat: string;

View File

@@ -189,7 +189,10 @@ export const useEditorEvents = (
noToolbar: readonly || editorPropReadonly || noToolbar,
doubleSpacedLines: doubleSpacedLines,
corsProxy: corsProxy,
fontSize: defaultFontSize,
fontSize:
typeof defaultFontSize === "string"
? parseInt(defaultFontSize)
: defaultFontSize,
fontFamily: SettingsService.get().defaultFontFamily,
dateFormat: db.settings?.getDateFormat(),
timeFormat: db.settings?.getTimeFormat()

View File

@@ -17,7 +17,8 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EVENTS } from "@notesnook/core/common";
import { getFormattedDate } from "@notesnook/common";
import { EVENTS } from "@notesnook/core/dist/common";
import { useThemeEngineStore } from "@notesnook/theme";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import WebView from "react-native-webview";
@@ -31,6 +32,7 @@ import {
openVault
} from "../../../services/event-manager";
import Navigation from "../../../services/navigation";
import Notifications from "../../../services/notifications";
import SettingsService from "../../../services/settings";
import { TipManager } from "../../../services/tip-manager";
import { useEditorStore } from "../../../stores/use-editor-store";
@@ -52,7 +54,6 @@ import {
makeSessionId,
post
} from "./utils";
import { getFormattedDate } from "@notesnook/common";
export const useEditor = (
editorId = "",
@@ -80,6 +81,7 @@ export const useEditor = (
const lock = useRef(false);
const loadedImages = useRef<{ [name: string]: boolean }>({});
const lockedSessionId = useRef<string>();
const loadingState = useRef<string>();
const postMessage = useCallback(
async <T>(type: string, data: T, waitFor = 300) =>
@@ -117,9 +119,8 @@ export const useEditor = (
useEffect(() => {
if (loading) {
setLoading(false);
} else {
state.current.ready = false;
setLoading(false);
}
}, [loading]);
@@ -133,7 +134,7 @@ export const useEditor = (
const reset = useCallback(
async (resetState = true, resetContent = true) => {
currentNote.current?.id && db.fs?.cancel(currentNote.current.id);
currentNote.current?.id && db.fs?.cancel(currentNote.current.id, null);
currentNote.current = null;
loadedImages.current = {};
currentContent.current = null;
@@ -234,6 +235,10 @@ export const useEditor = (
id && useEditorStore.getState().setCurrentlyEditingNote(id);
});
}
if (Notifications.isNotePinned(id as string)) {
Notifications.pinNote(id as string);
}
} else {
noteData.contentId = note?.contentId;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -363,6 +368,9 @@ export const useEditor = (
isDefaultEditor && editorState.setCurrentlyEditingNote(item.id);
currentNote.current && (await reset(false, false));
await loadContent(item as NoteType);
if (loadingState.current === currentContent.current?.data) {
return;
}
if (
!currentContent.current?.data ||
currentContent.current?.data.length < 50000
@@ -385,11 +393,13 @@ export const useEditor = (
currentNote.current = item as NoteType;
await commands.setStatus(getFormattedDate(item.dateEdited), "Saved");
await postMessage(EditorEvents.title, item.title);
loadingState.current = currentContent.current?.data;
await postMessage(
EditorEvents.html,
currentContent.current?.data,
10000
);
loadingState.current = undefined;
useEditorStore.getState().setReadonly(item.readonly);
await commands.setTags(currentNote.current);
commands.setSettings();
@@ -601,9 +611,11 @@ export const useEditor = (
const onReady = useCallback(async () => {
if (!(await isEditorLoaded(editorRef, sessionIdRef.current))) {
eSendEvent("webview_reset");
eSendEvent("webview_reset", "onReady");
return false;
} else {
isDefaultEditor && restoreEditorState();
return true;
}
}, [isDefaultEditor, restoreEditorState]);
@@ -616,15 +628,18 @@ export const useEditor = (
isDefaultEditor ? insets : { top: 0, left: 0, right: 0, bottom: 0 }
);
await commands.setSessionId(sessionIdRef.current);
await onReady();
state.current.ready = true;
await commands.setSettings();
if (currentNote.current) {
loadNote({ ...currentNote.current, forced: true });
} else {
await commands.setPlaceholder(placeholderTip.current);
}
}, 1000);
timers.current["editor:loaded"] = setTimeout(async () => {
if (!state.current.ready && (await onReady())) {
state.current.ready = true;
}
if (currentNote.current) {
loadNote({ ...currentNote.current, forced: true });
} else {
await commands.setPlaceholder(placeholderTip.current);
}
});
});
}, [
onReady,
postMessage,

View File

@@ -29,6 +29,7 @@ import SettingsService from "../../services/settings";
import useNavigationStore from "../../stores/use-navigation-store";
import { useNoteStore } from "../../stores/use-notes-store";
import { openEditor } from "../notes/common";
const prepareSearch = () => {
SearchService.update({
placeholder: "Type a keyword to search in notes",

View File

@@ -16,7 +16,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { groupArray } from "@notesnook/core/utils/grouping";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import React, { useEffect, useRef, useState } from "react";
import { db } from "../../common/database";
import DelayLayout from "../../components/delay-layout";

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { groupArray } from "@notesnook/core/utils/grouping";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import React from "react";
import NotesPage, { PLACEHOLDER_DATA } from ".";
import { db } from "../../common/database";

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { groupArray } from "@notesnook/core/utils/grouping";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import React from "react";
import NotesPage, { PLACEHOLDER_DATA } from ".";
import { db } from "../../common/database";

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { groupArray } from "@notesnook/core/utils/grouping";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import React from "react";
import NotesPage, { PLACEHOLDER_DATA } from ".";
import { db } from "../../common/database";

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { groupArray } from "@notesnook/core/utils/grouping";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import React from "react";
import NotesPage, { PLACEHOLDER_DATA } from ".";
import { db } from "../../common/database";

View File

@@ -66,6 +66,7 @@ export const Reminders = ({
});
SearchService.prepareSearch = prepareSearch;
useNavigationStore.getState().setButtonAction(PLACEHOLDER_DATA.action);
return !prev?.current;
},
onBlur: () => false,

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import Clipboard from "@react-native-clipboard/clipboard";
import { LogMessage } from "@notesnook/logger";
import { format, LogLevel, logManager } from "@notesnook/core/logger";
import { format, LogLevel, logManager } from "@notesnook/core/dist/logger";
import React, { useEffect, useRef, useState } from "react";
import { FlatList, Platform, TouchableOpacity, View } from "react-native";
import * as ScopedStorage from "react-native-scoped-storage";

View File

@@ -42,7 +42,8 @@ export async function verifyUser(
negativeText: closeText || "Cancel",
positivePress: async (value) => {
try {
let verified = await db.user.verifyPassword(value);
const user = await db.user.getUser();
let verified = !user ? true : await db.user.verifyPassword(value);
if (verified) {
sleep(300).then(async () => {
await onsuccess();
@@ -58,7 +59,7 @@ export async function verifyUser(
}
} catch (e) {
ToastEvent.show({
heading: "Failed to backup data",
heading: "Failed to verify",
message: e.message,
type: "error",
context: "global"

View File

@@ -87,12 +87,6 @@ const Home = ({
alignItems: "center"
}}
>
<Heading color={colors.primary.heading} size={SIZE.lg}>
Logging out
</Heading>
<Paragraph color={colors.secondary.icon}>
Please wait while we log out and clear app data.
</Paragraph>
<View
style={{
width: "100%",

View File

@@ -27,6 +27,8 @@ import PremiumService from "../../../services/premium";
import { useThemeColors } from "@notesnook/theme";
import { SIZE } from "../../../utils/size";
import { sleep } from "../../../utils/time";
import { verifyUser } from "../functions";
import { Dialog } from "../../../components/dialog";
interface PickerOptions<T> {
getValue: () => T;
@@ -37,6 +39,7 @@ interface PickerOptions<T> {
options: T[];
premium?: boolean;
onCheckOptionIsPremium?: (item: T) => boolean;
requiresVerification?: () => boolean;
}
export function SettingsPicker<T>({
@@ -47,7 +50,8 @@ export function SettingsPicker<T>({
options,
getItemKey,
premium,
onCheckOptionIsPremium = () => true
onCheckOptionIsPremium = () => true,
requiresVerification = () => false
}: PickerOptions<T>) {
const { colors } = useThemeColors("contextMenu");
const menuRef = useRef<any>();
@@ -118,11 +122,18 @@ export function SettingsPicker<T>({
</PressableButton>
}
>
<Dialog context="local" />
{options.map((item) => (
<MenuItem
key={getItemKey(item)}
onPress={async () => {
onChange(item);
if (requiresVerification?.()) {
verifyUser("local", () => {
onChange(item);
});
} else {
onChange(item);
}
}}
style={{
backgroundColor: compareValue(currentValue, item)

View File

@@ -21,11 +21,12 @@ import { db } from "../../../common/database";
import { ToastEvent } from "../../../services/event-manager";
import SettingsService from "../../../services/settings";
import { useSettingStore } from "../../../stores/use-setting-store";
import { MenuItemsList } from "../../../utils/constants";
import { MenuItemsList } from "../../../utils/menu-items";
import { createSettingsPicker } from ".";
import { getFontById, getFonts } from "@notesnook/editor/dist/utils/font";
import { DATE_FORMATS, TIME_FORMATS } from "@notesnook/core/common";
import { DATE_FORMATS, TIME_FORMATS } from "@notesnook/core/dist/common";
import dayjs from "dayjs";
import { useUserStore } from "../../../stores/use-user-store";
export const FontPicker = createSettingsPicker({
getValue: () => useSettingStore.getState().settings.defaultFontFamily,
@@ -127,6 +128,12 @@ export const BackupReminderPicker = createSettingsPicker({
options: ["useroff", "daily", "weekly", "monthly"],
compareValue: (current, item) => current === item,
premium: true,
requiresVerification: () => {
return (
!useSettingStore.getState().settings.encryptedBackup &&
useUserStore.getState().user
);
},
onCheckOptionIsPremium: (item) => {
return item !== "useroff";
}

View File

@@ -17,7 +17,6 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ThemeDark, ThemePitchBlack } from "@notesnook/theme";
import notifee from "@notifee/react-native";
import dayjs from "dayjs";
import React from "react";
@@ -288,9 +287,9 @@ export const settingsGroups: SettingSection[] = [
positiveText: "Logout",
positivePress: async () => {
try {
eSendEvent("settings-loading", true);
setImmediate(async () => {
eSendEvent(eCloseSimpleDialog);
eSendEvent(eCloseSimpleDialog);
setTimeout(async () => {
eSendEvent("settings-loading", true);
Navigation.popToTop();
await db.user?.logout();
setLoginMessage();
@@ -306,7 +305,7 @@ export const settingsGroups: SettingSection[] = [
setTimeout(() => {
eSendEvent("settings-loading", false);
}, 2000);
});
}, 300);
} catch (e) {
ToastEvent.error(e as Error, "Error logging out");
eSendEvent("settings-loading", false);
@@ -783,10 +782,11 @@ export const settingsGroups: SettingSection[] = [
description: "Create a backup of your data",
modifer: async () => {
const user = useUserStore.getState().user;
if (!user) {
if (!user || SettingsService.getProperty("encryptedBackup")) {
await BackupService.run(true);
return;
}
verifyUser(null, () => BackupService.run(true));
}
},
@@ -870,9 +870,17 @@ export const settingsGroups: SettingSection[] = [
});
return;
}
SettingsService.set({
encryptedBackup: !settings.encryptedBackup
});
if (settings.encryptedBackup) {
await verifyUser(null, () => {
SettingsService.set({
encryptedBackup: false
});
});
} else {
SettingsService.set({
encryptedBackup: true
});
}
}
}
]
@@ -902,7 +910,9 @@ export const settingsGroups: SettingSection[] = [
description:
"Export all notes as pdf, markdown, html or text in a single zip file",
modifer: () => {
ExportNotesSheet.present(undefined, true);
verifyUser(null, () => {
ExportNotesSheet.present(undefined, true);
});
}
}
]
@@ -972,7 +982,7 @@ export const settingsGroups: SettingSection[] = [
}
},
{
id: "reminder-sound",
id: "reminder-sound-ios",
type: "screen",
name: "Change notification sound",
description:
@@ -984,7 +994,7 @@ export const settingsGroups: SettingSection[] = [
(Platform.OS === "android" && Platform.Version > 25)
},
{
id: "reminder-sound",
id: "reminder-sound-android",
name: "Change notification sound",
description:
"Set the notification sound for reminder notifications",

View File

@@ -51,11 +51,11 @@ import { ToastEvent, presentSheet } from "../../services/event-manager";
import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
import { getElevationStyle } from "../../utils/elevation";
import { MenuItemsList } from "../../utils/constants";
import { MenuItemsList } from "../../utils/menu-items";
import { IconButton } from "../../components/ui/icon-button";
import { PressableButton } from "../../components/ui/pressable";
const THEME_SERVER_URL = "https://themes.notesnook.com";
const THEME_SERVER_URL = "https://themes-api.notesnook.com";
//@ts-ignore
export const themeTrpcClient = createTRPCProxyClient<ThemesRouter>({
links: [
@@ -103,10 +103,12 @@ function ThemeSelector() {
}
);
const select = (item: Partial<ThemeMetadata>) => {
const select = (item: Partial<ThemeMetadata>, fromFile?: boolean) => {
presentSheet({
context: "theme-details",
component: (ref, close) => <ThemeSetter close={close} theme={item} />
component: (ref, close) => (
<ThemeSetter close={close} theme={item} fromFile={fromFile} />
)
});
};
@@ -327,7 +329,6 @@ function ThemeSelector() {
) || []
);
}
return (
<>
<SheetProvider context="theme-details" />
@@ -397,16 +398,17 @@ function ThemeSelector() {
icon="folder"
fontSize={SIZE.xs}
onPress={() => {
DocumentPicker.pickSingle().then((r) => {
DocumentPicker.pickSingle({
allowMultiSelection: false
}).then((r) => {
fetch(r.uri).then(async (response) => {
const json = await response.json();
console.log(json);
const result = validateTheme(json);
if (result.error) {
ToastEvent.error(new Error(result.error));
return;
}
select(json);
select(json, true);
});
});
}}
@@ -445,6 +447,22 @@ function ThemeSelector() {
)}
</View>
}
ListFooterComponent={
themes.isError ? (
<View
style={{
height: 100,
width: "100%",
justifyContent: "center",
alignItems: "center"
}}
>
<Paragraph color={colors.error.paragraph}>
Error loading themes. {themes.error.message}.
</Paragraph>
</View>
) : null
}
estimatedItemSize={200}
renderItem={renderItem}
onEndReachedThreshold={0.1}
@@ -483,10 +501,12 @@ export default function ThemeSelectorWithQueryClient() {
const ThemeSetter = ({
theme,
close
close,
fromFile
}: {
theme: Partial<CompiledThemeDefinition>;
close?: (ctx?: string) => void;
fromFile?: boolean;
}) => {
const [darkTheme, lightTheme] = useThemeStore((state) => [
state.darkTheme,
@@ -502,14 +522,13 @@ const ThemeSetter = ({
if (!theme.id) return;
try {
const user = await db.user?.getUser();
const fullTheme = theme.scopes
const fullTheme = fromFile
? (theme as ThemeDefinition)
: await themeTrpcClient.installTheme.query({
compatibilityVersion: THEME_COMPATIBILITY_VERSION,
id: theme.id,
userId: user?.id
});
if (!fullTheme) return;
theme.colorScheme === "dark"
? useThemeStore.getState().setDarkTheme(fullTheme)

View File

@@ -114,7 +114,7 @@ export const Trash = ({ navigation, route }: NavigationProps<"Trash">) => {
<FloatingButton
title="Clear all trash"
onPress={onPressFloatingButton}
shouldShow={true}
alwaysVisible={true}
/>
) : null}
</DelayLayout>

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import EventManager from "@notesnook/core/utils/event-manager";
import EventManager from "@notesnook/core/dist/utils/event-manager";
import Clipboard from "@react-native-clipboard/clipboard";
import { RefObject } from "react";
import { ActionSheetRef } from "react-native-actions-sheet";

View File

@@ -46,6 +46,9 @@ import { useRelationStore } from "../stores/use-relation-store";
import { useReminderStore } from "../stores/use-reminder-store";
import { presentDialog } from "../components/dialog/functions";
import NetInfo from "@react-native-community/netinfo";
import { encodeNonAsciiHTML } from "entities";
import { convertNoteToText } from "../utils/note-to-text";
export type Reminder = {
id: string;
@@ -86,6 +89,28 @@ async function getNextMonthlyReminderDate(
return await getNextMonthlyReminderDate(reminder, dayjs().year() + 1);
}
export function textToHTML(src: string) {
return src
.split(/[\r\n]/)
.map((line) =>
line
? `<p data-spacing="single">${encodeLine(line)}</p>`
: `<p data-spacing="single"></p>`
)
.join("");
}
function encodeLine(line: string) {
line = encodeNonAsciiHTML(line);
line = line.replace(/(^ +)|( {2,})/g, (sub, ...args) => {
const [starting, inline] = args;
if (starting) return "&nbsp;".repeat(starting.length);
if (inline) return "&nbsp;".repeat(inline.length);
return sub;
});
return line;
}
async function initDatabase(notes = true) {
if (!db.isInitialized) {
await db.initCollections();
@@ -206,16 +231,41 @@ const onEvent = async ({ type, detail }: Event) => {
});
if (!db.isInitialized) await db.init();
await db.notes?.init();
await db.notes?.add({
const id = await db.notes?.add({
content: {
type: "tiptap",
data: `<p>${input} </p>`
data: textToHTML(input as string)
}
});
const defaultNotebook = db.settings?.getDefaultNotebook();
if (defaultNotebook) {
if (!defaultNotebook.topic) {
await db.relations?.add(
{ type: "notebook", id: defaultNotebook.id },
{ type: "note", id: id }
);
} else {
await db.notes?.addToNotebook(
{
topic: defaultNotebook.topic,
id: defaultNotebook?.id
},
id
);
}
}
const status = await NetInfo.fetch();
if (status.isInternetReachable) {
try {
await db.sync(false, false);
if (!globalThis["IS_MAIN_APP_RUNNING" as never]) {
await db.sync(false, false);
} else {
console.log("main app running, skipping sync");
}
} catch (e) {
console.log(e, (e as Error).stack);
}
@@ -757,6 +807,11 @@ function getPinnedNotes(): DisplayedNotification[] {
return pinned;
}
function isNotePinned(id: string) {
if (Platform.OS !== "android") return false;
return pinned.findIndex((notification) => notification.id === id) > -1;
}
function get(): Promise<DisplayedNotification[]> {
return new Promise((resolve) => {
if (Platform.OS === "ios") resolve([]);
@@ -844,6 +899,26 @@ async function setupReminders(checkNeedsScheduling = false) {
);
}
async function pinNote(id: string) {
try {
const note = db.notes?.note(id as string) as any;
let text = await convertNoteToText(note as any, false);
if (!text) text = "";
let html = text.replace(/\n/g, "<br />");
Notifications.displayNotification({
title: note.title,
message: note.headline || text,
subtitle: note.headline || text,
bigText: html,
ongoing: true,
actions: ["UNPIN"],
id: note.id
});
} catch (e) {
console.log(e);
}
}
const Notifications = {
init,
displayNotification,
@@ -859,7 +934,9 @@ const Notifications = {
checkAndRequestPermissions,
clearAllTriggers,
setupReminders,
getChannelId
getChannelId,
isNotePinned,
pinNote
};
export default Notifications;

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { CHECK_IDS } from "@notesnook/core/common";
import { CHECK_IDS } from "@notesnook/core/dist/common";
import React from "react";
import { Platform } from "react-native";
import Config from "react-native-config";

View File

@@ -166,4 +166,5 @@ export const SettingsService = {
resetSettings
};
init();
export default SettingsService;

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EVENTS } from "@notesnook/core/common";
import { EVENTS } from "@notesnook/core/dist/common";
import NetInfo from "@react-native-community/netinfo";
import { db } from "../common/database";
import { DatabaseLogger } from "../common/database/index";
@@ -41,6 +41,11 @@ const run = async (
full = true,
onCompleted
) => {
if (useUserStore.getState().syncing) {
DatabaseLogger.log("Sync in progress");
console.log("Sync in progress");
return;
}
clearTimeout(syncTimer);
syncTimer = setTimeout(async () => {
const status = await NetInfo.fetch();

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { groupArray } from "@notesnook/core/utils/grouping";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import create, { State } from "zustand";
import { db } from "../common/database";
import { NoteType } from "../utils/types";

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { groupArray } from "@notesnook/core/utils/grouping";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import create, { State } from "zustand";
import { db } from "../common/database";
import { NotebookType } from "../utils/types";

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { groupArray } from "@notesnook/core/utils/grouping";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import create, { State } from "zustand";
import { db } from "../common/database";
import { NoteType } from "../utils/types";

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { groupReminders } from "@notesnook/core/utils/grouping";
import { groupReminders } from "@notesnook/core/dist/utils/grouping";
import create, { State } from "zustand";
import { db } from "../common/database";
import { Reminder } from "../services/notifications";

View File

@@ -69,7 +69,7 @@ export type Settings = {
corsProxy: string;
disableRealtimeSync?: boolean;
notificationSound?: Sound & { platform: PlatformOSType };
defaultFontSize: string;
defaultFontSize: number;
defaultFontFamily: string;
colorScheme: "dark" | "light";
lighTheme: ThemeDefinition;
@@ -149,7 +149,7 @@ export const defaultSettings: SettingStore["settings"] = {
reminderNotificationMode: "urgent",
notificationSound: undefined,
defaultFontFamily: "sans-serif",
defaultFontSize: "16",
defaultFontSize: 16,
colorScheme: "light",
lighTheme: ThemeLight,
darkTheme: ThemeDark

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 "@notesnook/core/types";
import { groupArray } from "@notesnook/core/utils/grouping";
import "@notesnook/core/dist/types";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import create, { State } from "zustand";
import { db } from "../common/database";
import { TagType } from "../utils/types";

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { groupArray } from "@notesnook/core/utils/grouping";
import { groupArray } from "@notesnook/core/dist/utils/grouping";
import create, { State } from "zustand";
import { db } from "../common/database";
import { TrashType } from "../utils/types";

View File

@@ -100,49 +100,6 @@ export const SUBSCRIPTION_PROVIDER = {
}
};
export const MenuItemsList = [
{
name: "Notes",
icon: "home-variant-outline",
close: true
},
{
name: "Notebooks",
icon: "book-outline",
close: true
},
{
name: "Favorites",
icon: "star-outline",
close: true
},
{
name: "Tags",
icon: "pound",
close: true
},
{
name: "Reminders",
icon: "bell",
close: true,
isBeta: true
},
{
name: "Monographs",
icon: "text-box-multiple-outline",
close: true,
func: () => {
const Monographs = require("../screens/notes/monographs").Monographs;
Monographs.navigate();
}
},
{
name: "Trash",
icon: "delete-outline",
close: true
}
];
export const BUTTON_TYPES = {
transparent: {
primary: "transparent",

View File

@@ -0,0 +1,60 @@
/*
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 MenuItemsList = [
{
name: "Notes",
icon: "home-variant-outline",
close: true
},
{
name: "Notebooks",
icon: "book-outline",
close: true
},
{
name: "Favorites",
icon: "star-outline",
close: true
},
{
name: "Tags",
icon: "pound",
close: true
},
{
name: "Reminders",
icon: "bell",
close: true,
isBeta: true
},
{
name: "Monographs",
icon: "text-box-multiple-outline",
close: true,
func: () => {
const Monographs = require("../screens/notes/monographs").Monographs;
Monographs.navigate();
}
},
{
name: "Trash",
icon: "delete-outline",
close: true
}
];

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import Sodium from "@ammarahmed/react-native-sodium";
import { isImage } from "@notesnook/core/utils/filename";
import { isImage } from "@notesnook/core/dist/utils/filename";
import { Platform } from "react-native";
import RNFetchBlob from "react-native-blob-util";
import { db } from "../common/database";

View File

@@ -1,16 +0,0 @@
{
"testEnvironment": "./environment",
"testRunner": "jest-circus/runner",
"setupFilesAfterEnv": ["./setup.ts"],
"testTimeout": 120000,
"testRegex": "\\.e2e\\.js$",
"reporters": ["detox/runners/jest/streamlineReporter"],
"transformIgnorePatterns": ["<rootDir>/node_modules/"],
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": [
"babel-jest",
{ "configFile": "../native/babel.config.js" }
]
},
"verbose": true
}

View File

@@ -1,57 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const {
DetoxCircusEnvironment,
SpecReporter,
WorkerAssignReporter
} = require("detox/runners/jest-circus");
const sleep = (duration) =>
new Promise((resolve) =>
setTimeout(() => {
resolve();
}, duration)
);
class CustomDetoxEnvironment extends DetoxCircusEnvironment {
constructor(config, context) {
super(config, context);
// Can be safely removed, if you are content with the default value (=300000ms)
this.initTimeout = 300000;
// This takes care of generating status logs on a per-spec basis. By default, Jest only reports at file-level.
// This is strictly optional.
this.registerListeners({
SpecReporter,
WorkerAssignReporter
});
}
async initDetox() {
const instance = await this.detox.init(undefined, { launchApp: false });
await sleep(10000);
await instance.device.reverseTcpPort(8081); // added this line
await instance.device.launchApp();
return instance;
}
}
module.exports = CustomDetoxEnvironment;

View File

@@ -0,0 +1,20 @@
/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
rootDir: "..",
testMatch: ["<rootDir>/e2e/**/*.e2e.js"],
testTimeout: 120000,
maxWorkers: 1,
setupFilesAfterEnv: ["./e2e/setup.js"],
globalSetup: "detox/runners/jest/globalSetup",
globalTeardown: "detox/runners/jest/globalTeardown",
reporters: ["detox/runners/jest/reporter"],
testEnvironment: "detox/runners/jest/testEnvironment",
verbose: true,
transform: {
"^.+\\.(js|jsx|ts|tsx)$": [
"babel-jest",
{ configFile: "../native/babel.config.js" }
]
},
transformIgnorePatterns: ["<rootDir>/../node_modules/"]
};

7
apps/mobile/e2e/setup.js Normal file
View File

@@ -0,0 +1,7 @@
import { device } from "detox";
beforeAll(async () => {
await device.launchApp();
});
export {};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

@@ -35,7 +35,7 @@ async function sortBy(sorting, elementText = "Default") {
}
describe("Sort & filter", () => {
it.only("Sort by date-edited/date-created", async () => {
it("Sort by date-edited/date-created", async () => {
await prepare();
let webview = web(by.id(notesnook.editor.id));
await createNote("Note 1", "Note 1");
@@ -52,11 +52,11 @@ describe("Sort & filter", () => {
await device.pressBack();
await sortBy("Date created");
await tapById(notesnook.listitem.menu);
await visibleByText("Note 2");
//await visibleByText("Note 2");
await device.pressBack();
await sortBy("Date edited");
await tapById(notesnook.listitem.menu);
await visibleByText("Edited Note 1");
//await visibleByText("Edited Note 1");
await device.pressBack();
});

View File

@@ -34,7 +34,7 @@ import { sleep } from "./utils";
async function lockNote() {
await tapById(notesnook.listitem.menu);
await tapById("icon-Vault");
await tapById("icon-lock-unlock");
await sleep(1000);
await visibleByText("Lock");
await elementById(notesnook.ids.dialogs.vault.pwd).typeText("1234");
@@ -46,7 +46,7 @@ async function lockNote() {
async function removeFromVault() {
await tapById(notesnook.listitem.menu);
await tapById("icon-Vault");
await tapById("icon-lock-unlock");
await sleep(1000);
await elementById(notesnook.ids.dialogs.vault.pwd).typeText("1234");
await tapByText("Unlock");
@@ -127,7 +127,7 @@ describe("VAULT", () => {
await notVisibleById(notesnook.listitem.menu);
});
it.only("Add a note to vault", async () => {
it("Add a note to vault", async () => {
await prepare();
await createNote();
await lockNote();

View File

@@ -0,0 +1,85 @@
/** @type {Detox.DetoxConfig} */
module.exports = {
testRunner: {
args: {
'$0': 'jest',
config: '../e2e/jest.config.js'
},
jest: {
setupTimeout: 120000
}
},
apps: {
'ios.debug': {
type: 'ios.app',
binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/Notesnook.app',
build: 'xcodebuild -workspace ios/Notesnook.xcworkspace -scheme YOUR_APP -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build'
},
'ios.release': {
type: 'ios.app',
binaryPath: 'ios/build/Build/Products/Release-iphonesimulator/Notesnook.app',
build: 'xcodebuild -workspace ios/Notesnook.xcworkspace -scheme YOUR_APP -configuration Release -sdk iphonesimulator -derivedDataPath ios/build'
},
'android.debug': {
type: 'android.apk',
"binaryPath": "android/app/build/outputs/apk/debug/app-x86_64-debug.apk",
"testBinaryPath": "android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk",
"build": "cd android ; ENVFILE=.env.test ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd ..",
reversePorts: [
8081
]
},
'android.release': {
type: 'android.apk',
"binaryPath": "android/app/build/outputs/apk/release/app-x86_64-release.apk",
"testBinaryPath": "android/app/build/outputs/apk/androidTest/release/app-release-androidTest.apk",
"build": "cd android ; ENVFILE=.env.test ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release ; cd .."
}
},
devices: {
simulator: {
type: 'ios.simulator',
device: {
type: 'iPhone 12'
}
},
attached: {
type: 'android.attached',
device: {
adbName: '.*'
}
},
emulator: {
type: 'android.emulator',
device: {
avdName: 'Pixel_5_API_31'
}
}
},
configurations: {
'ios.sim.debug': {
device: 'simulator',
app: 'ios.debug'
},
'ios.sim.release': {
device: 'simulator',
app: 'ios.release'
},
'android.att.debug': {
device: 'attached',
app: 'android.debug'
},
'android.att.release': {
device: 'attached',
app: 'android.release'
},
'android.emu.debug': {
device: 'emulator',
app: 'android.debug'
},
'android.emu.release': {
device: 'emulator',
app: 'android.release'
}
}
};

View File

@@ -1,52 +0,0 @@
{
"testRunner": "jest",
"runnerConfig": "../e2e/config.json",
"devices": {
"emulator": {
"type": "android.emulator",
"device": {
"avdName": "Pixel_5_API_31"
}
},
"simulator": {
"type": "ios.simulator",
"device": {
"type": "iPhone 8"
}
}
},
"apps": {
"android.debug": {
"type": "android.apk",
"binaryPath": "android/app/build/outputs/apk/debug/app-x86_64-debug.apk",
"testBinaryPath": "android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk",
"build": "cd android ; ENVFILE=.env.test ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd .."
},
"android.release": {
"type": "android.apk",
"binaryPath": "android/app/build/outputs/apk/release/app-x86_64-release.apk",
"testBinaryPath": "android/app/build/outputs/apk/androidTest/release/app-release-androidTest.apk",
"build": "cd android ; ENVFILE=.env.test ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release ; cd .."
},
"ios.release": {
"name": "Notesnook",
"type": "ios.app",
"binaryPath": "ios/build/Build/Products/Release-iphonesimulator/Notesnook.app",
"build": "ENVFILE=.env.test xcodebuild -workspace ios/Notesnook.xcworkspace -scheme NotesnookRelease -sdk iphonesimulator -derivedDataPath ios/build"
}
},
"configurations": {
"android.emu.debug": {
"app": "android.debug",
"device": "emulator"
},
"android.emu.release": {
"app": "android.release",
"device": "emulator"
},
"ios.sim.release": {
"device": "simulator",
"app": "ios.release"
}
}
}

View File

@@ -111,7 +111,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled true
versionCode 2055
versionCode 2057
versionName getNpmVersion()
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
@@ -220,24 +220,31 @@ dependencies {
}
task deleteFiles(type: Delete) {
delete './src/main/assets/static'
}
task copyFiles(type: Copy) {
task copyEditorBundle(type: Copy) {
from '../../../../../packages/editor-mobile/build.bundle'
into './src/main/assets'
}
copyFiles.dependsOn(deleteFiles)
preBuild.dependsOn(copyFiles)
task copyPlainEditorBundle(type: Copy) {
from '../../ios/extension.bundle'
into './src/main/assets'
}
task copyFontFiles(type: Copy) {
from '../../fonts'
into './src/main/assets/fonts'
}
project.ext.vectoricons = [
iconFontNames: ['MaterialCommunityIcons.ttf' ],
iconFontsDir: "../../../node_modules/react-native-vector-icons/Fonts"
]
apply from: "../../../node_modules/react-native-vector-icons/fonts.gradle"
copyEditorBundle.dependsOn(deleteFiles)
copyFontFiles.dependsOn(copyEditorBundle);
copyPlainEditorBundle.dependsOn(copyFontFiles);
preBuild.dependsOn(copyPlainEditorBundle)
apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

View File

@@ -14,17 +14,11 @@ import androidx.test.rule.ActivityTestRule;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DetoxTest {
// Replace 'MainActivity' with the value of android:name entry in
// <activity> in AndroidManifest.xml
@Rule
@Rule // (2)
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class, false, false);
@Test
public void runDetoxTests() {
// This is optional - in case you've decided to integrate TestButler
// See https://github.com/wix/Detox/blob/master/docs/Introduction.Android.md#8-test-butler-support-optional
//TestButlerProbe.assertReadyIfInstalled();
DetoxConfig detoxConfig = new DetoxConfig();
detoxConfig.idlePolicyConfig.masterTimeoutSec = 90;
detoxConfig.idlePolicyConfig.idleResourceTimeoutSec = 60;

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