Compare commits
1183 Commits
v2.4.7
...
Linkwarden
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1f2f3484b | ||
|
|
1339b5d625 | ||
|
|
40abb89602 | ||
|
|
0a8d48a07a | ||
|
|
b3530225f4 | ||
|
|
78726a2f04 | ||
|
|
c44f044505 | ||
|
|
8508360dc7 | ||
|
|
c16b1c621c | ||
|
|
e098fe1c39 | ||
|
|
7f8c856f6c | ||
|
|
8b1a88f326 | ||
|
|
9ced58eae8 | ||
|
|
3b2e5089d4 | ||
|
|
3822475fa4 | ||
|
|
929e23850b | ||
|
|
3645c6f0ff | ||
|
|
1ad44a81a3 | ||
|
|
d4a808e808 | ||
|
|
3953bb000c | ||
|
|
2be900a3f0 | ||
|
|
92d335ddbe | ||
|
|
f5633089f9 | ||
|
|
1b6f8f1fc8 | ||
|
|
5cd0fbdf6f | ||
|
|
05a20d9279 | ||
|
|
91a5c548d8 | ||
|
|
95f3ae382a | ||
|
|
6e3354ff0b | ||
|
|
9d92e0103c | ||
|
|
a57fc3f1c2 | ||
|
|
cc3a719611 | ||
|
|
16107c8369 | ||
|
|
43f6314ce2 | ||
|
|
5884687abc | ||
|
|
835fe3de17 | ||
|
|
f8839dbdd2 | ||
|
|
b0987581c0 | ||
|
|
1a02ba64a8 | ||
|
|
0ed87d7ffc | ||
|
|
ddd47d74e3 | ||
|
|
213b0aafee | ||
|
|
396e41a232 | ||
|
|
e04c256bd3 | ||
|
|
2023d6984f | ||
|
|
43ebd72aca | ||
|
|
572fa267d0 | ||
|
|
846a233639 | ||
|
|
a6e3ae1de5 | ||
|
|
c0159e5a27 | ||
|
|
7bf4db9b25 | ||
|
|
803a97b7e0 | ||
|
|
87715b8f62 | ||
|
|
bbad712e0d | ||
|
|
32f481f65b | ||
|
|
b7e260e180 | ||
|
|
df89364c0d | ||
|
|
77731dcf8a | ||
|
|
292fadaa1e | ||
|
|
fc801f98a9 | ||
|
|
a005e05d72 | ||
|
|
6124062a85 | ||
|
|
1a69058c7a | ||
|
|
4580f8cd26 | ||
|
|
82f1bd943e | ||
|
|
6a8ce9614b | ||
|
|
60bb97e4ca | ||
|
|
c9f2799618 | ||
|
|
96b508c41a | ||
|
|
a9206ca6c9 | ||
|
|
441e97e4d9 | ||
|
|
a918d2c960 | ||
|
|
c9860c535b | ||
|
|
c2a660fd50 | ||
|
|
1790638012 | ||
|
|
c9c3941688 | ||
|
|
9f376a633c | ||
|
|
fa0c08a1b2 | ||
|
|
4e0d7f5d8e | ||
|
|
59b6b7228e | ||
|
|
352389958c | ||
|
|
6c75f3ee58 | ||
|
|
792d03f906 | ||
|
|
82f4921038 | ||
|
|
ff497b5f66 | ||
|
|
e012c8953c | ||
|
|
06d8cf3cb8 | ||
|
|
7ce78fc314 | ||
|
|
de5a43cea4 | ||
|
|
6e47cc6897 | ||
|
|
62b1bcbc59 | ||
|
|
8718b1acfe | ||
|
|
f36d36dec7 | ||
|
|
8b6ded9179 | ||
|
|
4333d2686c | ||
|
|
78c1f6246f | ||
|
|
941bc04fc8 | ||
|
|
cfa36fc8da | ||
|
|
9388073cbf | ||
|
|
90eeba5191 | ||
|
|
95846c1d09 | ||
|
|
31b8092472 | ||
|
|
2a62c1ee1a | ||
|
|
5a028e98e3 | ||
|
|
8ed5147762 | ||
|
|
a20c4a67a8 | ||
|
|
bf8ac7d801 | ||
|
|
2971871a51 | ||
|
|
834714a941 | ||
|
|
08523b2234 | ||
|
|
479fea3ea4 | ||
|
|
a34f1d7308 | ||
|
|
b18ce2239a | ||
|
|
17f32152c3 | ||
|
|
47c711fea6 | ||
|
|
4423a30a72 | ||
|
|
cefe5e9e1b | ||
|
|
d30fb4645e | ||
|
|
ae099dce4f | ||
|
|
7c740f01d2 | ||
|
|
2b8964ca64 | ||
|
|
048842efa4 | ||
|
|
29d90db991 | ||
|
|
c99067ac37 | ||
|
|
4a66e1ec9c | ||
|
|
1211b6b1ef | ||
|
|
fbb1ce9687 | ||
|
|
3959a42a30 | ||
|
|
759cb15148 | ||
|
|
8ecd35acfe | ||
|
|
db9ea8eef4 | ||
|
|
b32151eb7e | ||
|
|
d377fa6eb0 | ||
|
|
4b958faf7e | ||
|
|
6981ad6d7a | ||
|
|
2d97f3a138 | ||
|
|
e668b67a3d | ||
|
|
41eb7df457 | ||
|
|
7725a5dd8b | ||
|
|
37588acc0d | ||
|
|
6ad2511fbc | ||
|
|
f3cb12c962 | ||
|
|
99fa0b1d8b | ||
|
|
9db7ff329a | ||
|
|
6bdf0f1c91 | ||
|
|
cd23f10480 | ||
|
|
bea11edbe8 | ||
|
|
d565958e5f | ||
|
|
7222b19745 | ||
|
|
b9be960c7e | ||
|
|
b337045ab2 | ||
|
|
14db14ff07 | ||
|
|
6ca2774b28 | ||
|
|
c3d702ad53 | ||
|
|
921d8a3718 | ||
|
|
2b258680b1 | ||
|
|
82f5a7026f | ||
|
|
daef130728 | ||
|
|
a181b43529 | ||
|
|
968bd04b40 | ||
|
|
46c20af530 | ||
|
|
cfb4081112 | ||
|
|
61ca5cf3e5 | ||
|
|
cecbf694f5 | ||
|
|
0e122c7485 | ||
|
|
c6713f67f4 | ||
|
|
dc8e763b76 | ||
|
|
2a52a0c79f | ||
|
|
08e1f499e1 | ||
|
|
63196e7b99 | ||
|
|
7cae35ce8d | ||
|
|
369b3d6207 | ||
|
|
3762d971e9 | ||
|
|
f3d8a3cc95 | ||
|
|
56efeecbfd | ||
|
|
be8aef987a | ||
|
|
4b9de5cd96 | ||
|
|
59949e21ee | ||
|
|
6fda674529 | ||
|
|
4318207c39 | ||
|
|
c48ad18379 | ||
|
|
d647c60f04 | ||
|
|
f83a9e899c | ||
|
|
b7c0cef8de | ||
|
|
14340afb99 | ||
|
|
b903a12f8d | ||
|
|
c6f7c18441 | ||
|
|
6d334be82e | ||
|
|
195cb99c90 | ||
|
|
2ebd311e0e | ||
|
|
1da1f17ea3 | ||
|
|
bc36513952 | ||
|
|
b04ab898d7 | ||
|
|
778dd764f6 | ||
|
|
64f8922741 | ||
|
|
c8ed9ac72d | ||
|
|
6cfd26da32 | ||
|
|
b56cf3faa4 | ||
|
|
f7526df008 | ||
|
|
bbeba7f50f | ||
|
|
7e5fa3eacd | ||
|
|
89826bd721 | ||
|
|
fb819b6142 | ||
|
|
2e131403d4 | ||
|
|
83db594fde | ||
|
|
83b002d585 | ||
|
|
7207259cdf | ||
|
|
7c647ae02d | ||
|
|
0630ea536e | ||
|
|
f2f73fc894 | ||
|
|
7887f55dd0 | ||
|
|
5ba759bb41 | ||
|
|
f325be0364 | ||
|
|
f3c8647ff2 | ||
|
|
ceb6b8f8e7 | ||
|
|
94d953d449 | ||
|
|
7f74fd75c9 | ||
|
|
4151b37f9f | ||
|
|
1b45286aaf | ||
|
|
d578fdc0c4 | ||
|
|
2f2747cfc8 | ||
|
|
f254bd85b5 | ||
|
|
a321d12307 | ||
|
|
0e5e3ea00e | ||
|
|
6599fd7f5a | ||
|
|
225288c742 | ||
|
|
9bf77e849f | ||
|
|
44ae6d0dbf | ||
|
|
3684204a03 | ||
|
|
5d17b628cc | ||
|
|
197a5b3b74 | ||
|
|
278b674ea7 | ||
|
|
78e8078d6b | ||
|
|
2f05dbad5d | ||
|
|
0987475e41 | ||
|
|
41e34ba4ec | ||
|
|
dd78c1570f | ||
|
|
5bf90c56de | ||
|
|
35643faf85 | ||
|
|
72c5a05324 | ||
|
|
0de7988b29 | ||
|
|
43d5f0a205 | ||
|
|
d703ff072c | ||
|
|
6f80fa62d2 | ||
|
|
34b914b91f | ||
|
|
c6c8dab5db | ||
|
|
d4bbdebe31 | ||
|
|
2f5c431fa7 | ||
|
|
6d92ce64bd | ||
|
|
6c006bb748 | ||
|
|
d2cb7604fa | ||
|
|
dd061e9dc8 | ||
|
|
63c50d96d7 | ||
|
|
1360a03eb5 | ||
|
|
902c724f39 | ||
|
|
1677e5e0ab | ||
|
|
1989510aac | ||
|
|
ef3cf4bcfa | ||
|
|
645df6c0aa | ||
|
|
dfad34c3dd | ||
|
|
f5abe4e1a2 | ||
|
|
79e447c58d | ||
|
|
bc013e7819 | ||
|
|
12844f2529 | ||
|
|
92a66933ce | ||
|
|
bc01b6d4a9 | ||
|
|
23650bb684 | ||
|
|
140ee8c65d | ||
|
|
7c153d841a | ||
|
|
e06f52642a | ||
|
|
874a909d1c | ||
|
|
bbe702925b | ||
|
|
49262d52cf | ||
|
|
5a468b44a1 | ||
|
|
6678f9c971 | ||
|
|
b5a27968de | ||
|
|
4f1c6855aa | ||
|
|
50c7fcd012 | ||
|
|
de63ba523e | ||
|
|
5e2362ea62 | ||
|
|
db94b01859 | ||
|
|
9bd821baa9 | ||
|
|
b69b535155 | ||
|
|
0bee36eced | ||
|
|
d044a6cbba | ||
|
|
8095010835 | ||
|
|
bd21c3d8c3 | ||
|
|
2bacf6e07d | ||
|
|
5c73d7097f | ||
|
|
f77236d49e | ||
|
|
1152571e49 | ||
|
|
eda41d7132 | ||
|
|
dd58a8565a | ||
|
|
64d20df6f1 | ||
|
|
cd3f5f7e70 | ||
|
|
fca04dd0a0 | ||
|
|
e024b324ed | ||
|
|
f012eaee33 | ||
|
|
794f8f07fa | ||
|
|
0a9aa774cc | ||
|
|
ebbc23f581 | ||
|
|
bf7722aa2e | ||
|
|
33637a8bca | ||
|
|
80962c5df6 | ||
|
|
7fa9621de1 | ||
|
|
d17fed9c85 | ||
|
|
81536e61f7 | ||
|
|
c790781315 | ||
|
|
e7a067b358 | ||
|
|
4156126a71 | ||
|
|
95f456bbb6 | ||
|
|
102cd1a6cf | ||
|
|
395dc5c0cb | ||
|
|
7f0c8f4bbf | ||
|
|
671f27ccde | ||
|
|
c90b53376d | ||
|
|
13ed7b6cdc | ||
|
|
3c71301cbc | ||
|
|
833a871731 | ||
|
|
7b3a4e48c1 | ||
|
|
76112534f6 | ||
|
|
adafe36cd7 | ||
|
|
0123791b8a | ||
|
|
81f150c0ce | ||
|
|
9177ad6a72 | ||
|
|
d360f612e2 | ||
|
|
b0496e2e65 | ||
|
|
c5751386fa | ||
|
|
406647d687 | ||
|
|
5949a0965c | ||
|
|
c015bed8a7 | ||
|
|
504af53f18 | ||
|
|
d822db440b | ||
|
|
181e1009e5 | ||
|
|
db16044949 | ||
|
|
1626a277e0 | ||
|
|
616efffed2 | ||
|
|
c9dd143d59 | ||
|
|
0a4d62491d | ||
|
|
9e417b7f35 | ||
|
|
81e9b27683 | ||
|
|
942ae4af99 | ||
|
|
f7e9119450 | ||
|
|
d71216a908 | ||
|
|
f61ce5563d | ||
|
|
575d91832e | ||
|
|
15fe4575f9 | ||
|
|
9ba9b06ae3 | ||
|
|
cf16344aef | ||
|
|
29ed07c74a | ||
|
|
493e0e2f6b | ||
|
|
d76d99844c | ||
|
|
533f29706e | ||
|
|
88cf45c7c2 | ||
|
|
b100129d80 | ||
|
|
a267d4ed3a | ||
|
|
9d8d5f0fa0 | ||
|
|
aa6b068d92 | ||
|
|
4b230e01d3 | ||
|
|
d140e2109f | ||
|
|
d5703ba70e | ||
|
|
5f12046a49 | ||
|
|
edad55d608 | ||
|
|
fac46de09c | ||
|
|
007de56cd3 | ||
|
|
8efdf6d87b | ||
|
|
69225e0642 | ||
|
|
0aa23e27b3 | ||
|
|
3bf2daddd1 | ||
|
|
71644e6e4e | ||
|
|
6e7f92c046 | ||
|
|
8d4504262b | ||
|
|
20224c835a | ||
|
|
c3873b030f | ||
|
|
cf8a202afa | ||
|
|
c79b1e6492 | ||
|
|
e21e3ecaae | ||
|
|
b84840e12c | ||
|
|
f8a130ae6e | ||
|
|
852de0d587 | ||
|
|
eecfb112e3 | ||
|
|
81a35655e9 | ||
|
|
c45b44cdbc | ||
|
|
ecc48f8fe2 | ||
|
|
e1c4f85e53 | ||
|
|
f8c96b493c | ||
|
|
63904f6d41 | ||
|
|
9083d9a01b | ||
|
|
806cba8110 | ||
|
|
ae24358a77 | ||
|
|
f0dfd5568e | ||
|
|
9d17600124 | ||
|
|
6a72d7894b | ||
|
|
00c33d48f0 | ||
|
|
6573c683f6 | ||
|
|
5412545c6f | ||
|
|
eee06e2be9 | ||
|
|
c3e8097aac | ||
|
|
2d97feef17 | ||
|
|
74c0a40622 | ||
|
|
56741b123b | ||
|
|
e8c6cc45f4 | ||
|
|
d0c999655c | ||
|
|
05594e6507 | ||
|
|
b59663ea91 | ||
|
|
8d2029a19d | ||
|
|
cee2f0a759 | ||
|
|
032f96191e | ||
|
|
e87bfc83bf | ||
|
|
aa0c7d64f4 | ||
|
|
b8a1839fb6 | ||
|
|
629574c6b2 | ||
|
|
1bb7d3cc5c | ||
|
|
6b811c3e7d | ||
|
|
a941eec569 | ||
|
|
5ed79f0f5b | ||
|
|
010ca8eeae | ||
|
|
5840ffc620 | ||
|
|
14754a23f1 | ||
|
|
1a501b5365 | ||
|
|
3bc9bbf074 | ||
|
|
09a52dd260 | ||
|
|
84e99b55c9 | ||
|
|
22c4fbf613 | ||
|
|
0e1b51177b | ||
|
|
44499c1277 | ||
|
|
9d986356a7 | ||
|
|
1d854e16aa | ||
|
|
02c02fc3b9 | ||
|
|
99bdc7d55e | ||
|
|
62c7bbbb74 | ||
|
|
dfb31ab1b3 | ||
|
|
e0c0b76eb0 | ||
|
|
9bc261bc85 | ||
|
|
b2d2e23539 | ||
|
|
04c69bb05f | ||
|
|
0cc1fd8407 | ||
|
|
848e0bf50e | ||
|
|
c3981c7fff | ||
|
|
ec7d6f4a6b | ||
|
|
9d8b602839 | ||
|
|
f0f57fb1a9 | ||
|
|
88820361e9 | ||
|
|
be47c78e4d | ||
|
|
fa059d1b00 | ||
|
|
bcfec38adf | ||
|
|
0344467cb7 | ||
|
|
454ed7b7eb | ||
|
|
51da37a22f | ||
|
|
6edbc4f438 | ||
|
|
899ddafd90 | ||
|
|
755721f1c2 | ||
|
|
0b20f61913 | ||
|
|
e9cf93d769 | ||
|
|
f94d10a3d3 | ||
|
|
6a95f6efdc | ||
|
|
150eeb9f11 | ||
|
|
fe77625289 | ||
|
|
63e7377df4 | ||
|
|
458eae9a3c | ||
|
|
7ef2afae7f | ||
|
|
a1d02f110d | ||
|
|
378fec06bb | ||
|
|
e04997c8c4 | ||
|
|
aecb90b4a4 | ||
|
|
dac6ec966c | ||
|
|
582159f454 | ||
|
|
cf02b7a099 | ||
|
|
7b4d324852 | ||
|
|
8932b9929a | ||
|
|
6b416f23f0 | ||
|
|
fb25cf5c75 | ||
|
|
c8f33f4800 | ||
|
|
95f818959b | ||
|
|
a0aabde322 | ||
|
|
0e3ca5b51f | ||
|
|
a733cc69a3 | ||
|
|
cbc88ebcb2 | ||
|
|
c3b78a8f82 | ||
|
|
8ad9ab7755 | ||
|
|
4bf220c786 | ||
|
|
ed8f2d3777 | ||
|
|
5b87799fdd | ||
|
|
97abe5de0c | ||
|
|
731b259329 | ||
|
|
63cef8e6b0 | ||
|
|
18db677c29 | ||
|
|
6071aa617f | ||
|
|
f270adbffa | ||
|
|
6259048431 | ||
|
|
40f4a5acd9 | ||
|
|
4240d37d77 | ||
|
|
0abe065c0c | ||
|
|
346f41a12c | ||
|
|
2ffbede170 | ||
|
|
c148c2b953 | ||
|
|
a872f218fb | ||
|
|
ff1f87cb35 | ||
|
|
94b143c91a | ||
|
|
52a11040f6 | ||
|
|
e9c43d75fe | ||
|
|
47b226cf1f | ||
|
|
266f834018 | ||
|
|
c9885c0b73 | ||
|
|
ec885a7db2 | ||
|
|
5665fbb412 | ||
|
|
9e933bd630 | ||
|
|
3572e101fb | ||
|
|
fb06549330 | ||
|
|
991f12566f | ||
|
|
160845319f | ||
|
|
bff5a7ae9a | ||
|
|
6e01c135dc | ||
|
|
f32e5a8d05 | ||
|
|
e9003e5c45 | ||
|
|
9065756686 | ||
|
|
881df93c02 | ||
|
|
ed7fab0473 | ||
|
|
38d054e143 | ||
|
|
5e89658a11 | ||
|
|
d964e02ba1 | ||
|
|
a36eb23096 | ||
|
|
8f875d15b0 | ||
|
|
9f660ff70f | ||
|
|
e6f43bbbfa | ||
|
|
1609868149 | ||
|
|
9075618e00 | ||
|
|
179cd18ac5 | ||
|
|
5a5fa9ed6c | ||
|
|
5279d94b8c | ||
|
|
5c3848e833 | ||
|
|
27d7bbabb3 | ||
|
|
8ff1346bf1 | ||
|
|
71119d511e | ||
|
|
b7eb8f2c2f | ||
|
|
3d54cc05a4 | ||
|
|
8973bdd94e | ||
|
|
1af37f3619 | ||
|
|
5303d63e4b | ||
|
|
05a30e1ec6 | ||
|
|
b1a55785b5 | ||
|
|
24b47e9d4b | ||
|
|
34d19f9dbe | ||
|
|
3a70e138b5 | ||
|
|
47367c44c1 | ||
|
|
e1a31481ad | ||
|
|
95dddd7da0 | ||
|
|
1a949ecdc6 | ||
|
|
2e6f1c207c | ||
|
|
6aa0fa9465 | ||
|
|
8677df0340 | ||
|
|
125f6ac619 | ||
|
|
89ecf5c529 | ||
|
|
fa78d6057f | ||
|
|
cfc28be898 | ||
|
|
c8efd4f9db | ||
|
|
ada4e53b46 | ||
|
|
91494b0188 | ||
|
|
e9fd6ec4d5 | ||
|
|
f08f4058dc | ||
|
|
d60200205a | ||
|
|
de38eb2963 | ||
|
|
f22dd4535d | ||
|
|
043589b301 | ||
|
|
4556827d79 | ||
|
|
98ebd6d7bc | ||
|
|
0a3ca4a1d4 | ||
|
|
106410f55a | ||
|
|
1ffe1b68a9 | ||
|
|
91ab0e609b | ||
|
|
cbb7a666cd | ||
|
|
e8cf14334f | ||
|
|
019790791b | ||
|
|
e41ba2668f | ||
|
|
66a09fdc4b | ||
|
|
e50143ca7e | ||
|
|
162b120e55 | ||
|
|
b4dd47aa37 | ||
|
|
256c232a85 | ||
|
|
b7ddf22662 | ||
|
|
5f60e9833e | ||
|
|
ceed23ff51 | ||
|
|
a4c83dc82f | ||
|
|
46f81ebf25 | ||
|
|
0ac5009a4a | ||
|
|
6842da4283 | ||
|
|
78ecf3ddb5 | ||
|
|
e39645e135 | ||
|
|
836360f99d | ||
|
|
9c9fd969bc | ||
|
|
213105942b | ||
|
|
0b7acb35b7 | ||
|
|
9b58ea5c98 | ||
|
|
c85c3bb0d7 | ||
|
|
7ca574b76f | ||
|
|
8593df4673 | ||
|
|
ddc2079f4b | ||
|
|
0de5caffa1 | ||
|
|
b14e77bdf9 | ||
|
|
8d366ae7d8 | ||
|
|
a18938ba2a | ||
|
|
6eac8423f8 | ||
|
|
cbf93dcf06 | ||
|
|
2993347dc7 | ||
|
|
cc45c8fc3e | ||
|
|
d5602a09cd | ||
|
|
736e98ac7d | ||
|
|
7eaff332a9 | ||
|
|
7931e2d7b6 | ||
|
|
ac3888f9b3 | ||
|
|
ac8add8c5d | ||
|
|
a6a0f6965b | ||
|
|
b2c5c3c6dd | ||
|
|
4555874725 | ||
|
|
0f5b70eda7 | ||
|
|
d1c3748681 | ||
|
|
2524139113 | ||
|
|
6c2b86fc4b | ||
|
|
d0e0526655 | ||
|
|
43e94ebd0b | ||
|
|
aeafe6e15d | ||
|
|
5ec221d87d | ||
|
|
d6d6442bc4 | ||
|
|
d12d12518e | ||
|
|
02ced62832 | ||
|
|
4febe1ace5 | ||
|
|
2e1e94112f | ||
|
|
d86bbcd940 | ||
|
|
eed80ca812 | ||
|
|
394251c1f1 | ||
|
|
68cdde91ad | ||
|
|
1ef286a38c | ||
|
|
508844dd9d | ||
|
|
fa1f9873d5 | ||
|
|
891803547e | ||
|
|
24d45f8e8e | ||
|
|
f95350405c | ||
|
|
665019dc59 | ||
|
|
b09de5a8af | ||
|
|
cfd33e9bd1 | ||
|
|
d3d2d5069e | ||
|
|
cffc74caa4 | ||
|
|
3cd8eadee3 | ||
|
|
d146ec296c | ||
|
|
fb4aa42eef | ||
|
|
f68582e28c | ||
|
|
d042c82cb0 | ||
|
|
8738dd45e9 | ||
|
|
839de18d7a | ||
|
|
2ba0851fee | ||
|
|
d99972a335 | ||
|
|
e071b9eb07 | ||
|
|
eb00d151b7 | ||
|
|
22aaa52b3e | ||
|
|
4541277b28 | ||
|
|
39faece9d7 | ||
|
|
a21b0760de | ||
|
|
04149fe86b | ||
|
|
ff6e71d494 | ||
|
|
5b02c1cfc9 | ||
|
|
1ff13e8aa0 | ||
|
|
eaf4524598 | ||
|
|
a276065288 | ||
|
|
1cf7421b76 | ||
|
|
ed4a334024 | ||
|
|
a5b1952e0d | ||
|
|
01826b1634 | ||
|
|
3b17d4ddfe | ||
|
|
f104fa095f | ||
|
|
b08e6690f3 | ||
|
|
33a654d21a | ||
|
|
e1262142f8 | ||
|
|
0a43279665 | ||
|
|
5491ac74a5 | ||
|
|
bbcfca4cde | ||
|
|
bf9a7d4fa0 | ||
|
|
edf4e489ec | ||
|
|
20c5a20851 | ||
|
|
6f47a20e87 | ||
|
|
384937e210 | ||
|
|
d22d989c91 | ||
|
|
4e0294322f | ||
|
|
75d5061bdf | ||
|
|
0150a9a6e3 | ||
|
|
87b79ffbac | ||
|
|
5a40677191 | ||
|
|
95ce2f30a8 | ||
|
|
e6a0ecbab5 | ||
|
|
e4c9cf8a38 | ||
|
|
eaca3d7453 | ||
|
|
fbe3642be4 | ||
|
|
bc32abbb92 | ||
|
|
38f731f313 | ||
|
|
aaf3590542 | ||
|
|
8bb6e32bfa | ||
|
|
7bd3872195 | ||
|
|
906779010e | ||
|
|
b0f87e8659 | ||
|
|
653b1bc396 | ||
|
|
9b1506a64e | ||
|
|
fb1869ca7a | ||
|
|
5e7835b4d5 | ||
|
|
0a91c47f83 | ||
|
|
dc9db05e75 | ||
|
|
e1149c2733 | ||
|
|
0591d7c134 | ||
|
|
4602269dd8 | ||
|
|
9ae6a22236 | ||
|
|
442da02956 | ||
|
|
dfcc271343 | ||
|
|
43d50dfd1b | ||
|
|
40bb3e6fae | ||
|
|
3e077fa247 | ||
|
|
3de8872f26 | ||
|
|
e9072bba51 | ||
|
|
d20c915970 | ||
|
|
1a378de267 | ||
|
|
d594159c15 | ||
|
|
aee10fa406 | ||
|
|
820d686c37 | ||
|
|
4189062c4c | ||
|
|
1461caf68a | ||
|
|
e7c7fedf8b | ||
|
|
b7adbbc86f | ||
|
|
975716937f | ||
|
|
2d0e52f65b | ||
|
|
e9afe0ef25 | ||
|
|
a38133d618 | ||
|
|
6498ae794b | ||
|
|
0371695eb3 | ||
|
|
9ae9c7c81a | ||
|
|
642374c2e5 | ||
|
|
f368c2aa81 | ||
|
|
fae9e95fa9 | ||
|
|
03639adc22 | ||
|
|
9fe829771d | ||
|
|
ed7b268c2b | ||
|
|
bf1a6efd2e | ||
|
|
6df2e44213 | ||
|
|
ae2324ecd3 | ||
|
|
accbd4cbfa | ||
|
|
5f4e0d4262 | ||
|
|
c072fed99f | ||
|
|
b4a9f917b5 | ||
|
|
078e5ba95f | ||
|
|
495509c888 | ||
|
|
dc388ebba5 | ||
|
|
21578bac8d | ||
|
|
1062e07065 | ||
|
|
2893d3caf2 | ||
|
|
9f74f62330 | ||
|
|
c6e3147bb6 | ||
|
|
1260e8c093 | ||
|
|
5cb4bdced3 | ||
|
|
03b4240b8b | ||
|
|
9a3e82470a | ||
|
|
ee2319996b | ||
|
|
c979adfe69 | ||
|
|
2b83522eaa | ||
|
|
8c738d4a99 | ||
|
|
63678b7f1e | ||
|
|
b73e845299 | ||
|
|
898b126231 | ||
|
|
17d1cb45e3 | ||
|
|
0aad2d9e4b | ||
|
|
c18a5f4162 | ||
|
|
df7814385a | ||
|
|
d568f22e00 | ||
|
|
6bd1c90417 | ||
|
|
a40026040c | ||
|
|
334ad9f3dc | ||
|
|
f944345745 | ||
|
|
6b647573f0 | ||
|
|
d81493e021 | ||
|
|
03f4523d57 | ||
|
|
c24e76adac | ||
|
|
5d26617251 | ||
|
|
0e47ad9920 | ||
|
|
ca45076b6c | ||
|
|
3bf6dcad2f | ||
|
|
23860b8511 | ||
|
|
8758976f8d | ||
|
|
550dbd2bf0 | ||
|
|
04d2b3c6b2 | ||
|
|
cc1c17363b | ||
|
|
7bd0e29538 | ||
|
|
5baf55694c | ||
|
|
193a70c6e8 | ||
|
|
5b430cf31e | ||
|
|
684609a1dd | ||
|
|
ebb2016915 | ||
|
|
c103b66694 | ||
|
|
863bcc3838 | ||
|
|
66b0aacc3f | ||
|
|
299498ffa6 | ||
|
|
8031432995 | ||
|
|
9cc3a7206e | ||
|
|
d15d965139 | ||
|
|
bc04ea0fe8 | ||
|
|
bd34dacf21 | ||
|
|
80f366cd7b | ||
|
|
c5602dc79f | ||
|
|
0158e58d90 | ||
|
|
602f399119 | ||
|
|
012caab606 | ||
|
|
102690fc10 | ||
|
|
a73e5fa6c6 | ||
|
|
75b1ae738f | ||
|
|
8563a09a07 | ||
|
|
da8dc83b8f | ||
|
|
e889509697 | ||
|
|
237499fd03 | ||
|
|
9a287d1aef | ||
|
|
299a2331ff | ||
|
|
be5400f7cb | ||
|
|
099bc9e054 | ||
|
|
5c5dd967c4 | ||
|
|
d1ed33b532 | ||
|
|
05c5bdf63c | ||
|
|
a1248fe62f | ||
|
|
8f7e0b8d09 | ||
|
|
9d91d2064b | ||
|
|
d631754b50 | ||
|
|
94be3a7448 | ||
|
|
4faf389a2b | ||
|
|
ff31732ba3 | ||
|
|
fa051c0d4d | ||
|
|
02cb93065f | ||
|
|
15a0084fb7 | ||
|
|
cd82083e09 | ||
|
|
c0abf2f411 | ||
|
|
061e22d225 | ||
|
|
a886437589 | ||
|
|
8e6f88d29f | ||
|
|
0b8a9b4310 | ||
|
|
ce1aa5a0ec | ||
|
|
a82c4ef85f | ||
|
|
6983e41576 | ||
|
|
7e96ba63df | ||
|
|
7036b46084 | ||
|
|
af7f0fb47c | ||
|
|
2bba8198b8 | ||
|
|
9d8ae6970c | ||
|
|
96a70a9689 | ||
|
|
6cae2fb634 | ||
|
|
288fd9df87 | ||
|
|
5e6d46b6b9 | ||
|
|
e79b98d3b0 | ||
|
|
7d43ed52a4 | ||
|
|
614653bf29 | ||
|
|
1b9dafbe47 | ||
|
|
abc93f1bf9 | ||
|
|
c23964a46d | ||
|
|
a76e996fc1 | ||
|
|
2264abd384 | ||
|
|
6544e3ecbb | ||
|
|
a8ffbc87d1 | ||
|
|
92c7f40956 | ||
|
|
6c29d905d9 | ||
|
|
9b85a2b1bb | ||
|
|
cebe746ca7 | ||
|
|
5b0297bfe0 | ||
|
|
9c5226ee51 | ||
|
|
6d30912812 | ||
|
|
78111f010b | ||
|
|
abb73f80bd | ||
|
|
e8d0cce58a | ||
|
|
a2637d4526 | ||
|
|
479995366a | ||
|
|
7edd7f893b | ||
|
|
0185ec57c7 | ||
|
|
e045c18b7d | ||
|
|
a1f48bbd79 | ||
|
|
7c95761990 | ||
|
|
c67526e54c | ||
|
|
8db5307747 | ||
|
|
54beb50576 | ||
|
|
9ab01da369 | ||
|
|
78c80a5fea | ||
|
|
644b827669 | ||
|
|
d66c784d3f | ||
|
|
1e2ed6c293 | ||
|
|
576d50f467 | ||
|
|
06234e42df | ||
|
|
8a901ba0e9 | ||
|
|
39422e54df | ||
|
|
a71f42af6e | ||
|
|
5b8e1d53cc | ||
|
|
52f7cbb10b | ||
|
|
22b2734494 | ||
|
|
9fa9fe5db0 | ||
|
|
6003c6c449 | ||
|
|
239589eaed | ||
|
|
586074ef43 | ||
|
|
afd5e5f036 | ||
|
|
8082efdc67 | ||
|
|
3618ba907d | ||
|
|
c68f9d68ad | ||
|
|
359d22e61b | ||
|
|
c216a92474 | ||
|
|
e45384c855 | ||
|
|
eadc98fbbe | ||
|
|
8505667f73 | ||
|
|
71678ba9dd | ||
|
|
d261bd39ec | ||
|
|
2c87459f35 | ||
|
|
83cd9f6a06 | ||
|
|
adcc4e85ac | ||
|
|
f921ecaa96 | ||
|
|
deb6ed7ec8 | ||
|
|
17cdb7efa4 | ||
|
|
7e98de6122 | ||
|
|
5f34f03355 | ||
|
|
4344183564 | ||
|
|
bc3ec3cc54 | ||
|
|
fc97735703 | ||
|
|
8f38c82ed7 | ||
|
|
b0ea14737f | ||
|
|
75d91fbac7 | ||
|
|
bcb6aea119 | ||
|
|
cb50de96a3 | ||
|
|
fc66dac933 | ||
|
|
f310cd79ad | ||
|
|
d262041f33 | ||
|
|
a498f3a10d | ||
|
|
811628a952 | ||
|
|
0fd10396f4 | ||
|
|
329019b34e | ||
|
|
73dda21573 | ||
|
|
27061ada43 | ||
|
|
78fa417f06 | ||
|
|
f0621dac2e | ||
|
|
90efec3c6e | ||
|
|
142af9b5c0 | ||
|
|
f68ca100a1 | ||
|
|
db446d450f | ||
|
|
7442799836 | ||
|
|
341154e928 | ||
|
|
65b29830f0 | ||
|
|
74030b26c5 | ||
|
|
861f8e55f4 | ||
|
|
2dd49ff844 | ||
|
|
f1655aad15 | ||
|
|
80ad01a2d0 | ||
|
|
915d08a315 | ||
|
|
08c2ff278f | ||
|
|
58d71a863b | ||
|
|
b4ea7dcd8e | ||
|
|
6f4759d928 | ||
|
|
eb8eb74a32 | ||
|
|
30ef557f43 | ||
|
|
7fb50337d3 | ||
|
|
d66019bfea | ||
|
|
ba1e096cff | ||
|
|
9354842065 | ||
|
|
464d2f920d | ||
|
|
1c55ec8d97 | ||
|
|
d181d5db20 | ||
|
|
154d0d5fb6 | ||
|
|
ca076b1be8 | ||
|
|
4f6368fcbf | ||
|
|
2b04bcb1df | ||
|
|
1a96ca32f9 | ||
|
|
d37b25c5a2 | ||
|
|
7856e76b15 | ||
|
|
04547e1bdf | ||
|
|
f37a4b9c9e | ||
|
|
163bf6a0cc | ||
|
|
489ad14c3b | ||
|
|
7c14cf7bf1 | ||
|
|
b8d7bd57c8 | ||
|
|
ce7a94e492 | ||
|
|
cd09843b99 | ||
|
|
389db59b28 | ||
|
|
b702aa0401 | ||
|
|
9a92b4d229 | ||
|
|
8278878673 | ||
|
|
4640c1c966 | ||
|
|
49fbbe966c | ||
|
|
3610e73d3b | ||
|
|
76a5dcb90b | ||
|
|
e51fba41e7 | ||
|
|
e8edd1c9a0 | ||
|
|
f30c652676 | ||
|
|
8cf621bc62 | ||
|
|
a89274fc03 | ||
|
|
baadd6c06b | ||
|
|
4a71af8a67 | ||
|
|
ece09c6f3b | ||
|
|
189db27c5b | ||
|
|
68d8d403cf | ||
|
|
07b87be7f1 | ||
|
|
e67fef1d04 | ||
|
|
87eb2471ff | ||
|
|
58b6f7339c | ||
|
|
c659711181 | ||
|
|
5503483502 | ||
|
|
a6d018fb53 | ||
|
|
3929f32e63 | ||
|
|
c08522386b | ||
|
|
b51a876904 | ||
|
|
2e2d7baee1 | ||
|
|
2b8f7d4be2 | ||
|
|
797ddc4b73 | ||
|
|
237d301f88 | ||
|
|
6d7d364853 | ||
|
|
495af0a752 | ||
|
|
388b9d9184 | ||
|
|
ede3882a94 | ||
|
|
e5fcf18fa4 | ||
|
|
a3d3b353a1 | ||
|
|
546e216ac9 | ||
|
|
ffc037b854 | ||
|
|
5fe6a5b19a | ||
|
|
cc2d7c863d | ||
|
|
53a65774f0 | ||
|
|
5990d4ce2d | ||
|
|
ce2eb8eafb | ||
|
|
bae4cf1d4f | ||
|
|
4e20d71a41 | ||
|
|
4a0e75c6e5 | ||
|
|
cac90524ed | ||
|
|
9fce74971f | ||
|
|
3feeecdc1d | ||
|
|
bde7b9aae0 | ||
|
|
bda0dc6c87 | ||
|
|
7dd254af48 | ||
|
|
a57c3114d8 | ||
|
|
3969cc5abd | ||
|
|
252d41886a | ||
|
|
d8bab2eb24 | ||
|
|
9bfba6037e | ||
|
|
e59ab23b3d | ||
|
|
01b3b4485e | ||
|
|
8c76b0d141 | ||
|
|
d2b867c438 | ||
|
|
f26cd31694 | ||
|
|
8dcd2c67d2 | ||
|
|
750aa294d0 | ||
|
|
281b376eac | ||
|
|
837241186f | ||
|
|
51cf8172ff | ||
|
|
9c51a65f31 | ||
|
|
a451e9fa2e | ||
|
|
ba4860a910 | ||
|
|
84aeac96ce | ||
|
|
ac70c9e29c | ||
|
|
f77ef58396 | ||
|
|
4442ce8705 | ||
|
|
4ff7298a3b | ||
|
|
a8be4d8f2f | ||
|
|
f183f122e9 | ||
|
|
5164f287d4 | ||
|
|
439c562002 | ||
|
|
cc02ab3615 | ||
|
|
d2e59d48c2 | ||
|
|
dbfdb587b6 | ||
|
|
7fd9f5b806 | ||
|
|
69ac3eb01f | ||
|
|
44272540aa | ||
|
|
0dda77db1e | ||
|
|
60aa7b830e | ||
|
|
b6ad2b5900 | ||
|
|
aee1828c15 | ||
|
|
67bf6b7d75 | ||
|
|
bbc2e4c457 | ||
|
|
1f28d9d461 | ||
|
|
df1da9f1f8 | ||
|
|
b476b3ccd4 | ||
|
|
ae561ff227 | ||
|
|
d438381ebd | ||
|
|
72266d1cd5 | ||
|
|
f560422427 | ||
|
|
7b7b979b20 | ||
|
|
c3c74b8162 | ||
|
|
0e60dee47d | ||
|
|
c3f72c4be8 | ||
|
|
79bd95f650 | ||
|
|
88d73703f8 | ||
|
|
41df9d0c82 | ||
|
|
0b2e78332a | ||
|
|
558ba11db7 | ||
|
|
155c77cbc4 | ||
|
|
a3c487d074 | ||
|
|
1cff2db876 | ||
|
|
2112176d6e | ||
|
|
aef33d859e | ||
|
|
5128bd44d8 | ||
|
|
0a77ee90a7 | ||
|
|
e2c6993a6d | ||
|
|
e1c4a8575b | ||
|
|
0c531760e8 | ||
|
|
5f468cd95d | ||
|
|
63597a041f | ||
|
|
e753f1dded | ||
|
|
8ecedf7cae | ||
|
|
44daffbae6 | ||
|
|
d5f262200b | ||
|
|
ccd3fcb8c1 | ||
|
|
059fcecc5f | ||
|
|
58e2fb22c9 | ||
|
|
2ace10c058 | ||
|
|
4b8f4c4179 | ||
|
|
8f62f4dffb | ||
|
|
95dc3b31db | ||
|
|
ebdeedc2ec | ||
|
|
325c41254d | ||
|
|
fda782ec44 | ||
|
|
080be856cc | ||
|
|
e1ef638f0e | ||
|
|
582607e726 | ||
|
|
9eaa106766 | ||
|
|
e0705ece4f | ||
|
|
da0533ac36 | ||
|
|
e3d9912378 | ||
|
|
26997475fd | ||
|
|
ea31eb47ae | ||
|
|
193c66123b | ||
|
|
eba9d3c86d | ||
|
|
b51355b406 | ||
|
|
0a070deebd | ||
|
|
c78aa2da0d | ||
|
|
aef55d65a1 | ||
|
|
efddd55841 | ||
|
|
f7a53d53e2 | ||
|
|
ef08edf1fb | ||
|
|
39261de45e | ||
|
|
cc915c8a64 | ||
|
|
7d9cc1f1f0 | ||
|
|
b06cb7c379 | ||
|
|
d5bd095827 | ||
|
|
daed2d82f4 | ||
|
|
39e022f87b | ||
|
|
3600f6398a | ||
|
|
392d98f090 | ||
|
|
6252b61b89 | ||
|
|
00bfdfb926 | ||
|
|
2d0093172a | ||
|
|
34e0115a0f | ||
|
|
dba2453453 | ||
|
|
ae3cf104b7 | ||
|
|
8534572662 | ||
|
|
2901db7035 | ||
|
|
5be194235c | ||
|
|
05563134b4 | ||
|
|
39db72a201 | ||
|
|
1d14d17e7a | ||
|
|
1716e1d408 | ||
|
|
4591f8ebc7 | ||
|
|
86bcd5ef07 | ||
|
|
047e156cfb | ||
|
|
dfe9fec4b4 | ||
|
|
cf8e409bb3 | ||
|
|
3565ad3e7c | ||
|
|
f35bc7b9fd | ||
|
|
23f4142414 | ||
|
|
ee3dca92cd | ||
|
|
4e47a6bffb | ||
|
|
d4f59d7f32 | ||
|
|
d91ebb3fa2 | ||
|
|
0c78187a10 | ||
|
|
834d25a99e | ||
|
|
bc46f6f64b | ||
|
|
a67980b29d | ||
|
|
07eb242c26 | ||
|
|
7880551c4d | ||
|
|
f71acd86df | ||
|
|
98fbb5b678 | ||
|
|
0c2c837028 | ||
|
|
a5b166f41d | ||
|
|
89de1829c2 | ||
|
|
fbca98984b | ||
|
|
06ab784441 | ||
|
|
4da2310e95 | ||
|
|
a8f4072f1c | ||
|
|
93bcfc67fe | ||
|
|
ba49946974 | ||
|
|
d16b296b15 | ||
|
|
3fc61ac5ce | ||
|
|
ced51e4801 | ||
|
|
254c090605 | ||
|
|
2a83ced9d8 | ||
|
|
52d333f085 |
105
.env.sample
@@ -1,11 +1,12 @@
|
||||
NEXTAUTH_SECRET=very_sensitive_secret
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
NEXTAUTH_URL=http://localhost:3000/api/v1/auth
|
||||
NEXTAUTH_SECRET=
|
||||
|
||||
# Manual installation database settings
|
||||
DATABASE_URL=postgresql://user:password@localhost:5432/linkwarden
|
||||
# Example: DATABASE_URL=postgresql://user:password@localhost:5432/linkwarden
|
||||
DATABASE_URL=
|
||||
|
||||
# Docker installation database settings
|
||||
POSTGRES_PASSWORD=super_secret_password
|
||||
POSTGRES_PASSWORD=
|
||||
|
||||
# Additional Optional Settings
|
||||
PAGINATION_TAKE_COUNT=
|
||||
@@ -14,12 +15,62 @@ AUTOSCROLL_TIMEOUT=
|
||||
NEXT_PUBLIC_DISABLE_REGISTRATION=
|
||||
NEXT_PUBLIC_CREDENTIALS_ENABLED=
|
||||
DISABLE_NEW_SSO_USERS=
|
||||
RE_ARCHIVE_LIMIT=
|
||||
NEXT_PUBLIC_MAX_FILE_SIZE=
|
||||
MAX_LINKS_PER_USER=
|
||||
ARCHIVE_TAKE_COUNT=
|
||||
BROWSER_TIMEOUT=
|
||||
IGNORE_UNAUTHORIZED_CA=
|
||||
IGNORE_HTTPS_ERRORS=
|
||||
IGNORE_URL_SIZE_LIMIT=
|
||||
NEXT_PUBLIC_DEMO=
|
||||
NEXT_PUBLIC_DEMO_USERNAME=
|
||||
NEXT_PUBLIC_DEMO_PASSWORD=
|
||||
NEXT_PUBLIC_ADMIN=
|
||||
NEXT_PUBLIC_MAX_FILE_BUFFER=
|
||||
PDF_MAX_BUFFER=
|
||||
SCREENSHOT_MAX_BUFFER=
|
||||
READABILITY_MAX_BUFFER=
|
||||
PREVIEW_MAX_BUFFER=
|
||||
MONOLITH_MAX_BUFFER=
|
||||
MONOLITH_CUSTOM_OPTIONS=
|
||||
IMPORT_LIMIT=
|
||||
PLAYWRIGHT_LAUNCH_OPTIONS_EXECUTABLE_PATH=
|
||||
PLAYWRIGHT_WS_URL=
|
||||
MAX_WORKERS=
|
||||
DISABLE_PRESERVATION=
|
||||
NEXT_PUBLIC_RSS_POLLING_INTERVAL_MINUTES=
|
||||
RSS_SUBSCRIPTION_LIMIT_PER_USER=
|
||||
TEXT_CONTENT_LIMIT=
|
||||
SEARCH_FILTER_LIMIT=
|
||||
INDEX_TAKE_COUNT=
|
||||
MEILI_TIMEOUT=
|
||||
|
||||
# AI Settings
|
||||
NEXT_PUBLIC_OLLAMA_ENDPOINT_URL=
|
||||
OLLAMA_MODEL=
|
||||
|
||||
# https://ai-sdk.dev/providers/openai-compatible-providers
|
||||
OPENAI_API_KEY=
|
||||
OPENAI_MODEL=
|
||||
# Optional: Set a custom OpenAI base URL and name (for third-party providers)
|
||||
CUSTOM_OPENAI_BASE_URL=
|
||||
CUSTOM_OPENAI_NAME=
|
||||
|
||||
# https://sdk.vercel.ai/providers/ai-sdk-providers/azure
|
||||
AZURE_API_KEY=
|
||||
AZURE_RESOURCE_NAME=
|
||||
AZURE_MODEL=
|
||||
|
||||
# https://sdk.vercel.ai/providers/ai-sdk-providers/anthropic
|
||||
ANTHROPIC_API_KEY=
|
||||
ANTHROPIC_MODEL=
|
||||
|
||||
# https://github.com/OpenRouterTeam/ai-sdk-provider
|
||||
OPENROUTER_API_KEY=
|
||||
OPENROUTER_MODEL=
|
||||
|
||||
# MeiliSearch Settings
|
||||
MEILI_HOST=
|
||||
MEILI_MASTER_KEY=
|
||||
|
||||
# AWS S3 Settings
|
||||
SPACES_KEY=
|
||||
@@ -33,11 +84,21 @@ SPACES_FORCE_PATH_STYLE=
|
||||
NEXT_PUBLIC_EMAIL_PROVIDER=
|
||||
EMAIL_FROM=
|
||||
EMAIL_SERVER=
|
||||
BASE_URL=
|
||||
|
||||
# Proxy settings
|
||||
PROXY=
|
||||
PROXY_USERNAME=
|
||||
PROXY_PASSWORD=
|
||||
PROXY_BYPASS=
|
||||
|
||||
#
|
||||
# SSO Providers
|
||||
#
|
||||
# PDF archive settings
|
||||
PDF_MARGIN_TOP=
|
||||
PDF_MARGIN_BOTTOM=
|
||||
|
||||
#################
|
||||
# SSO Providers #
|
||||
#################
|
||||
|
||||
# 42 School
|
||||
NEXT_PUBLIC_FORTYTWO_ENABLED=
|
||||
@@ -65,6 +126,12 @@ AUTH0_ISSUER=
|
||||
AUTH0_CLIENT_SECRET=
|
||||
AUTH0_CLIENT_ID=
|
||||
|
||||
# Authelia
|
||||
NEXT_PUBLIC_AUTHELIA_ENABLED=""
|
||||
AUTHELIA_CLIENT_ID=""
|
||||
AUTHELIA_CLIENT_SECRET=""
|
||||
AUTHELIA_WELLKNOWN_URL=""
|
||||
|
||||
# Authentik
|
||||
NEXT_PUBLIC_AUTHENTIK_ENABLED=
|
||||
AUTHENTIK_CUSTOM_NAME=
|
||||
@@ -72,12 +139,25 @@ AUTHENTIK_ISSUER=
|
||||
AUTHENTIK_CLIENT_ID=
|
||||
AUTHENTIK_CLIENT_SECRET=
|
||||
|
||||
# Azure AD B2C
|
||||
NEXT_PUBLIC_AZURE_AD_B2C_ENABLED=
|
||||
AZURE_AD_B2C_TENANT_NAME=
|
||||
AZURE_AD_B2C_CLIENT_ID=
|
||||
AZURE_AD_B2C_CLIENT_SECRET=
|
||||
AZURE_AD_B2C_PRIMARY_USER_FLOW=
|
||||
|
||||
# Azure AD
|
||||
NEXT_PUBLIC_AZURE_AD_ENABLED=
|
||||
AZURE_AD_CLIENT_ID=
|
||||
AZURE_AD_CLIENT_SECRET=
|
||||
AZURE_AD_TENANT_ID=
|
||||
|
||||
# Battle.net
|
||||
NEXT_PUBLIC_BATTLENET_ENABLED=
|
||||
BATTLENET_CUSTOM_NAME=
|
||||
BATTLENET_CLIENT_ID=
|
||||
BATTLENET_CLIENT_SECRET=
|
||||
BATLLENET_ISSUER=
|
||||
BATTLENET_ISSUER=
|
||||
|
||||
# Box
|
||||
NEXT_PUBLIC_BOX_ENABLED=
|
||||
@@ -166,14 +246,15 @@ FUSIONAUTH_TENANT_ID=
|
||||
# GitHub
|
||||
NEXT_PUBLIC_GITHUB_ENABLED=
|
||||
GITHUB_CUSTOM_NAME=
|
||||
GITHUB_CLIENT_ID=
|
||||
GITHUB_CLIENT_SECRET=
|
||||
GITHUB_ID=
|
||||
GITHUB_SECRET=
|
||||
|
||||
# GitLab
|
||||
NEXT_PUBLIC_GITLAB_ENABLED=
|
||||
GITLAB_CUSTOM_NAME=
|
||||
GITLAB_CLIENT_ID=
|
||||
GITLAB_CLIENT_SECRET=
|
||||
GITLAB_AUTH_URL=
|
||||
|
||||
# Google
|
||||
NEXT_PUBLIC_GOOGLE_ENABLED=
|
||||
|
||||
13
.github/ISSUE_TEMPLATE/installation-problem.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
name: Installation Problem
|
||||
title: Installation Problem
|
||||
description: Report an issue with installation
|
||||
labels: installation
|
||||
body:
|
||||
- type: textarea
|
||||
id: feature-description
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: For installation issues, please visit discord.linkwarden.app
|
||||
description: "Invite link: https://discord.com/invite/CtuYV47nuJ"
|
||||
placeholder: Please do not submit installation issues on GitHub.
|
||||
22
.github/SECURITY.md
vendored
@@ -1,17 +1,19 @@
|
||||
# Security Policy
|
||||
# Security
|
||||
|
||||
## Supported Versions
|
||||
The Linkwarden team and community take security bugs in Linkwarden seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | --------- |
|
||||
| 1.x.x | ✅ |
|
||||
# Reporting Security Issues
|
||||
|
||||
## Reporting a Vulnerability
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
First off, we really appreciate the time you spent!
|
||||
Instead, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/linkwarden/linkwarden/security/advisories/new) tab.
|
||||
|
||||
If you found a vulnerability, these are the ways you can reach us:
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message:
|
||||
[security@linkwarden.app](mailto:security@linkwarden.app)
|
||||
|
||||
Email: [security@linkwarden.app](mailto:security@linkwarden.app)
|
||||
|
||||
Or you can directly DM me via Twitter: [@daniel31x13](https://twitter.com/Daniel31X13).
|
||||
After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
|
||||
|
||||
# Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
18
.github/workflows/check-branch.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Check pull request source branch
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
- edited
|
||||
jobs:
|
||||
check-branches:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check branches
|
||||
run: |
|
||||
if [ ${{ github.head_ref }} != "dev" ] && [ ${{ github.base_ref }} == "main" ]; then
|
||||
echo "Merge requests to main branch are only allowed from dev branch. Please rebase your changes to dev branch."
|
||||
exit 1
|
||||
fi
|
||||
139
.github/workflows/playwright-tests.yml
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
name: Linkwarden Playwright Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- qacomet/**
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
PGHOST: localhost
|
||||
PGPORT: 5432
|
||||
PGUSER: postgres
|
||||
PGPASSWORD: password
|
||||
PGDATABASE: postgres
|
||||
|
||||
TEST_POSTGRES_USER: test_linkwarden_user
|
||||
TEST_POSTGRES_PASSWORD: password
|
||||
TEST_POSTGRES_DATABASE: test_linkwarden_db
|
||||
TEST_POSTGRES_DATABASE_TEMPLATE: test_linkwarden_db_template
|
||||
TEST_POSTGRES_HOST: localhost
|
||||
TEST_POSTGREST_PORT: 5432
|
||||
PRODUCTION_POSTGRES_DATABASE: linkwarden_db
|
||||
|
||||
NEXTAUTH_SECRET: very_sensitive_secret
|
||||
NEXTAUTH_URL: http://localhost:3000/api/v1/auth
|
||||
|
||||
# Manual installation database settings
|
||||
DATABASE_URL: postgresql://test_linkwarden_user:password@localhost:5432/test_linkwarden_db
|
||||
|
||||
# Docker installation database settings
|
||||
POSTGRES_PASSWORD: password
|
||||
|
||||
TEST_USERNAME: test-user
|
||||
TEST_PASSWORD: password
|
||||
|
||||
jobs:
|
||||
playwright-test-runner:
|
||||
strategy:
|
||||
matrix:
|
||||
test_case: ['@login']
|
||||
timeout-minutes: 20
|
||||
runs-on:
|
||||
- ubuntu-22.04
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: password
|
||||
POSTGRES_DB: postgres
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "18"
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Initialize PostgreSQL
|
||||
run: |
|
||||
echo "Initializing Databases"
|
||||
psql -h localhost -U postgres -d postgres -c "CREATE USER ${{ env.TEST_POSTGRES_USER }} WITH PASSWORD '${{ env.TEST_POSTGRES_PASSWORD }}';"
|
||||
psql -h localhost -U postgres -d postgres -c "CREATE DATABASE ${{ env.TEST_POSTGRES_DATABASE }} OWNER ${{ env.TEST_POSTGRES_USER }};"
|
||||
|
||||
- name: Install packages
|
||||
run: yarn install -y
|
||||
|
||||
- name: Cache playwright dependencies
|
||||
uses: awalsh128/cache-apt-pkgs-action@latest
|
||||
with:
|
||||
packages: |
|
||||
ffmpeg fonts-freefont-ttf fonts-ipafont-gothic fonts-tlwg-loma-otf
|
||||
fonts-unifont fonts-wqy-zenhei gstreamer1.0-libav gstreamer1.0-plugins-bad
|
||||
gstreamer1.0-plugins-base gstreamer1.0-plugins-good libaa1 libass9
|
||||
libasyncns0 libavc1394-0 libavcodec58 libavdevice58 libavfilter7
|
||||
libavformat58 libavutil56 libbluray2 libbs2b0 libcaca0 libcdio-cdda2
|
||||
libcdio-paranoia2 libcdio19 libcdparanoia0 libchromaprint1 libcodec2-1.0
|
||||
libdc1394-25 libdca0 libdecor-0-0 libdv4 libdvdnav4 libdvdread8 libegl-mesa0
|
||||
libegl1 libevdev2 libevent-2.1-7 libfaad2 libffi7 libflac8 libflite1
|
||||
libfluidsynth3 libfreeaptx0 libgles2 libgme0 libgsm1 libgssdp-1.2-0
|
||||
libgstreamer-gl1.0-0 libgstreamer-plugins-bad1.0-0
|
||||
libgstreamer-plugins-base1.0-0 libgstreamer-plugins-good1.0-0 libgupnp-1.2-1
|
||||
libgupnp-igd-1.0-4 libharfbuzz-icu0 libhyphen0 libiec61883-0
|
||||
libinstpatch-1.0-2 libjack-jackd2-0 libkate1 libldacbt-enc2 liblilv-0-0
|
||||
libltc11 libmanette-0.2-0 libmfx1 libmjpegutils-2.1-0 libmodplug1
|
||||
libmp3lame0 libmpcdec6 libmpeg2encpp-2.1-0 libmpg123-0 libmplex2-2.1-0
|
||||
libmysofa1 libnice10 libnotify4 libopenal-data libopenal1 libopengl0
|
||||
libopenh264-6 libopenmpt0 libopenni2-0 libopus0 liborc-0.4-0
|
||||
libpocketsphinx3 libpostproc55 libpulse0 libqrencode4 libraw1394-11
|
||||
librubberband2 libsamplerate0 libsbc1 libsdl2-2.0-0 libserd-0-0 libshine3
|
||||
libshout3 libsndfile1 libsndio7.0 libsord-0-0 libsoundtouch1 libsoup-3.0-0
|
||||
libsoup-3.0-common libsoxr0 libspandsp2 libspeex1 libsphinxbase3
|
||||
libsratom-0-0 libsrt1.4-gnutls libsrtp2-1 libssh-gcrypt-4 libswresample3
|
||||
libswscale5 libtag1v5 libtag1v5-vanilla libtheora0 libtwolame0 libudfread0
|
||||
libv4l-0 libv4lconvert0 libva-drm2 libva-x11-2 libva2 libvdpau1
|
||||
libvidstab1.1 libvisual-0.4-0 libvo-aacenc0 libvo-amrwbenc0 libvorbisenc2
|
||||
libvpx7 libwavpack1 libwebrtc-audio-processing1 libwildmidi2 libwoff1
|
||||
libx264-163 libxcb-shape0 libxv1 libxvidcore4 libzbar0 libzimg2
|
||||
libzvbi-common libzvbi0 libzxingcore1 ocl-icd-libopencl1 timgm6mb-soundfont
|
||||
xfonts-cyrillic xfonts-encodings xfonts-scalable xfonts-utils
|
||||
|
||||
- name: Cache playwright browsers
|
||||
id: cache-playwright
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-playwright-
|
||||
|
||||
- name: Setup project
|
||||
run: |
|
||||
yarn prisma:generate
|
||||
yarn web:build
|
||||
yarn prisma:deploy
|
||||
|
||||
- name: Start linkwarden server and worker
|
||||
run: yarn concurrently:start &
|
||||
|
||||
- name: Run Tests
|
||||
run: yarn workspace @linkwarden/web playwright test --grep ${{ matrix.test_case }}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: test-results
|
||||
retention-days: 30
|
||||
5
.github/workflows/release-container.yml
vendored
@@ -1,6 +1,7 @@
|
||||
name: Create and publish a container image on release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
@@ -27,7 +28,7 @@ jobs:
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -40,7 +41,7 @@ jobs:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
|
||||
27
.gitignore
vendored
@@ -1,5 +1,5 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
.next
|
||||
/out/
|
||||
|
||||
# production
|
||||
@@ -34,16 +34,21 @@ yarn-error.log*
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# tests
|
||||
/apps/web/tests
|
||||
/apps/web/test-results/
|
||||
/apps/web/blob-report/
|
||||
/apps/web/playwright-report/
|
||||
/apps/web/playwright/.cache/
|
||||
/apps/web/playwright/.auth/
|
||||
|
||||
# docker
|
||||
pgdata
|
||||
certificates
|
||||
|
||||
# generated files and folders
|
||||
/data
|
||||
.idea
|
||||
prisma/dev.db
|
||||
|
||||
# tests
|
||||
/tests
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
|
||||
# docker
|
||||
pgdata
|
||||
data.ms
|
||||
.turbo
|
||||
@@ -1,11 +1,8 @@
|
||||
node_modules
|
||||
.next
|
||||
public
|
||||
|
||||
/public
|
||||
*.lock
|
||||
*.log
|
||||
|
||||
.github
|
||||
|
||||
data
|
||||
pgdata
|
||||
|
||||
7
.vscode/settings.json
vendored
@@ -1 +1,6 @@
|
||||
{}
|
||||
{
|
||||
"tailwindCSS.experimental.classRegex": [
|
||||
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
|
||||
["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
|
||||
]
|
||||
}
|
||||
|
||||
52
Dockerfile
@@ -1,4 +1,16 @@
|
||||
FROM node:18.18-bullseye-slim
|
||||
# Stage: monolith-builder
|
||||
# Purpose: Uses the Rust image to build monolith
|
||||
# Notes:
|
||||
# - Fine to leave extra here, as only the resulting binary is copied out
|
||||
FROM docker.io/rust:1.86-bullseye AS monolith-builder
|
||||
|
||||
RUN set -eux && cargo install --locked monolith
|
||||
|
||||
# Stage: main-app
|
||||
# Purpose: Compiles the frontend and
|
||||
# Notes:
|
||||
# - Nothing extra should be left here. All commands should cleanup
|
||||
FROM node:22.14-bullseye-slim AS main-app
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
@@ -6,18 +18,42 @@ RUN mkdir /data
|
||||
|
||||
WORKDIR /data
|
||||
|
||||
COPY ./package.json ./yarn.lock ./playwright.config.ts ./
|
||||
COPY ./apps/web/package.json ./apps/web/playwright.config.ts ./apps/web/
|
||||
|
||||
# Increase timeout to pass github actions arm64 build
|
||||
RUN yarn install --network-timeout 10000000
|
||||
COPY ./apps/worker/package.json ./apps/worker/
|
||||
|
||||
RUN npx playwright install-deps && \
|
||||
COPY ./packages ./packages
|
||||
|
||||
COPY ./yarn.lock ./package.json ./
|
||||
|
||||
RUN --mount=type=cache,sharing=locked,target=/usr/local/share/.cache/yarn \
|
||||
set -eux && \
|
||||
yarn install --network-timeout 10000000 && \
|
||||
# Install curl for healthcheck, and ca-certificates to prevent monolith from failing to retrieve resources due to invalid certificates
|
||||
apt-get update && \
|
||||
apt-get install -yqq --no-install-recommends curl ca-certificates && \
|
||||
apt-get autoremove && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy the compiled monolith binary from the builder stage
|
||||
COPY --from=monolith-builder /usr/local/cargo/bin/monolith /usr/local/bin/monolith
|
||||
|
||||
RUN set -eux && \
|
||||
apt-get clean && \
|
||||
yarn cache clean
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN yarn prisma generate && \
|
||||
yarn build
|
||||
RUN yarn prisma:generate && \
|
||||
yarn web:build
|
||||
|
||||
CMD yarn prisma migrate deploy && yarn start
|
||||
HEALTHCHECK --interval=30s \
|
||||
--timeout=5s \
|
||||
--start-period=10s \
|
||||
--retries=3 \
|
||||
CMD [ "/usr/bin/curl", "--silent", "--fail", "http://127.0.0.1:3000/" ]
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["sh", "-c", "yarn prisma:deploy && yarn concurrently:start"]
|
||||
|
||||
86
README.md
@@ -1,59 +1,63 @@
|
||||
<div align="center">
|
||||
<img src="./assets/logo.png" width="100px" />
|
||||
<h1>Linkwarden</h1>
|
||||
<h3>Bookmark Preservation for Individuals and Teams</h3>
|
||||
|
||||
<a href="https://discord.com/invite/CtuYV47nuJ"><img src="https://img.shields.io/discord/1117993124669702164?logo=discord&style=flat" alt="Discord"></a>
|
||||
<a href="https://twitter.com/LinkwardenHQ"><img src="https://img.shields.io/twitter/follow/linkwarden" alt="Twitter"></a>
|
||||
<a href="https://twitter.com/LinkwardenHQ"><img src="https://img.shields.io/twitter/follow/linkwarden" alt="Twitter"></a> <a href="https://news.ycombinator.com/item?id=36942308"><img src="https://img.shields.io/badge/Hacker%20News-280-%23FF6600"></img></a>
|
||||
|
||||
<img alt="GitHub commits since latest release" src="https://img.shields.io/github/commits-since/linkwarden/linkwarden/latest/dev?style=for-the-badge&label=COMMITS%20SINCE%20LATEST%20RELEASE">
|
||||
<a href="https://github.com/linkwarden/linkwarden/releases"><img alt="GitHub release" src="https://img.shields.io/github/v/release/linkwarden/linkwarden"></a>
|
||||
<a href="https://crowdin.com/project/linkwarden">
|
||||
<img src="https://badges.crowdin.net/linkwarden/localized.svg" alt="Crowdin" /></a>
|
||||
<a href="https://opencollective.com/linkwarden"><img src="https://img.shields.io/opencollective/all/linkwarden" alt="Open Collective"></a>
|
||||
|
||||
</div>
|
||||
|
||||
<div align='center'>
|
||||
|
||||
[Website](https://linkwarden.app) | [Getting Started](https://docs.linkwarden.app) | [Features](https://github.com/linkwarden/linkwarden#features) | [Roadmap](https://github.com/orgs/linkwarden/projects/1) | [Support ❤](https://github.com/linkwarden/linkwarden#support-)
|
||||
[« LAUNCH DEMO »](https://demo.linkwarden.app)
|
||||
|
||||
[Cloud](https://cloud.linkwarden.app) · [Website](https://linkwarden.app) · [Features](https://github.com/linkwarden/linkwarden#features) · [Docs](https://docs.linkwarden.app)
|
||||
|
||||
</div>
|
||||
|
||||
## Intro & motivation
|
||||
|
||||
**Linkwarden is a self-hosted, open-source collaborative bookmark manager to collect, organize and archive webpages.** The objective is to organize useful webpages and articles you find across the web in one place, and since useful webpages can go away (see the inevitability of [Link Rot](https://www.howtogeek.com/786227/what-is-link-rot-and-how-does-it-threaten-the-web/)), Linkwarden also saves a copy of each webpage as a Screenshot and PDF, ensuring accessibility even if the original content is no longer available.
|
||||
**Linkwarden is a self-hosted, open-source collaborative bookmark manager to collect, organize and archive webpages.**
|
||||
|
||||
The objective is to organize useful webpages and articles you find across the web in one place, and since useful webpages can go away (see the inevitability of [Link Rot](https://www.howtogeek.com/786227/what-is-link-rot-and-how-does-it-threaten-the-web/)), Linkwarden also saves a copy of each webpage as a Screenshot and PDF, ensuring accessibility even if the original content is no longer available.
|
||||
|
||||
Additionally, Linkwarden is designed with collaboration in mind, sharing links with the public and/or allowing multiple users to work together seamlessly.
|
||||
|
||||
> [!TIP]
|
||||
> Our official [Cloud](https://linkwarden.app/#pricing) offering provides the simplest way to begin using Linkwarden and it's the preferred choice for many due to its time-saving benefits. <br> Your subscription supports our hosting infrastructure and ongoing development. <br> Alternatively, if you prefer [self-hosting](https://docs.linkwarden.app/self-hosting/installation) Linkwarden, no problem! You'll still have access to all the premium features.
|
||||
> Our official [Cloud](https://linkwarden.app/#pricing) offering provides the simplest way to begin using Linkwarden and it's the preferred choice for many due to its time-saving benefits. <br> Your subscription supports our hosting infrastructure and ongoing development. <br> Alternatively, if you prefer self-hosting Linkwarden, you can do so by following our [Installation documentation](https://docs.linkwarden.app/self-hosting/installation).
|
||||
|
||||
<img src="./assets/dashboard.png" />
|
||||
|
||||
<div align="center">
|
||||
<img src="./assets/all_links.png" width="32%" />
|
||||
<img src="./assets/all_links.jpg" width="23%" />
|
||||
|
||||
<img src="./assets/all_collections.png" width="32%" />
|
||||
<img src="./assets/list_view.jpg" width="23%" />
|
||||
|
||||
<img src="./assets/manage_team.png" width="32%" />
|
||||
<img src="./assets/all_collections.jpg" width="23%" />
|
||||
|
||||
<img src="./assets/readable_view.png" width="32%" />
|
||||
<img src="./assets/manage_team.jpg" width="23%" />
|
||||
|
||||
<img src="./assets/public_page.png" width="32%" />
|
||||
<img src="./assets/readable_view.jpg" width="23%" />
|
||||
|
||||
<img src="./assets/light_mode.png" width="32%" />
|
||||
<img src="./assets/preserved_formats.jpg" width="23%" />
|
||||
|
||||
<img src="./assets/public_page.jpg" width="23%" />
|
||||
|
||||
<img src="./assets/light_dashboard.jpg" width="23%" />
|
||||
</div>
|
||||
|
||||
<details>
|
||||
<summary><b>A bit of a "history"</b></summary>
|
||||
Linkwarden has been completely rebuilt and redesigned from ground up, so pretty much the only thing it has in common with its predecessor is the idea behind it - bookmark management.
|
||||
|
||||
**What happened to the old version?**
|
||||
We've forked the old version from the current repository into [this repo](https://github.com/linkwarden/linkwarden-old).
|
||||
|
||||
</details>
|
||||
|
||||
## Features
|
||||
|
||||
- 📸 Auto capture a screenshot, PDF, and readable view of each webpage.
|
||||
- 📸 Auto capture a screenshot, PDF, single html file, and readable view of each webpage.
|
||||
- 🏛️ Send your webpage to Wayback Machine ([archive.org](https://archive.org)) for a snapshot. (Optional)
|
||||
- 📂 Organize links by collection, name, description and multiple tags.
|
||||
- ✨ Local AI Tagging to automatically tag your links based on their content (Optional).
|
||||
- 📂 Organize links by collection, sub-collection, name, description and multiple tags.
|
||||
- 👥 Collaborate on gathering links in a collection.
|
||||
- 🎛️ Customize the permissions of each member.
|
||||
- 🌐 Share your collected links and preserved formats with the world.
|
||||
@@ -61,10 +65,20 @@ We've forked the old version from the current repository into [this repo](https:
|
||||
- 🔍 Full text search, filter and sort for easy retrieval.
|
||||
- 📱 Responsive design and supports most modern browsers.
|
||||
- 🌓 Dark/Light mode support.
|
||||
- 🧩 Browser extension, managed by the community. [Star it here!](https://github.com/linkwarden/browser-extension)
|
||||
- 🧩 Browser extension. [Star it here!](https://github.com/linkwarden/browser-extension)
|
||||
- 🔄 Browser Synchronization (using [Floccus](https://floccus.org)!)
|
||||
- ⬇️ Import and export your bookmarks.
|
||||
- 🔐 SSO integration. (Enterprise and Self-hosted users only)
|
||||
- ✨ And so many more features!
|
||||
- 📦 Installable Progressive Web App (PWA).
|
||||
- 🍎 iOS Shortcut to save Links to Linkwarden.
|
||||
- 🔑 API keys.
|
||||
- ✅ Bulk actions.
|
||||
- 👥 User administration.
|
||||
- 🌐 Support for Other Languages (i18n).
|
||||
- 📁 Image and PDF Uploads.
|
||||
- 🎨 Custom Icons for Links and Collections.
|
||||
- 🔔 RSS Feed Subscription.
|
||||
- ✨ And many more features. (Literally!)
|
||||
|
||||
## Like what we're doing? Give us a Star ⭐
|
||||
|
||||
@@ -82,25 +96,39 @@ Join and follow us in the following platforms to stay up to date about the most
|
||||
|
||||
## Suggestions
|
||||
|
||||
We _usually_ go after the [popular suggestions](https://github.com/linkwarden/linkwarden/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc). Feel free to open a [new issue](https://github.com/linkwarden/linkwarden/issues/new?assignees=&labels=enhancement&projects=&template=feature_request.md&title=) to suggest one - others might be interested too! :)
|
||||
We _usually_ go after the [popular suggestions](https://github.com/linkwarden/linkwarden/issues?q=is%3Aissue%20is%3Aopen%20sort%3Areactions-%2B1-desc). Feel free to open a [new issue](https://github.com/linkwarden/linkwarden/issues/new?assignees=&labels=enhancement&projects=&template=feature_request.md&title=) to suggest one - others might be interested too! :)
|
||||
|
||||
## Roadmap
|
||||
|
||||
Make sure to check out our [public roadmap](https://github.com/orgs/linkwarden/projects/1).
|
||||
|
||||
## Docs
|
||||
## Community Projects
|
||||
|
||||
For information on how to get started or to set up your own instance, please visit the [documentation](https://docs.linkwarden.app).
|
||||
Here are some community-maintained projects that are built around Linkwarden:
|
||||
|
||||
- [My Links](https://apps.apple.com/ca/app/my-links-for-linkwarden/id6504573402) - iOS and MacOS Apps, maintained by [JGeek00](https://github.com/JGeek00).
|
||||
- [LinkDroid](https://fossdroid.com/a/linkdroid-for-linkwarden.html) - Android App with share sheet integration, [source code](https://github.com/Dacid99/LinkDroid-for-Linkwarden).
|
||||
- [LinkGuardian](https://github.com/Elbullazul/LinkGuardian) - An Android client for Linkwarden. Built with Kotlin and Jetpack compose.
|
||||
- [StarWarden](https://github.com/rtuszik/starwarden) - A browser extension to save your starred GitHub repositories to Linkwarden.
|
||||
|
||||
## Development
|
||||
|
||||
If you want to contribute, Thanks! Start by checking our [public roadmap](https://github.com/orgs/linkwarden/projects/1), there you'll see a [README for contributers](https://github.com/orgs/linkwarden/projects/1?pane=issue&itemId=34708277) for the rest of the info on how to contribute and the main tech stack.
|
||||
If you want to contribute, Thanks! Start by choosing one of our [popular suggestions](https://github.com/linkwarden/linkwarden/issues?q=is%3Aissue%20is%3Aopen%20sort%3Areactions-%2B1-desc), just please stay in touch with [@daniel31x13](https://github.com/daniel31x13) before starting.
|
||||
|
||||
# Translations
|
||||
|
||||
If you want to help us translate Linkwarden to your language, please join our [Crowdin project](https://crowdin.com/project/linkwarden) and start translating. We would love to have your help!
|
||||
|
||||
To start translating a new language, please create an issue so we can set it up for you. New languages will be added once they reach at least 50% translation completion.
|
||||
|
||||
<a href="https://crowdin.com/project/linkwarden">
|
||||
<img src="https://badges.crowdin.net/linkwarden/localized.svg" alt="Crowdin" /></a>
|
||||
|
||||
## Security
|
||||
|
||||
If you found a security vulnerability, please do **not** create a public issue, instead send an email to [security@linkwarden.app](mailto:security@linkwarden.app) stating the vulnerability. Thanks!
|
||||
|
||||
## Support ❤
|
||||
## Support <3
|
||||
|
||||
Other than using our official [Cloud](https://linkwarden.app/#pricing) offering, any [donations](https://opencollective.com/linkwarden) are highly appreciated as well!
|
||||
|
||||
|
||||
2
apps/mobile/.env.sample
Normal file
@@ -0,0 +1,2 @@
|
||||
LINKWARDEN_URL=
|
||||
EXPO_PUBLIC_SHOW_LOGS=
|
||||
39
apps/mobile/.gitignore
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# Expo
|
||||
.expo/
|
||||
dist/
|
||||
web-build/
|
||||
expo-env.d.ts
|
||||
|
||||
# Native
|
||||
*.orig.*
|
||||
*.jks
|
||||
*.p8
|
||||
*.p12
|
||||
*.key
|
||||
*.mobileprovision
|
||||
|
||||
# Metro
|
||||
.metro-health-check*
|
||||
|
||||
# debug
|
||||
npm-debug.*
|
||||
yarn-debug.*
|
||||
yarn-error.*
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
|
||||
app-example
|
||||
.env
|
||||
1
apps/mobile/.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
node-linker=hoisted
|
||||
16
apps/mobile/android/.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# OSX
|
||||
#
|
||||
.DS_Store
|
||||
|
||||
# Android/IntelliJ
|
||||
#
|
||||
build/
|
||||
.idea
|
||||
.gradle
|
||||
local.properties
|
||||
*.iml
|
||||
*.hprof
|
||||
.cxx/
|
||||
|
||||
# Bundle artifacts
|
||||
*.jsbundle
|
||||
176
apps/mobile/android/app/build.gradle
Normal file
@@ -0,0 +1,176 @@
|
||||
apply plugin: "com.android.application"
|
||||
apply plugin: "org.jetbrains.kotlin.android"
|
||||
apply plugin: "com.facebook.react"
|
||||
|
||||
def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
|
||||
|
||||
/**
|
||||
* This is the configuration block to customize your React Native Android app.
|
||||
* By default you don't need to apply any configuration, just uncomment the lines you need.
|
||||
*/
|
||||
react {
|
||||
entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim())
|
||||
reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
|
||||
hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
|
||||
codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
|
||||
|
||||
// Use Expo CLI to bundle the app, this ensures the Metro config
|
||||
// works correctly with Expo projects.
|
||||
cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim())
|
||||
bundleCommand = "export:embed"
|
||||
|
||||
/* Folders */
|
||||
// The root of your project, i.e. where "package.json" lives. Default is '../..'
|
||||
// root = file("../../")
|
||||
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
|
||||
// reactNativeDir = file("../../node_modules/react-native")
|
||||
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
|
||||
// codegenDir = file("../../node_modules/@react-native/codegen")
|
||||
|
||||
/* 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'.
|
||||
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
|
||||
// debuggableVariants = ["liteDebug", "prodDebug"]
|
||||
|
||||
/* Bundling */
|
||||
// A list containing the node command and its flags. Default is just 'node'.
|
||||
// nodeExecutableAndArgs = ["node"]
|
||||
|
||||
//
|
||||
// The path to the CLI configuration file. Default is empty.
|
||||
// bundleConfig = file(../rn-cli.config.js)
|
||||
//
|
||||
// The name of the generated asset file containing your JS bundle
|
||||
// bundleAssetName = "MyApplication.android.bundle"
|
||||
//
|
||||
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
|
||||
// entryFile = file("../js/MyApplication.android.js")
|
||||
//
|
||||
// A list of extra flags to pass to the 'bundle' commands.
|
||||
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
|
||||
// extraPackagerArgs = []
|
||||
|
||||
/* Hermes Commands */
|
||||
// The hermes compiler command to run. By default it is 'hermesc'
|
||||
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
|
||||
//
|
||||
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
|
||||
// hermesFlags = ["-O", "-output-source-map"]
|
||||
|
||||
/* Autolinking */
|
||||
autolinkLibrariesWithApp()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
|
||||
*/
|
||||
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()
|
||||
|
||||
/**
|
||||
* The preferred build flavor of JavaScriptCore (JSC)
|
||||
*
|
||||
* For example, to use the international variant, you can use:
|
||||
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
|
||||
*
|
||||
* 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:+'
|
||||
|
||||
android {
|
||||
ndkVersion rootProject.ext.ndkVersion
|
||||
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
compileSdk rootProject.ext.compileSdkVersion
|
||||
|
||||
namespace 'com.anonymous.mobileapp'
|
||||
defaultConfig {
|
||||
applicationId 'com.anonymous.mobileapp'
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0.0"
|
||||
}
|
||||
signingConfigs {
|
||||
debug {
|
||||
storeFile file('debug.keystore')
|
||||
storePassword 'android'
|
||||
keyAlias 'androiddebugkey'
|
||||
keyPassword 'android'
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
release {
|
||||
// Caution! In production, you need to generate your own keystore file.
|
||||
// see https://reactnative.dev/docs/signed-apk-android.
|
||||
signingConfig signingConfigs.debug
|
||||
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
jniLibs {
|
||||
useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
|
||||
}
|
||||
}
|
||||
androidResources {
|
||||
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
|
||||
}
|
||||
}
|
||||
|
||||
// Apply static values from `gradle.properties` to the `android.packagingOptions`
|
||||
// Accepts values in comma delimited lists, example:
|
||||
// android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini
|
||||
["pickFirsts", "excludes", "merges", "doNotStrip"].each { prop ->
|
||||
// Split option: 'foo,bar' -> ['foo', 'bar']
|
||||
def options = (findProperty("android.packagingOptions.$prop") ?: "").split(",");
|
||||
// Trim all elements in place.
|
||||
for (i in 0..<options.size()) options[i] = options[i].trim();
|
||||
// `[] - ""` is essentially `[""].filter(Boolean)` removing all empty strings.
|
||||
options -= ""
|
||||
|
||||
if (options.length > 0) {
|
||||
println "android.packagingOptions.$prop += $options ($options.length)"
|
||||
// Ex: android.packagingOptions.pickFirsts += '**/SCCS/**'
|
||||
options.each {
|
||||
android.packagingOptions[prop] += it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// The version of react-native is set by the React Native Gradle Plugin
|
||||
implementation("com.facebook.react:react-android")
|
||||
|
||||
def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
|
||||
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
|
||||
def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";
|
||||
|
||||
if (isGifEnabled) {
|
||||
// For animated gif support
|
||||
implementation("com.facebook.fresco:animated-gif:${reactAndroidLibs.versions.fresco.get()}")
|
||||
}
|
||||
|
||||
if (isWebpEnabled) {
|
||||
// For webp support
|
||||
implementation("com.facebook.fresco:webpsupport:${reactAndroidLibs.versions.fresco.get()}")
|
||||
if (isWebpAnimatedEnabled) {
|
||||
// Animated webp support
|
||||
implementation("com.facebook.fresco:animated-webp:${reactAndroidLibs.versions.fresco.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
if (hermesEnabled.toBoolean()) {
|
||||
implementation("com.facebook.react:hermes-android")
|
||||
} else {
|
||||
implementation jscFlavor
|
||||
}
|
||||
}
|
||||
BIN
apps/mobile/android/app/debug.keystore
Normal file
14
apps/mobile/android/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# react-native-reanimated
|
||||
-keep class com.swmansion.reanimated.** { *; }
|
||||
-keep class com.facebook.react.turbomodule.** { *; }
|
||||
|
||||
# Add any project specific keep options here:
|
||||
7
apps/mobile/android/app/src/debug/AndroidManifest.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
|
||||
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:usesCleartextTraffic" />
|
||||
</manifest>
|
||||
33
apps/mobile/android/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data android:scheme="https"/>
|
||||
</intent>
|
||||
</queries>
|
||||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:fullBackupContent="@xml/secure_store_backup_rules" android:dataExtractionRules="@xml/secure_store_data_extraction_rules">
|
||||
<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
|
||||
<activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data android:scheme="myapp"/>
|
||||
<data android:scheme="com.anonymous.mobileapp"/>
|
||||
<data android:scheme="exp+mobile-app"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.anonymous.mobileapp
|
||||
import expo.modules.splashscreen.SplashScreenManager
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
|
||||
import com.facebook.react.ReactActivity
|
||||
import com.facebook.react.ReactActivityDelegate
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
|
||||
import com.facebook.react.defaults.DefaultReactActivityDelegate
|
||||
|
||||
import expo.modules.ReactActivityDelegateWrapper
|
||||
|
||||
class MainActivity : ReactActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// Set the theme to AppTheme BEFORE onCreate to support
|
||||
// coloring the background, status bar, and navigation bar.
|
||||
// This is required for expo-splash-screen.
|
||||
// setTheme(R.style.AppTheme);
|
||||
// @generated begin expo-splashscreen - expo prebuild (DO NOT MODIFY) sync-f3ff59a738c56c9a6119210cb55f0b613eb8b6af
|
||||
SplashScreenManager.registerOnActivity(this)
|
||||
// @generated end expo-splashscreen
|
||||
super.onCreate(null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the main component registered from JavaScript. This is used to schedule
|
||||
* rendering of the component.
|
||||
*/
|
||||
override fun getMainComponentName(): String = "main"
|
||||
|
||||
/**
|
||||
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
|
||||
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
|
||||
*/
|
||||
override fun createReactActivityDelegate(): ReactActivityDelegate {
|
||||
return ReactActivityDelegateWrapper(
|
||||
this,
|
||||
BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
|
||||
object : DefaultReactActivityDelegate(
|
||||
this,
|
||||
mainComponentName,
|
||||
fabricEnabled
|
||||
){})
|
||||
}
|
||||
|
||||
/**
|
||||
* Align the back button behavior with Android S
|
||||
* where moving root activities to background instead of finishing activities.
|
||||
* @see <a href="https://developer.android.com/reference/android/app/Activity#onBackPressed()">onBackPressed</a>
|
||||
*/
|
||||
override fun invokeDefaultOnBackPressed() {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
|
||||
if (!moveTaskToBack(false)) {
|
||||
// For non-root activities, use the default implementation to finish them.
|
||||
super.invokeDefaultOnBackPressed()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Use the default back button implementation on Android S
|
||||
// because it's doing more than [Activity.moveTaskToBack] in fact.
|
||||
super.invokeDefaultOnBackPressed()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.anonymous.mobileapp
|
||||
|
||||
import android.app.Application
|
||||
import android.content.res.Configuration
|
||||
|
||||
import com.facebook.react.PackageList
|
||||
import com.facebook.react.ReactApplication
|
||||
import com.facebook.react.ReactNativeHost
|
||||
import com.facebook.react.ReactPackage
|
||||
import com.facebook.react.ReactHost
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
|
||||
import com.facebook.react.defaults.DefaultReactNativeHost
|
||||
import com.facebook.react.soloader.OpenSourceMergedSoMapping
|
||||
import com.facebook.soloader.SoLoader
|
||||
|
||||
import expo.modules.ApplicationLifecycleDispatcher
|
||||
import expo.modules.ReactNativeHostWrapper
|
||||
|
||||
class MainApplication : Application(), ReactApplication {
|
||||
|
||||
override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(
|
||||
this,
|
||||
object : DefaultReactNativeHost(this) {
|
||||
override fun getPackages(): List<ReactPackage> {
|
||||
val packages = PackageList(this).packages
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
// packages.add(new MyReactNativePackage());
|
||||
return packages
|
||||
}
|
||||
|
||||
override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
|
||||
|
||||
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
|
||||
|
||||
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
|
||||
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
|
||||
}
|
||||
)
|
||||
|
||||
override val reactHost: ReactHost
|
||||
get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost)
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
SoLoader.init(this, OpenSourceMergedSoMapping)
|
||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||
// If you opted-in for the New Architecture, we load the native entry point for this app.
|
||||
load()
|
||||
}
|
||||
ApplicationLifecycleDispatcher.onApplicationCreate(this)
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 65 KiB |
@@ -0,0 +1,6 @@
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@color/splashscreen_background"/>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splashscreen_logo"/>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2014 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
|
||||
android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
|
||||
android:insetTop="@dimen/abc_edit_text_inset_top_material"
|
||||
android:insetBottom="@dimen/abc_edit_text_inset_bottom_material"
|
||||
>
|
||||
|
||||
<selector>
|
||||
<!--
|
||||
This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).
|
||||
The item below with state_pressed="false" and state_focused="false" causes a NullPointerException.
|
||||
NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'
|
||||
|
||||
<item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
|
||||
|
||||
For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.
|
||||
-->
|
||||
<item android:state_enabled="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
|
||||
<item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
|
||||
</selector>
|
||||
|
||||
</inset>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/iconBackground"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/iconBackground"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1 @@
|
||||
<resources/>
|
||||
6
apps/mobile/android/app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<resources>
|
||||
<color name="splashscreen_background">#ffffff</color>
|
||||
<color name="iconBackground">#ffffff</color>
|
||||
<color name="colorPrimary">#023c69</color>
|
||||
<color name="colorPrimaryDark">#ffffff</color>
|
||||
</resources>
|
||||
6
apps/mobile/android/app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<resources>
|
||||
<string name="app_name">mobile-app</string>
|
||||
<string name="expo_system_ui_user_interface_style" translatable="false">automatic</string>
|
||||
<string name="expo_splash_screen_resize_mode" translatable="false">contain</string>
|
||||
<string name="expo_splash_screen_status_bar_translucent" translatable="false">false</string>
|
||||
</resources>
|
||||
19
apps/mobile/android/app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
<item name="android:editTextStyle">@style/ResetEditText</item>
|
||||
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="android:statusBarColor">#ffffff</item>
|
||||
</style>
|
||||
<style name="ResetEditText" parent="@android:style/Widget.EditText">
|
||||
<item name="android:padding">0dp</item>
|
||||
<item name="android:textColorHint">#c8c8c8</item>
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
</style>
|
||||
<style name="Theme.App.SplashScreen" parent="Theme.SplashScreen">
|
||||
<item name="windowSplashScreenBackground">@color/splashscreen_background</item>
|
||||
<item name="windowSplashScreenAnimatedIcon">@drawable/splashscreen_logo</item>
|
||||
<item name="postSplashScreenTheme">@style/AppTheme</item>
|
||||
</style>
|
||||
</resources>
|
||||
41
apps/mobile/android/build.gradle
Normal file
@@ -0,0 +1,41 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '35.0.0'
|
||||
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '24')
|
||||
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '35')
|
||||
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34')
|
||||
kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.25'
|
||||
|
||||
ndkVersion = "26.1.10909125"
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath('com.android.tools.build:gradle')
|
||||
classpath('com.facebook.react:react-native-gradle-plugin')
|
||||
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: "com.facebook.react.rootproject"
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven {
|
||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
||||
url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android'))
|
||||
}
|
||||
maven {
|
||||
// Android JSC is installed from npm
|
||||
url(new File(['node', '--print', "require.resolve('jsc-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), '../dist'))
|
||||
}
|
||||
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url 'https://www.jitpack.io' }
|
||||
}
|
||||
}
|
||||
56
apps/mobile/android/gradle.properties
Normal file
@@ -0,0 +1,56 @@
|
||||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
|
||||
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
|
||||
# Enable AAPT2 PNG crunching
|
||||
android.enablePngCrunchInReleaseBuilds=true
|
||||
|
||||
# Use this property to specify which architecture you want to build.
|
||||
# You can also override it from the CLI using
|
||||
# ./gradlew <task> -PreactNativeArchitectures=x86_64
|
||||
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
|
||||
|
||||
# Use this property to enable support to the new architecture.
|
||||
# This will allow you to use TurboModules and the Fabric render in
|
||||
# your application. You should enable this flag either if you want
|
||||
# to write custom TurboModules/Fabric components OR use libraries that
|
||||
# are providing them.
|
||||
newArchEnabled=true
|
||||
|
||||
# Use this property to enable or disable the Hermes JS engine.
|
||||
# If set to false, you will be using JSC instead.
|
||||
hermesEnabled=true
|
||||
|
||||
# Enable GIF support in React Native images (~200 B increase)
|
||||
expo.gif.enabled=true
|
||||
# Enable webp support in React Native images (~85 KB increase)
|
||||
expo.webp.enabled=true
|
||||
# Enable animated webp support (~3.4 MB increase)
|
||||
# Disabled by default because iOS doesn't support animated webp
|
||||
expo.webp.animated=false
|
||||
|
||||
# Enable network inspector
|
||||
EX_DEV_CLIENT_NETWORK_INSPECTOR=true
|
||||
|
||||
# Use legacy packaging to compress native libraries in the resulting APK.
|
||||
expo.useLegacyPackaging=false
|
||||
BIN
apps/mobile/android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
7
apps/mobile/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
252
apps/mobile/android/gradlew
vendored
Executable file
@@ -0,0 +1,252 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
94
apps/mobile/android/gradlew.bat
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
38
apps/mobile/android/settings.gradle
Normal file
@@ -0,0 +1,38 @@
|
||||
pluginManagement {
|
||||
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().toString())
|
||||
}
|
||||
plugins { id("com.facebook.react.settings") }
|
||||
|
||||
extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
|
||||
if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
|
||||
ex.autolinkLibrariesFromCommand()
|
||||
} else {
|
||||
def command = [
|
||||
'node',
|
||||
'--no-warnings',
|
||||
'--eval',
|
||||
'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
|
||||
'react-native-config',
|
||||
'--json',
|
||||
'--platform',
|
||||
'android'
|
||||
].toList()
|
||||
ex.autolinkLibrariesFromCommand(command)
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = 'mobile-app'
|
||||
|
||||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
reactAndroidLibs {
|
||||
from(files(new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../gradle/libs.versions.toml")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
|
||||
useExpoModules()
|
||||
|
||||
include ':app'
|
||||
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile())
|
||||
44
apps/mobile/app.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "mobile-app",
|
||||
"slug": "mobile-app",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/images/icon.png",
|
||||
"scheme": "myapp",
|
||||
"userInterfaceStyle": "automatic",
|
||||
"newArchEnabled": true,
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "com.anonymous.mobile-app"
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/images/adaptive-icon.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"package": "com.anonymous.mobileapp"
|
||||
},
|
||||
"web": {
|
||||
"bundler": "metro",
|
||||
"output": "static",
|
||||
"favicon": "./assets/images/favicon.png"
|
||||
},
|
||||
"plugins": [
|
||||
"expo-router",
|
||||
[
|
||||
"expo-splash-screen",
|
||||
{
|
||||
"image": "./assets/images/splash-icon.png",
|
||||
"imageWidth": 200,
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#ffffff"
|
||||
}
|
||||
],
|
||||
"expo-secure-store"
|
||||
],
|
||||
"experiments": {
|
||||
"typedRoutes": true
|
||||
}
|
||||
}
|
||||
}
|
||||
65
apps/mobile/app/(tabs)/_layout.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import { Tabs, useRouter } from "expo-router";
|
||||
import React from "react";
|
||||
import { Platform, TouchableOpacity, useColorScheme } from "react-native";
|
||||
import HapticTab from "@/components/HapticTab";
|
||||
import { IconSymbol } from "@/components/ui/IconSymbol";
|
||||
// import "react-native-reanimated";
|
||||
import TabBarBackground from "@/components/ui/TabBarBackground";
|
||||
|
||||
export default function TabLayout() {
|
||||
const colorScheme = useColorScheme();
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
tabBarBackground: TabBarBackground,
|
||||
tabBarActiveTintColor: colorScheme === "dark" ? "white" : "black",
|
||||
tabBarButton: HapticTab,
|
||||
// headerShown: false,
|
||||
tabBarStyle: Platform.select({
|
||||
ios: {
|
||||
position: "absolute",
|
||||
},
|
||||
default: {},
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<Tabs.Screen
|
||||
name="dashboard"
|
||||
options={{
|
||||
title: "Dashboard",
|
||||
headerShown: false,
|
||||
tabBarIcon: ({ color }) => (
|
||||
<IconSymbol size={28} name="house.fill" color={color} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="links"
|
||||
options={{
|
||||
title: "Links",
|
||||
headerSearchBarOptions: {
|
||||
placeholder: "Search",
|
||||
autoCapitalize: "none",
|
||||
onChangeText: (e) => {
|
||||
router.setParams({ search: e.nativeEvent.text });
|
||||
},
|
||||
},
|
||||
tabBarIcon: ({ color }) => (
|
||||
<IconSymbol size={28} name="link" color={color} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="settings"
|
||||
options={{
|
||||
title: "Settings",
|
||||
tabBarIcon: ({ color }) => (
|
||||
<IconSymbol size={28} name="gearshape.fill" color={color} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
54
apps/mobile/app/(tabs)/dashboard.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { Text, StyleSheet, TouchableOpacity } from "react-native";
|
||||
import { IconSymbol } from "@/components/ui/IconSymbol";
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import { useState } from "react";
|
||||
// import AddLink from "@/components/Modals/AddLink";
|
||||
import ModalBase from "@/components/ModalBase";
|
||||
|
||||
export default function DashboardScreen() {
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<SafeAreaView className="flex-1 justify-center items-center">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<TouchableOpacity>
|
||||
<IconSymbol size={20} name="plus" color={""} />
|
||||
</TouchableOpacity>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.Item key="new-link" onSelect={() => setModalOpen(true)}>
|
||||
<DropdownMenu.ItemTitle>New Link</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
key="new-collection"
|
||||
onSelect={() => alert("Item 2 selected")}
|
||||
>
|
||||
<DropdownMenu.ItemTitle>New Collection</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
key="upload-file"
|
||||
onSelect={() => alert("Item 3 selected")}
|
||||
>
|
||||
<DropdownMenu.ItemTitle>Upload File</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
<Text>Dashboard</Text>
|
||||
{/* <TouchableOpacity>
|
||||
<IconSymbol size={20} name="plus" color={""} />
|
||||
</TouchableOpacity> */}
|
||||
<ModalBase
|
||||
isVisible={modalOpen}
|
||||
onClose={() => {
|
||||
setModalOpen(false);
|
||||
}}
|
||||
>
|
||||
<Text>Hi</Text>
|
||||
</ModalBase>
|
||||
{/* <AddLink isVisible={modalOpen} onClose={() => setModalOpen(false)} /> */}
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
61
apps/mobile/app/(tabs)/links.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import { useLinks } from "@linkwarden/router/links";
|
||||
import { View, StyleSheet, FlatList, Platform } from "react-native";
|
||||
import useAuthStore from "@/store/auth";
|
||||
import LinkListing from "@/components/LinkListing";
|
||||
import { useLocalSearchParams } from "expo-router";
|
||||
import React from "react";
|
||||
import { LinkIncludingShortenedCollectionAndTags } from "@linkwarden/types";
|
||||
|
||||
const RenderItem = React.memo(
|
||||
({ item }: { item: LinkIncludingShortenedCollectionAndTags }) => {
|
||||
return <LinkListing link={item} />;
|
||||
}
|
||||
);
|
||||
|
||||
export default function LinksScreen() {
|
||||
const { auth } = useAuthStore();
|
||||
const { search } = useLocalSearchParams<{ search?: string }>();
|
||||
|
||||
const { links, data } = useLinks(
|
||||
{
|
||||
sort: 0,
|
||||
searchQueryString: search ?? search,
|
||||
},
|
||||
auth
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<FlatList
|
||||
ListHeaderComponent={() => <></>}
|
||||
data={links || []}
|
||||
onRefresh={() => data.refetch()}
|
||||
refreshing={data.isRefetching}
|
||||
initialNumToRender={4}
|
||||
keyExtractor={(item) => item.id?.toString() || ""}
|
||||
renderItem={({ item }) => (
|
||||
<RenderItem item={item} key={item.id?.toString()} />
|
||||
)}
|
||||
onEndReached={() => data.fetchNextPage()}
|
||||
onEndReachedThreshold={0.5}
|
||||
ItemSeparatorComponent={() => (
|
||||
<View
|
||||
style={{
|
||||
height: 1,
|
||||
backgroundColor: "#eee",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: Platform.select({
|
||||
ios: {
|
||||
paddingBottom: 83,
|
||||
},
|
||||
default: {},
|
||||
}),
|
||||
});
|
||||
21
apps/mobile/app/(tabs)/settings.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import useAuthStore from "@/store/auth";
|
||||
import { View, Text, StyleSheet, Button } from "react-native";
|
||||
|
||||
export default function SettingsScreen() {
|
||||
const { signOut } = useAuthStore();
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Settings</Text>
|
||||
<Button title="Sign out" onPress={() => signOut()} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
});
|
||||
20
apps/mobile/app/+not-found.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Link, Stack } from "expo-router";
|
||||
import { View, StyleSheet } from "react-native";
|
||||
|
||||
export default function NotFoundScreen() {
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen options={{ title: "Oops! This screen doesn't exist." }} />
|
||||
<View style={styles.container}>
|
||||
<Link href="/">Go to home screen</Link>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
});
|
||||
52
apps/mobile/app/_layout.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Stack } from "expo-router";
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
import { PersistQueryClientProvider } from "@tanstack/react-query-persist-client";
|
||||
import { mmkvPersister } from "@/lib/queryPersister";
|
||||
import { useState } from "react";
|
||||
import "../styles/global.css";
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
staleTime: 1000 * 60 * 60 * 24, // never refetch for 24h
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default function RootLayout() {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
return (
|
||||
<PersistQueryClientProvider
|
||||
client={queryClient}
|
||||
persistOptions={{
|
||||
persister: mmkvPersister,
|
||||
maxAge: Infinity,
|
||||
}}
|
||||
onSuccess={() => setIsLoading(false)}
|
||||
>
|
||||
{!isLoading && (
|
||||
<Stack
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
}}
|
||||
>
|
||||
{/* <Stack.Screen name="(tabs)" /> */}
|
||||
<Stack.Screen
|
||||
name="links/[id]"
|
||||
options={{
|
||||
headerBackTitle: "Back",
|
||||
headerShown: true,
|
||||
headerTitle: "",
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen name="login" />
|
||||
<Stack.Screen name="+not-found" />
|
||||
</Stack>
|
||||
)}
|
||||
</PersistQueryClientProvider>
|
||||
);
|
||||
}
|
||||
26
apps/mobile/app/index.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import useAuthStore from "@/store/auth";
|
||||
import { Redirect, router } from "expo-router";
|
||||
import { useEffect } from "react";
|
||||
import { View, Text, StyleSheet, Button } from "react-native";
|
||||
|
||||
export default function HomeScreen() {
|
||||
const { setAuth, auth } = useAuthStore();
|
||||
|
||||
useEffect(() => {
|
||||
setAuth();
|
||||
}, []);
|
||||
|
||||
if (auth.session) {
|
||||
return <Redirect href="/dashboard" />;
|
||||
} else {
|
||||
return <Redirect href="/login" />;
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
});
|
||||
177
apps/mobile/app/links/[id].tsx
Normal file
@@ -0,0 +1,177 @@
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
View,
|
||||
ActivityIndicator,
|
||||
Text,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
} from "react-native";
|
||||
import { WebView } from "react-native-webview";
|
||||
import * as FileSystem from "expo-file-system";
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
import useAuthStore from "@/store/auth";
|
||||
import { useLocalSearchParams, useRouter } from "expo-router";
|
||||
import { useUser } from "@linkwarden/router/user";
|
||||
import { generateLinkHref } from "@linkwarden/lib/generateLinkHref";
|
||||
import { useWindowDimensions } from "react-native";
|
||||
import RenderHtml from "@linkwarden/react-native-render-html";
|
||||
import ElementNotSupported from "@/components/ElementNotSupported";
|
||||
import { decode } from "html-entities";
|
||||
import { IconSymbol } from "@/components/ui/IconSymbol";
|
||||
import { useLinks } from "@linkwarden/router/links";
|
||||
|
||||
const CACHE_DIR = FileSystem.documentDirectory + "archivedData/readable/";
|
||||
const htmlPath = (id: string) => `${CACHE_DIR}link_${id}.html`;
|
||||
|
||||
async function ensureCacheDir() {
|
||||
const info = await FileSystem.getInfoAsync(CACHE_DIR);
|
||||
if (!info.exists) {
|
||||
await FileSystem.makeDirectoryAsync(CACHE_DIR, { intermediates: true });
|
||||
}
|
||||
}
|
||||
|
||||
export default function LinkScreen() {
|
||||
const { auth } = useAuthStore();
|
||||
const { id, format } = useLocalSearchParams();
|
||||
const { data: user } = useUser(auth);
|
||||
const [url, setUrl] = useState<string>();
|
||||
const [htmlContent, setHtmlContent] = useState<string>("");
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const { width } = useWindowDimensions();
|
||||
const router = useRouter();
|
||||
const { links } = useLinks(
|
||||
{
|
||||
sort: 0,
|
||||
},
|
||||
auth
|
||||
);
|
||||
|
||||
const link = useMemo(() => {
|
||||
return links?.find((link) => link.id === Number(id));
|
||||
}, [links, id]);
|
||||
|
||||
useEffect(() => {
|
||||
async function loadCacheOrFetch() {
|
||||
await ensureCacheDir();
|
||||
const htmlFile = htmlPath(id as string);
|
||||
|
||||
const [htmlInfo] = await Promise.all([FileSystem.getInfoAsync(htmlFile)]);
|
||||
|
||||
if (format === "3" && htmlInfo.exists) {
|
||||
const rawHtml = await FileSystem.readAsStringAsync(htmlFile);
|
||||
setHtmlContent(rawHtml);
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
const net = await NetInfo.fetch();
|
||||
if (net.isConnected) {
|
||||
await fetchLinkData();
|
||||
}
|
||||
}
|
||||
|
||||
if (user && user[0]?.id && !url) {
|
||||
loadCacheOrFetch();
|
||||
}
|
||||
}, [user, url]);
|
||||
|
||||
async function fetchLinkData() {
|
||||
if (link?.id && format === "3") {
|
||||
const apiUrl = `${auth.instance}/api/v1/archives/${link.id}?format=${format}`;
|
||||
setUrl(apiUrl);
|
||||
try {
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: { Authorization: `Bearer ${auth.session}` },
|
||||
});
|
||||
const html = (await response.json()).content;
|
||||
setHtmlContent(html);
|
||||
await FileSystem.writeAsStringAsync(htmlPath(id as string), html, {
|
||||
encoding: FileSystem.EncodingType.UTF8,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch HTML content", e);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
} else if (link?.id && !format) {
|
||||
setUrl(generateLinkHref(link, user[0], auth.instance, true));
|
||||
} else if (link?.id && format) {
|
||||
setUrl(`${auth.instance}/api/v1/archives/${link.id}?format=${format}`);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{format === "3" && htmlContent ? (
|
||||
<ScrollView
|
||||
className="flex-1 bg-white"
|
||||
contentContainerClassName="p-4"
|
||||
nestedScrollEnabled
|
||||
>
|
||||
<Text className="text-2xl font-bold mb-2.5">
|
||||
{decode(link?.name || link?.description || link?.url || "")}
|
||||
</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
className="flex-row items-center gap-1 mb-2.5 pr-5"
|
||||
onPress={() => router.replace(`/links/${id}`)}
|
||||
>
|
||||
<IconSymbol name="link" size={16} color="gray" />
|
||||
<Text className="text-base text-gray-500 flex-1" numberOfLines={1}>
|
||||
{link?.url}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<View className="flex-row items-center gap-1 mb-2.5">
|
||||
<IconSymbol name="calendar" size={16} color="gray" />
|
||||
<Text className="text-base text-gray-500">
|
||||
{new Date(
|
||||
(link?.importDate || link?.createdAt) as string
|
||||
).toLocaleString("en-US", {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View className="border-t border-gray-200 mt-2.5 mb-5" />
|
||||
|
||||
<RenderHtml
|
||||
contentWidth={width}
|
||||
source={{ html: htmlContent }}
|
||||
renderers={{
|
||||
table: () => (
|
||||
<ElementNotSupported
|
||||
onPress={() => router.replace(`/links/${id}`)}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
tagsStyles={{
|
||||
p: { fontSize: 16, lineHeight: 24, marginVertical: 10 },
|
||||
}}
|
||||
/>
|
||||
</ScrollView>
|
||||
) : (
|
||||
<View className="flex-1 bg-white">
|
||||
{url && (
|
||||
<WebView
|
||||
className={isLoading ? "opacity-0" : "flex-1"}
|
||||
source={{
|
||||
uri: url,
|
||||
headers: { Authorization: `Bearer ${auth.session}` },
|
||||
}}
|
||||
onLoadEnd={() => setIsLoading(false)}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{isLoading && (
|
||||
<View className="absolute inset-0 flex-1 justify-center items-center bg-white p-5">
|
||||
<ActivityIndicator size="large" color="gray" />
|
||||
<Text className="text-base mt-2.5 text-gray-500">Loading...</Text>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
85
apps/mobile/app/login.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import useAuthStore from "@/store/auth";
|
||||
import { Link } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
} from "react-native";
|
||||
|
||||
export default function HomeScreen() {
|
||||
const { signIn } = useAuthStore();
|
||||
const [form, setForm] = useState({
|
||||
user: "",
|
||||
password: "",
|
||||
instance: "",
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Login</Text>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
marginVertical: 10,
|
||||
gap: 10,
|
||||
}}
|
||||
>
|
||||
<TextInput
|
||||
style={{
|
||||
height: 40,
|
||||
width: 250,
|
||||
borderRadius: 5,
|
||||
padding: 10,
|
||||
borderColor: "gray",
|
||||
borderWidth: 1,
|
||||
}}
|
||||
placeholder="Username"
|
||||
value={form.user}
|
||||
onChangeText={(text) => setForm({ ...form, user: text })}
|
||||
/>
|
||||
<TextInput
|
||||
style={{
|
||||
height: 40,
|
||||
width: 250,
|
||||
borderRadius: 5,
|
||||
padding: 10,
|
||||
borderColor: "gray",
|
||||
borderWidth: 1,
|
||||
}}
|
||||
placeholder="Password"
|
||||
secureTextEntry
|
||||
value={form.password}
|
||||
onChangeText={(text) => setForm({ ...form, password: text })}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
backgroundColor: "#000000",
|
||||
padding: 10,
|
||||
borderRadius: 5,
|
||||
}}
|
||||
onPress={() =>
|
||||
signIn(
|
||||
form.user,
|
||||
form.password,
|
||||
form.instance ? form.instance : undefined
|
||||
)
|
||||
}
|
||||
>
|
||||
<Text style={{ color: "#fff", textAlign: "center" }}>Login</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
});
|
||||
BIN
apps/mobile/assets/fonts/SpaceMono-Regular.ttf
Executable file
BIN
apps/mobile/assets/images/adaptive-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
apps/mobile/assets/images/favicon.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
apps/mobile/assets/images/icon.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
apps/mobile/assets/images/partial-react-logo.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
apps/mobile/assets/images/react-logo.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
apps/mobile/assets/images/react-logo@2x.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
apps/mobile/assets/images/react-logo@3x.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
apps/mobile/assets/images/splash-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
9
apps/mobile/babel.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
module.exports = function (api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: [
|
||||
["babel-preset-expo", { jsxImportSource: "nativewind" }],
|
||||
"nativewind/babel",
|
||||
],
|
||||
};
|
||||
};
|
||||
18
apps/mobile/components/ElementNotSupported.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { View, Text, Button } from "react-native";
|
||||
|
||||
export default function ElementNotSupported({
|
||||
message = "This element is currently not supported in this view.",
|
||||
buttonTitle = "Open original",
|
||||
onPress,
|
||||
}: {
|
||||
message?: string;
|
||||
buttonTitle?: string;
|
||||
onPress: () => void;
|
||||
}) {
|
||||
return (
|
||||
<View className="border-y border-gray-200 my-2 py-5 flex justify-center items-center">
|
||||
<Text>{message}</Text>
|
||||
<Button onPress={onPress} title={buttonTitle} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
18
apps/mobile/components/HapticTab.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { BottomTabBarButtonProps } from "@react-navigation/bottom-tabs";
|
||||
import { PlatformPressable } from "@react-navigation/elements";
|
||||
import * as Haptics from "expo-haptics";
|
||||
|
||||
export default function HapticTab(props: BottomTabBarButtonProps) {
|
||||
return (
|
||||
<PlatformPressable
|
||||
{...props}
|
||||
onPressIn={(ev) => {
|
||||
if (process.env.EXPO_OS === "ios") {
|
||||
// Add a soft haptic feedback when pressing down on the tabs.
|
||||
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||
}
|
||||
props.onPressIn?.(ev);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
192
apps/mobile/components/LinkListing.tsx
Normal file
@@ -0,0 +1,192 @@
|
||||
import { View, Text, Image, Pressable, Platform } from "react-native";
|
||||
import { decode } from "html-entities";
|
||||
import { LinkIncludingShortenedCollectionAndTags } from "@linkwarden/types";
|
||||
import { IconSymbol } from "@/components/ui/IconSymbol";
|
||||
import { ArchivedFormat } from "@linkwarden/types";
|
||||
import {
|
||||
atLeastOneFormatAvailable,
|
||||
formatAvailable,
|
||||
} from "@linkwarden/lib/formatStats";
|
||||
import useAuthStore from "@/store/auth";
|
||||
import { useRouter } from "expo-router";
|
||||
import * as ContextMenu from "zeego/context-menu";
|
||||
|
||||
type Props = {
|
||||
link: LinkIncludingShortenedCollectionAndTags;
|
||||
};
|
||||
|
||||
const LinkListing = ({ link }: Props) => {
|
||||
const { auth } = useAuthStore();
|
||||
const router = useRouter();
|
||||
|
||||
let shortendURL;
|
||||
|
||||
try {
|
||||
if (link.url) {
|
||||
shortendURL = new URL(link.url).host.toLowerCase();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
return (
|
||||
<ContextMenu.Root
|
||||
onOpenChange={() => {
|
||||
/* track open/close if needed */
|
||||
}}
|
||||
>
|
||||
<ContextMenu.Trigger asChild>
|
||||
<Pressable
|
||||
className={`p-5 flex-row justify-between bg-white ${
|
||||
Platform.OS === "android" ? "active:bg-white" : "active:bg-gray-200"
|
||||
}`}
|
||||
onPress={() => router.push(`/links/${link.id}`)}
|
||||
android_ripple={{ color: "#ddd", borderless: false }}
|
||||
>
|
||||
<View className="flex-row justify-between">
|
||||
<View className="w-[70%] flex-col justify-between">
|
||||
<Text numberOfLines={2} className="font-medium text-lg">
|
||||
{decode(link.name || link.description || link.url)}
|
||||
</Text>
|
||||
|
||||
{shortendURL && (
|
||||
<Text numberOfLines={1} className="mt-1.5 font-light text-sm">
|
||||
{shortendURL}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<View className="flex flex-row gap-1 items-center mt-1.5 pr-1.5 self-start rounded-md">
|
||||
<IconSymbol
|
||||
name="folder.fill"
|
||||
size={16}
|
||||
color={link.collection.color || ""}
|
||||
/>
|
||||
<Text numberOfLines={1} className="font-light text-xs">
|
||||
{link.collection.name}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="flex-col items-end">
|
||||
<View className="rounded-lg overflow-hidden relative">
|
||||
{formatAvailable(link, "preview") ? (
|
||||
<Image
|
||||
source={{
|
||||
uri: `${auth.instance}/api/v1/archives/${link.id}?format=${ArchivedFormat.jpeg}&preview=true&updatedAt=${link.updatedAt}`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.session}`,
|
||||
},
|
||||
}}
|
||||
className="rounded-md h-[60px] w-[90px] object-cover scale-105"
|
||||
/>
|
||||
) : (
|
||||
<View className="h-[60px] w-[90px]" />
|
||||
)}
|
||||
</View>
|
||||
<View className="flex flex-row gap-1 items-center mt-5 self-start">
|
||||
<IconSymbol name="calendar" size={16} color="gray" />
|
||||
<Text numberOfLines={1} className="font-light text-xs">
|
||||
{new Date(link.createdAt as string).toLocaleString("en-US", {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Pressable>
|
||||
</ContextMenu.Trigger>
|
||||
|
||||
<ContextMenu.Content avoidCollisions>
|
||||
<ContextMenu.Item
|
||||
key="open-link"
|
||||
onSelect={() => router.push(`/links/${link.id}`)}
|
||||
>
|
||||
<ContextMenu.ItemTitle>Open Link</ContextMenu.ItemTitle>
|
||||
</ContextMenu.Item>
|
||||
|
||||
{link.url && atLeastOneFormatAvailable(link) && (
|
||||
<ContextMenu.Sub>
|
||||
<ContextMenu.SubTrigger key="preserved-formats">
|
||||
<ContextMenu.ItemTitle>Preserved Formats</ContextMenu.ItemTitle>
|
||||
</ContextMenu.SubTrigger>
|
||||
<ContextMenu.SubContent>
|
||||
{formatAvailable(link, "monolith") && (
|
||||
<ContextMenu.Item
|
||||
key="preserved-formats-webpage"
|
||||
onSelect={() =>
|
||||
router.push(
|
||||
`/links/${link.id}?format=${ArchivedFormat.monolith}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<ContextMenu.ItemTitle>Webpage</ContextMenu.ItemTitle>
|
||||
</ContextMenu.Item>
|
||||
)}
|
||||
{formatAvailable(link, "image") && (
|
||||
<ContextMenu.Item
|
||||
key="preserved-formats-screenshot"
|
||||
onSelect={() =>
|
||||
router.push(
|
||||
`/links/${link.id}?format=${
|
||||
link.image?.endsWith(".png")
|
||||
? ArchivedFormat.png
|
||||
: ArchivedFormat.jpeg
|
||||
}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<ContextMenu.ItemTitle>Screenshot</ContextMenu.ItemTitle>
|
||||
</ContextMenu.Item>
|
||||
)}
|
||||
{formatAvailable(link, "pdf") && (
|
||||
<ContextMenu.Item
|
||||
key="preserved-formats-pdf"
|
||||
onSelect={() =>
|
||||
router.push(
|
||||
`/links/${link.id}?format=${ArchivedFormat.pdf}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<ContextMenu.ItemTitle>PDF</ContextMenu.ItemTitle>
|
||||
</ContextMenu.Item>
|
||||
)}
|
||||
{formatAvailable(link, "readable") && (
|
||||
<ContextMenu.Item
|
||||
key="preserved-formats-readable"
|
||||
onSelect={() =>
|
||||
router.push(
|
||||
`/links/${link.id}?format=${ArchivedFormat.readability}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<ContextMenu.ItemTitle>Readable</ContextMenu.ItemTitle>
|
||||
</ContextMenu.Item>
|
||||
)}
|
||||
</ContextMenu.SubContent>
|
||||
</ContextMenu.Sub>
|
||||
)}
|
||||
|
||||
<ContextMenu.Item
|
||||
key="copy-url"
|
||||
onSelect={() => {
|
||||
/* copy URL */
|
||||
}}
|
||||
>
|
||||
<ContextMenu.ItemTitle>Copy URL</ContextMenu.ItemTitle>
|
||||
</ContextMenu.Item>
|
||||
<ContextMenu.Item
|
||||
key="delete-link"
|
||||
onSelect={() => {
|
||||
/* delete link */
|
||||
}}
|
||||
>
|
||||
<ContextMenu.ItemTitle>Delete</ContextMenu.ItemTitle>
|
||||
</ContextMenu.Item>
|
||||
</ContextMenu.Content>
|
||||
</ContextMenu.Root>
|
||||
);
|
||||
};
|
||||
|
||||
export default LinkListing;
|
||||
32
apps/mobile/components/ModalBase.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Modal, View, Text, TouchableOpacity, Platform } from "react-native";
|
||||
import { PropsWithChildren } from "react";
|
||||
import { IconSymbol } from "./ui/IconSymbol";
|
||||
|
||||
type Props = PropsWithChildren<{
|
||||
isVisible: boolean;
|
||||
onClose: () => void;
|
||||
children?: React.ReactNode;
|
||||
}>;
|
||||
|
||||
export default function ModalBase({ isVisible, children, onClose }: Props) {
|
||||
return (
|
||||
<Modal
|
||||
animationType="slide"
|
||||
visible={isVisible}
|
||||
onRequestClose={onClose}
|
||||
transparent={false}
|
||||
presentationStyle={Platform.OS === "ios" ? "formSheet" : "overFullScreen"}
|
||||
>
|
||||
<TouchableOpacity onPress={onClose} className="absolute top-5 right-5">
|
||||
<IconSymbol name="xmark" size={16} color="" />
|
||||
</TouchableOpacity>
|
||||
{/* Overlay */}
|
||||
<View className="flex-1 justify-center items-center">
|
||||
{/* Modal content */}
|
||||
<View className="bg-white rounded-2xl p-8 mx-5 items-center shadow-lg w-full">
|
||||
{children}
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
17
apps/mobile/components/Modals/AddLink.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { PropsWithChildren } from "react";
|
||||
import { IconSymbol } from "../ui/IconSymbol";
|
||||
import ModalBase from "../ModalBase";
|
||||
import { Text } from "react-native";
|
||||
|
||||
type Props = PropsWithChildren<{
|
||||
isVisible: boolean;
|
||||
onClose: () => void;
|
||||
}>;
|
||||
|
||||
export default function AddLink({ isVisible, onClose }: Props) {
|
||||
return (
|
||||
// <ModalBase isVisible={isVisible} onClose={onClose}>
|
||||
<Text>Hi</Text>
|
||||
// </ModalBase>
|
||||
);
|
||||
}
|
||||
32
apps/mobile/components/ui/IconSymbol.ios.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import { SymbolView, SymbolViewProps, SymbolWeight } from "expo-symbols";
|
||||
import { StyleProp, ViewStyle } from "react-native";
|
||||
|
||||
export function IconSymbol({
|
||||
name,
|
||||
size = 24,
|
||||
color,
|
||||
style,
|
||||
weight = "regular",
|
||||
}: {
|
||||
name: SymbolViewProps["name"];
|
||||
size?: number;
|
||||
color: string;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
weight?: SymbolWeight;
|
||||
}) {
|
||||
return (
|
||||
<SymbolView
|
||||
weight={weight}
|
||||
tintColor={color}
|
||||
resizeMode="scaleAspectFit"
|
||||
name={name}
|
||||
style={[
|
||||
{
|
||||
width: size,
|
||||
height: size,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
50
apps/mobile/components/ui/IconSymbol.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
// This file is a fallback for using MaterialIcons on Android and web.
|
||||
|
||||
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
|
||||
import { SymbolWeight } from "expo-symbols";
|
||||
import React from "react";
|
||||
import { OpaqueColorValue, StyleProp, TextStyle } from "react-native";
|
||||
|
||||
// Add your SFSymbol to MaterialIcons mappings here.
|
||||
const MAPPING = {
|
||||
// See MaterialIcons here: https://icons.expo.fyi
|
||||
// See SF Symbols in the SF Symbols app on Mac.
|
||||
"house.fill": "home",
|
||||
"paperplane.fill": "send",
|
||||
"chevron.left.forwardslash.chevron.right": "code",
|
||||
"chevron.right": "chevron-right",
|
||||
} as Partial<
|
||||
Record<
|
||||
import("expo-symbols").SymbolViewProps["name"],
|
||||
React.ComponentProps<typeof MaterialIcons>["name"]
|
||||
>
|
||||
>;
|
||||
|
||||
export type IconSymbolName = keyof typeof MAPPING;
|
||||
|
||||
/**
|
||||
* An icon component that uses native SFSymbols on iOS, and MaterialIcons on Android and web. This ensures a consistent look across platforms, and optimal resource usage.
|
||||
*
|
||||
* Icon `name`s are based on SFSymbols and require manual mapping to MaterialIcons.
|
||||
*/
|
||||
export function IconSymbol({
|
||||
name,
|
||||
size = 24,
|
||||
color,
|
||||
style,
|
||||
}: {
|
||||
name: IconSymbolName;
|
||||
size?: number;
|
||||
color: string | OpaqueColorValue;
|
||||
style?: StyleProp<TextStyle>;
|
||||
weight?: SymbolWeight;
|
||||
}) {
|
||||
return (
|
||||
<MaterialIcons
|
||||
color={color}
|
||||
size={size}
|
||||
name={MAPPING[name]}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
22
apps/mobile/components/ui/TabBarBackground.ios.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs";
|
||||
import { BlurView } from "expo-blur";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
|
||||
export default function BlurTabBarBackground() {
|
||||
return (
|
||||
<BlurView
|
||||
// System chrome material automatically adapts to the system's theme
|
||||
// and matches the native tab bar appearance on iOS.
|
||||
tint="systemChromeMaterial"
|
||||
intensity={100}
|
||||
style={StyleSheet.absoluteFill}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function useBottomTabOverflow() {
|
||||
const tabHeight = useBottomTabBarHeight();
|
||||
const { bottom } = useSafeAreaInsets();
|
||||
return tabHeight - bottom;
|
||||
}
|
||||
6
apps/mobile/components/ui/TabBarBackground.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
// This is a shim for web and Android where the tab bar is generally opaque.
|
||||
export default undefined;
|
||||
|
||||
export function useBottomTabOverflow() {
|
||||
return 0;
|
||||
}
|
||||
30
apps/mobile/ios/.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# OSX
|
||||
#
|
||||
.DS_Store
|
||||
|
||||
# Xcode
|
||||
#
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
project.xcworkspace
|
||||
.xcode.env.local
|
||||
|
||||
# Bundle artifacts
|
||||
*.jsbundle
|
||||
|
||||
# CocoaPods
|
||||
/Pods/
|
||||
11
apps/mobile/ios/.xcode.env
Normal file
@@ -0,0 +1,11 @@
|
||||
# This `.xcode.env` file is versioned and is used to source the environment
|
||||
# used when running script phases inside Xcode.
|
||||
# To customize your local environment, you can create an `.xcode.env.local`
|
||||
# file that is not versioned.
|
||||
|
||||
# NODE_BINARY variable contains the PATH to the node executable.
|
||||
#
|
||||
# Customize the NODE_BINARY variable here.
|
||||
# For example, to use nvm with brew, add the following line
|
||||
# . "$(brew --prefix nvm)/nvm.sh" --no-use
|
||||
export NODE_BINARY=$(command -v node)
|
||||
66
apps/mobile/ios/Podfile
Normal file
@@ -0,0 +1,66 @@
|
||||
require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
|
||||
require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
|
||||
|
||||
require 'json'
|
||||
podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
|
||||
|
||||
ENV['RCT_NEW_ARCH_ENABLED'] = podfile_properties['newArchEnabled'] == 'true' ? '1' : '0'
|
||||
ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
|
||||
|
||||
platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1'
|
||||
install! 'cocoapods',
|
||||
:deterministic_uuids => false
|
||||
|
||||
prepare_react_native_project!
|
||||
|
||||
target 'mobileapp' do
|
||||
use_expo_modules!
|
||||
|
||||
if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
|
||||
config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
|
||||
else
|
||||
config_command = [
|
||||
'node',
|
||||
'--no-warnings',
|
||||
'--eval',
|
||||
'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
|
||||
'react-native-config',
|
||||
'--json',
|
||||
'--platform',
|
||||
'ios'
|
||||
]
|
||||
end
|
||||
|
||||
config = use_native_modules!(config_command)
|
||||
|
||||
use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
|
||||
use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
|
||||
|
||||
use_react_native!(
|
||||
:path => config[:reactNativePath],
|
||||
:hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
|
||||
# An absolute path to your application root.
|
||||
:app_path => "#{Pod::Config.instance.installation_root}/..",
|
||||
:privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false',
|
||||
)
|
||||
|
||||
post_install do |installer|
|
||||
react_native_post_install(
|
||||
installer,
|
||||
config[:reactNativePath],
|
||||
:mac_catalyst_enabled => false,
|
||||
:ccache_enabled => podfile_properties['apple.ccacheEnabled'] == 'true',
|
||||
)
|
||||
|
||||
# This is necessary for Xcode 14, because it signs resource bundles by default
|
||||
# when building for devices.
|
||||
installer.target_installation_results.pod_target_installation_results
|
||||
.each do |pod_name, target_installation_result|
|
||||
target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
|
||||
resource_bundle_target.build_configurations.each do |config|
|
||||
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
2577
apps/mobile/ios/Podfile.lock
Normal file
5
apps/mobile/ios/Podfile.properties.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"expo.jsEngine": "hermes",
|
||||
"EX_DEV_CLIENT_NETWORK_INSPECTOR": "true",
|
||||
"newArchEnabled": "true"
|
||||
}
|
||||
544
apps/mobile/ios/mobileapp.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,544 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
|
||||
96905EF65AED1B983A6B3ABC /* libPods-mobileapp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-mobileapp.a */; };
|
||||
98F5742C729033F29C656840 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = E49C0DC702346D367B33AAEF /* PrivacyInfo.xcprivacy */; };
|
||||
B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; };
|
||||
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
|
||||
DD111B9AA6FE4075B8E1E6D2 /* noop-file.swift in Sources */ = {isa = PBXBuildFile; fileRef = 588141A975DE4C1BBF1048E5 /* noop-file.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
13B07F961A680F5B00A75B9A /* mobileapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = mobileapp.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = mobileapp/AppDelegate.h; sourceTree = "<group>"; };
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = mobileapp/AppDelegate.mm; sourceTree = "<group>"; };
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = mobileapp/Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = mobileapp/Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = mobileapp/main.m; sourceTree = "<group>"; };
|
||||
51E9021565CB454F93B79E34 /* mobileapp-Bridging-Header.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "mobileapp-Bridging-Header.h"; path = "mobileapp/mobileapp-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
588141A975DE4C1BBF1048E5 /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "noop-file.swift"; path = "mobileapp/noop-file.swift"; sourceTree = "<group>"; };
|
||||
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-mobileapp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-mobileapp.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6C2E3173556A471DD304B334 /* Pods-mobileapp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-mobileapp.debug.xcconfig"; path = "Target Support Files/Pods-mobileapp/Pods-mobileapp.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
7A4D352CD337FB3A3BF06240 /* Pods-mobileapp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-mobileapp.release.xcconfig"; path = "Target Support Files/Pods-mobileapp/Pods-mobileapp.release.xcconfig"; sourceTree = "<group>"; };
|
||||
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = mobileapp/SplashScreen.storyboard; sourceTree = "<group>"; };
|
||||
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; };
|
||||
E49C0DC702346D367B33AAEF /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = mobileapp/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-mobileapp/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
96905EF65AED1B983A6B3ABC /* libPods-mobileapp.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
13B07FAE1A68108700A75B9A /* mobileapp */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BB2F792B24A3F905000567C9 /* Supporting */,
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.mm */,
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */,
|
||||
13B07FB61A68108700A75B9A /* Info.plist */,
|
||||
13B07FB71A68108700A75B9A /* main.m */,
|
||||
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */,
|
||||
588141A975DE4C1BBF1048E5 /* noop-file.swift */,
|
||||
51E9021565CB454F93B79E34 /* mobileapp-Bridging-Header.h */,
|
||||
E49C0DC702346D367B33AAEF /* PrivacyInfo.xcprivacy */,
|
||||
);
|
||||
name = mobileapp;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
|
||||
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-mobileapp.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07FAE1A68108700A75B9A /* mobileapp */,
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */,
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
2D16E6871FA4F8E400B85C8A /* Frameworks */,
|
||||
D65327D7A22EEC0BE12398D9 /* Pods */,
|
||||
D7E4C46ADA2E9064B798F356 /* ExpoModulesProviders */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 2;
|
||||
usesTabs = 0;
|
||||
};
|
||||
83CBBA001A601CBA00E9B192 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07F961A680F5B00A75B9A /* mobileapp.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
92DBD88DE9BF7D494EA9DA96 /* mobileapp */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */,
|
||||
);
|
||||
name = mobileapp;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BB2F792B24A3F905000567C9 /* Supporting */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BB2F792C24A3F905000567C9 /* Expo.plist */,
|
||||
);
|
||||
name = Supporting;
|
||||
path = mobileapp/Supporting;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D65327D7A22EEC0BE12398D9 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6C2E3173556A471DD304B334 /* Pods-mobileapp.debug.xcconfig */,
|
||||
7A4D352CD337FB3A3BF06240 /* Pods-mobileapp.release.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D7E4C46ADA2E9064B798F356 /* ExpoModulesProviders */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
92DBD88DE9BF7D494EA9DA96 /* mobileapp */,
|
||||
);
|
||||
name = ExpoModulesProviders;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
13B07F861A680F5B00A75B9A /* mobileapp */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "mobileapp" */;
|
||||
buildPhases = (
|
||||
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */,
|
||||
33C9CB6682BF7BB3053F48FC /* [Expo] Configure project */,
|
||||
13B07F871A680F5B00A75B9A /* Sources */,
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */,
|
||||
3C1F4EFB27CCA985BA2789D2 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = mobileapp;
|
||||
productName = mobileapp;
|
||||
productReference = 13B07F961A680F5B00A75B9A /* mobileapp.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
83CBB9F71A601CBA00E9B192 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1130;
|
||||
TargetAttributes = {
|
||||
13B07F861A680F5B00A75B9A = {
|
||||
LastSwiftMigration = 1250;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "mobileapp" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 83CBB9F61A601CBA00E9B192;
|
||||
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
13B07F861A680F5B00A75B9A /* mobileapp */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */,
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
||||
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */,
|
||||
98F5742C729033F29C656840 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Bundle React Native code and images";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n# Source .xcode.env.updates if it exists to allow\n# SKIP_BUNDLING to be unset if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\n# Source local changes to allow overrides\n# if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n";
|
||||
};
|
||||
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-mobileapp-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
33C9CB6682BF7BB3053F48FC /* [Expo] Configure project */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[Expo] Configure project";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-mobileapp/expo-configure-project.sh\"\n";
|
||||
};
|
||||
3C1F4EFB27CCA985BA2789D2 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-mobileapp/Pods-mobileapp-frameworks.sh",
|
||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-mobileapp/Pods-mobileapp-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-mobileapp/Pods-mobileapp-resources.sh",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoSystemUI/ExpoSystemUI_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-launcher/EXDevLauncher.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-menu/EXDevMenu.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoSystemUI_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevLauncher.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevMenu.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-mobileapp/Pods-mobileapp-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
13B07F871A680F5B00A75B9A /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */,
|
||||
B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */,
|
||||
DD111B9AA6FE4075B8E1E6D2 /* noop-file.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
13B07F941A680F5B00A75B9A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 6C2E3173556A471DD304B334 /* Pods-mobileapp.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = mobileapp/mobileapp.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"FB_SONARKIT_ENABLED=1",
|
||||
);
|
||||
INFOPLIST_FILE = mobileapp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 1.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.mobile-app";
|
||||
PRODUCT_NAME = mobileapp;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "mobileapp/mobileapp-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
13B07F951A680F5B00A75B9A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7A4D352CD337FB3A3BF06240 /* Pods-mobileapp.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = mobileapp/mobileapp.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
INFOPLIST_FILE = mobileapp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 1.0;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.mobile-app";
|
||||
PRODUCT_NAME = mobileapp;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "mobileapp/mobileapp-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
83CBBA201A601CBA00E9B192 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
USE_HERMES = true;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
83CBBA211A601CBA00E9B192 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
USE_HERMES = true;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "mobileapp" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
13B07F941A680F5B00A75B9A /* Debug */,
|
||||
13B07F951A680F5B00A75B9A /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "mobileapp" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
83CBBA201A601CBA00E9B192 /* Debug */,
|
||||
83CBBA211A601CBA00E9B192 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1130"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "mobileapp.app"
|
||||
BlueprintName = "mobileapp"
|
||||
ReferencedContainer = "container:mobileapp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
|
||||
BuildableName = "mobileappTests.xctest"
|
||||
BlueprintName = "mobileappTests"
|
||||
ReferencedContainer = "container:mobileapp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "mobileapp.app"
|
||||
BlueprintName = "mobileapp"
|
||||
ReferencedContainer = "container:mobileapp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "mobileapp.app"
|
||||
BlueprintName = "mobileapp"
|
||||
ReferencedContainer = "container:mobileapp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
10
apps/mobile/ios/mobileapp.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:mobileapp.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
7
apps/mobile/ios/mobileapp/AppDelegate.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#import <RCTAppDelegate.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <Expo/Expo.h>
|
||||
|
||||
@interface AppDelegate : EXAppDelegateWrapper
|
||||
|
||||
@end
|
||||
62
apps/mobile/ios/mobileapp/AppDelegate.mm
Normal file
@@ -0,0 +1,62 @@
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <React/RCTLinkingManager.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
self.moduleName = @"main";
|
||||
|
||||
// You can add your custom initial props in the dictionary below.
|
||||
// They will be passed down to the ViewController used by React Native.
|
||||
self.initialProps = @{};
|
||||
|
||||
return [super application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
}
|
||||
|
||||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
||||
{
|
||||
return [self bundleURL];
|
||||
}
|
||||
|
||||
- (NSURL *)bundleURL
|
||||
{
|
||||
#if DEBUG
|
||||
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"];
|
||||
#else
|
||||
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
#endif
|
||||
}
|
||||
|
||||
// Linking API
|
||||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
||||
return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
|
||||
}
|
||||
|
||||
// Universal Links
|
||||
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
|
||||
BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
|
||||
return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;
|
||||
}
|
||||
|
||||
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
|
||||
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
|
||||
{
|
||||
return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
|
||||
}
|
||||
|
||||
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
|
||||
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
|
||||
{
|
||||
return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];
|
||||
}
|
||||
|
||||
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
|
||||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
|
||||
{
|
||||
return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
|
||||
}
|
||||
|
||||
@end
|
||||
|
After Width: | Height: | Size: 58 KiB |
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "App-Icon-1024x1024@1x.png",
|
||||
"idiom": "universal",
|
||||
"platform": "ios",
|
||||
"size": "1024x1024"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "expo"
|
||||
}
|
||||
}
|
||||
6
apps/mobile/ios/mobileapp/Images.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "expo"
|
||||
}
|
||||
}
|
||||