Compare commits
787 Commits
mobile-rel
...
mobile-rel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0af831d50b | ||
|
|
3efaeaeeb9 | ||
|
|
eda284ca25 | ||
|
|
1ed331b4bb | ||
|
|
9621b43bf2 | ||
|
|
503c1a5c8d | ||
|
|
a2fa1d4d78 | ||
|
|
6c6ad9a766 | ||
|
|
fc8807f74d | ||
|
|
edec48f9d4 | ||
|
|
ce98551057 | ||
|
|
74a2cc5b19 | ||
|
|
9628a940e9 | ||
|
|
d48643cbb9 | ||
|
|
558beaf216 | ||
|
|
6cc5d2452b | ||
|
|
e934ef7ffd | ||
|
|
e2d8032ef4 | ||
|
|
81e6101fb5 | ||
|
|
070354920b | ||
|
|
404168fb86 | ||
|
|
d5fa9fd02b | ||
|
|
6cc66d91be | ||
|
|
20a3b3b95e | ||
|
|
9145ea4234 | ||
|
|
0fa79433bd | ||
|
|
5185273b38 | ||
|
|
eadd23de4d | ||
|
|
71d9738980 | ||
|
|
80328af888 | ||
|
|
5e83da5575 | ||
|
|
521afe90ca | ||
|
|
ee3b7b5d7d | ||
|
|
95a9775c26 | ||
|
|
93d1319b25 | ||
|
|
b2bac3808b | ||
|
|
ebf58e68cf | ||
|
|
dc3e909dfe | ||
|
|
bf09e9615a | ||
|
|
b2d30d47d6 | ||
|
|
b1296fd24f | ||
|
|
62d8c89300 | ||
|
|
80c44eee89 | ||
|
|
153eb126fc | ||
|
|
f1fc166713 | ||
|
|
dda36bb036 | ||
|
|
843ad08813 | ||
|
|
a0e3c923e4 | ||
|
|
3095b03b09 | ||
|
|
ea5a0e0a7c | ||
|
|
2b4ec5b03b | ||
|
|
59f7add065 | ||
|
|
9c7bfc2347 | ||
|
|
ef90f40be4 | ||
|
|
bca6a4f22c | ||
|
|
1d3e2b56b2 | ||
|
|
a93a20ed5b | ||
|
|
971a80c183 | ||
|
|
125b60facc | ||
|
|
ef99b47178 | ||
|
|
d65f870213 | ||
|
|
5b3f1c9de2 | ||
|
|
4afb090cb1 | ||
|
|
8cf6e65ed8 | ||
|
|
c85c51ec08 | ||
|
|
dbeabea6c5 | ||
|
|
dfbe2d0f0f | ||
|
|
ea2277ea4e | ||
|
|
ad78105a6e | ||
|
|
36584175e2 | ||
|
|
084b1fdfd2 | ||
|
|
bed091e20f | ||
|
|
4420663687 | ||
|
|
677ae82ffa | ||
|
|
48a3fac9e0 | ||
|
|
e797d37b01 | ||
|
|
ffafd2e787 | ||
|
|
8500c971eb | ||
|
|
46a67a56fb | ||
|
|
5dc62e6df2 | ||
|
|
4479d6cf56 | ||
|
|
1faaf1f6b1 | ||
|
|
1f33ef191a | ||
|
|
d5bf8a6e3c | ||
|
|
5c252c7843 | ||
|
|
d2e10ccaf6 | ||
|
|
89d2b6870f | ||
|
|
26a9086d96 | ||
|
|
9fc8e6b1e5 | ||
|
|
6718650619 | ||
|
|
a622949f23 | ||
|
|
5a2df5b2c1 | ||
|
|
ae751cdd65 | ||
|
|
0d00bb2866 | ||
|
|
4299965064 | ||
|
|
6f3fc8db3d | ||
|
|
db731856f8 | ||
|
|
217f1dd6d4 | ||
|
|
cf87929476 | ||
|
|
d343a0720e | ||
|
|
51bd58edb2 | ||
|
|
f778d83316 | ||
|
|
b169206c68 | ||
|
|
4cea69e71d | ||
|
|
04d422b411 | ||
|
|
49dec52aa0 | ||
|
|
b83a62814d | ||
|
|
ce5449f25a | ||
|
|
aa769a8921 | ||
|
|
a8d4e6c754 | ||
|
|
f2402cf086 | ||
|
|
07a481f002 | ||
|
|
f41638db6d | ||
|
|
82baf41d8e | ||
|
|
e60370d4dc | ||
|
|
3e412323ee | ||
|
|
d635c1a056 | ||
|
|
f02db2a024 | ||
|
|
8c74324ff8 | ||
|
|
f2230eb39b | ||
|
|
ab900ae5da | ||
|
|
1cf28c56c2 | ||
|
|
08cd33a0cf | ||
|
|
7b0d2a239d | ||
|
|
5d922d934c | ||
|
|
5bab9ea914 | ||
|
|
da06d7e636 | ||
|
|
aece140473 | ||
|
|
656f87e3c6 | ||
|
|
36a95616d9 | ||
|
|
60bdc4715d | ||
|
|
7da168ab52 | ||
|
|
b20ad48b31 | ||
|
|
8b17495f0e | ||
|
|
e113e1b59c | ||
|
|
6bd4924c0b | ||
|
|
a2939aa183 | ||
|
|
effa726b65 | ||
|
|
20d9bf1f23 | ||
|
|
09e5d014df | ||
|
|
add1b8a68a | ||
|
|
fe143f66b7 | ||
|
|
75c8ca29ef | ||
|
|
c52779df23 | ||
|
|
b7b77646e6 | ||
|
|
1157c6b7cd | ||
|
|
ab824d7f66 | ||
|
|
702e28a6e6 | ||
|
|
0e0ab58959 | ||
|
|
e5cdc9ea3d | ||
|
|
d3c9744e65 | ||
|
|
6b02144b30 | ||
|
|
91cbc5ddf0 | ||
|
|
93aa1ca5aa | ||
|
|
6ae13ebb2f | ||
|
|
73cdbf64c7 | ||
|
|
0aeea965c0 | ||
|
|
a63b15637f | ||
|
|
5153b43bc6 | ||
|
|
9ea7d09722 | ||
|
|
b7b474b245 | ||
|
|
e2184a8bdf | ||
|
|
9ea84ca9ae | ||
|
|
50136e3689 | ||
|
|
e87f5e5f89 | ||
|
|
d44792d132 | ||
|
|
50b01e0b1b | ||
|
|
122c3a96c7 | ||
|
|
4d407bd646 | ||
|
|
16b6b37b94 | ||
|
|
8c766ef4f0 | ||
|
|
b7d2865435 | ||
|
|
8d9df5030c | ||
|
|
4a158b2547 | ||
|
|
af014cf8c1 | ||
|
|
1ddd7b1e6e | ||
|
|
9ef0179566 | ||
|
|
38690d18d4 | ||
|
|
e381e54bb7 | ||
|
|
7001f98353 | ||
|
|
a836642d74 | ||
|
|
a3d3add48f | ||
|
|
994060cce2 | ||
|
|
75103dc706 | ||
|
|
cf63c2fdc5 | ||
|
|
c07f5393f6 | ||
|
|
406c63721d | ||
|
|
97f3e02f59 | ||
|
|
5c6564f00b | ||
|
|
605e75efb3 | ||
|
|
496f9ba340 | ||
|
|
f98283f2dd | ||
|
|
2d32e85a64 | ||
|
|
1a56a22a33 | ||
|
|
c85204d0c1 | ||
|
|
1d8a958eaf | ||
|
|
b52f70d57d | ||
|
|
12687dae7b | ||
|
|
c53c3167d8 | ||
|
|
f15b4cf634 | ||
|
|
6430611e3e | ||
|
|
afe57e41ce | ||
|
|
86f3f90143 | ||
|
|
d3ea51cc01 | ||
|
|
60df472d53 | ||
|
|
67fe25bc8b | ||
|
|
94dbec4486 | ||
|
|
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 | ||
|
|
95f52fba51 |
@@ -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
|
||||
|
||||
30
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
## Description
|
||||
<!-- Add a detailed summary of what this feature/bugfix does -->
|
||||
|
||||
## Type of Change
|
||||
- [ ] Bug fix
|
||||
- [ ] Feature
|
||||
|
||||
## Visuals
|
||||
- [ ] Attached relevant screenshots / screen recording / GIF
|
||||
- [ ] N/A (not a feature or no UI changes)
|
||||
|
||||
## Testing
|
||||
- [ ] Ran all E2E tests
|
||||
- [ ] Ran all integration tests
|
||||
- [ ] Added/updated tests for this change (if needed)
|
||||
- [ ] N/A (tests not needed — explanation provided below)
|
||||
|
||||
### If tests were not added, explain why
|
||||
<!-- explanation -->
|
||||
|
||||
## Platform
|
||||
<!-- Describe which platforms this PR is related to -->
|
||||
|
||||
- [ ] Web
|
||||
- [ ] Mobile
|
||||
- [ ] Desktop
|
||||
|
||||
## Sign-off
|
||||
- [ ] QA passed
|
||||
- [ ] UI/UX passed
|
||||
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
|
||||
|
||||
3
.github/workflows/core.tests.yml
vendored
@@ -52,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
|
||||
|
||||
22
.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
|
||||
|
||||
17
.github/workflows/desktop.tests.yml
vendored
@@ -33,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
|
||||
@@ -49,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
|
||||
@@ -70,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: |
|
||||
@@ -114,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: |
|
||||
@@ -164,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: |
|
||||
|
||||
8
.github/workflows/editor.tests.yml
vendored
@@ -38,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
|
||||
|
||||
2
.github/workflows/monograph.publish.yml
vendored
@@ -39,7 +39,7 @@ 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
|
||||
|
||||
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
|
||||
|
||||
|
||||
4
.github/workflows/web.tests.yml
vendored
@@ -49,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
|
||||
|
||||
|
||||
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.**
|
||||
|
||||
|
||||
697
apps/desktop/package-lock.json
generated
@@ -2,7 +2,7 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.10",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./dist/cjs/index.js",
|
||||
@@ -36,8 +36,8 @@
|
||||
"electron-trpc": "0.7.1",
|
||||
"electron-updater": "^6.6.2",
|
||||
"icojs": "^0.19.5",
|
||||
"sqlite-better-trigram": "0.0.3",
|
||||
"sqlite3-fts5-html": "^0.0.4",
|
||||
"sqlite-better-trigram": "0.0.5",
|
||||
"sqlite3-fts5-html": "^0.0.6",
|
||||
"typed-emitter": "^2.1.0",
|
||||
"yargs": "^17.7.2",
|
||||
"zod": "3.24.3"
|
||||
@@ -47,7 +47,7 @@
|
||||
"@types/node": "22.15.3",
|
||||
"@types/yargs": "^17.0.33",
|
||||
"chokidar": "^4.0.3",
|
||||
"electron": "^36.0.0",
|
||||
"electron": "^37.0.0",
|
||||
"electron-builder": "^26.0.12",
|
||||
"esbuild": "0.21.5",
|
||||
"node-abi": "^4.5.0",
|
||||
|
||||
@@ -113,7 +113,8 @@ export class SQLite {
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof Error) e.message += ` (query: ${sql})`;
|
||||
if (e instanceof Error)
|
||||
throw rewriteError(e, `${e.message} (query: ${sql})`);
|
||||
throw e;
|
||||
} finally {
|
||||
// Since SQLite 3.48.0 (SQLite3MC v2.0.2) it's not possible to load fts5
|
||||
@@ -212,3 +213,11 @@ function getExtensionPath(extensionName: string, entryPoint: string) {
|
||||
}
|
||||
return loadablePath;
|
||||
}
|
||||
|
||||
function rewriteError(e: Error, message: string) {
|
||||
const error = new Error(message);
|
||||
error.stack = e.stack;
|
||||
error.name = e.name;
|
||||
error.cause = e.cause;
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,17 @@ export const windowRouter = t.router({
|
||||
}),
|
||||
maximized: t.procedure.query(() => globalThis.window?.isMaximized()),
|
||||
fullscreen: t.procedure.query(() => globalThis.window?.isFullScreen()),
|
||||
onClose: t.procedure.subscription(() => {
|
||||
return observable<void>((emit) => {
|
||||
function listener() {
|
||||
emit.next();
|
||||
}
|
||||
globalThis.window?.addListener("close", listener);
|
||||
return () => {
|
||||
globalThis.window?.removeListener("close", listener);
|
||||
};
|
||||
});
|
||||
}),
|
||||
onWindowStateChanged: t.procedure.subscription(() => {
|
||||
return observable<{ maximized: boolean; fullscreen: boolean }>((emit) => {
|
||||
function listener() {
|
||||
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "./overrides";
|
||||
import { app, BrowserWindow, nativeTheme, shell } from "electron";
|
||||
import { app, BrowserWindow, nativeTheme, shell, dialog } from "electron";
|
||||
import { isDevelopment } from "./utils";
|
||||
import { registerProtocol, PROTOCOL_URL } from "./utils/protocol";
|
||||
import { configureAutoUpdater } from "./utils/autoupdater";
|
||||
@@ -52,6 +52,9 @@ locale.then(({ default: locale }) => {
|
||||
});
|
||||
setI18nGlobal(i18n);
|
||||
|
||||
const appHostnames = isDevelopment()
|
||||
? ["localhost", "127.0.0.1"]
|
||||
: ["app.notesnook.com"];
|
||||
// only run a single instance
|
||||
if (!MAC_APP_STORE && !app.requestSingleInstanceLock()) {
|
||||
console.log("Another instance is already running!");
|
||||
@@ -173,6 +176,19 @@ async function createWindow() {
|
||||
return { action: "deny" };
|
||||
});
|
||||
|
||||
mainWindow.webContents.on("will-navigate", (event, url) => {
|
||||
try {
|
||||
const parsedUrl = new URL(url);
|
||||
if (!appHostnames.includes(parsedUrl.hostname)) {
|
||||
event.preventDefault();
|
||||
shell.openExternal(url);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("will-navigate: failed to parse URL", url, e);
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
nativeTheme.on("updated", () => {
|
||||
setupTray();
|
||||
setupJumplist();
|
||||
@@ -182,6 +198,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();
|
||||
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,17 @@ function registerProtocol() {
|
||||
headers: { "Content-Type": extensionToMimeType[fileExtension] }
|
||||
});
|
||||
} else {
|
||||
return net.fetch(request, { bypassCustomProtocolHandlers: true });
|
||||
const requestHeaders = new Headers(request.headers);
|
||||
if (!requestHeaders.has("referer"))
|
||||
requestHeaders.set("referer", PROTOCOL_URL);
|
||||
return await net.fetch(
|
||||
new Request(request, {
|
||||
headers: requestHeaders
|
||||
}),
|
||||
{
|
||||
bypassCustomProtocolHandlers: true
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
console.info(`${SCHEME} protocol inteception "successful"`);
|
||||
|
||||
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
|
||||
@@ -3,10 +3,8 @@
|
||||
</p>
|
||||
|
||||
<h1 align="center">Notesnook Mobile</h1>
|
||||
<h3 align="center">The mobile app is built using React Native, Typescript & Javascript for both iOS & Android.</h3>
|
||||
<p align="center">
|
||||
<a href="#developer-guide">Developer guide</a> | <a href="#build-instructions">How to build?</a>
|
||||
</p>
|
||||
<h3 align="center">The mobile app is built with React Native for both iOS and Android.</h3>
|
||||
<p align="center"><a href="#build-instructions">Build instructions</a> | <a href="#developer-guide">Developer guide</a> | <a href="#running-e2e-tests-detox">E2E tests</a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://play.google.com/store/apps/details?id=com.streetwriters.notesnook">
|
||||
@@ -25,21 +23,21 @@
|
||||
|
||||
Requirements:
|
||||
|
||||
1. [Node.js](https://nodejs.org/en/download/)
|
||||
1. [Node.js](https://nodejs.org/en/download/) 20+ (the repo is pinned to Node `22.20.0` via Volta)
|
||||
2. [git](https://git-scm.com/downloads)
|
||||
3. NPM (not yarn or pnpm)
|
||||
4. [React Native](https://reactnative.dev/docs/environment-setup)
|
||||
3. `npm`
|
||||
4. [React Native environment setup](https://reactnative.dev/docs/set-up-your-environment)
|
||||
|
||||
To run the app locally, you will need to setup React Native on your system:
|
||||
To run the app locally, first complete React Native native tooling setup:
|
||||
|
||||
1. Open the official [environment setup guide here](https://reactnative.dev/docs/environment-setup)
|
||||
1. Open [React Native environment setup](https://reactnative.dev/docs/set-up-your-environment)
|
||||
2. Select `React Native CLI Quickstart`
|
||||
3. Select your OS & the platform to run the app on (iOS or Android)
|
||||
3. Select your OS and target platform(s): iOS and/or Android
|
||||
4. Follow the steps listed.
|
||||
|
||||
> Please keep in mind that **Expo is not supported**.
|
||||
> Expo is not used in this project.
|
||||
|
||||
Once you have completed the setup, the first step is to `clone` the monorepo:
|
||||
Clone the monorepo:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/streetwriters/notesnook.git
|
||||
@@ -48,26 +46,27 @@ git clone https://github.com/streetwriters/notesnook.git
|
||||
cd notesnook
|
||||
```
|
||||
|
||||
Once you are inside the `./notesnook` directory, run the preparation step:
|
||||
Install dependencies and bootstrap the mobile workspace:
|
||||
|
||||
```bash
|
||||
# this might take a while to complete
|
||||
npm install
|
||||
npm run bootstrap -- --scope=mobile
|
||||
```
|
||||
|
||||
### Running the app on Android
|
||||
|
||||
[Setup an Android emulator from Android Studio](https://developer.android.com/studio/run/managing-avds) if you haven't already, and then run the following command to start the app in the Emulator:
|
||||
[Set up an Android emulator from Android Studio](https://developer.android.com/studio/run/managing-avds) (or connect a physical device), then run:
|
||||
|
||||
```bash
|
||||
npm run start:android
|
||||
```
|
||||
|
||||
If you want to run the app on your phone, make sure to [enable USB debugging](https://developer.android.com/studio/debug/dev-options).
|
||||
If you are using a physical device, enable [USB debugging](https://developer.android.com/studio/debug/dev-options).
|
||||
|
||||
### Running the app on iOS
|
||||
|
||||
To run the app on iOS:
|
||||
Install CocoaPods dependencies first, then run the iOS app:
|
||||
|
||||
```bash
|
||||
# this might take a while to complete
|
||||
@@ -76,90 +75,87 @@ npm run prepare:ios
|
||||
npm run start:ios
|
||||
```
|
||||
|
||||
### Useful development commands
|
||||
|
||||
```bash
|
||||
# start Metro only
|
||||
npm run start:metro
|
||||
|
||||
# start Re.Pack bundler
|
||||
npm run start:repack
|
||||
```
|
||||
|
||||
## Developer guide
|
||||
|
||||
> This project is in a transition state between Javascript & Typescript. We are gradually porting everything over to Typescript, so if you can help with that, it'd be great!
|
||||
> The mobile app is a mixed TypeScript/JavaScript codebase.
|
||||
|
||||
### The tech stack
|
||||
|
||||
We try to keep the stack as lean as possible:
|
||||
|
||||
1. React Native
|
||||
2. Typescript/Javascript
|
||||
3. Zustand: State management
|
||||
4. Detox: Runs all our e2e tests
|
||||
5. React Native MMKV: Database & persistence
|
||||
6. libsodium: Encryption
|
||||
1. React Native `0.82`
|
||||
2. React `19`
|
||||
3. TypeScript + JavaScript
|
||||
4. Zustand (state management)
|
||||
5. Detox (end-to-end testing)
|
||||
6. libsodium (encryption)
|
||||
|
||||
### Project structure
|
||||
|
||||
The app codebase is distributed over two primary directories. `native/` and `app/`.
|
||||
Top-level directories in `apps/mobile/`:
|
||||
|
||||
- `native/`: Includes `android/` and `ios/` folders and everything related to react native core functionality like bundling, development, and packaging. Any react-native dependency with native code, i.e., android & ios folders, is installed here.
|
||||
- `app/`: Main React Native app source (`components`, `common`, `hooks`, `navigation`, `screens`, `services`, `stores`, `utils`, etc.)
|
||||
- `android/`: Android native project
|
||||
- `ios/`: iOS native project
|
||||
- `e2e/`: Detox test suite and config
|
||||
- `patches/`: `patch-package` patches
|
||||
- `scripts/`: Mobile-specific scripts
|
||||
|
||||
- `app/`: Includes all the app code other than the native part. All JS-only dependencies are installed here.
|
||||
- `components/`: Each component serves a specific purpose in the app UI. For example, the `Paragraph` component is used to render paragraphs in the app, and a `Header` component is used to render a `header` on all screens.
|
||||
- `common/`: Features that are integral to the app's functionality. For example, the notesnook core is initialized here.
|
||||
- `hooks/`: Hooks for different app logic
|
||||
- `navigation/`: Includes app navigation-specific code. Here the app navigation, editor & side menu are rendered side by side in fluid tabs.
|
||||
- `screens`: Navigator screens.
|
||||
- `services`: Parts of code that do a specific function. For example, the `sync` service runs Sync from anywhere in the app.
|
||||
- `stores`: We use `zustand` for global state management in the app. Multiple stores provide the state for different parts of the app.
|
||||
- `utils`: General purpose stuff such as constant values, utility functions, etc.
|
||||
## Running E2E tests (Detox)
|
||||
|
||||
There are several other folders at the root:
|
||||
Detox device defaults in this repo:
|
||||
|
||||
- `share/`: Code for the iOS Share Extension and Android widget.
|
||||
- `e2e/`: Detox End to end tests
|
||||
- `patches/`: Patches for various react native dependencies.
|
||||
|
||||
### Running the tests
|
||||
|
||||
When you are done making the required changes, you must run the tests to ensure you didn't break anything. We use Detox as the testing framework & the tests can be started as follows:
|
||||
- Android emulator: `Pixel_5_API_36`
|
||||
- iOS simulator: `iPhone 17 Pro Max`
|
||||
|
||||
### Android
|
||||
|
||||
To run the tests on Android, you will need to create an emulator device on your system:
|
||||
Build and run Android Detox tests:
|
||||
|
||||
```
|
||||
$ANDROID_HOME/tools/bin/avdmanager create avd -n Pixel_5_API_31 -d pixel --package "system-images;android-31;default;x86_64"
|
||||
```
|
||||
|
||||
If you face problems, follow the detailed guide in [Detox documentation](https://wix.github.io/Detox/docs/introduction/android-dev-env). Keep the emulator name set to `Pixel_5_API_31`.
|
||||
|
||||
Once you have created an emulator device, build the Android apks:
|
||||
|
||||
```
|
||||
```bash
|
||||
npm run build:android
|
||||
```
|
||||
|
||||
Finally, run the tests:
|
||||
|
||||
```
|
||||
npm run test:android
|
||||
```
|
||||
|
||||
For debug configuration:
|
||||
|
||||
```bash
|
||||
npm run build:android:debug
|
||||
npm run start:metro
|
||||
npm run test:android:debug
|
||||
```
|
||||
|
||||
### iOS
|
||||
|
||||
To run e2e tests on the iOS simulator, you must be on a Mac with XCode installed.
|
||||
|
||||
First, install [AppleSimulatorUtils](https://github.com/wix/AppleSimulatorUtils):
|
||||
Build and run iOS Detox tests:
|
||||
|
||||
```bash
|
||||
npm run build:ios
|
||||
npm run test:ios
|
||||
```
|
||||
|
||||
If simulator tooling is missing, install [AppleSimulatorUtils](https://github.com/wix/AppleSimulatorUtils):
|
||||
|
||||
```bash
|
||||
brew tap wix/brew
|
||||
brew install applesimutils
|
||||
```
|
||||
|
||||
Now build the iOS app for testing:
|
||||
## Release commands
|
||||
|
||||
```
|
||||
npm run build:ios
|
||||
```
|
||||
|
||||
Finally, run the tests:
|
||||
Android release helpers:
|
||||
|
||||
```bash
|
||||
npm run release:android
|
||||
npm run release:android:bundle
|
||||
```
|
||||
npm run test:ios
|
||||
```
|
||||
|
||||
All tests on iOS are configured to run on `iPhone 8` simulator.
|
||||
|
||||
@@ -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 3070
|
||||
versionCode 3097
|
||||
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.* { *; }
|
||||
@@ -152,7 +152,7 @@
|
||||
<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>
|
||||
@@ -166,7 +166,6 @@
|
||||
android:exported="true"
|
||||
android:label="@string/title_activity_share"
|
||||
android:noHistory="true"
|
||||
android:screenOrientation="unspecified"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/AppThemeB"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@@ -39,28 +39,32 @@ 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",
|
||||
NotificationManager.IMPORTANCE_DEFAULT);
|
||||
try {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel("com.streetwriters.notesnook",
|
||||
"Default",
|
||||
NotificationManager.IMPORTANCE_DEFAULT);
|
||||
|
||||
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
|
||||
notification = new NotificationCompat.Builder(this, channel.getId())
|
||||
.setContentTitle("Sync on boot")
|
||||
.setContentText("")
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.build();
|
||||
if (android.os.Build.VERSION.SDK_INT >= 34) {
|
||||
this.startForeground(
|
||||
1,
|
||||
notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);
|
||||
} else {
|
||||
this.startForeground(
|
||||
1,
|
||||
notification);
|
||||
}
|
||||
|
||||
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
|
||||
notification = new NotificationCompat.Builder(this, channel.getId())
|
||||
.setContentTitle("Sync on boot")
|
||||
.setContentText("")
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.build();
|
||||
if (android.os.Build.VERSION.SDK_INT >= 34) {
|
||||
this.startForeground(
|
||||
1,
|
||||
notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);
|
||||
} else {
|
||||
this.startForeground(
|
||||
1,
|
||||
notification);
|
||||
}
|
||||
|
||||
} catch (Exception ignored) {
|
||||
stopSelf(startId);
|
||||
}
|
||||
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
@@ -20,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);
|
||||
@@ -31,19 +32,6 @@ public class MainActivity extends ReactActivity {
|
||||
startService(new Intent(getBaseContext(), OnClearFromRecentService.class));
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 35) {
|
||||
final View rootView = findViewById(android.R.id.content);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, insets) -> {
|
||||
Insets innerPadding = insets.getInsets(WindowInsetsCompat.Type.ime());
|
||||
rootView.setPadding(
|
||||
innerPadding.left,
|
||||
innerPadding.top,
|
||||
innerPadding.right,
|
||||
innerPadding.bottom
|
||||
);
|
||||
return insets;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,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 |
@@ -2,6 +2,7 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="10dp"
|
||||
android:id="@+id/reminder_item_btn">
|
||||
|
||||
<TextView
|
||||
@@ -2,6 +2,7 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="10dp"
|
||||
android:id="@+id/reminder_item_btn">
|
||||
|
||||
<TextView
|
||||
@@ -25,9 +25,9 @@
|
||||
android:text="Upcoming Reminders"/>
|
||||
|
||||
<ImageButton
|
||||
android:layout_width="30dp"
|
||||
android:layout_width="35dp"
|
||||
android:id="@+id/add_button"
|
||||
android:layout_height="30dp"
|
||||
android:layout_height="35dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="@drawable/ic_newnote" />
|
||||
</RelativeLayout>
|
||||
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |