Compare commits
1137 Commits
fix-androi
...
fix-loadin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d9df5030c | ||
|
|
af014cf8c1 | ||
|
|
1ddd7b1e6e | ||
|
|
9ef0179566 | ||
|
|
38690d18d4 | ||
|
|
c07f5393f6 | ||
|
|
406c63721d | ||
|
|
97f3e02f59 | ||
|
|
5c6564f00b | ||
|
|
605e75efb3 | ||
|
|
496f9ba340 | ||
|
|
f98283f2dd | ||
|
|
2d32e85a64 | ||
|
|
1a56a22a33 | ||
|
|
c85204d0c1 | ||
|
|
1d8a958eaf | ||
|
|
b52f70d57d | ||
|
|
12687dae7b | ||
|
|
c53c3167d8 | ||
|
|
60df472d53 | ||
|
|
67fe25bc8b | ||
|
|
44a7aed308 | ||
|
|
f22937e1eb | ||
|
|
c816f8b15b | ||
|
|
fa4f4e7bea | ||
|
|
076cea6d6d | ||
|
|
d951b97bed | ||
|
|
bd888e57e5 | ||
|
|
3ba1234056 | ||
|
|
4c5a668114 | ||
|
|
06d1891389 | ||
|
|
c97a228ec8 | ||
|
|
d11a200ebb | ||
|
|
bfedc1f43e | ||
|
|
b148083750 | ||
|
|
cdfd7333cd | ||
|
|
2ed32efefb | ||
|
|
e3331e6dee | ||
|
|
b3406be1ad | ||
|
|
751d0ca861 | ||
|
|
a614693dfa | ||
|
|
c4bbceef67 | ||
|
|
d39e7c990d | ||
|
|
e248dbfa5b | ||
|
|
29f789493e | ||
|
|
2b0e5c41c8 | ||
|
|
e241b2fe72 | ||
|
|
a91983340c | ||
|
|
2aa3aaf2f8 | ||
|
|
6b2bf369ff | ||
|
|
fea5818951 | ||
|
|
e6eb71a484 | ||
|
|
1e023500be | ||
|
|
2c078de2c0 | ||
|
|
b373881b8b | ||
|
|
6b37cf0dda | ||
|
|
1025c4ec6e | ||
|
|
c44f9f685d | ||
|
|
5633d4504f | ||
|
|
c7aa49e541 | ||
|
|
ee139463d2 | ||
|
|
2cf7f0cc27 | ||
|
|
210549445e | ||
|
|
5b85158a7c | ||
|
|
09cba1a1df | ||
|
|
d75e2e85c9 | ||
|
|
966673dfd1 | ||
|
|
b8ad9265b9 | ||
|
|
b2f1fda641 | ||
|
|
1544b656e0 | ||
|
|
d97314c484 | ||
|
|
1432553897 | ||
|
|
f585fb0381 | ||
|
|
98557be52d | ||
|
|
e7da0a35d3 | ||
|
|
965a7f91ed | ||
|
|
2b1c973177 | ||
|
|
7e87cf7fdc | ||
|
|
c8cd5a4dc8 | ||
|
|
d00f7f6255 | ||
|
|
e8690e3419 | ||
|
|
72ff45c722 | ||
|
|
22a6271423 | ||
|
|
a6032ffd72 | ||
|
|
69ea9992ce | ||
|
|
36b4d69c2d | ||
|
|
2129533aa9 | ||
|
|
e635ace338 | ||
|
|
e729086015 | ||
|
|
3fbb7ce548 | ||
|
|
e0c31d6fdd | ||
|
|
d19c5b9775 | ||
|
|
f01b88083f | ||
|
|
d3ab1d1d2a | ||
|
|
7855442d33 | ||
|
|
bbaa6c76b4 | ||
|
|
cf71809f6c | ||
|
|
3b7d0ddb36 | ||
|
|
482fea91f3 | ||
|
|
4bace10bab | ||
|
|
603b7da9e6 | ||
|
|
bf4d168c96 | ||
|
|
756bb82fb7 | ||
|
|
81b1005b02 | ||
|
|
7ba52d1358 | ||
|
|
fcfb2c7e01 | ||
|
|
fa0a5afa63 | ||
|
|
b881b236a0 | ||
|
|
ec9c40bd64 | ||
|
|
f0f7857355 | ||
|
|
9c59cbbc40 | ||
|
|
6dce41a070 | ||
|
|
dffeb05f86 | ||
|
|
ecfbfd83b9 | ||
|
|
0aea1deea0 | ||
|
|
f041b92360 | ||
|
|
64074030dd | ||
|
|
3387dda22b | ||
|
|
534b810350 | ||
|
|
50666c1307 | ||
|
|
200c9bd9eb | ||
|
|
2f93c6fdc8 | ||
|
|
5c21c0a498 | ||
|
|
93c07d6842 | ||
|
|
5d9f18ed77 | ||
|
|
313d47d9ff | ||
|
|
304a9f3218 | ||
|
|
a160725acb | ||
|
|
05535b50da | ||
|
|
70fdcf2b44 | ||
|
|
67d47c283e | ||
|
|
dd59aab328 | ||
|
|
509b308419 | ||
|
|
7a12fd701e | ||
|
|
9396a06a89 | ||
|
|
9d9c3b7db5 | ||
|
|
4cfb10db7c | ||
|
|
50024b62cb | ||
|
|
f31084baa7 | ||
|
|
2688becb05 | ||
|
|
8298900f76 | ||
|
|
b0c18a8ece | ||
|
|
9659a12d70 | ||
|
|
6abc25f58a | ||
|
|
a164ac67ce | ||
|
|
255677d98e | ||
|
|
2a92ea4efd | ||
|
|
608b4f3009 | ||
|
|
a69cb1bf9c | ||
|
|
be40b3d160 | ||
|
|
51147b17cd | ||
|
|
5d0c2ae0b9 | ||
|
|
8435e69cb5 | ||
|
|
1d6a33e3be | ||
|
|
3f4d78af7d | ||
|
|
f94012d184 | ||
|
|
ca73c0c2ce | ||
|
|
742bf31038 | ||
|
|
1369b64cb1 | ||
|
|
bc3488512f | ||
|
|
51f87911e1 | ||
|
|
4d4af5c278 | ||
|
|
a6fcff4d86 | ||
|
|
50b7f9eb68 | ||
|
|
a81c534258 | ||
|
|
67cd2e6504 | ||
|
|
ed5c84b069 | ||
|
|
f6c442ba88 | ||
|
|
19e59b778d | ||
|
|
0643a74ade | ||
|
|
1babbb567c | ||
|
|
11899501f2 | ||
|
|
9982d7b7b4 | ||
|
|
22497199c5 | ||
|
|
873b180dab | ||
|
|
ca8e505cd0 | ||
|
|
465e1af838 | ||
|
|
2f66ee04cc | ||
|
|
a829594fad | ||
|
|
1427518e4b | ||
|
|
ecf75a07e4 | ||
|
|
41094c80d5 | ||
|
|
09b12c6d7e | ||
|
|
c560685285 | ||
|
|
48d2099308 | ||
|
|
ca3604129d | ||
|
|
583a68cabe | ||
|
|
924eaf8486 | ||
|
|
9c1a02dbd5 | ||
|
|
637a19ee21 | ||
|
|
896420064f | ||
|
|
f6140e8396 | ||
|
|
b59a3fb5de | ||
|
|
0a7f8631b6 | ||
|
|
de37cb0da1 | ||
|
|
50d0827972 | ||
|
|
a0d4be2379 | ||
|
|
e4eb5d1f0f | ||
|
|
9ae4d3df55 | ||
|
|
95b6b45cc4 | ||
|
|
9280d0ef7e | ||
|
|
5171b2e5e2 | ||
|
|
8455ff876a | ||
|
|
167ce97dd9 | ||
|
|
0503af6819 | ||
|
|
a218ee1c02 | ||
|
|
fbaba8ebe8 | ||
|
|
64c70f51c9 | ||
|
|
946da6e274 | ||
|
|
f42489ecb5 | ||
|
|
abd5fa00ed | ||
|
|
9450849b9d | ||
|
|
d66bda7adc | ||
|
|
461c4acfb7 | ||
|
|
ccb0840771 | ||
|
|
b5a706a6a9 | ||
|
|
a45b54dd85 | ||
|
|
a4d29f3e7a | ||
|
|
2a8ec8245f | ||
|
|
d85f32e1f2 | ||
|
|
adc7bb1d9e | ||
|
|
2dafde0117 | ||
|
|
7582a01b3f | ||
|
|
9081012673 | ||
|
|
bf83dfbd28 | ||
|
|
903b96e629 | ||
|
|
3e9007806e | ||
|
|
b6ec0091f0 | ||
|
|
726b4f5c0d | ||
|
|
2fdd3a2a85 | ||
|
|
4fbb39efd0 | ||
|
|
88ecb58153 | ||
|
|
d084da2914 | ||
|
|
716de6f9eb | ||
|
|
dfc4cbe01f | ||
|
|
3a5b4c48f5 | ||
|
|
08b0fd498e | ||
|
|
3f365e7ee1 | ||
|
|
ebb5c078c9 | ||
|
|
f536def5fa | ||
|
|
2918b8f04b | ||
|
|
bb3b05aab0 | ||
|
|
2cdfe2c158 | ||
|
|
d1dfafe1da | ||
|
|
144febb3cc | ||
|
|
22b2d50139 | ||
|
|
121e521eb7 | ||
|
|
7ada9cacda | ||
|
|
5585d69dcf | ||
|
|
f5d73a0c8f | ||
|
|
4563739f6e | ||
|
|
79ed081c99 | ||
|
|
dc1c9a9d37 | ||
|
|
25c90537c8 | ||
|
|
b7aadf4b17 | ||
|
|
b9587e0fd5 | ||
|
|
38e529f5bf | ||
|
|
81e2d7738f | ||
|
|
380a681cc1 | ||
|
|
8c2a557618 | ||
|
|
7b98d2ede2 | ||
|
|
64c544a86e | ||
|
|
a048125a14 | ||
|
|
4c37e16e92 | ||
|
|
c448bc151b | ||
|
|
efcbefe1c8 | ||
|
|
339a15803c | ||
|
|
582a06c05a | ||
|
|
852f1ec31a | ||
|
|
2ca142566c | ||
|
|
9a13d112cb | ||
|
|
bc9cbbc1f6 | ||
|
|
129bf49204 | ||
|
|
a29acb6f30 | ||
|
|
c957094b1e | ||
|
|
8e5743f417 | ||
|
|
4ff42f1ae4 | ||
|
|
06c8f5367e | ||
|
|
f74d7cf37e | ||
|
|
b971b4d07a | ||
|
|
09fd5d8642 | ||
|
|
97447e8d6c | ||
|
|
c388045c68 | ||
|
|
db4d998705 | ||
|
|
011cc992e8 | ||
|
|
2c1d8b0eea | ||
|
|
65ae22e70e | ||
|
|
81da60333d | ||
|
|
aa572febd4 | ||
|
|
6060cb457d | ||
|
|
6ac0107274 | ||
|
|
95de4855c0 | ||
|
|
bcfff70e78 | ||
|
|
11e7d34961 | ||
|
|
e48e523b90 | ||
|
|
4689b4290e | ||
|
|
f9af8d116c | ||
|
|
1f9339e5ab | ||
|
|
4bc9b718cc | ||
|
|
eae6b058fc | ||
|
|
a29bcf713f | ||
|
|
6b171f578d | ||
|
|
3f45c2ebd4 | ||
|
|
883b1a63b2 | ||
|
|
4c0efa8b08 | ||
|
|
ed2a04d590 | ||
|
|
52a3d1c373 | ||
|
|
573b24f28f | ||
|
|
e68e5bc6fb | ||
|
|
6473ce4244 | ||
|
|
82685314f7 | ||
|
|
c1370af395 | ||
|
|
7779a8b752 | ||
|
|
3de225f7c9 | ||
|
|
1d6ff96dd9 | ||
|
|
9f403b9d7f | ||
|
|
ea63e6a325 | ||
|
|
c6d471cec9 | ||
|
|
f7914c57c7 | ||
|
|
fc55cbf3d7 | ||
|
|
a5f2d39b07 | ||
|
|
e5395bf05a | ||
|
|
30466e4a76 | ||
|
|
499ab7cdfe | ||
|
|
2e49893841 | ||
|
|
c295e1c9be | ||
|
|
6dd16f6791 | ||
|
|
97d21c818e | ||
|
|
3beb60d8b6 | ||
|
|
3d00502341 | ||
|
|
7975dfcc78 | ||
|
|
907406e7b2 | ||
|
|
8b03f96a3f | ||
|
|
5183b33f9d | ||
|
|
bfddf288eb | ||
|
|
28ada2b032 | ||
|
|
6343212d7e | ||
|
|
f728ad8826 | ||
|
|
33c3bf0d69 | ||
|
|
2fc3cc3c76 | ||
|
|
69a3fa4d90 | ||
|
|
bd4f130ef8 | ||
|
|
28b563b95b | ||
|
|
71952a354e | ||
|
|
41ad8e0988 | ||
|
|
3e87e2ea5a | ||
|
|
a6541b9731 | ||
|
|
b96af6c4cf | ||
|
|
cc584461ad | ||
|
|
6069a41fa4 | ||
|
|
7190207e5c | ||
|
|
05ea085cdc | ||
|
|
015453a40b | ||
|
|
dad92a186c | ||
|
|
7e5e19e72c | ||
|
|
8e1484a029 | ||
|
|
4a3b3a14ec | ||
|
|
758157cf78 | ||
|
|
a1a171d648 | ||
|
|
b2645fc4d9 | ||
|
|
92ba4d7624 | ||
|
|
d44ee5ca05 | ||
|
|
58f060ae59 | ||
|
|
d7dde74675 | ||
|
|
5fde1c0f07 | ||
|
|
d9ea44f92a | ||
|
|
ffddbe2d7a | ||
|
|
eb3998d72d | ||
|
|
fca61afd7c | ||
|
|
1bf86386fa | ||
|
|
33559250d8 | ||
|
|
38daca0099 | ||
|
|
6fc328c4dd | ||
|
|
36c8b8cc25 | ||
|
|
dd4ca817c7 | ||
|
|
a60a1aa406 | ||
|
|
594ceb1f52 | ||
|
|
fbc74ec359 | ||
|
|
0dfc1dfa52 | ||
|
|
b9c14ef9aa | ||
|
|
3fec2b397f | ||
|
|
ec841caef7 | ||
|
|
c163fc3be4 | ||
|
|
1e04315596 | ||
|
|
9aef28b03d | ||
|
|
7bd1931195 | ||
|
|
88628c650f | ||
|
|
9523fd52d8 | ||
|
|
c59091f946 | ||
|
|
8cc6df92f4 | ||
|
|
042656856a | ||
|
|
5921c61e98 | ||
|
|
6a017c237d | ||
|
|
c5cd214d97 | ||
|
|
b30c35e59d | ||
|
|
ce4fa13758 | ||
|
|
1f47df0f45 | ||
|
|
27c641536a | ||
|
|
91109278b6 | ||
|
|
78e4672871 | ||
|
|
dbecd6a466 | ||
|
|
e690973107 | ||
|
|
17b14e0ac6 | ||
|
|
0f8da747f9 | ||
|
|
df7d91e4f3 | ||
|
|
7eefecd961 | ||
|
|
2ec764d862 | ||
|
|
5a9b9da47e | ||
|
|
c5a82bd779 | ||
|
|
9c2a807025 | ||
|
|
4fa1ea4380 | ||
|
|
351d412fdf | ||
|
|
38600bf2a5 | ||
|
|
4720456d63 | ||
|
|
5a2221c5d3 | ||
|
|
91ef98df4f | ||
|
|
8aa0a539f8 | ||
|
|
68b921887b | ||
|
|
dea91c48a2 | ||
|
|
f2e91d4a5c | ||
|
|
47be00355d | ||
|
|
61549e8e06 | ||
|
|
05c4051cc9 | ||
|
|
71fe6bbebc | ||
|
|
317be2c8da | ||
|
|
74ed529f16 | ||
|
|
24a6d8c3f9 | ||
|
|
14c1567c07 | ||
|
|
fb778f56ed | ||
|
|
1eb0ef0cbe | ||
|
|
a81c8d0064 | ||
|
|
36099c6b4d | ||
|
|
8f7a15e692 | ||
|
|
de4a660eb2 | ||
|
|
c53fab603f | ||
|
|
a3e11b62e0 | ||
|
|
5d1775151d | ||
|
|
a0f5880e2c | ||
|
|
3dc7e70890 | ||
|
|
2fa1fc8662 | ||
|
|
879a65a41c | ||
|
|
d5b68bf0da | ||
|
|
fd460d3e90 | ||
|
|
a74bd4972c | ||
|
|
0ed8839ea9 | ||
|
|
d7b0f2684a | ||
|
|
b5be9b3abf | ||
|
|
911105c409 | ||
|
|
200c842671 | ||
|
|
5e5930e9e8 | ||
|
|
fd64c1cf2d | ||
|
|
48e2916874 | ||
|
|
a4b0e5bfef | ||
|
|
0b56121a26 | ||
|
|
f3f61d0e19 | ||
|
|
faaf1eeadf | ||
|
|
4fbaecc24e | ||
|
|
4fb056095c | ||
|
|
2d6142381b | ||
|
|
d97d14e830 | ||
|
|
f2f3f7e393 | ||
|
|
50176d2b3a | ||
|
|
c47c410446 | ||
|
|
3a5558eb16 | ||
|
|
f8171ddc3f | ||
|
|
ece7b29005 | ||
|
|
8cd8e93487 | ||
|
|
8900a6b080 | ||
|
|
19d90fa221 | ||
|
|
55fb3d5332 | ||
|
|
2e5ff859eb | ||
|
|
06747575ee | ||
|
|
98bb8ca186 | ||
|
|
d5f68602b6 | ||
|
|
312999aa5b | ||
|
|
607a4d26f4 | ||
|
|
a88b6615e4 | ||
|
|
f900098201 | ||
|
|
d51aaa8eb1 | ||
|
|
e9a48ae028 | ||
|
|
90a0f619ec | ||
|
|
ed3662a636 | ||
|
|
26eda3b105 | ||
|
|
8f43882e29 | ||
|
|
e239597eb1 | ||
|
|
bf1ef07d3a | ||
|
|
7d2e1dab4c | ||
|
|
80392d394a | ||
|
|
9ffa4d38c3 | ||
|
|
3ebcd36ca9 | ||
|
|
efec2dc898 | ||
|
|
5bd032e480 | ||
|
|
c1bd4cfb01 | ||
|
|
0b943d8ecd | ||
|
|
75e22a591e | ||
|
|
66498e12ce | ||
|
|
d5fefd2f10 | ||
|
|
e2556d3228 | ||
|
|
2eb38d236e | ||
|
|
d9c57162f1 | ||
|
|
9f8f0e8413 | ||
|
|
ea52893be1 | ||
|
|
eef63d2028 | ||
|
|
14e0112e17 | ||
|
|
8ec9034fb2 | ||
|
|
dc5973d75d | ||
|
|
12126b2f9f | ||
|
|
9fa256be0e | ||
|
|
c103328098 | ||
|
|
ea2022bbe4 | ||
|
|
d7ced57319 | ||
|
|
2cc200dc2b | ||
|
|
baa74d0353 | ||
|
|
72b906da14 | ||
|
|
6db8c2fac2 | ||
|
|
09d5c0a65e | ||
|
|
0b6b6a02cc | ||
|
|
f49c673e8e | ||
|
|
64a8e9a075 | ||
|
|
e998b07ca5 | ||
|
|
c189279030 | ||
|
|
12ddd6f958 | ||
|
|
da06afda8a | ||
|
|
bf808b7a2e | ||
|
|
13476a3f50 | ||
|
|
cfdf77a7b5 | ||
|
|
070c90362a | ||
|
|
c8d9858a0c | ||
|
|
2685f60409 | ||
|
|
8d3bb5185c | ||
|
|
1f748a4026 | ||
|
|
b27f064ad4 | ||
|
|
27f781cc63 | ||
|
|
1427958eca | ||
|
|
436e09c255 | ||
|
|
cc9b2dd5b0 | ||
|
|
0ba25419f3 | ||
|
|
9238de4cb4 | ||
|
|
2d5fe1058c | ||
|
|
b01d1fc87e | ||
|
|
9f4c0a4c9a | ||
|
|
9eebda86c2 | ||
|
|
d43e856fea | ||
|
|
7af1596038 | ||
|
|
652f6eab0b | ||
|
|
fdaddfdb92 | ||
|
|
9a1adf2065 | ||
|
|
f10b258f58 | ||
|
|
7f558cbd41 | ||
|
|
641eb28ce7 | ||
|
|
2c59a5f6f9 | ||
|
|
712f02e61e | ||
|
|
e5ad405a23 | ||
|
|
cd1b78d8df | ||
|
|
3b1ca46945 | ||
|
|
96c1636f88 | ||
|
|
a10f949856 | ||
|
|
9ff4757ed6 | ||
|
|
17c1e77f54 | ||
|
|
187a2a7262 | ||
|
|
4621230549 | ||
|
|
d7cb3317a2 | ||
|
|
6d81f26864 | ||
|
|
5219814b5a | ||
|
|
bef9fd0fd0 | ||
|
|
2341293d92 | ||
|
|
215387f8a9 | ||
|
|
534b8c5ad0 | ||
|
|
b7b2ead9eb | ||
|
|
b3e34d68e1 | ||
|
|
39079612aa | ||
|
|
be1af3111f | ||
|
|
8dcff49797 | ||
|
|
687fb4e105 | ||
|
|
25ae780ad8 | ||
|
|
b695367e6c | ||
|
|
bb274a84fe | ||
|
|
364dccbf7a | ||
|
|
105fb0fc69 | ||
|
|
89c408981c | ||
|
|
110534edec | ||
|
|
00e2190b2d | ||
|
|
e5c3fc667e | ||
|
|
9aef8194f9 | ||
|
|
f76e0b7931 | ||
|
|
0457e4417f | ||
|
|
dae8b5c542 | ||
|
|
60107dd77f | ||
|
|
4f3e19aaa2 | ||
|
|
8c621f9f47 | ||
|
|
74544efd62 | ||
|
|
c30ccbb68d | ||
|
|
c77050eccc | ||
|
|
f40ccdae41 | ||
|
|
0a0aa09eea | ||
|
|
e2c55fb758 | ||
|
|
12e3335d52 | ||
|
|
f29439539d | ||
|
|
13c9fdba52 | ||
|
|
2cb087972c | ||
|
|
41a32ede15 | ||
|
|
95f52fba51 | ||
|
|
e2159b7614 | ||
|
|
ee33875edf | ||
|
|
28681fb1b0 | ||
|
|
33194dc9f0 | ||
|
|
7509766df2 | ||
|
|
30a02a4977 | ||
|
|
f67f4138c3 | ||
|
|
49d51da1bd | ||
|
|
17bfe4e075 | ||
|
|
d5905a4e5f | ||
|
|
e1b46d33f4 | ||
|
|
ce7c003c54 | ||
|
|
7f473ce7c8 | ||
|
|
c239f490b0 | ||
|
|
1ad1915fcc | ||
|
|
14029de484 | ||
|
|
5d07db366b | ||
|
|
9e265dbecf | ||
|
|
717bce36e6 | ||
|
|
17831cdd8c | ||
|
|
02e37c6ed4 | ||
|
|
16b52e9633 | ||
|
|
77eee945ca | ||
|
|
f21f235d37 | ||
|
|
2949fcde38 | ||
|
|
6ae1674de5 | ||
|
|
2bd74e043a | ||
|
|
1a05acbe9a | ||
|
|
a0597e13fe | ||
|
|
d11d665395 | ||
|
|
ab2758ac79 | ||
|
|
bb682a6f6e | ||
|
|
4377b8b340 | ||
|
|
eb0c9b823b | ||
|
|
a595b12431 | ||
|
|
ebd9b45cac | ||
|
|
5ae024f20a | ||
|
|
9ae93dec4c | ||
|
|
93ecc9b1ac | ||
|
|
28455f8b31 | ||
|
|
b49be89b06 | ||
|
|
23e0748137 | ||
|
|
2f6d222cca | ||
|
|
ba1cfe05c4 | ||
|
|
6f80334296 | ||
|
|
86da8a3620 | ||
|
|
11702c9209 | ||
|
|
240d9b533f | ||
|
|
8dc12f01b9 | ||
|
|
3b0dce6c6f | ||
|
|
901dc4fe6d | ||
|
|
61748f40b6 | ||
|
|
871824f857 | ||
|
|
032c321568 | ||
|
|
4883f02b62 | ||
|
|
b43a8cbafe | ||
|
|
11c1fe3853 | ||
|
|
4a4576ebd5 | ||
|
|
0b5128b13b | ||
|
|
d1dbb85459 | ||
|
|
ae1005d5f9 | ||
|
|
11e6074e21 | ||
|
|
ea9aa2a136 | ||
|
|
203fe5bee0 | ||
|
|
4262641567 | ||
|
|
c0f79be78c | ||
|
|
239e301042 | ||
|
|
23bb80bbd6 | ||
|
|
d7232a4f1f | ||
|
|
2bfc1af8ff | ||
|
|
3ac6873be4 | ||
|
|
ce487a108c | ||
|
|
827930e28f | ||
|
|
8a13cf01b4 | ||
|
|
641c541305 | ||
|
|
9285bae0cc | ||
|
|
954ac3154f | ||
|
|
571f3242e2 | ||
|
|
9052948b8a | ||
|
|
af91a6ee98 | ||
|
|
16633dbd05 | ||
|
|
8a506edd37 | ||
|
|
fdbac8e608 | ||
|
|
cdca90bd54 | ||
|
|
fb7d8b0893 | ||
|
|
a49bc92a13 | ||
|
|
58c1f5e3ca | ||
|
|
f1a0c1b447 | ||
|
|
d8534da4df | ||
|
|
28daa38d80 | ||
|
|
5c275adda8 | ||
|
|
26ecf2a7fd | ||
|
|
e23c0f55b7 | ||
|
|
a6b03635c7 | ||
|
|
6587541729 | ||
|
|
bc4bfa63f7 | ||
|
|
bdda2d4987 | ||
|
|
ab34073870 | ||
|
|
152a59fe26 | ||
|
|
cf169eb6d6 | ||
|
|
16da396289 | ||
|
|
7ad3fd4057 | ||
|
|
aecf4f1ee8 | ||
|
|
8f48fcd788 | ||
|
|
cf64fb3743 | ||
|
|
a21111368e | ||
|
|
383b914c52 | ||
|
|
555255a923 | ||
|
|
cd5a2ab179 | ||
|
|
48903f924c | ||
|
|
7d46dd4fb0 | ||
|
|
cfa9f11f44 | ||
|
|
1377ac38db | ||
|
|
d88b30b538 | ||
|
|
cfe0cded15 | ||
|
|
322f6b7aae | ||
|
|
62ae26c464 | ||
|
|
c920c999eb | ||
|
|
288f601651 | ||
|
|
d4f902f63d | ||
|
|
7dddebef2e | ||
|
|
dc1498d672 | ||
|
|
eb36c1d7cb | ||
|
|
29c119a945 | ||
|
|
860bc10747 | ||
|
|
215ca23190 | ||
|
|
4b9d9e4353 | ||
|
|
fd5d4e56ea | ||
|
|
9801d117a1 | ||
|
|
3c4fb8cb53 | ||
|
|
ae17b34be9 | ||
|
|
1a544754ef | ||
|
|
1ddfd15ee9 | ||
|
|
035126ab2f | ||
|
|
e157ae8bc8 | ||
|
|
25b0503a25 | ||
|
|
ef235dd0aa | ||
|
|
699080048d | ||
|
|
3c9b315f78 | ||
|
|
1464006531 | ||
|
|
6921fcb3ae | ||
|
|
286f8dd7cc | ||
|
|
d3e3ef5986 | ||
|
|
ea1ffc59b8 | ||
|
|
5524886868 | ||
|
|
68b63cf635 | ||
|
|
74de09e441 | ||
|
|
b82e9598bd | ||
|
|
25889192c4 | ||
|
|
76eac69f94 | ||
|
|
97f8f1e3c3 | ||
|
|
8722b6bc68 | ||
|
|
8e8d2a4083 | ||
|
|
4caac77706 | ||
|
|
0f73f266b2 | ||
|
|
8c70abda04 | ||
|
|
6881a5f432 | ||
|
|
22e9ae6bf8 | ||
|
|
eb73de6d8d | ||
|
|
1af7f1bd7f | ||
|
|
3a0273a12b | ||
|
|
05795ca052 | ||
|
|
a5746c56eb | ||
|
|
80f66ab0ba | ||
|
|
44e62f0eb0 | ||
|
|
a6e107f61d | ||
|
|
31bb78bfca | ||
|
|
8bb9308173 | ||
|
|
46d279ca3b | ||
|
|
0a5bdaaa7f | ||
|
|
3480b8c5da | ||
|
|
32e1fb5f56 | ||
|
|
d94e8d04c8 | ||
|
|
26e2b380b3 | ||
|
|
06710ff416 | ||
|
|
32a7f866c3 | ||
|
|
86b650712e | ||
|
|
0178e455f9 | ||
|
|
39693966c1 | ||
|
|
dc08a39173 | ||
|
|
1be518510a | ||
|
|
e513081010 | ||
|
|
9bc8bddc12 | ||
|
|
986b99f62e | ||
|
|
16092a4185 | ||
|
|
26eafcfee9 | ||
|
|
f20c1ef4f4 | ||
|
|
3f076d90c8 | ||
|
|
df70fee70e | ||
|
|
4df9c7d9f7 | ||
|
|
59916b924c | ||
|
|
aafce93117 | ||
|
|
97ef91abdb | ||
|
|
b426d61c3a | ||
|
|
f08c484d40 | ||
|
|
b03a4559c5 | ||
|
|
d2f491ed66 | ||
|
|
1a2a1da086 | ||
|
|
872f4d7e91 | ||
|
|
bce063e1bd | ||
|
|
e6dc5ddfed | ||
|
|
bcbcd516f6 | ||
|
|
24da82313e | ||
|
|
5fe29af51a | ||
|
|
fbe551eb29 | ||
|
|
c097c4d457 | ||
|
|
a792a3d6e4 | ||
|
|
28f1f276ce | ||
|
|
9470d2b61f | ||
|
|
95795a20c2 | ||
|
|
64b7b57b3e | ||
|
|
5e05d96487 | ||
|
|
18c9912068 | ||
|
|
cd85753252 | ||
|
|
bdb135036c | ||
|
|
5d70f58a0d | ||
|
|
b7d2d66e82 | ||
|
|
6b028ef850 | ||
|
|
8f85795e53 | ||
|
|
a0b7dff5fd | ||
|
|
352018c042 | ||
|
|
2b1ac822ed | ||
|
|
b3c3890443 | ||
|
|
99e642780e | ||
|
|
47088a0a66 | ||
|
|
fd48684396 | ||
|
|
9b25ab8708 | ||
|
|
c725ba8530 | ||
|
|
98287fbfc4 | ||
|
|
3260695a09 | ||
|
|
3a3434b021 | ||
|
|
9f24bd2250 | ||
|
|
94f2a216ad | ||
|
|
aeb4c984eb | ||
|
|
78e3ee5fd2 | ||
|
|
e94a2b2aa1 | ||
|
|
1ddcf44eb0 | ||
|
|
5c5fb2ba2c | ||
|
|
9344eadf34 | ||
|
|
aa4995d871 | ||
|
|
e40c42afc3 | ||
|
|
f818c41a02 | ||
|
|
178d7e7471 | ||
|
|
3f9d954e2f | ||
|
|
48a3eee232 | ||
|
|
f1fcd227e7 | ||
|
|
84af1a9411 | ||
|
|
44d910121c | ||
|
|
1258a95aad | ||
|
|
295ab2c073 | ||
|
|
7aa350a9d2 | ||
|
|
ee76e43fca | ||
|
|
1379193065 | ||
|
|
0fa3598783 | ||
|
|
02960fb5a9 | ||
|
|
a7fa42e944 | ||
|
|
02ab8e3938 | ||
|
|
01c629f612 | ||
|
|
5c120676e1 | ||
|
|
3821dc29ef | ||
|
|
3c51f73427 | ||
|
|
8db373ee34 | ||
|
|
1be6e6b444 | ||
|
|
adcb73a2fc | ||
|
|
4c97b3481d | ||
|
|
38579c37e1 | ||
|
|
4785544e18 | ||
|
|
7812c15b48 | ||
|
|
251145ea74 | ||
|
|
5e4972c1d0 | ||
|
|
64bfc80a42 | ||
|
|
b841c6e0eb | ||
|
|
7241dce7a6 | ||
|
|
8f25f9ba3e | ||
|
|
6ab58c68e1 | ||
|
|
ae5b422965 | ||
|
|
55b6be0f15 | ||
|
|
f9324d9da5 | ||
|
|
2362902675 | ||
|
|
dfe6a73ac1 | ||
|
|
afcb8835d2 | ||
|
|
9dc9f186e1 | ||
|
|
875125cfe4 | ||
|
|
32d9cdd265 | ||
|
|
669f830dd7 | ||
|
|
09deae9dbf | ||
|
|
337582ac70 | ||
|
|
820c78ce81 | ||
|
|
23924a34a3 | ||
|
|
428f1e746a | ||
|
|
565e692af8 | ||
|
|
94e4721663 | ||
|
|
8157c0812a | ||
|
|
bc36837cd0 | ||
|
|
33540b000c | ||
|
|
5a63a45d00 | ||
|
|
6eb1f2a4a7 | ||
|
|
8fce6b5eb6 | ||
|
|
5bd1999269 | ||
|
|
4e44661e1b | ||
|
|
827ca2e427 | ||
|
|
81fd1c097e | ||
|
|
aaf82f359b | ||
|
|
aa7f14ae79 | ||
|
|
0ad63da4a2 | ||
|
|
2885b9ac3e | ||
|
|
1ae9e04e7a | ||
|
|
693311a3db | ||
|
|
a15ab99056 | ||
|
|
222cdbfa63 | ||
|
|
a1d8b34fb4 | ||
|
|
35d08a6dfa | ||
|
|
874352e753 | ||
|
|
6bb5e44442 | ||
|
|
49d1ab4be5 | ||
|
|
54a0d0fd0c | ||
|
|
65a80dbd46 | ||
|
|
dfeb01320d | ||
|
|
e55456f492 | ||
|
|
d33209afcc | ||
|
|
3f9fce0d34 | ||
|
|
2ae094cf1f | ||
|
|
5530270b06 | ||
|
|
bc224f1674 | ||
|
|
8bb1582cca | ||
|
|
c759408fdc | ||
|
|
d02125a93c | ||
|
|
30553ed0f1 | ||
|
|
d91ce4e936 | ||
|
|
b315e70e1e | ||
|
|
deb902549b | ||
|
|
d6c6db68ba | ||
|
|
e41ed07805 | ||
|
|
f6e8dc0a88 | ||
|
|
0738b96161 | ||
|
|
044dd5ce59 | ||
|
|
6cca06fcbc | ||
|
|
50feebc0b0 | ||
|
|
b24830666c | ||
|
|
470802c3e2 | ||
|
|
0e869708f7 | ||
|
|
7e0e1eac93 | ||
|
|
58cbf653b2 | ||
|
|
4b35f2ecd2 | ||
|
|
48d9a863ec | ||
|
|
1d616cf68f | ||
|
|
efda6f86ae | ||
|
|
cdf6a4bb5b | ||
|
|
1b3735e2b2 | ||
|
|
54008a0de2 | ||
|
|
850fc6b066 | ||
|
|
67a398f583 | ||
|
|
8a62070c8e | ||
|
|
8aa31b8380 | ||
|
|
f445a963f9 | ||
|
|
d6e3f27612 | ||
|
|
4688d74edb | ||
|
|
e88c755ba8 | ||
|
|
1985007039 | ||
|
|
039c8faabe | ||
|
|
fb1eb234b6 | ||
|
|
7e70cd96b9 | ||
|
|
f9a89783ed | ||
|
|
26282352cb | ||
|
|
7f3c74b55b | ||
|
|
301ac781d6 | ||
|
|
ce3c98ae9b | ||
|
|
1c3a6ffbde | ||
|
|
2447b3bea7 | ||
|
|
63888ff70e | ||
|
|
c6e3d1bd47 | ||
|
|
e03e02d702 | ||
|
|
1abf51ae2b | ||
|
|
c41dfa3185 | ||
|
|
52a07da230 | ||
|
|
f572bb1637 | ||
|
|
773ede4b6c | ||
|
|
e4d42c8bac | ||
|
|
5b85067e15 | ||
|
|
0d111f3a79 | ||
|
|
f6b6f2b4b7 | ||
|
|
d55a2aa04d | ||
|
|
0185eea740 | ||
|
|
d44e8874b8 | ||
|
|
e34d33dd61 | ||
|
|
4b2fb80c23 | ||
|
|
acbac95818 | ||
|
|
3c908ac079 | ||
|
|
563f068948 | ||
|
|
6bf4300372 | ||
|
|
1344b958cb | ||
|
|
32d7cab70c | ||
|
|
6f8f6d47f8 | ||
|
|
04a48979eb | ||
|
|
1293fa2dec | ||
|
|
ff3a8fa738 | ||
|
|
8542cbf37e | ||
|
|
62c6fba9a0 | ||
|
|
2d84154226 | ||
|
|
c4e306d569 | ||
|
|
83b6c6de1c | ||
|
|
e86f7491ef | ||
|
|
5151d83af9 | ||
|
|
e462cb0596 | ||
|
|
a30c0e4608 | ||
|
|
dbe8c1b9e6 | ||
|
|
f90e7982f7 | ||
|
|
40c69d7cba | ||
|
|
c9e6f3e532 | ||
|
|
23ee50f688 | ||
|
|
a7c857fb71 | ||
|
|
0f6622360c | ||
|
|
578bc6e546 | ||
|
|
70fd038207 | ||
|
|
b30110a48a | ||
|
|
21978c4c1d | ||
|
|
ec48f2350d | ||
|
|
fe1e3bb847 | ||
|
|
69776f26d8 | ||
|
|
ab4092c088 | ||
|
|
4948a8d7de | ||
|
|
0a607bce18 | ||
|
|
e59820e3d6 | ||
|
|
85a2d25c1b | ||
|
|
3bc7fc84f9 | ||
|
|
249ce1ecbb | ||
|
|
be7f8d9916 | ||
|
|
0a0495f1a7 | ||
|
|
2f7afa8556 | ||
|
|
2f40905372 | ||
|
|
a6d0177153 | ||
|
|
b9e24888e7 | ||
|
|
976199e5c6 | ||
|
|
9017dae664 | ||
|
|
94acc241d9 | ||
|
|
765f3a476d | ||
|
|
449287e25a | ||
|
|
db2669d699 | ||
|
|
2cdb916233 | ||
|
|
5f14261aba | ||
|
|
5ae7855c7f | ||
|
|
20138505c4 | ||
|
|
49c09bfd85 | ||
|
|
d8ed47ddb8 | ||
|
|
39bfc41d33 | ||
|
|
68a8ac588f | ||
|
|
49d9ece15a | ||
|
|
475edf6732 | ||
|
|
76ea89b668 | ||
|
|
56b3a8df6b | ||
|
|
e02de0c0f6 | ||
|
|
84bfab2a72 | ||
|
|
a6825a2df2 | ||
|
|
f9dc539057 | ||
|
|
833b40bdc3 | ||
|
|
9ba58d1a46 | ||
|
|
29a99d3f97 | ||
|
|
a8b6fe78ba | ||
|
|
4abd69b460 | ||
|
|
0ca1d82861 | ||
|
|
3dd25b9f83 | ||
|
|
5c55b49976 | ||
|
|
c932961dd4 | ||
|
|
20cd5bef16 | ||
|
|
9b058bb17f | ||
|
|
47357c3e25 | ||
|
|
3ec5a1cf2c | ||
|
|
13d8a7baf7 | ||
|
|
19b1e74d06 | ||
|
|
82de9b9b94 | ||
|
|
2325f4e31c | ||
|
|
867af58695 | ||
|
|
cdd50f0258 | ||
|
|
8c8b92cc4e | ||
|
|
c0a3df0aa8 | ||
|
|
31dd1619f6 | ||
|
|
ba6be6c84d | ||
|
|
b126b98eb0 | ||
|
|
afb010e3ae | ||
|
|
f14e3d0f5e | ||
|
|
ddebdcda43 | ||
|
|
29c69418e9 | ||
|
|
3e565e5195 | ||
|
|
a13878d4a8 | ||
|
|
1b352d6162 | ||
|
|
258aa77cdd | ||
|
|
bc8de87cda | ||
|
|
7789bd145c | ||
|
|
c1457cc83f | ||
|
|
3ca0089ee8 | ||
|
|
29c9476c16 | ||
|
|
9e72f51851 | ||
|
|
a349611a30 | ||
|
|
1cd21087c2 | ||
|
|
eecb8f9c05 | ||
|
|
e36fd28f47 | ||
|
|
7ce44f4d84 | ||
|
|
6d8e4e8ebc | ||
|
|
deb507859a | ||
|
|
a165675b2a | ||
|
|
8b316d0abf | ||
|
|
def5059ff1 | ||
|
|
e1febfae31 | ||
|
|
82aa506902 | ||
|
|
de1aa40ecf | ||
|
|
53724b437e | ||
|
|
1592620141 | ||
|
|
28ef87a95b | ||
|
|
d4019eea99 | ||
|
|
d13b46cbba | ||
|
|
f1eb215bb9 | ||
|
|
92c7e1a0c1 | ||
|
|
b81cc178b5 | ||
|
|
dd42b82dbf | ||
|
|
ca6b50081a | ||
|
|
4fa27046bb | ||
|
|
8cadc6eaa4 | ||
|
|
ccae629833 | ||
|
|
4a1cbe632c | ||
|
|
579813d93a | ||
|
|
00d00c02ea | ||
|
|
765949cc40 | ||
|
|
87cea6a120 | ||
|
|
83526d4d46 | ||
|
|
fca4faa114 | ||
|
|
171628c7b9 | ||
|
|
d456132dd6 | ||
|
|
4ac7941b6c | ||
|
|
e7f5463917 | ||
|
|
6e41ce459d | ||
|
|
f5095fa643 | ||
|
|
e6a5b85011 | ||
|
|
409c5a2517 | ||
|
|
35cd6b101d | ||
|
|
2440e28168 |
@@ -7,7 +7,7 @@ runs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
node-version: 22.x
|
||||
cache: "npm"
|
||||
cache-dependency-path: |
|
||||
package-lock.json
|
||||
|
||||
11
.github/workflows/android.e2e.yml
vendored
@@ -47,16 +47,21 @@ jobs:
|
||||
- name: Install Detox CLI
|
||||
run: npm install detox-cli --global
|
||||
|
||||
- name: Check for typescript errors
|
||||
run: |
|
||||
cd apps/mobile
|
||||
npx tsc --noEmit
|
||||
|
||||
- name: Detox build
|
||||
run: |
|
||||
yarn build:android
|
||||
ls apps/mobile/native/android/app/build/outputs/apk
|
||||
ls apps/mobile/native/android/app/build/outputs/apk/release
|
||||
ls apps/mobile/android/app/build/outputs/apk
|
||||
ls apps/mobile/android/app/build/outputs/apk/release
|
||||
|
||||
- name: Get device name
|
||||
id: device
|
||||
run: |
|
||||
AVD_NAME=$(node -p "require('./apps/mobile/native/.detoxrc.js').devices.emulator.device.avdName")
|
||||
AVD_NAME=$(node -p "require('./apps/mobile/.detoxrc.js').devices.emulator.device.avdName")
|
||||
echo "AVD_NAME=$AVD_NAME" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: AVD cache
|
||||
|
||||
56
.github/workflows/android.publish.internal.yml
vendored
@@ -5,7 +5,6 @@ on: workflow_dispatch
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 40
|
||||
env:
|
||||
CMAKE_C_COMPILER_LAUNCHER: ccache
|
||||
CMAKE_CXX_COMPILER_LAUNCHER: ccache
|
||||
@@ -31,7 +30,23 @@ jobs:
|
||||
npm run bootstrap -- --scope=mobile
|
||||
|
||||
- name: Make Gradlew Executable
|
||||
run: cd apps/mobile/native/android && chmod +x ./gradlew
|
||||
run: cd apps/mobile/android && chmod +x ./gradlew
|
||||
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
# this might remove tools that are actually needed,
|
||||
# if set to "true" but frees about 6 GB
|
||||
tool-cache: false
|
||||
|
||||
# all of these default to true, but feel free to set to
|
||||
# "false" if necessary for your workflow
|
||||
android: false
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: true
|
||||
docker-images: true
|
||||
swap-storage: true
|
||||
|
||||
- name: Install CCache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.11
|
||||
@@ -73,6 +88,15 @@ jobs:
|
||||
- name: CCache Stats Before Build
|
||||
run: ccache -sv
|
||||
|
||||
- name: Check for typescript errors
|
||||
run: |
|
||||
npm run tx mobile:build
|
||||
cd apps/mobile
|
||||
npx tsc --noEmit
|
||||
|
||||
- name: Remove debug keystore
|
||||
run: rm -rf apps/mobile/android/app/debug.keystore
|
||||
|
||||
- name: Build unsigned app bundle
|
||||
run: yarn release:android:bundle
|
||||
|
||||
@@ -83,13 +107,13 @@ jobs:
|
||||
id: sign_app
|
||||
uses: r0adkll/sign-android-release@master
|
||||
with:
|
||||
releaseDirectory: apps/mobile/native/android/app/build/outputs/bundle/release
|
||||
releaseDirectory: apps/mobile/android/app/build/outputs/bundle/release
|
||||
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
||||
alias: ${{ secrets.ALIAS }}
|
||||
keyStorePassword: ${{ secrets.KEY_PASSWORD }}
|
||||
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||
env:
|
||||
BUILD_TOOLS_VERSION: "33.0.0"
|
||||
BUILD_TOOLS_VERSION: "36.0.0"
|
||||
|
||||
- name: Build apks for Github release
|
||||
run: yarn release:android
|
||||
@@ -98,17 +122,17 @@ jobs:
|
||||
id: sign_apk
|
||||
uses: r0adkll/sign-android-release@master
|
||||
with:
|
||||
releaseDirectory: apps/mobile/native/android/app/build/outputs/apk/release
|
||||
releaseDirectory: apps/mobile/android/app/build/outputs/apk/release
|
||||
signingKeyBase64: ${{ secrets.PUBLIC_SIGNING_KEY }}
|
||||
alias: ${{ secrets.PUBLIC_ALIAS }}
|
||||
keyStorePassword: ${{ secrets.PUBLIC_KEY_PASSWORD }}
|
||||
keyPassword: ${{ secrets.PUBLIC_KEY_PASSWORD }}
|
||||
env:
|
||||
BUILD_TOOLS_VERSION: "33.0.0"
|
||||
BUILD_TOOLS_VERSION: "36.0.0"
|
||||
|
||||
- name: Rename apk files
|
||||
run: |
|
||||
cd apps/mobile/native/android/app/build/outputs/apk/release/
|
||||
cd apps/mobile/android/app/build/outputs/apk/release/
|
||||
mv app-arm64-v8a-release-unsigned-signed.apk notesnook-arm64-v8a.apk
|
||||
mv app-armeabi-v7a-release-unsigned-signed.apk notesnook-armeabi-v7a.apk
|
||||
mv app-x86-release-unsigned-signed.apk notesnook-x86.apk
|
||||
@@ -116,7 +140,7 @@ jobs:
|
||||
|
||||
- name: Get app version
|
||||
id: package-version
|
||||
uses: martinbeentjes/npm-get-version-action@master
|
||||
uses: saionaro/extract-package-version@master
|
||||
with:
|
||||
path: apps/mobile
|
||||
|
||||
@@ -129,21 +153,21 @@ jobs:
|
||||
releaseFiles: ${{steps.sign_app.outputs.signedReleaseFile}}
|
||||
track: beta
|
||||
status: completed
|
||||
whatsNewDirectory: apps/mobile/native/android/releasenotes/
|
||||
whatsNewDirectory: apps/mobile/android/releasenotes/
|
||||
|
||||
- name: Create release draft on Github
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: true
|
||||
tag_name: ${{ steps.package-version.outputs.current-version}}-beta-android
|
||||
name: Notesnook Android v${{ steps.package-version.outputs.current-version}}
|
||||
tag_name: ${{ steps.package-version.outputs.version}}-beta-android
|
||||
name: Notesnook Android v${{ steps.package-version.outputs.version}}
|
||||
repository: streetwriters/notesnook
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: |
|
||||
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-arm64-v8a.apk
|
||||
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-armeabi-v7a.apk
|
||||
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-x86.apk
|
||||
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-x86_64.apk
|
||||
apps/mobile/android/app/build/outputs/apk/release/notesnook-arm64-v8a.apk
|
||||
apps/mobile/android/app/build/outputs/apk/release/notesnook-armeabi-v7a.apk
|
||||
apps/mobile/android/app/build/outputs/apk/release/notesnook-x86.apk
|
||||
apps/mobile/android/app/build/outputs/apk/release/notesnook-x86_64.apk
|
||||
${{steps.sign_app.outputs.signedReleaseFile}}
|
||||
|
||||
- name: Upload sourcemaps
|
||||
@@ -151,5 +175,5 @@ jobs:
|
||||
with:
|
||||
name: sourcemaps
|
||||
path: |
|
||||
apps/mobile/native/android/app/build/**/*.map
|
||||
apps/mobile/android/app/build/**/*.map
|
||||
packages/editor-mobile/sourcemaps/*.map
|
||||
|
||||
56
.github/workflows/android.publish.yml
vendored
@@ -5,7 +5,6 @@ on: workflow_dispatch
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 40
|
||||
env:
|
||||
CMAKE_C_COMPILER_LAUNCHER: ccache
|
||||
CMAKE_CXX_COMPILER_LAUNCHER: ccache
|
||||
@@ -25,13 +24,29 @@ jobs:
|
||||
java-version: "17"
|
||||
architecture: "x64"
|
||||
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
# this might remove tools that are actually needed,
|
||||
# if set to "true" but frees about 6 GB
|
||||
tool-cache: false
|
||||
|
||||
# all of these default to true, but feel free to set to
|
||||
# "false" if necessary for your workflow
|
||||
android: false
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: true
|
||||
docker-images: true
|
||||
swap-storage: true
|
||||
|
||||
- name: Install node modules
|
||||
run: |
|
||||
npm ci --ignore-scripts --prefer-offline --no-audit
|
||||
npm run bootstrap -- --scope=mobile
|
||||
|
||||
- name: Make Gradlew Executable
|
||||
run: cd apps/mobile/native/android && chmod +x ./gradlew
|
||||
run: cd apps/mobile/android && chmod +x ./gradlew
|
||||
|
||||
- name: Install CCache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.11
|
||||
@@ -73,6 +88,15 @@ jobs:
|
||||
- name: CCache Stats Before Build
|
||||
run: ccache -sv
|
||||
|
||||
- name: Check for typescript errors
|
||||
run: |
|
||||
npm run tx mobile:build
|
||||
cd apps/mobile
|
||||
npx tsc --noEmit
|
||||
|
||||
- name: Remove debug keystore
|
||||
run: rm -rf apps/mobile/android/app/debug.keystore
|
||||
|
||||
- name: Build unsigned app bundle
|
||||
run: yarn release:android:bundle
|
||||
|
||||
@@ -83,13 +107,13 @@ jobs:
|
||||
id: sign_app
|
||||
uses: r0adkll/sign-android-release@master
|
||||
with:
|
||||
releaseDirectory: apps/mobile/native/android/app/build/outputs/bundle/release
|
||||
releaseDirectory: apps/mobile/android/app/build/outputs/bundle/release
|
||||
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
||||
alias: ${{ secrets.ALIAS }}
|
||||
keyStorePassword: ${{ secrets.KEY_PASSWORD }}
|
||||
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||
env:
|
||||
BUILD_TOOLS_VERSION: "33.0.0"
|
||||
BUILD_TOOLS_VERSION: "36.0.0"
|
||||
|
||||
- name: Build apks for Github release
|
||||
run: yarn release:android
|
||||
@@ -98,17 +122,17 @@ jobs:
|
||||
id: sign_apk
|
||||
uses: r0adkll/sign-android-release@master
|
||||
with:
|
||||
releaseDirectory: apps/mobile/native/android/app/build/outputs/apk/release
|
||||
releaseDirectory: apps/mobile/android/app/build/outputs/apk/release
|
||||
signingKeyBase64: ${{ secrets.PUBLIC_SIGNING_KEY }}
|
||||
alias: ${{ secrets.PUBLIC_ALIAS }}
|
||||
keyStorePassword: ${{ secrets.PUBLIC_KEY_PASSWORD }}
|
||||
keyPassword: ${{ secrets.PUBLIC_KEY_PASSWORD }}
|
||||
env:
|
||||
BUILD_TOOLS_VERSION: "33.0.0"
|
||||
BUILD_TOOLS_VERSION: "36.0.0"
|
||||
|
||||
- name: Rename apk files
|
||||
run: |
|
||||
cd apps/mobile/native/android/app/build/outputs/apk/release/
|
||||
cd apps/mobile/android/app/build/outputs/apk/release/
|
||||
mv app-arm64-v8a-release-unsigned-signed.apk notesnook-arm64-v8a.apk
|
||||
mv app-armeabi-v7a-release-unsigned-signed.apk notesnook-armeabi-v7a.apk
|
||||
mv app-x86-release-unsigned-signed.apk notesnook-x86.apk
|
||||
@@ -116,7 +140,7 @@ jobs:
|
||||
|
||||
- name: Get app version
|
||||
id: package-version
|
||||
uses: martinbeentjes/npm-get-version-action@master
|
||||
uses: saionaro/extract-package-version@master
|
||||
with:
|
||||
path: apps/mobile
|
||||
|
||||
@@ -129,26 +153,26 @@ jobs:
|
||||
releaseFiles: ${{steps.sign_app.outputs.signedReleaseFile}}
|
||||
track: production
|
||||
status: completed
|
||||
whatsNewDirectory: apps/mobile/native/android/releasenotes/
|
||||
whatsNewDirectory: apps/mobile/android/releasenotes/
|
||||
|
||||
- name: Create release draft on Github
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: true
|
||||
tag_name: ${{ steps.package-version.outputs.current-version}}-android
|
||||
name: Notesnook Android v${{ steps.package-version.outputs.current-version}}
|
||||
tag_name: ${{ steps.package-version.outputs.version}}-android
|
||||
name: Notesnook Android v${{ steps.package-version.outputs.version}}
|
||||
repository: streetwriters/notesnook
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: |
|
||||
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-arm64-v8a.apk
|
||||
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-armeabi-v7a.apk
|
||||
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-x86.apk
|
||||
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-x86_64.apk
|
||||
apps/mobile/android/app/build/outputs/apk/release/notesnook-arm64-v8a.apk
|
||||
apps/mobile/android/app/build/outputs/apk/release/notesnook-armeabi-v7a.apk
|
||||
apps/mobile/android/app/build/outputs/apk/release/notesnook-x86.apk
|
||||
apps/mobile/android/app/build/outputs/apk/release/notesnook-x86_64.apk
|
||||
|
||||
- name: Upload sourcemaps
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sourcemaps
|
||||
path: |
|
||||
apps/mobile/native/android/app/build/**/*.map
|
||||
apps/mobile/android/app/build/**/*.map
|
||||
packages/editor-mobile/sourcemaps/*.map
|
||||
|
||||
25
.github/workflows/core.tests.yml
vendored
@@ -9,7 +9,13 @@ on:
|
||||
- "packages/core/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/core.tests.yml"
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- "packages/core/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/core.tests.yml"
|
||||
types:
|
||||
- "ready_for_review"
|
||||
- "opened"
|
||||
@@ -17,11 +23,21 @@ on:
|
||||
- "reopened"
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
authorize:
|
||||
environment: ${{ github.event_name == 'pull_request_target' &&
|
||||
github.event.pull_request.head.repo.full_name != github.repository &&
|
||||
'external' || 'internal' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo true
|
||||
|
||||
test:
|
||||
needs: authorize
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.ref }}
|
||||
|
||||
- name: Setup Node
|
||||
uses: ./.github/actions/setup-node-with-cache
|
||||
@@ -36,7 +52,6 @@ jobs:
|
||||
echo "USER_PASSWORD=${{ secrets.USER_PASSWORD }}" >> $GITHUB_ENV
|
||||
echo "USER_TOTP_SECRET=${{ secrets.USER_TOTP_SECRET }}" >> $GITHUB_ENV
|
||||
echo "USER_HASHED_PASSWORD=${{ secrets.USER_HASHED_PASSWORD }}" >> $GITHUB_ENV
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Run all @notesnook/core tests
|
||||
run: npx nx test:e2e @notesnook/core
|
||||
run: npm run tx @notesnook/core:test:e2e
|
||||
|
||||
27
.github/workflows/desktop.publish.yml
vendored
@@ -65,17 +65,13 @@ jobs:
|
||||
npm i --cpu x64 sqlite-better-trigram
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate desktop build (stable)
|
||||
if: ${{ inputs.release-track == 'stable' }}
|
||||
run: npx nx build:desktop @notesnook/web
|
||||
run: npm run tx @notesnook/web:build:desktop
|
||||
|
||||
- name: Generate desktop build (beta)
|
||||
if: ${{ inputs.release-track == 'beta' }}
|
||||
run: BETA=true npx nx build:desktop @notesnook/web
|
||||
run: BETA=true npm run tx @notesnook/web:build:desktop
|
||||
|
||||
- name: Build desktop bundle
|
||||
working-directory: ./apps/desktop
|
||||
@@ -199,9 +195,9 @@ jobs:
|
||||
CSC_LINK: ${{ secrets.mac_certs }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.mac_certs_password }}
|
||||
run: |
|
||||
npx nx run release --project @notesnook/desktop -- --variant=mas
|
||||
npm run tx @notesnook/desktop:release -- --variant=mas
|
||||
cd apps/desktop
|
||||
yarn electron-builder --config=electron-builder.config.js --mac mas --universal -p never
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build zip and dmg
|
||||
env:
|
||||
@@ -212,13 +208,13 @@ jobs:
|
||||
APPLE_API_KEY_ID: ${{ secrets.api_key_id }}
|
||||
APPLE_API_ISSUER: ${{ secrets.api_key_issuer_id }}
|
||||
run: |
|
||||
npx nx run release --project @notesnook/desktop
|
||||
npm run tx @notesnook/desktop:release
|
||||
cd apps/desktop
|
||||
if [ ${{ inputs.publish-github }} == true ]; then
|
||||
yarn electron-builder --config=electron-builder.config.js --mac zip dmg --arm64 --x64 -p always
|
||||
else
|
||||
yarn electron-builder --config=electron-builder.config.js --mac zip dmg --arm64 --x64 -p never
|
||||
fi
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Deploy to Testflight
|
||||
if: inputs.publish-apple && steps.appstore.outputs.app-version-latest != steps.app_metadata.outputs.app_version
|
||||
@@ -271,8 +267,7 @@ jobs:
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
run: npm run tx @notesnook/desktop:release
|
||||
|
||||
- name: Build snap
|
||||
if: inputs.publish-snap
|
||||
@@ -339,8 +334,7 @@ jobs:
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
run: npm run tx @notesnook/desktop:release
|
||||
|
||||
# - name: Build snap
|
||||
# if: inputs.publish-snap
|
||||
@@ -402,10 +396,13 @@ jobs:
|
||||
run: |
|
||||
npm i --cpu arm64 sqlite-better-trigram
|
||||
npm i --cpu x64 sqlite-better-trigram
|
||||
|
||||
npm i --cpu arm64 sqlite3-fts5-html
|
||||
npm i --cpu x64 sqlite3-fts5-html
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
run: node scripts/execute.mjs @notesnook/desktop:release
|
||||
|
||||
- name: Publish
|
||||
env:
|
||||
|
||||
31
.github/workflows/desktop.tests.yml
vendored
@@ -6,10 +6,16 @@ on:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- "app/desktop/**"
|
||||
- "apps/desktop/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/desktop.tests.yml"
|
||||
pull_request:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- "apps/desktop/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/desktop.tests.yml"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -27,12 +33,8 @@ jobs:
|
||||
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
|
||||
|
||||
- name: Generate desktop build
|
||||
run: npx nx build:desktop @notesnook/web
|
||||
run: npm run tx @notesnook/web:build:desktop
|
||||
|
||||
- name: Archive build artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -43,7 +45,7 @@ jobs:
|
||||
test-macos-x64:
|
||||
name: Test macOS x64
|
||||
needs: build
|
||||
runs-on: macos-13
|
||||
runs-on: macos-15-intel
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
@@ -64,8 +66,7 @@ jobs:
|
||||
npm run bootstrap -- --scope=desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
run: npm run tx @notesnook/desktop:release
|
||||
|
||||
- name: Build app
|
||||
run: |
|
||||
@@ -108,8 +109,7 @@ jobs:
|
||||
npm run bootstrap -- --scope=desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
run: npm run tx @notesnook/desktop:release
|
||||
|
||||
- name: Build app
|
||||
run: |
|
||||
@@ -158,8 +158,7 @@ jobs:
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
run: npm run tx @notesnook/desktop:release
|
||||
|
||||
- name: Build app
|
||||
run: |
|
||||
@@ -205,11 +204,13 @@ jobs:
|
||||
run: |
|
||||
npm i --cpu arm64 sqlite-better-trigram
|
||||
npm i --cpu x64 sqlite-better-trigram
|
||||
|
||||
npm i --cpu arm64 sqlite3-fts5-html
|
||||
npm i --cpu x64 sqlite3-fts5-html
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
run: node scripts/execute.mjs @notesnook/desktop:release
|
||||
|
||||
- name: Build app
|
||||
run: |
|
||||
|
||||
14
.github/workflows/editor.tests.yml
vendored
@@ -10,6 +10,12 @@ on:
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/editor.tests.yml"
|
||||
pull_request:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- "packages/editor/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/editor.tests.yml"
|
||||
types:
|
||||
- "ready_for_review"
|
||||
- "opened"
|
||||
@@ -32,12 +38,8 @@ jobs:
|
||||
npm ci --ignore-scripts --prefer-offline --no-audit
|
||||
npm run bootstrap -- --scope=editor
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build editor
|
||||
run: npx nx build @notesnook/editor
|
||||
run: npm run tx @notesnook/editor:build
|
||||
|
||||
- name: Run all @notesnook/editor tests
|
||||
run: npx nx test @notesnook/editor
|
||||
run: npm run tx @notesnook/editor:test
|
||||
|
||||
31
.github/workflows/ios.publish.yml
vendored
@@ -4,7 +4,7 @@ on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-14
|
||||
runs-on: macos-26
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
- name: Setup Xcode
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: "16.1"
|
||||
xcode-version: "26.1.1"
|
||||
|
||||
- name: Install node modules
|
||||
run: |
|
||||
@@ -25,12 +25,12 @@ jobs:
|
||||
npm run bootstrap -- --scope=mobile
|
||||
|
||||
- name: Build packages
|
||||
run: npx nx run @notesnook/mobile:build
|
||||
run: npm run tx @notesnook/mobile:build
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.11
|
||||
with:
|
||||
key: ${{ runner.os }}-ccache-${{ hashFiles(format('apps/mobile/native/ios/Podfile.lock')) }}
|
||||
key: ${{ runner.os }}-ccache-${{ hashFiles(format('apps/mobile/ios/Podfile.lock')) }}
|
||||
max-size: 1500M
|
||||
restore-keys: |
|
||||
${{ runner.os }}-ccache-
|
||||
@@ -55,14 +55,19 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
id: pods-cache
|
||||
with:
|
||||
path: apps/mobile/native/ios/Pods
|
||||
key: ${{ runner.os }}-pods-${{ hashFiles('apps/mobile/native/ios/Podfile.lock') }}
|
||||
path: apps/mobile/ios/Pods
|
||||
key: ${{ runner.os }}-pods-${{ hashFiles('apps/mobile/ios/Podfile.lock') }}
|
||||
|
||||
- name: Install Pods
|
||||
run: |
|
||||
cd apps/mobile/native/ios
|
||||
bundle install
|
||||
RCT_NEW_ARCH_ENABLED=0 bundle exec pod install
|
||||
cd apps/mobile/ios
|
||||
pod install
|
||||
|
||||
- name: Check for typescript errors
|
||||
run: |
|
||||
npm run tx mobile:build
|
||||
cd apps/mobile
|
||||
npx tsc --noEmit
|
||||
|
||||
- name: CCache Stats Before Build
|
||||
run: ccache -sv
|
||||
@@ -73,9 +78,9 @@ jobs:
|
||||
bundle-identifier: org.streetwriters.notesnook
|
||||
scheme: Notesnook
|
||||
configuration: "Release"
|
||||
export-options: apps/mobile/native/ios/ExportOptions.plist
|
||||
project-path: apps/mobile/native/ios/Notesnook.xcodeproj
|
||||
workspace-path: apps/mobile/native/ios/Notesnook.xcworkspace
|
||||
export-options: apps/mobile/ios/ExportOptions.plist
|
||||
project-path: apps/mobile/ios/Notesnook.xcodeproj
|
||||
workspace-path: apps/mobile/ios/Notesnook.xcworkspace
|
||||
update-targets: |
|
||||
Notesnook
|
||||
Make Note
|
||||
@@ -111,5 +116,5 @@ jobs:
|
||||
name: Notesnook.zip
|
||||
path: |
|
||||
Notesnook.ipa
|
||||
apps/mobile/native/ios/**/*.map
|
||||
apps/mobile/ios/**/*.map
|
||||
packages/editor-mobile/sourcemaps/*.map
|
||||
|
||||
6
.github/workflows/monograph.publish.yml
vendored
@@ -39,13 +39,13 @@ jobs:
|
||||
echo ::set-output name=app_version::$(cat package.json | jq -r .version)
|
||||
|
||||
- name: Generate build
|
||||
run: npx nx build @notesnook/monograph
|
||||
run: npm run tx @notesnook/monograph:build
|
||||
|
||||
# Setup Buildx
|
||||
- name: Docker Setup Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
context: apps/monograph
|
||||
file: apps/monograph/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: streetwriters/monograph:${{ steps.package_metadata.outputs.app_version }},streetwriters/monograph:latest
|
||||
cache-from: streetwriters/monograph:latest
|
||||
|
||||
|
||||
1
.github/workflows/theme-builder.publish.yml
vendored
@@ -20,7 +20,6 @@ jobs:
|
||||
|
||||
- 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
|
||||
|
||||
|
||||
78
.github/workflows/themes.publish.yml
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
# GitHub recommends pinning actions to a commit SHA.
|
||||
# To get a newer version, you will need to update the SHA.
|
||||
# You can also reference a tag or branch, but the action may change without warning.
|
||||
|
||||
name: Publish @notesnook/themes-server
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
name: Push Docker image to Docker Hub
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
attestations: write
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Collect package metadata
|
||||
id: package_metadata
|
||||
working-directory: ./servers/themes
|
||||
run: |
|
||||
echo ::set-output name=app_version::$(cat package.json | jq -r .version)
|
||||
|
||||
# Setup Buildx
|
||||
- name: Docker Setup Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
ecr: auto
|
||||
logout: true
|
||||
|
||||
# Pull previous image from docker hub to use it as cache to improve the image build time.
|
||||
- name: docker pull cache image
|
||||
continue-on-error: true
|
||||
run: docker pull streetwriters/themes-server:latest
|
||||
|
||||
# Setup QEMU
|
||||
# - name: Set up QEMU
|
||||
# uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: streetwriters/themes-server
|
||||
|
||||
- name: Build and push Docker image
|
||||
id: push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: servers/themes/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: streetwriters/themes-server:${{ steps.package_metadata.outputs.app_version }},streetwriters/themes-server:latest
|
||||
cache-from: streetwriters/themes-server:latest
|
||||
|
||||
- name: Generate artifact attestation
|
||||
uses: actions/attest-build-provenance@v1
|
||||
with:
|
||||
subject-name: index.docker.io/streetwriters/themes-server
|
||||
subject-digest: ${{ steps.push.outputs.digest }}
|
||||
push-to-registry: true
|
||||
1
.github/workflows/vericrypt.publish.yml
vendored
@@ -20,7 +20,6 @@ jobs:
|
||||
|
||||
- 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
|
||||
|
||||
|
||||
4
.github/workflows/web.benchmarks.yml
vendored
@@ -27,10 +27,6 @@ jobs:
|
||||
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
|
||||
|
||||
- name: Build
|
||||
run: npm run build:web
|
||||
|
||||
|
||||
1
.github/workflows/web.publish.yml
vendored
@@ -30,7 +30,6 @@ jobs:
|
||||
|
||||
- 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
|
||||
|
||||
|
||||
25
.github/workflows/web.tests.yml
vendored
@@ -9,7 +9,13 @@ on:
|
||||
- "apps/web/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/web.tests.yml"
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- "apps/web/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/web.tests.yml"
|
||||
types:
|
||||
- "ready_for_review"
|
||||
- "opened"
|
||||
@@ -17,12 +23,23 @@ on:
|
||||
- "reopened"
|
||||
|
||||
jobs:
|
||||
authorize:
|
||||
environment: ${{ github.event_name == 'pull_request_target' &&
|
||||
github.event.pull_request.head.repo.full_name != github.repository &&
|
||||
'external' || 'internal' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo true
|
||||
|
||||
build:
|
||||
needs: authorize
|
||||
name: Build
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.ref }}
|
||||
|
||||
- name: Setup Node
|
||||
uses: ./.github/actions/setup-node-with-cache
|
||||
@@ -32,10 +49,6 @@ jobs:
|
||||
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
|
||||
|
||||
- name: Generate test build
|
||||
run: npm run build:test:web
|
||||
|
||||
@@ -54,6 +67,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.ref }}
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
1
.gitignore
vendored
@@ -12,3 +12,4 @@ site
|
||||
node_modules.backup
|
||||
.nx
|
||||
/*.patch
|
||||
.taskcache
|
||||
2
.vscode/settings.json
vendored
@@ -11,5 +11,5 @@
|
||||
"cache": true,
|
||||
"cacheStrategy": "content"
|
||||
},
|
||||
"git.rebaseWhenSync": true
|
||||
"git.rebaseWhenSync": false
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ Notesnook is built using the following technologies:
|
||||
3. React Native — For mobile apps we are using React Native
|
||||
4. Electron — For desktop app
|
||||
5. NPM — listed here because we **don't** use Yarn or PNPM or XYZ across any of our projects.
|
||||
6. Nx — maintaining monorepos is hard but Nx makes it easier.
|
||||
|
||||
> **Note: Each project in the monorepo contains its own architecture details which you can refer to.**
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Requirements:
|
||||
|
||||
Before you can do anything, you'll need to [install Node.js](https://nodejs.org/en/download/) v16 or later on your system.
|
||||
|
||||
Once you have completed the setup, the first step is to `clone` the monorepo:
|
||||
1. `clone` the monorepo:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/streetwriters/notesnook.git
|
||||
@@ -33,19 +33,28 @@ git clone https://github.com/streetwriters/notesnook.git
|
||||
cd notesnook
|
||||
```
|
||||
|
||||
Once you are inside the `./notesnook` directory, run the preparation step:
|
||||
2. Install dependencies:
|
||||
|
||||
```bash
|
||||
# this might take a while to complete
|
||||
npm install
|
||||
```
|
||||
|
||||
Now you can finally start the desktop app for development:
|
||||
3. Run the webapp for desktop environment:
|
||||
|
||||
```bash
|
||||
cd apps/web
|
||||
npm run start:desktop
|
||||
```
|
||||
|
||||
4. In a separate terminal session, run the desktop app from the root of the project:
|
||||
|
||||
```bash
|
||||
npm run start:desktop
|
||||
```
|
||||
|
||||
### Release mode
|
||||
|
||||
To run the app in release mode:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -17,230 +17,226 @@ 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 { test } from "vitest";
|
||||
import { harness } from "./utils.js";
|
||||
import { testCleanup, test } from "./test-override.js";
|
||||
import { writeFile } from "fs/promises";
|
||||
import { Page } from "playwright";
|
||||
import { gt, lt } from "semver";
|
||||
import { describe } from "vitest";
|
||||
|
||||
test("update starts downloading if version is outdated", async (t) => {
|
||||
await harness(
|
||||
t,
|
||||
async ({ page }) => {
|
||||
await page.waitForSelector("#authForm");
|
||||
test("update starts downloading if version is outdated", async ({
|
||||
ctx: { page },
|
||||
expect,
|
||||
onTestFinished
|
||||
}) => {
|
||||
onTestFinished(testCleanup);
|
||||
|
||||
t.expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
await page.waitForSelector("#authForm");
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await skipDialog(page);
|
||||
await skipDialog(page);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /updating/i })
|
||||
.waitFor({ state: "attached" });
|
||||
},
|
||||
{ version: "3.0.0" }
|
||||
);
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /updating/i })
|
||||
.waitFor({ state: "attached" });
|
||||
});
|
||||
|
||||
test("update is only shown if version is outdated and auto updates are disabled", async (t) => {
|
||||
await harness(
|
||||
t,
|
||||
async (ctx) => {
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false
|
||||
})
|
||||
);
|
||||
test("update is only shown if version is outdated and auto updates are disabled", async ({
|
||||
ctx,
|
||||
expect,
|
||||
onTestFinished
|
||||
}) => {
|
||||
onTestFinished(testCleanup);
|
||||
|
||||
await ctx.relaunch();
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false
|
||||
})
|
||||
);
|
||||
|
||||
const { page } = ctx;
|
||||
await ctx.relaunch();
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
const { page } = ctx;
|
||||
|
||||
t.expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await skipDialog(page);
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
await skipDialog(page);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i })
|
||||
.waitFor({ state: "attached" });
|
||||
});
|
||||
|
||||
describe("update to stable if it is newer", () => {
|
||||
test.scoped({ options: { version: "3.0.0-beta.0" } });
|
||||
test("test", async ({ ctx, expect, onTestFinished }) => {
|
||||
onTestFinished(testCleanup);
|
||||
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "beta"
|
||||
})
|
||||
);
|
||||
|
||||
await ctx.relaunch();
|
||||
|
||||
const { page } = ctx;
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await skipDialog(page);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
const updateButton = page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i });
|
||||
await updateButton.waitFor({ state: "visible" });
|
||||
const content = await updateButton.textContent();
|
||||
const version = content?.split(" ")?.[0] || "";
|
||||
expect(gt(version, "3.0.0-beta.0")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("update is not available if it latest stable version is older", () => {
|
||||
test.scoped({ options: { version: "99.0.0-beta.0" } });
|
||||
test("test", async ({ ctx, expect, onTestFinished }) => {
|
||||
onTestFinished(testCleanup);
|
||||
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "beta"
|
||||
})
|
||||
);
|
||||
|
||||
await ctx.relaunch();
|
||||
|
||||
const { page } = ctx;
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await skipDialog(page);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /checking for updates/i })
|
||||
.waitFor({ state: "hidden" });
|
||||
|
||||
expect(
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i })
|
||||
.waitFor({ state: "attached" });
|
||||
},
|
||||
{ version: "3.0.0" }
|
||||
);
|
||||
.isHidden()
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
test("update to stable if it is newer", async (t) => {
|
||||
await harness(
|
||||
t,
|
||||
async (ctx) => {
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "beta"
|
||||
})
|
||||
);
|
||||
describe("downgrade to stable on switching to stable release track", () => {
|
||||
test.scoped({ options: { version: "99.0.0-beta.0" } });
|
||||
test("test", async ({ ctx, expect, onTestFinished }) => {
|
||||
onTestFinished(testCleanup);
|
||||
|
||||
await ctx.relaunch();
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "stable"
|
||||
})
|
||||
);
|
||||
|
||||
const { page } = ctx;
|
||||
await ctx.relaunch();
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
const { page } = ctx;
|
||||
|
||||
t.expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await skipDialog(page);
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
await skipDialog(page);
|
||||
|
||||
const updateButton = page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i });
|
||||
await updateButton.waitFor({ state: "visible" });
|
||||
const content = await updateButton.textContent();
|
||||
const version = content?.split(" ")?.[0] || "";
|
||||
t.expect(gt(version, "3.0.0-beta.0")).toBe(true);
|
||||
},
|
||||
{ version: "3.0.0-beta.0" }
|
||||
);
|
||||
});
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
test("update is not available if it latest stable version is older", async (t) => {
|
||||
await harness(
|
||||
t,
|
||||
async (ctx) => {
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "beta"
|
||||
})
|
||||
);
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /checking for updates/i })
|
||||
.waitFor({ state: "hidden" });
|
||||
|
||||
await ctx.relaunch();
|
||||
|
||||
const { page } = ctx;
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
t.expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await skipDialog(page);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /checking for updates/i })
|
||||
.waitFor({ state: "hidden" });
|
||||
|
||||
t.expect(
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i })
|
||||
.isHidden()
|
||||
).toBe(true);
|
||||
},
|
||||
{ version: "99.0.0-beta.0" }
|
||||
);
|
||||
});
|
||||
|
||||
test("downgrade to stable on switching to stable release track", async (t) => {
|
||||
await harness(
|
||||
t,
|
||||
async (ctx) => {
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "stable"
|
||||
})
|
||||
);
|
||||
|
||||
await ctx.relaunch();
|
||||
|
||||
const { page } = ctx;
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
t.expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await skipDialog(page);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /checking for updates/i })
|
||||
.waitFor({ state: "hidden" });
|
||||
|
||||
const updateButton = page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i });
|
||||
await updateButton.waitFor({ state: "visible" });
|
||||
const content = await updateButton.textContent();
|
||||
const version = content?.split(" ")?.[0] || "";
|
||||
t.expect(lt(version, "99.0.0-beta.0")).toBe(true);
|
||||
},
|
||||
{ version: "99.0.0-beta.0" }
|
||||
);
|
||||
const updateButton = page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i });
|
||||
await updateButton.waitFor({ state: "visible" });
|
||||
const content = await updateButton.textContent();
|
||||
const version = content?.split(" ")?.[0] || "";
|
||||
expect(lt(version, "99.0.0-beta.0")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
async function skipDialog(page: Page) {
|
||||
await page
|
||||
.waitForSelector(".ReactModal__Content", {
|
||||
timeout: 1000
|
||||
})
|
||||
.catch(() => {})
|
||||
.then(async () => {
|
||||
const positiveButton = page.locator(
|
||||
"button[data-role='positive-button']"
|
||||
);
|
||||
const negativeButton = page.locator(
|
||||
"button[data-role='negative-button']"
|
||||
);
|
||||
if (await positiveButton.isVisible()) await positiveButton.click();
|
||||
else if (await negativeButton.isVisible()) await negativeButton.click();
|
||||
});
|
||||
try {
|
||||
const dialog = page.locator(".ReactModal__Content");
|
||||
const positiveButton = dialog.locator(
|
||||
"button[data-role='positive-button']"
|
||||
);
|
||||
const negativeButton = dialog.locator(
|
||||
"button[data-role='negative-button']"
|
||||
);
|
||||
if (await positiveButton.isVisible())
|
||||
await positiveButton.click({ timeout: 1000 });
|
||||
else if (await negativeButton.isVisible())
|
||||
await negativeButton.click({ timeout: 1000 });
|
||||
} catch (e) {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
24
apps/desktop/__tests__/global-setup.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { buildApp } from "./utils";
|
||||
|
||||
export default async function setup() {
|
||||
await buildApp();
|
||||
}
|
||||
@@ -17,22 +17,24 @@ 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 { test } from "vitest";
|
||||
import { harness } from "./utils.js";
|
||||
import assert from "assert";
|
||||
import { testCleanup, test } from "./test-override.js";
|
||||
|
||||
test("make sure app loads", async (t) => {
|
||||
await harness(t, async ({ page }) => {
|
||||
await page.waitForSelector("#authForm");
|
||||
test("make sure app loads", async ({
|
||||
ctx: { page },
|
||||
expect,
|
||||
onTestFinished
|
||||
}) => {
|
||||
onTestFinished(testCleanup);
|
||||
|
||||
assert.ok(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
);
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
});
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
});
|
||||
|
||||
64
apps/desktop/__tests__/test-override.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { test as vitestTest, TestContext } from "vitest";
|
||||
import { buildAndLaunchApp, Fixtures, TestOptions } from "./utils";
|
||||
import { mkdir, rm } from "fs/promises";
|
||||
import path from "path";
|
||||
import slugify from "slugify";
|
||||
|
||||
export const test = vitestTest.extend<Fixtures>({
|
||||
options: { version: "3.0.0" } as TestOptions,
|
||||
ctx: async ({ options }, use) => {
|
||||
const ctx = await buildAndLaunchApp(options);
|
||||
await use(ctx);
|
||||
}
|
||||
});
|
||||
|
||||
export async function testCleanup(context: TestContext) {
|
||||
const ctx = (context.task.context as unknown as Fixtures).ctx;
|
||||
if (context.task.result?.state === "fail") {
|
||||
await mkdir("test-results", { recursive: true });
|
||||
await ctx.page.screenshot({
|
||||
path: path.join(
|
||||
"test-results",
|
||||
`${slugify(context.task.name)}-${process.platform}-${
|
||||
process.arch
|
||||
}-error.png`
|
||||
)
|
||||
});
|
||||
}
|
||||
await ctx.app.close();
|
||||
await rm(ctx.userDataDir, {
|
||||
force: true,
|
||||
recursive: true,
|
||||
maxRetries: 3,
|
||||
retryDelay: 5000
|
||||
}).catch(() => {
|
||||
/*ignore */
|
||||
});
|
||||
await rm(ctx.outputDir, {
|
||||
force: true,
|
||||
recursive: true,
|
||||
maxRetries: 3,
|
||||
retryDelay: 5000
|
||||
}).catch(() => {
|
||||
/*ignore */
|
||||
});
|
||||
}
|
||||
@@ -18,146 +18,200 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { execSync } from "child_process";
|
||||
import { mkdir } from "fs/promises";
|
||||
import { cp } from "fs/promises";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import path from "path";
|
||||
import path, { join, resolve } from "path";
|
||||
import { _electron as electron } from "playwright";
|
||||
import slugify from "slugify";
|
||||
import { TaskContext } from "vitest";
|
||||
import { existsSync } from "fs";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const IS_DEBUG = process.env.NN_DEBUG === "true" || process.env.CI === "true";
|
||||
const productName = `NotesnookTestHarness`;
|
||||
const SOURCE_DIR = resolve("output", productName);
|
||||
|
||||
interface AppContext {
|
||||
export interface AppContext {
|
||||
app: import("playwright").ElectronApplication;
|
||||
page: import("playwright").Page;
|
||||
configPath: string;
|
||||
userDataDir: string;
|
||||
outputDir: string;
|
||||
relaunch: () => Promise<void>;
|
||||
}
|
||||
|
||||
interface TestOptions {
|
||||
export interface TestOptions {
|
||||
version: string;
|
||||
}
|
||||
|
||||
export async function harness(
|
||||
t: TaskContext,
|
||||
cb: (ctx: AppContext) => Promise<void>,
|
||||
options?: TestOptions
|
||||
) {
|
||||
const ctx = await buildAndLaunchApp(options);
|
||||
|
||||
t.onTestFinished(async (result) => {
|
||||
if (result.state === "fail") {
|
||||
await mkdir("test-results", { recursive: true });
|
||||
await ctx.page.screenshot({
|
||||
path: path.join(
|
||||
"test-results",
|
||||
`${slugify(t.task.name)}-${process.platform}-${
|
||||
process.arch
|
||||
}-error.png`
|
||||
)
|
||||
});
|
||||
}
|
||||
await ctx.app.close();
|
||||
});
|
||||
|
||||
await cb(ctx);
|
||||
export interface Fixtures {
|
||||
options: TestOptions;
|
||||
ctx: AppContext;
|
||||
}
|
||||
|
||||
async function buildAndLaunchApp(options?: TestOptions): Promise<AppContext> {
|
||||
const productName = makeid(10);
|
||||
const executablePath = await buildApp({ ...options, productName });
|
||||
const { app, page, configPath } = await launchApp(executablePath);
|
||||
export async function buildAndLaunchApp(
|
||||
options?: TestOptions
|
||||
): Promise<AppContext> {
|
||||
const productName = `notesnooktest${makeid(10)}`;
|
||||
const outputDir = path.join("test-artifacts", `${productName}-output`);
|
||||
const executablePath = await copyBuild({
|
||||
...options,
|
||||
outputDir
|
||||
});
|
||||
const { app, page, configPath, userDataDir } = await launchApp(
|
||||
executablePath,
|
||||
productName,
|
||||
options?.version
|
||||
);
|
||||
const ctx: AppContext = {
|
||||
app,
|
||||
page,
|
||||
configPath,
|
||||
userDataDir,
|
||||
outputDir,
|
||||
relaunch: async () => {
|
||||
const { app, page, configPath } = await launchApp(executablePath);
|
||||
const { app, page, configPath, userDataDir } = await launchApp(
|
||||
executablePath,
|
||||
productName,
|
||||
options?.version
|
||||
);
|
||||
ctx.app = app;
|
||||
ctx.page = page;
|
||||
ctx.userDataDir = userDataDir;
|
||||
ctx.configPath = configPath;
|
||||
}
|
||||
};
|
||||
return ctx;
|
||||
}
|
||||
|
||||
async function launchApp(executablePath: string) {
|
||||
async function launchApp(
|
||||
executablePath: string,
|
||||
packageName: string,
|
||||
version?: string
|
||||
) {
|
||||
const userDataDir = resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
"test-artifacts",
|
||||
"user_data_dirs",
|
||||
packageName
|
||||
);
|
||||
const app = await electron.launch({
|
||||
executablePath,
|
||||
args: IS_DEBUG ? [] : ["--hidden"],
|
||||
env:
|
||||
process.platform === "linux"
|
||||
env: {
|
||||
...(process.platform === "linux"
|
||||
? {
|
||||
...(process.env as Record<string, string>),
|
||||
APPIMAGE: "true"
|
||||
}
|
||||
: (process.env as Record<string, string>)
|
||||
: (process.env as Record<string, string>)),
|
||||
CUSTOM_USER_DATA_DIR: userDataDir,
|
||||
...(version
|
||||
? {
|
||||
CUSTOM_APP_VERSION: version
|
||||
}
|
||||
: {})
|
||||
}
|
||||
});
|
||||
|
||||
const page = await app.firstWindow();
|
||||
|
||||
const userDataDirectory = await app.evaluate((a) => {
|
||||
return a.app.getPath("userData");
|
||||
});
|
||||
const configPath = path.join(userDataDirectory, "config.json");
|
||||
const configPath = path.join(userDataDir, "UserData", "config.json");
|
||||
return {
|
||||
app,
|
||||
page,
|
||||
configPath
|
||||
configPath,
|
||||
userDataDir
|
||||
};
|
||||
}
|
||||
|
||||
async function buildApp({
|
||||
version,
|
||||
productName
|
||||
}: {
|
||||
version?: string;
|
||||
productName: string;
|
||||
}) {
|
||||
const buildRoot = path.join("test-artifacts", `${productName}-build`);
|
||||
const output = path.join("test-artifacts", `${productName}-output`);
|
||||
execSync(`npm run release -- --root ${buildRoot} --skip-tsc-build`, {
|
||||
stdio: IS_DEBUG ? "inherit" : "ignore"
|
||||
});
|
||||
|
||||
const args = [
|
||||
`--config electron-builder.config.js`,
|
||||
`--c.extraMetadata.productName=${productName}`,
|
||||
"--publish=never"
|
||||
];
|
||||
if (version) args.push(`--c.extraMetadata.version=${version}`);
|
||||
|
||||
execSync(`npx electron-builder --dir --${process.arch} ${args.join(" ")}`, {
|
||||
stdio: IS_DEBUG ? "inherit" : "ignore",
|
||||
env: {
|
||||
...process.env,
|
||||
NOTESNOOK_STAGING: "true",
|
||||
NN_BUILD_ROOT: buildRoot,
|
||||
NN_PRODUCT_NAME: productName,
|
||||
NN_APP_ID: `com.notesnook.test.${productName}`,
|
||||
NN_OUTPUT_DIR: output
|
||||
let MAX_RETRIES = 3;
|
||||
export async function buildApp(version?: string) {
|
||||
if (!existsSync(SOURCE_DIR)) {
|
||||
const args = [
|
||||
"electron-builder",
|
||||
"--dir",
|
||||
`--${process.arch}`,
|
||||
`--config electron-builder.config.js`,
|
||||
`--c.extraMetadata.productName=${productName}`,
|
||||
`--c.compression=store`,
|
||||
"--publish=never"
|
||||
];
|
||||
if (version) args.push(`--c.extraMetadata.version=${version}`);
|
||||
try {
|
||||
execSync(`npx ${args.join(" ")}`, {
|
||||
stdio: IS_DEBUG ? "inherit" : "ignore",
|
||||
env: {
|
||||
...process.env,
|
||||
NOTESNOOK_STAGING: "true",
|
||||
NN_PRODUCT_NAME: productName,
|
||||
NN_APP_ID: `com.notesnook.test.${productName}`,
|
||||
NN_OUTPUT_DIR: SOURCE_DIR
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
if (--MAX_RETRIES) {
|
||||
console.log("retrying...");
|
||||
return await buildApp(version);
|
||||
} else throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return path.join(
|
||||
async function copyBuild({ outputDir }: { outputDir: string }) {
|
||||
return process.platform === "win32"
|
||||
? await makeBuildCopyWindows(outputDir, productName)
|
||||
: process.platform === "darwin"
|
||||
? await makeBuildCopyMacOS(outputDir, productName)
|
||||
: await makeBuildCopyLinux(outputDir, productName);
|
||||
}
|
||||
|
||||
async function makeBuildCopyLinux(outputDir: string, productName: string) {
|
||||
const platformDir =
|
||||
process.arch === "arm64" ? "linux-arm64-unpacked" : "linux-unpacked";
|
||||
const appDir = await makeBuildCopy(outputDir, platformDir);
|
||||
return resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
output,
|
||||
process.platform === "linux"
|
||||
? process.arch === "arm64"
|
||||
? "linux-arm64-unpacked"
|
||||
: "linux-unpacked"
|
||||
: process.platform === "darwin"
|
||||
? process.arch === "arm64"
|
||||
? `mac-arm64/${productName}.app/Contents/MacOS/`
|
||||
: `mac/${productName}.app/Contents/MacOS/`
|
||||
: "win-unpacked",
|
||||
process.platform === "win32" ? `${productName}.exe` : productName
|
||||
appDir,
|
||||
productName.toLowerCase().replace(/\s+/g, "-")
|
||||
);
|
||||
}
|
||||
|
||||
async function makeBuildCopyWindows(outputDir: string, productName: string) {
|
||||
const platformDir =
|
||||
process.arch === "arm64" ? "win-arm64-unpacked" : "win-unpacked";
|
||||
const appDir = await makeBuildCopy(outputDir, platformDir);
|
||||
return resolve(__dirname, "..", appDir, `${productName}.exe`);
|
||||
}
|
||||
|
||||
async function makeBuildCopyMacOS(outputDir: string, productName: string) {
|
||||
const platformDir = process.arch === "arm64" ? "mac-arm64" : "mac";
|
||||
const appDir = await makeBuildCopy(outputDir, platformDir);
|
||||
return resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
appDir,
|
||||
`${productName}.app`,
|
||||
"Contents",
|
||||
"MacOS",
|
||||
productName
|
||||
);
|
||||
}
|
||||
|
||||
async function makeBuildCopy(outputDir: string, platformDir: string) {
|
||||
const appDir = outputDir;
|
||||
await cp(join(SOURCE_DIR, platformDir), outputDir, {
|
||||
recursive: true,
|
||||
preserveTimestamps: true,
|
||||
verbatimSymlinks: true,
|
||||
dereference: false,
|
||||
force: true
|
||||
});
|
||||
|
||||
return appDir;
|
||||
}
|
||||
|
||||
function makeid(length: number) {
|
||||
let result = "";
|
||||
const characters =
|
||||
|
||||
@@ -47,7 +47,11 @@ module.exports = {
|
||||
copyright: `Copyright © ${year} Streetwriters (Private) Limited`,
|
||||
artifactName: "notesnook_${os}_${arch}.${ext}",
|
||||
generateUpdatesFilesForAllChannels: true,
|
||||
asar: false,
|
||||
asar: true,
|
||||
asarUnpack: [
|
||||
"node_modules/sqlite-better-trigram-@(linux|darwin|windows)-${arch}/**/*",
|
||||
"node_modules/sqlite3-fts5-html-@(linux|darwin|windows)-${arch}/**/*"
|
||||
],
|
||||
files: [
|
||||
"!*.chunk.js.map",
|
||||
"!*.chunk.js.LICENSE.txt",
|
||||
|
||||
1644
apps/desktop/package-lock.json
generated
@@ -2,13 +2,15 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.2.1",
|
||||
"version": "3.3.8",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./dist/cjs/index.js",
|
||||
"module": "./dist/esm/index.js",
|
||||
"types": "./dist/types/index.d.ts",
|
||||
"sideEffects": false,
|
||||
"sideEffects": [
|
||||
"src/overrides.ts"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"require": {
|
||||
@@ -30,12 +32,12 @@
|
||||
"@notesnook/ui": "file:../../packages/ui",
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/server": "10.45.2",
|
||||
"better-sqlite3-multiple-ciphers": "11.3.0",
|
||||
"better-sqlite3-multiple-ciphers": "^12.4.1",
|
||||
"electron-trpc": "0.7.1",
|
||||
"electron-updater": "^6.6.2",
|
||||
"icojs": "^0.19.5",
|
||||
"sqlite-better-trigram": "0.0.3",
|
||||
"sqlite3-fts5-html": "^0.0.3",
|
||||
"sqlite-better-trigram": "0.0.5",
|
||||
"sqlite3-fts5-html": "^0.0.6",
|
||||
"typed-emitter": "^2.1.0",
|
||||
"yargs": "^17.7.2",
|
||||
"zod": "3.24.3"
|
||||
@@ -45,7 +47,7 @@
|
||||
"@types/node": "22.15.3",
|
||||
"@types/yargs": "^17.0.33",
|
||||
"chokidar": "^4.0.3",
|
||||
"electron": "^34.0.0",
|
||||
"electron": "^37.0.0",
|
||||
"electron-builder": "^26.0.12",
|
||||
"esbuild": "0.21.5",
|
||||
"node-abi": "^4.5.0",
|
||||
@@ -55,7 +57,7 @@
|
||||
"slugify": "1.6.6",
|
||||
"tree-kill": "^1.2.2",
|
||||
"undici": "^7.8.0",
|
||||
"vitest": "2.1.8"
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"dmg-license": "^1.0.11"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/node_modules/better-sqlite3-multiple-ciphers/deps/defines.gypi b/node_modules/better-sqlite3-multiple-ciphers/deps/defines.gypi
|
||||
index 1a14ecd..dabcce2 100644
|
||||
index 1a14ecd..ff938f1 100644
|
||||
--- a/node_modules/better-sqlite3-multiple-ciphers/deps/defines.gypi
|
||||
+++ b/node_modules/better-sqlite3-multiple-ciphers/deps/defines.gypi
|
||||
@@ -38,5 +38,6 @@
|
||||
@@ -17,6 +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/>.
|
||||
*/
|
||||
|
||||
console.log("starting build...");
|
||||
import path from "path";
|
||||
import fs from "fs/promises";
|
||||
import { existsSync } from "fs";
|
||||
@@ -26,6 +27,7 @@ import * as childProcess from "child_process";
|
||||
import { fileURLToPath } from "url";
|
||||
import { patchBetterSQLite3 } from "./patch-better-sqlite3.mjs";
|
||||
|
||||
console.log("imports done...");
|
||||
const args = yargs(process.argv);
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -34,11 +36,22 @@ const skipTscBuild = args.skipTscBuild || false;
|
||||
|
||||
const webAppPath = path.resolve(path.join(__dirname, "..", "..", "web"));
|
||||
|
||||
console.log("loaded args", {
|
||||
args,
|
||||
__filename,
|
||||
__dirname,
|
||||
root,
|
||||
skipTscBuild,
|
||||
webAppPath
|
||||
});
|
||||
await fs.rm(path.join(root, "build"), { force: true, recursive: true });
|
||||
|
||||
console.log("removed build folder");
|
||||
|
||||
if (args.rebuild || !existsSync(path.join(webAppPath, "build"))) {
|
||||
console.log("rebuilding...");
|
||||
await exec(
|
||||
"npx nx build:desktop @notesnook/web",
|
||||
"node scripts/execute.mjs @notesnook/web:build:desktop",
|
||||
path.join(__dirname, "..", "..", "..")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ export class SQLite {
|
||||
initialized = false;
|
||||
preparedStatements: Map<string, Statement<unknown[]>> = new Map();
|
||||
retryCounter: Record<string, number> = {};
|
||||
extensionsLoaded = false;
|
||||
|
||||
constructor() {
|
||||
console.log("new sqlite worker");
|
||||
}
|
||||
@@ -46,10 +48,6 @@ export class SQLite {
|
||||
this.sqlite = require("better-sqlite3-multiple-ciphers")(
|
||||
filePath
|
||||
).unsafeMode(true);
|
||||
const betterTrigram = require("sqlite-better-trigram");
|
||||
const fts5Html = require("sqlite3-fts5-html");
|
||||
betterTrigram.load(this.sqlite);
|
||||
fts5Html.load(this.sqlite);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,9 +115,29 @@ export class SQLite {
|
||||
} catch (e) {
|
||||
if (e instanceof Error) e.message += ` (query: ${sql})`;
|
||||
throw e;
|
||||
} finally {
|
||||
// Since SQLite 3.48.0 (SQLite3MC v2.0.2) it's not possible to load fts5
|
||||
// extensions before database has been decrypting. This is because
|
||||
// executing a `SELECT` now accesses the underlying databases resulting in
|
||||
// an error. Since FTS5 extensions depend on `SELECT fts5` to load the
|
||||
// fts5 API, we must wait decrypt the database before we can load
|
||||
// the extensions.
|
||||
if (!this.extensionsLoaded && (await this.isDatabaseReady())) {
|
||||
this.loadExtensions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private loadExtensions() {
|
||||
this.sqlite?.loadExtension(
|
||||
getExtensionPath("sqlite-better-trigram", "better-trigram")
|
||||
);
|
||||
this.sqlite?.loadExtension(
|
||||
getExtensionPath("sqlite3-fts5-html", "fts5-html")
|
||||
);
|
||||
this.extensionsLoaded = true;
|
||||
}
|
||||
|
||||
async run<R>(
|
||||
sql: string,
|
||||
parameters?: SQLiteCompatibleType[]
|
||||
@@ -144,4 +162,53 @@ export class SQLite {
|
||||
retryDelay: 500
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This just executes `SELECT 1` on the database to make sure its ready.
|
||||
* On an encrypted database, this will fail until `PRAGMA key` has been
|
||||
* called.
|
||||
*/
|
||||
private async isDatabaseReady() {
|
||||
// return this.exec(`SELECT 1;`)
|
||||
// .then(() => true)
|
||||
// .catch(() => false);
|
||||
if (!this.sqlite) return false;
|
||||
try {
|
||||
this.sqlite.prepare(`SELECT 1;`).run();
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getExtensionPath(extensionName: string, entryPoint: string) {
|
||||
const path = require("path");
|
||||
const { statSync } = require("fs");
|
||||
|
||||
const os = process.platform === "win32" ? "windows" : process.platform;
|
||||
const packageName = `${extensionName}-${os}-${process.arch}`;
|
||||
const extensionSuffix =
|
||||
process.platform === "win32"
|
||||
? "dll"
|
||||
: process.platform === "darwin"
|
||||
? "dylib"
|
||||
: "so";
|
||||
let loadablePath = path.join(
|
||||
require.resolve(extensionName),
|
||||
"..",
|
||||
"..",
|
||||
packageName,
|
||||
`${entryPoint}.${extensionSuffix}`
|
||||
);
|
||||
|
||||
if (loadablePath.includes(".asar"))
|
||||
loadablePath = loadablePath
|
||||
.replace("electron.asar", "app.asar")
|
||||
.replace(".asar", ".asar.unpacked");
|
||||
|
||||
if (!statSync(loadablePath, { throwIfNoEntry: false })) {
|
||||
throw new Error(`${extensionName} not found at ${loadablePath}.`);
|
||||
}
|
||||
return loadablePath;
|
||||
}
|
||||
|
||||
@@ -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 { app, BrowserWindow, nativeTheme, shell } from "electron";
|
||||
import "./overrides";
|
||||
import { app, BrowserWindow, nativeTheme, shell, dialog } from "electron";
|
||||
import { isDevelopment } from "./utils";
|
||||
import { registerProtocol, PROTOCOL_URL } from "./utils/protocol";
|
||||
import { configureAutoUpdater } from "./utils/autoupdater";
|
||||
@@ -181,6 +182,17 @@ async function createWindow() {
|
||||
app.once("ready", async () => {
|
||||
console.info("App ready. Opening window.");
|
||||
|
||||
if (app.runningUnderARM64Translation) {
|
||||
console.log("App is running under ARM64 translation");
|
||||
dialog.showMessageBoxSync({
|
||||
message:
|
||||
"Notesnook detected that it is running under ARM64 translation. For the best performance, please download the ARM64 build of Notesnook from our website.",
|
||||
type: "warning",
|
||||
buttons: ["Okay"],
|
||||
title: "Degraded Performance Warning"
|
||||
});
|
||||
}
|
||||
|
||||
if (config.customDns) enableCustomDns();
|
||||
else disableCustomDns();
|
||||
|
||||
|
||||
41
apps/desktop/src/overrides.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { app } from "electron";
|
||||
import path from "path";
|
||||
|
||||
const customVersion = process.env.CUSTOM_APP_VERSION;
|
||||
if (customVersion) {
|
||||
app.getVersion = () => customVersion;
|
||||
console.log("setting custom version:", customVersion);
|
||||
}
|
||||
|
||||
if (process.env.CUSTOM_USER_DATA_DIR) {
|
||||
app.setPath(
|
||||
"appData",
|
||||
path.join(process.env.CUSTOM_USER_DATA_DIR, "AppData")
|
||||
);
|
||||
app.setPath(
|
||||
"userData",
|
||||
path.join(process.env.CUSTOM_USER_DATA_DIR, "UserData")
|
||||
);
|
||||
app.setPath(
|
||||
"documents",
|
||||
path.join(process.env.CUSTOM_USER_DATA_DIR, "Documents")
|
||||
);
|
||||
}
|
||||
@@ -39,7 +39,7 @@ const LINUX_AUTOSTART_DIRECTORY_PATH = path.join(
|
||||
"autostart"
|
||||
);
|
||||
|
||||
const STARTUP_ARGS = ["--hidden"];
|
||||
const HIDDEN_ARG = "--hidden";
|
||||
|
||||
export class AutoLaunch {
|
||||
static enable(hidden: boolean) {
|
||||
@@ -54,13 +54,13 @@ export class AutoLaunch {
|
||||
);
|
||||
} else {
|
||||
const loginItemSettings = app.getLoginItemSettings({
|
||||
args: STARTUP_ARGS
|
||||
args: hidden ? [HIDDEN_ARG] : undefined
|
||||
});
|
||||
if (loginItemSettings.openAtLogin) return;
|
||||
app.setLoginItemSettings({
|
||||
openAtLogin: true,
|
||||
openAsHidden: hidden,
|
||||
args: STARTUP_ARGS
|
||||
args: hidden ? [HIDDEN_ARG] : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,13 @@ import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
testTimeout: process.env.CI ? 120 * 1000 : 120 * 1000,
|
||||
testTimeout: 120 * 1000,
|
||||
hookTimeout: 120 * 1000,
|
||||
sequence: {
|
||||
concurrent: true,
|
||||
shuffle: true
|
||||
},
|
||||
globalSetup: "./__tests__/global-setup.ts",
|
||||
dir: "./__tests__/",
|
||||
exclude: [
|
||||
"**/node_modules/**",
|
||||
|
||||
92
apps/mobile/.detoxrc.js
Normal file
@@ -0,0 +1,92 @@
|
||||
/** @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-arm64-v8a-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-arm64-v8a-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 17 Pro Max"
|
||||
}
|
||||
},
|
||||
attached: {
|
||||
type: "android.attached",
|
||||
device: {
|
||||
adbName: ".*"
|
||||
}
|
||||
},
|
||||
emulator: {
|
||||
type: "android.emulator",
|
||||
device: {
|
||||
avdName: "Pixel_5_API_36"
|
||||
}
|
||||
}
|
||||
},
|
||||
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"
|
||||
}
|
||||
}
|
||||
};
|
||||
13
apps/mobile/.gitignore
vendored
@@ -4,7 +4,7 @@ artifacts/
|
||||
#
|
||||
.DS_Store
|
||||
|
||||
native/android/app/src/main/assets/
|
||||
android/app/src/main/assets/
|
||||
*Issues.md
|
||||
build_cache/
|
||||
#
|
||||
@@ -16,11 +16,12 @@ build_cache/
|
||||
.cxx/
|
||||
*.keystore
|
||||
!debug.keystore
|
||||
.kotlin/
|
||||
|
||||
# Xcode
|
||||
#
|
||||
native/ios/Pods
|
||||
native/ios/DerivedData
|
||||
ios/Pods
|
||||
ios/DerivedData
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
@@ -39,7 +40,7 @@ DerivedData
|
||||
*.xcuserstate
|
||||
*.hprof
|
||||
**/.xcode.env.local
|
||||
native/cache
|
||||
cache
|
||||
# Android/IntelliJ
|
||||
#
|
||||
rn-build-deps/
|
||||
@@ -57,7 +58,7 @@ yarn-error.log
|
||||
# BUCK
|
||||
buck-out/
|
||||
\.buckd/
|
||||
*.keystore
|
||||
|
||||
|
||||
# fastlane
|
||||
#
|
||||
@@ -69,7 +70,7 @@ buck-out/
|
||||
*/fastlane/report.xml
|
||||
*/fastlane/Preview.html
|
||||
*/fastlane/screenshots
|
||||
native/vendor
|
||||
vendor
|
||||
|
||||
# Bundle artifact
|
||||
*.jsbundle
|
||||
|
||||
@@ -8,3 +8,9 @@ gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
|
||||
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
|
||||
gem 'xcodeproj', '< 1.26.0'
|
||||
gem 'concurrent-ruby', '< 1.3.4'
|
||||
|
||||
# Ruby 3.4.0 has removed some libraries from the standard library.
|
||||
gem 'bigdecimal'
|
||||
gem 'logger'
|
||||
gem 'benchmark'
|
||||
gem 'mutex_m'
|
||||
@@ -109,8 +109,12 @@ PLATFORMS
|
||||
|
||||
DEPENDENCIES
|
||||
activesupport (>= 6.1.7.5, != 7.1.0)
|
||||
benchmark
|
||||
bigdecimal
|
||||
cocoapods (>= 1.13, != 1.15.1, != 1.15.0)
|
||||
concurrent-ruby (< 1.3.4)
|
||||
logger
|
||||
mutex_m
|
||||
xcodeproj (< 1.26.0)
|
||||
|
||||
RUBY VERSION
|
||||
@@ -1,6 +1,7 @@
|
||||
apply plugin: "com.android.application"
|
||||
apply plugin: "org.jetbrains.kotlin.android"
|
||||
apply plugin: "com.facebook.react"
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
|
||||
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
|
||||
|
||||
@@ -11,13 +12,13 @@ import org.apache.tools.ant.taskdefs.condition.Os
|
||||
react {
|
||||
/* Folders */
|
||||
// The root of your project, i.e. where "package.json" lives. Default is '..'
|
||||
root = file("$rootDir/../")
|
||||
//root = file("$rootDir/..")
|
||||
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
|
||||
reactNativeDir = file("$rootDir/../../node_modules/react-native")
|
||||
//reactNativeDir = file("$rootDir/../node_modules/react-native")
|
||||
// The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
|
||||
codegenDir = file("$rootDir/../../node_modules/react-native-codegen")
|
||||
//codegenDir = file("$rootDir/../node_modules/react-native-codegen")
|
||||
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
|
||||
cliFile = file("$rootDir/../../node_modules/react-native/cli.js")
|
||||
// cliFile = file("$rootDir/../node_modules/react-native/cli.js")
|
||||
/* Variants */
|
||||
// The list of variants to that are debuggable. For those we're going to
|
||||
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
|
||||
@@ -44,7 +45,7 @@ react {
|
||||
// extraPackagerArgs = []
|
||||
/* Hermes Commands */
|
||||
// The hermes compiler command to run. By default it is 'hermesc'
|
||||
hermesCommand = "$rootDir/../../node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc"
|
||||
hermesCommand = "$rootDir/../node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc"
|
||||
//
|
||||
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
|
||||
hermesFlags = ["-O", "-output-source-map"]
|
||||
@@ -72,14 +73,14 @@ def enableProguardInReleaseBuilds = true
|
||||
* The preferred build flavor of JavaScriptCore.
|
||||
*
|
||||
* For example, to use the international variant, you can use:
|
||||
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
|
||||
* `def jscFlavor = io.github.react-native-community:jsc-android-intl:2026004.+`
|
||||
*
|
||||
* The international variant includes ICU i18n library and necessary data
|
||||
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
|
||||
* give correct results when using with locales other than en-US. Note that
|
||||
* this variant is about 6MiB larger per architecture than default.
|
||||
*/
|
||||
def jscFlavor = 'org.webkit:android-jsc:+'
|
||||
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
|
||||
|
||||
/**
|
||||
* Architectures to build native code for.
|
||||
@@ -94,7 +95,7 @@ def fdroidBuild() {
|
||||
}
|
||||
|
||||
def getNpmVersion() {
|
||||
def inputFile = file("$rootDir/../../package.json")
|
||||
def inputFile = file("$rootDir/../package.json")
|
||||
def jsonPackage = new JsonSlurper().parseText(inputFile.text)
|
||||
print(jsonPackage["version"])
|
||||
return jsonPackage["version"]
|
||||
@@ -124,7 +125,7 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
multiDexEnabled true
|
||||
versionCode 3057
|
||||
versionCode 3091
|
||||
versionName getNpmVersion()
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
@@ -165,7 +166,7 @@ android {
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
shrinkResources false
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
proguardFile "${rootProject.projectDir}/../../node_modules/detox/android/detox/proguard-rules-app.pro"
|
||||
proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro"
|
||||
buildConfigField "boolean", "FDROID_BUILD", "${fdroidBuild()}"
|
||||
|
||||
}
|
||||
@@ -221,6 +222,8 @@ dependencies {
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.2'
|
||||
implementation 'com.squareup.okhttp3:okhttp-urlconnection:4.9.2'
|
||||
implementation 'com.google.code.gson:gson:2.11.0'
|
||||
|
||||
implementation project(":react-native-config")
|
||||
|
||||
androidTestImplementation('com.wix:detox:+')
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
@@ -232,16 +235,14 @@ dependencies {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
task deleteFiles(type: Delete) {
|
||||
delete './src/main/assets/static'
|
||||
}
|
||||
|
||||
task copyEditorBundle(type: Copy) {
|
||||
from '../../../../../packages/editor-mobile/build.bundle'
|
||||
from '../../../../packages/editor-mobile/build.bundle'
|
||||
into './src/main/assets'
|
||||
}
|
||||
|
||||
BIN
apps/mobile/android/app/debug.keystore
Normal file
@@ -63,4 +63,7 @@
|
||||
-keepattributes Signature
|
||||
-keep class com.google.gson.reflect.TypeToken { *; }
|
||||
-keep class * extends com.google.gson.reflect.TypeToken
|
||||
-keep class com.streetwriters.notesnook.datatypes.* { *; }
|
||||
-keep class com.streetwriters.notesnook.datatypes.* { *; }
|
||||
|
||||
-keep class net.gotev.uploadservice.* { *; }
|
||||
-keep class kotlinx.parcelize.* { *; }
|
||||
@@ -11,57 +11,68 @@
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
tools:node="remove" />
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission
|
||||
android:name="android.permission.USE_FULL_SCREEN_INTENT"
|
||||
tools:node="remove" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false" />
|
||||
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="application/pdf" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="text/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="image/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="application/pdf" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="text/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="image/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
|
||||
<data android:mimeType="video/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="audio/*" />
|
||||
</intent>
|
||||
</queries>
|
||||
<data android:mimeType="video/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="audio/*" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:theme="@style/BootTheme"
|
||||
android:largeHeap="true"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:supportsRtl="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config">
|
||||
|
||||
<receiver android:exported="false" android:label="@string/quick_note" android:name=".NoteWidget">
|
||||
android:theme="@style/BootTheme">
|
||||
|
||||
<receiver
|
||||
android:name=".NoteWidget"
|
||||
android:exported="false"
|
||||
android:label="@string/quick_note">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
@@ -71,7 +82,10 @@
|
||||
android:resource="@xml/new_note_widget_info" />
|
||||
</receiver>
|
||||
|
||||
<receiver android:exported="false" android:label="@string/note" android:name=".NotePreviewWidget">
|
||||
<receiver
|
||||
android:name=".NotePreviewWidget"
|
||||
android:exported="false"
|
||||
android:label="@string/note">
|
||||
<intent-filter>"
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
@@ -81,7 +95,10 @@
|
||||
android:resource="@xml/note_widget_info" />
|
||||
</receiver>
|
||||
|
||||
<receiver android:exported="false" android:label="@string/reminders_title" android:name=".ReminderWidgetProvider">
|
||||
<receiver
|
||||
android:name=".ReminderWidgetProvider"
|
||||
android:exported="false"
|
||||
android:label="@string/reminders_title">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
@@ -90,33 +107,37 @@
|
||||
android:resource="@xml/widget_reminders_info" />
|
||||
</receiver>
|
||||
|
||||
<activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
<activity
|
||||
android:name=".NotePreviewConfigureActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
android:exported="true"
|
||||
android:label="NotePreviewConfigure"
|
||||
android:launchMode="singleTask"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:windowSoftInputMode="adjustResize" android:name=".NotePreviewConfigureActivity">
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask"
|
||||
android:resizeableActivity="true"
|
||||
android:exported="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:label="Notesnook">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
@@ -127,29 +148,32 @@
|
||||
|
||||
<intent-filter android:label="Notesnook">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="com.streetwriters.notesnook" />
|
||||
<data android:scheme="notesnook" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
<activity android:exported="false" android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
<activity
|
||||
android:name="com.facebook.react.devsupport.DevSettingsActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ShareActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true"
|
||||
android:label="@string/title_activity_share"
|
||||
android:noHistory="true"
|
||||
android:screenOrientation="unspecified"
|
||||
android:exported="true"
|
||||
android:taskAffinity=""
|
||||
android:excludeFromRecents="true"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:theme="@style/AppThemeB">
|
||||
android:theme="@style/AppThemeB"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
|
||||
<intent-filter android:label="Make Note">
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="text/*" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="video/*" />
|
||||
@@ -160,6 +184,7 @@
|
||||
<intent-filter android:label="Make Note">
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="text/*" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="video/*" />
|
||||
@@ -179,35 +204,41 @@
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:stopWithTask="false" />
|
||||
<service android:name="com.asterinet.react.bgactions.RNBackgroundActionsTask" />
|
||||
<service android:name="com.asterinet.react.bgactions.RNBackgroundActionsTask" />
|
||||
|
||||
<service android:name="com.streetwriters.notesnook.BootTaskService" android:foregroundServiceType="dataSync" />
|
||||
<service
|
||||
android:name="com.streetwriters.notesnook.BootTaskService"
|
||||
android:foregroundServiceType="specialUse">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="The service is required by the app to restore notifications of pinned notes, restore notification with reply input for creating notes and restore data in note preview widgets on device reboot." />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".NotesnookTileService"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/add_note"
|
||||
android:label="New note"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE"/>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".ReminderViewsService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
<service
|
||||
android:name=".ReminderViewsService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_viewer_provider_paths" />
|
||||
</provider>
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_viewer_provider_paths" />
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name="com.vinzscam.reactnativefileviewer.FileProvider"
|
||||
@@ -219,12 +250,14 @@
|
||||
android:resource="@xml/file_viewer_provider_paths" />
|
||||
</provider>
|
||||
|
||||
<receiver android:exported="true" android:name=".BootRecieverService">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".BootRecieverService"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
</application>
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@@ -39,7 +39,6 @@ public class BootTaskService extends HeadlessJsTaskService {
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel("com.streetwriters.notesnook",
|
||||
"Default",
|
||||
@@ -55,7 +54,7 @@ public class BootTaskService extends HeadlessJsTaskService {
|
||||
this.startForeground(
|
||||
1,
|
||||
notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);
|
||||
} else {
|
||||
this.startForeground(
|
||||
1,
|
||||
@@ -3,8 +3,16 @@ package com.streetwriters.notesnook;
|
||||
import com.facebook.react.ReactActivity;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import androidx.core.graphics.Insets;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import androidx.core.view.OnApplyWindowInsetsListener;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import com.facebook.react.ReactActivityDelegate;
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
|
||||
import com.facebook.react.defaults.DefaultReactActivityDelegate;
|
||||
@@ -12,8 +20,9 @@ import com.zoontek.rnbootsplash.RNBootSplash;
|
||||
|
||||
public class MainActivity extends ReactActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
RNBootSplash.init(this);
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
RNBootSplash.init(this, R.style.BootTheme);
|
||||
|
||||
super.onCreate(null);
|
||||
if (BuildConfig.DEBUG) {
|
||||
WebView.setWebContentsDebuggingEnabled(true);
|
||||
@@ -22,6 +31,7 @@ public class MainActivity extends ReactActivity {
|
||||
try {
|
||||
startService(new Intent(getBaseContext(), OnClearFromRecentService.class));
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,20 +47,20 @@ public class MainActivity extends ReactActivity {
|
||||
DefaultNewArchitectureEntryPoint.getFabricEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
}
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getReactInstanceManager().onConfigurationChanged(this, newConfig);
|
||||
Intent intent = new Intent("onConfigurationChanged");
|
||||
intent.putExtra("newConfig", newConfig);
|
||||
this.sendBroadcast(intent);
|
||||
}
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getReactHost().onConfigurationChanged(this);
|
||||
Intent intent = new Intent("onConfigurationChanged");
|
||||
intent.putExtra("newConfig", newConfig);
|
||||
this.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMainComponentName() {
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.streetwriters.notesnook
|
||||
|
||||
import android.app.Application
|
||||
import com.facebook.react.PackageList
|
||||
import com.facebook.react.ReactApplication
|
||||
import com.facebook.react.ReactHost
|
||||
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
|
||||
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
|
||||
import org.wonday.orientation.OrientationActivityLifecycle;
|
||||
class MainApplication : Application(), ReactApplication {
|
||||
override val reactHost: ReactHost by lazy {
|
||||
getDefaultReactHost(
|
||||
context = applicationContext,
|
||||
packageList =
|
||||
PackageList(this).packages.apply {
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
// add(MyReactNativePackage())
|
||||
add(NNativeModulePackage());
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
registerActivityLifecycleCallbacks(OrientationActivityLifecycle.getInstance());
|
||||
loadReactNative(this)
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public class NotePreviewWidget extends AppWidgetProvider {
|
||||
intent.putExtra(OpenNoteId, note.getId());
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.putExtra(RCTNNativeModule.IntentType, "OpenNote");
|
||||
intent.setData(Uri.parse("https://notesnook.com/open_note?id=" + note.getId()));
|
||||
intent.setData(Uri.parse("https://app.notesnook.com/open_note?id=" + note.getId()));
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE, getActivityOptionsBundle());
|
||||
views.setOnClickPendingIntent(R.id.open_note, pendingIntent);
|
||||
|
||||
@@ -0,0 +1,465 @@
|
||||
package com.streetwriters.notesnook;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.streetwriters.notesnook.datatypes.Note;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class RCTNNativeModule extends ReactContextBaseJavaModule {
|
||||
Intent lastIntent;
|
||||
ReactContext mContext;
|
||||
static String IntentType = "com.streetwriters.notesnook.IntentType";
|
||||
|
||||
public RCTNNativeModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
mContext = reactContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "NNativeModule";
|
||||
}
|
||||
|
||||
|
||||
@ReactMethod
|
||||
public void setBackgroundColor(final String color) {
|
||||
try {
|
||||
getCurrentActivity().getWindow().getDecorView().setBackgroundColor(Color.parseColor(color));
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getActivityName(Promise promise) {
|
||||
try {
|
||||
promise.resolve(getCurrentActivity().getClass().getSimpleName());
|
||||
} catch (Exception e) {
|
||||
promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setSecureMode(final boolean mode) {
|
||||
try {
|
||||
|
||||
getCurrentActivity().runOnUiThread(() -> {
|
||||
|
||||
try {
|
||||
if (mode)
|
||||
getCurrentActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||
else
|
||||
getCurrentActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
});
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setAppState(final String appState) {
|
||||
SharedPreferences appStateDetails = getReactApplicationContext().getSharedPreferences("appStateDetails", Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor edit = appStateDetails.edit();
|
||||
edit.putString("appState", appState);
|
||||
edit.apply();
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public String getAppState() {
|
||||
SharedPreferences appStateDetails = getReactApplicationContext().getSharedPreferences("appStateDetails", Context.MODE_PRIVATE);
|
||||
String appStateValue = appStateDetails.getString("appState", "");
|
||||
return appStateValue.isEmpty() ? null : appStateValue;
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public int getWidgetId() {
|
||||
return NotePreviewConfigureActivity.appWidgetId;
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setString(final String storeName, final String key, final String value) {
|
||||
SharedPreferences details = getReactApplicationContext().getSharedPreferences(storeName, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor edit = details.edit();
|
||||
edit.putString(key, value);
|
||||
edit.apply();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void removeString(final String storeName, final String key) {
|
||||
SharedPreferences details = getReactApplicationContext().getSharedPreferences(storeName, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor edit = details.edit();
|
||||
edit.remove(key);
|
||||
edit.apply();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getString(final String storeName, final String key, Promise promise) {
|
||||
SharedPreferences details = getReactApplicationContext().getSharedPreferences(storeName, Context.MODE_PRIVATE);
|
||||
String value = details.getString(key, "");
|
||||
promise.resolve(value.isEmpty() ? null : value);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void saveAndFinish() {
|
||||
NotePreviewConfigureActivity.saveAndFinish(mContext);
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public WritableMap getIntent() {
|
||||
WritableMap map = Arguments.createMap();
|
||||
if (getCurrentActivity() != null) {
|
||||
Intent intent = getCurrentActivity().getIntent();
|
||||
Bundle extras = getCurrentActivity().getIntent().getExtras();
|
||||
|
||||
if (extras != null && intent != lastIntent) {
|
||||
lastIntent = intent;
|
||||
if (Objects.equals(extras.getString(IntentType), "NewReminder")) {
|
||||
map.putString(ReminderWidgetProvider.NewReminder, extras.getString(ReminderWidgetProvider.NewReminder));
|
||||
} else if (Objects.equals(extras.getString(IntentType), "OpenReminder")) {
|
||||
map.putString(ReminderViewsService.OpenReminderId, extras.getString(ReminderViewsService.OpenReminderId));
|
||||
} else if (Objects.equals(extras.getString(IntentType), "OpenNote")) {
|
||||
map.putString(NotePreviewWidget.OpenNoteId, extras.getString(NotePreviewWidget.OpenNoteId));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void cancelAndFinish() {
|
||||
NotePreviewConfigureActivity.activity.setResult(Activity.RESULT_CANCELED);
|
||||
NotePreviewConfigureActivity.activity.finish();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getWidgetNotes(Promise promise) {
|
||||
SharedPreferences pref = getReactApplicationContext().getSharedPreferences("appPreview", Context.MODE_PRIVATE);
|
||||
Map<String, ?> map = pref.getAll();
|
||||
WritableArray arr = Arguments.createArray();
|
||||
for(Map.Entry<String,?> entry : map.entrySet()){
|
||||
if (entry.getKey().equals("remindersList")) continue;
|
||||
String value = (String) entry.getValue();
|
||||
Gson gson = new Gson();
|
||||
Note note = gson.fromJson(value, Note.class);
|
||||
arr.pushString(note.getId());
|
||||
}
|
||||
promise.resolve(arr);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void hasWidgetNote(final String noteId, Promise promise) {
|
||||
SharedPreferences pref = getReactApplicationContext().getSharedPreferences("appPreview", Context.MODE_PRIVATE);
|
||||
Map<String, ?> map = pref.getAll();
|
||||
boolean found = false;
|
||||
for(Map.Entry<String,?> entry : map.entrySet()){
|
||||
String value = (String) entry.getValue();
|
||||
if (value.contains(noteId)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
promise.resolve(found);
|
||||
}
|
||||
@ReactMethod
|
||||
public void updateWidgetNote(final String noteId, final String data) {
|
||||
SharedPreferences pref = getReactApplicationContext().getSharedPreferences("appPreview", Context.MODE_PRIVATE);
|
||||
Map<String, ?> map = pref.getAll();
|
||||
SharedPreferences.Editor edit = pref.edit();
|
||||
ArrayList<String> ids = new ArrayList<>();
|
||||
for(Map.Entry<String,?> entry : map.entrySet()) {
|
||||
String value = (String) entry.getValue();
|
||||
if (value.contains(noteId)) {
|
||||
edit.putString(entry.getKey(), data);
|
||||
ids.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
edit.apply();
|
||||
for (String id: ids) {
|
||||
NotePreviewWidget.updateAppWidget(mContext, AppWidgetManager.getInstance(mContext), Integer.parseInt(id));
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void updateReminderWidget() {
|
||||
AppWidgetManager wm = AppWidgetManager.getInstance(mContext);
|
||||
int[] ids = wm.getAppWidgetIds(ComponentName.createRelative(mContext.getPackageName(), ReminderWidgetProvider.class.getName()));
|
||||
for (int id: ids) {
|
||||
Log.d("Reminders", "Updating" + id);
|
||||
RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.widget_reminders);
|
||||
ReminderWidgetProvider.updateAppWidget(mContext, wm, id, views);
|
||||
wm.notifyAppWidgetViewDataChanged(id, R.id.widget_list_view);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public boolean isGestureNavigationEnabled() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
try {
|
||||
String navBarMode = Settings.Secure.getString(
|
||||
mContext.getContentResolver(),
|
||||
"navigation_mode"
|
||||
);
|
||||
return "2".equals(navBarMode);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void addShortcut(final String id, final String type, final String title, final String description, final String color, Promise promise) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
promise.reject("UNSUPPORTED", "Pinned launcher shortcuts require Android 8.0 or higher");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ShortcutManager shortcutManager = mContext.getSystemService(ShortcutManager.class);
|
||||
if (shortcutManager == null) {
|
||||
promise.reject("ERROR", "ShortcutManager not available");
|
||||
return;
|
||||
}
|
||||
|
||||
String uri = "https://app.notesnook.com/open_" + type + "?id=" + id;
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(uri));
|
||||
intent.setPackage(mContext.getPackageName());
|
||||
|
||||
Icon icon = createLetterIcon(type, title, color);
|
||||
ShortcutInfo shortcut = new ShortcutInfo.Builder(mContext, id)
|
||||
.setShortLabel(title)
|
||||
.setLongLabel(description != null && !description.isEmpty() ? description : title)
|
||||
.setIcon(icon)
|
||||
.setCategories(Set.of(type))
|
||||
.setIntent(intent)
|
||||
.build();
|
||||
|
||||
shortcutManager.requestPinShortcut(shortcut, null);
|
||||
promise.resolve(true);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void removeShortcut(final String id, Promise promise) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
promise.reject("UNSUPPORTED", "Pinned launcher shortcuts require Android 8.0 or higher");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ShortcutManager shortcutManager = mContext.getSystemService(ShortcutManager.class);
|
||||
if (shortcutManager == null) {
|
||||
promise.reject("ERROR", "ShortcutManager not available");
|
||||
return;
|
||||
}
|
||||
|
||||
shortcutManager.disableShortcuts(java.util.Collections.singletonList(id));
|
||||
promise.resolve(true);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void updateShortcut(final String id, final String type, final String title, final String description,final String color, Promise promise) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
promise.reject("UNSUPPORTED", "Pinned launcher shortcuts require Android 8.0 or higher");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ShortcutManager shortcutManager = mContext.getSystemService(ShortcutManager.class);
|
||||
if (shortcutManager == null) {
|
||||
promise.reject("ERROR", "ShortcutManager not available");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get existing shortcut to preserve icon and intent
|
||||
List<ShortcutInfo> shortcuts = shortcutManager.getPinnedShortcuts();
|
||||
ShortcutInfo existingShortcut = null;
|
||||
for (ShortcutInfo s : shortcuts) {
|
||||
if (s.getId().equals(id)) {
|
||||
existingShortcut = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (existingShortcut == null) {
|
||||
return;
|
||||
}
|
||||
Icon icon = createLetterIcon(type, title, color);
|
||||
ShortcutInfo updatedShortcut = new ShortcutInfo.Builder(mContext, id)
|
||||
.setShortLabel(title)
|
||||
.setIcon(icon)
|
||||
.setLongLabel(description != null && !description.isEmpty() ? description : title)
|
||||
.setIntent(existingShortcut.getIntent())
|
||||
.build();
|
||||
|
||||
shortcutManager.updateShortcuts(java.util.Collections.singletonList(updatedShortcut));
|
||||
promise.resolve(true);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void removeAllShortcuts(Promise promise) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
promise.reject("UNSUPPORTED", "Pinned launcher shortcuts require Android 8.0 or higher");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ShortcutManager shortcutManager = mContext.getSystemService(ShortcutManager.class);
|
||||
if (shortcutManager == null) {
|
||||
promise.reject("ERROR", "ShortcutManager not available");
|
||||
return;
|
||||
}
|
||||
|
||||
List<ShortcutInfo> pinnedShortcuts = shortcutManager.getPinnedShortcuts();
|
||||
if (!pinnedShortcuts.isEmpty()) {
|
||||
List<String> ids = new ArrayList<>();
|
||||
for (ShortcutInfo shortcut : pinnedShortcuts) {
|
||||
ids.add(shortcut.getId());
|
||||
}
|
||||
shortcutManager.disableShortcuts(ids);
|
||||
}
|
||||
promise.resolve(true);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getAllShortcuts(Promise promise) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return;
|
||||
}
|
||||
ShortcutManager shortcutManager = mContext.getSystemService(ShortcutManager.class);
|
||||
WritableArray shortcuts = Arguments.createArray();
|
||||
List<ShortcutInfo> infos = shortcutManager.getPinnedShortcuts();
|
||||
|
||||
for (ShortcutInfo info: infos) {
|
||||
WritableMap data = Arguments.createMap();
|
||||
data.putString("id", info.getId());
|
||||
if (info.getShortLabel() != null) {
|
||||
data.putString("title", info.getShortLabel().toString());
|
||||
}
|
||||
|
||||
if (info.getLongLabel() != null) {
|
||||
data.putString("description", info.getLongLabel().toString());
|
||||
}
|
||||
|
||||
|
||||
if (!Objects.requireNonNull(info.getCategories()).isEmpty()) {
|
||||
if (info.getCategories().contains("note")) {
|
||||
data.putString("type", "note");
|
||||
} else if (info.getCategories().contains("notebook")) {
|
||||
data.putString("type", "notebook");
|
||||
} else if (info.getCategories().contains("tag")) {
|
||||
data.putString("type", "tag");
|
||||
} else if (info.getCategories().contains("color")) {
|
||||
data.putString("type", "color");
|
||||
}
|
||||
}
|
||||
shortcuts.pushMap(data);
|
||||
}
|
||||
promise.resolve(shortcuts);
|
||||
}
|
||||
|
||||
private Icon createLetterIcon(String type, String title, String colorCode) {
|
||||
|
||||
String letter = type.contains("tag") ? "#" : title != null && !title.isEmpty()
|
||||
? title.substring(0, 1).toUpperCase()
|
||||
: "?";
|
||||
int color = type.equals("color") ? Color.parseColor(colorCode) : getColorForLetter(letter);
|
||||
|
||||
if (type.equals("notebook")) return Icon.createWithResource(mContext, R.drawable.ic_notebook);
|
||||
// Use a larger canvas and fill it completely to avoid white borders from launcher masking.
|
||||
int iconSize = 256;
|
||||
Bitmap bitmap = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
|
||||
if (type.equals("color")) {
|
||||
Paint backgroundPaint = new Paint();
|
||||
backgroundPaint.setColor(color);
|
||||
backgroundPaint.setAntiAlias(true);
|
||||
canvas.drawCircle(iconSize / 2, iconSize / 2, iconSize/2, backgroundPaint);
|
||||
} else {
|
||||
Paint textPaint = new Paint();
|
||||
textPaint.setColor(color);
|
||||
textPaint.setTextSize(130);
|
||||
textPaint.setAntiAlias(true);
|
||||
textPaint.setTextAlign(Paint.Align.CENTER);
|
||||
textPaint.setTypeface(android.graphics.Typeface.create(android.graphics.Typeface.DEFAULT, android.graphics.Typeface.BOLD));
|
||||
|
||||
float x = iconSize / 2f;
|
||||
float y = (iconSize / 2f) - ((textPaint.descent() + textPaint.ascent()) / 2f);
|
||||
|
||||
canvas.drawText(letter, x, y, textPaint);
|
||||
}
|
||||
|
||||
return Icon.createWithBitmap(bitmap);
|
||||
}
|
||||
|
||||
private int getColorForLetter(String letter) {
|
||||
int[] colors = {
|
||||
0xFF1976D2, // Blue
|
||||
0xFFD32F2F, // Red
|
||||
0xFF388E3C, // Green
|
||||
0xFFF57C00, // Orange
|
||||
0xFF7B1FA2, // Purple
|
||||
0xFF0097A7, // Cyan
|
||||
0xFFC2185B, // Pink
|
||||
0xFF455A64, // Blue Grey
|
||||
0xFF6A1B9A, // Deep Purple
|
||||
0xFF00796B, // Teal
|
||||
0xFF512DA8, // Indigo
|
||||
0xFF1565C0 // Dark Blue
|
||||
};
|
||||
|
||||
int hash = Math.abs(letter.hashCode());
|
||||
return colors[hash % colors.length];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -75,7 +75,7 @@ class ReminderRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactor
|
||||
final Intent fillInIntent = new Intent();
|
||||
final Bundle extras = new Bundle();
|
||||
extras.putString(ReminderViewsService.OpenReminderId, reminder.getId());
|
||||
fillInIntent.setData(Uri.parse("https://notesnook.com/open_reminder?id=" + reminder.getId()));
|
||||
fillInIntent.setData(Uri.parse("https://app.notesnook.com/open_reminder?id=" + reminder.getId()));
|
||||
fillInIntent.putExtra(RCTNNativeModule.IntentType, "OpenReminder");
|
||||
fillInIntent.putExtras(extras);
|
||||
views.setOnClickFillInIntent(R.id.reminder_item_btn, fillInIntent);
|
||||
@@ -43,7 +43,7 @@ public class ReminderWidgetProvider extends AppWidgetProvider {
|
||||
new_reminder_intent.putExtra(NewReminder, NewReminder);
|
||||
new_reminder_intent.setAction(Intent.ACTION_VIEW);
|
||||
new_reminder_intent.putExtra(RCTNNativeModule.IntentType, "NewReminder");
|
||||
new_reminder_intent.setData(Uri.parse("https://notesnook.com/new_reminder"));
|
||||
new_reminder_intent.setData(Uri.parse("https://app.notesnook.com/new_reminder"));
|
||||
PendingIntent pendingIntent2 = PendingIntent.getActivity(context, appWidgetId, new_reminder_intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE, getActivityOptionsBundle());
|
||||
views.setOnClickPendingIntent(R.id.add_button, pendingIntent2);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="#008837"
|
||||
android:alpha="1">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M240,880Q207,880 183.5,856.5Q160,833 160,800L160,160Q160,127 183.5,103.5Q207,80 240,80L720,80Q753,80 776.5,103.5Q800,127 800,160L800,800Q800,833 776.5,856.5Q753,880 720,880L240,880ZM240,800L720,800Q720,800 720,800Q720,800 720,800L720,160Q720,160 720,160Q720,160 720,160L640,160L640,440L540,380L440,440L440,160L240,160Q240,160 240,160Q240,160 240,160L240,800Q240,800 240,800Q240,800 240,800ZM240,800Q240,800 240,800Q240,800 240,800L240,160Q240,160 240,160Q240,160 240,160L240,160Q240,160 240,160Q240,160 240,160L240,800Q240,800 240,800Q240,800 240,800ZM440,440L540,380L640,440L640,440L540,380L440,440Z"/>
|
||||
</vector>
|
||||
|
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 229 B |
|
Before Width: | Height: | Size: 178 B After Width: | Height: | Size: 178 B |
|
After Width: | Height: | Size: 284 B |
|
Before Width: | Height: | Size: 509 B After Width: | Height: | Size: 509 B |
|
Before Width: | Height: | Size: 160 B After Width: | Height: | Size: 160 B |
|
Before Width: | Height: | Size: 112 B After Width: | Height: | Size: 112 B |
|
After Width: | Height: | Size: 211 B |
|
Before Width: | Height: | Size: 358 B After Width: | Height: | Size: 358 B |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 245 B After Width: | Height: | Size: 245 B |
|
Before Width: | Height: | Size: 150 B After Width: | Height: | Size: 150 B |
|
After Width: | Height: | Size: 440 B |
|
Before Width: | Height: | Size: 667 B After Width: | Height: | Size: 667 B |
|
Before Width: | Height: | Size: 331 B After Width: | Height: | Size: 331 B |
|
Before Width: | Height: | Size: 250 B After Width: | Height: | Size: 250 B |
|
After Width: | Height: | Size: 807 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |