mirror of
https://github.com/CatimaLoyalty/Android.git
synced 2025-12-24 15:47:53 -05:00
Compare commits
619 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3aad062e3d | ||
|
|
dd09d0e130 | ||
|
|
0de1fcbe9b | ||
|
|
2b8214e144 | ||
|
|
0300aaa850 | ||
|
|
2605372e5d | ||
|
|
72b09506dc | ||
|
|
14b42e8980 | ||
|
|
7c25bb9b79 | ||
|
|
f3b2e1e1ac | ||
|
|
ef4ad0e197 | ||
|
|
34d8331c50 | ||
|
|
8430dff21c | ||
|
|
ba87ee739e | ||
|
|
41503f912f | ||
|
|
fd396b8fc7 | ||
|
|
2abc8b8f64 | ||
|
|
160e61ead4 | ||
|
|
c2e8577674 | ||
|
|
66b8f35994 | ||
|
|
b141009350 | ||
|
|
0e8dd2fd64 | ||
|
|
988336cfec | ||
|
|
5e3668820b | ||
|
|
81c919448e | ||
|
|
23ca0802cb | ||
|
|
40c2337054 | ||
|
|
7db8b1602d | ||
|
|
32b35382a6 | ||
|
|
3ec6cbe416 | ||
|
|
90322f75ce | ||
|
|
534c4001c1 | ||
|
|
e21030aed3 | ||
|
|
d6d12174d5 | ||
|
|
27e78dbadd | ||
|
|
0d520b48e1 | ||
|
|
d7a49013ec | ||
|
|
fc974e2038 | ||
|
|
7144f60340 | ||
|
|
883af7fd10 | ||
|
|
fcb2be604c | ||
|
|
d24366a3ba | ||
|
|
a0aa19f26f | ||
|
|
589f009a65 | ||
|
|
e849fd379e | ||
|
|
e28c5e877b | ||
|
|
ae90b46c05 | ||
|
|
a8a1158b4b | ||
|
|
8789be5340 | ||
|
|
93af3dbc36 | ||
|
|
96c111f0c8 | ||
|
|
89dca33ce8 | ||
|
|
f9f1149bb5 | ||
|
|
cfd5fbe3ae | ||
|
|
028905df42 | ||
|
|
3dd74fd674 | ||
|
|
0af9549d02 | ||
|
|
a367d24125 | ||
|
|
dfa0c36af5 | ||
|
|
66fcad7658 | ||
|
|
370ec55df1 | ||
|
|
b03ead95ea | ||
|
|
90e6463688 | ||
|
|
80cfb516c0 | ||
|
|
989cf31897 | ||
|
|
caf9e163df | ||
|
|
8363115faf | ||
|
|
48cc286b14 | ||
|
|
07e7b56c9f | ||
|
|
4cac19acb9 | ||
|
|
ed1db31d62 | ||
|
|
2a2a711375 | ||
|
|
c96cef5298 | ||
|
|
8506c05081 | ||
|
|
9adc6d0704 | ||
|
|
ca62d542ef | ||
|
|
84c343e41f | ||
|
|
d12283e75d | ||
|
|
0297304751 | ||
|
|
966846c507 | ||
|
|
48de759eb0 | ||
|
|
4e23fb4195 | ||
|
|
1cfd04ba67 | ||
|
|
c6f1e0cffe | ||
|
|
027d153747 | ||
|
|
bd1376e6bf | ||
|
|
7fa8ae8697 | ||
|
|
0b01604c4e | ||
|
|
d37dca7e7d | ||
|
|
5eb2753168 | ||
|
|
502e2e5e21 | ||
|
|
bbb2c0d81f | ||
|
|
59e62c2805 | ||
|
|
15d9a16ead | ||
|
|
e99cba7fcb | ||
|
|
781b6ecc48 | ||
|
|
ec8536976f | ||
|
|
2f9101e9f2 | ||
|
|
0cc2fd44ac | ||
|
|
6db4cbab9b | ||
|
|
0b2111b6f0 | ||
|
|
b3f118ef15 | ||
|
|
db8a652e5b | ||
|
|
d7a4f81eba | ||
|
|
d0c0694662 | ||
|
|
0fdf79449c | ||
|
|
cbf8b2d5f0 | ||
|
|
e194cca5f1 | ||
|
|
5d450852e1 | ||
|
|
ce86811d7c | ||
|
|
9fb3b765e7 | ||
|
|
d02dac2c41 | ||
|
|
243536d0d1 | ||
|
|
b258ba8654 | ||
|
|
5ec87a7a3a | ||
|
|
c84692db35 | ||
|
|
efe2a720f4 | ||
|
|
8b876f51fc | ||
|
|
033de00ad4 | ||
|
|
81f0e769b8 | ||
|
|
dd14533c6c | ||
|
|
f7c50caeb1 | ||
|
|
b00aa74bfe | ||
|
|
944089536f | ||
|
|
266732f744 | ||
|
|
33ee23a0e1 | ||
|
|
b064851254 | ||
|
|
19782fdb9c | ||
|
|
eb7658c35a | ||
|
|
fff35d7a74 | ||
|
|
ed5506554a | ||
|
|
dac7e8cb46 | ||
|
|
5ad27b1b53 | ||
|
|
ca3c29f5e4 | ||
|
|
935ef20955 | ||
|
|
86ec70ee72 | ||
|
|
2303caf1be | ||
|
|
ee1e5c0d0e | ||
|
|
4bdb5a86ad | ||
|
|
92ac59a783 | ||
|
|
89ea86e795 | ||
|
|
ffe6236c2d | ||
|
|
c057e03e97 | ||
|
|
372834f60f | ||
|
|
1265c6d801 | ||
|
|
2ae0ddd9e7 | ||
|
|
fba6f3a111 | ||
|
|
357b005b15 | ||
|
|
8df25a301b | ||
|
|
71c7252458 | ||
|
|
41f8fc2094 | ||
|
|
b5752967a2 | ||
|
|
5ee14c2fe8 | ||
|
|
a34321c680 | ||
|
|
56ed2f454d | ||
|
|
40ac0d83c5 | ||
|
|
b8de73b5b3 | ||
|
|
547af33f40 | ||
|
|
f1b525396c | ||
|
|
50890c4f31 | ||
|
|
3322133d1e | ||
|
|
5b6c6b4466 | ||
|
|
5f2402dd15 | ||
|
|
b34533a92a | ||
|
|
c521fae4ee | ||
|
|
ce47efecb0 | ||
|
|
133da20f93 | ||
|
|
cee8074232 | ||
|
|
6f78e2b404 | ||
|
|
b05b46f10a | ||
|
|
1188e58fb0 | ||
|
|
575150af9e | ||
|
|
d82e0bebb6 | ||
|
|
72131a6b2d | ||
|
|
b89a13ce70 | ||
|
|
389a53b2cc | ||
|
|
be0f534f66 | ||
|
|
36eee3686c | ||
|
|
5c76cb01bf | ||
|
|
e57cd9eea3 | ||
|
|
e795ec6907 | ||
|
|
5e69f18b88 | ||
|
|
6bb6d54b6a | ||
|
|
86f049d9a4 | ||
|
|
5cb02ae0f2 | ||
|
|
88380878e0 | ||
|
|
59c7341aad | ||
|
|
e3596adae4 | ||
|
|
8d697c3414 | ||
|
|
c1b0fead33 | ||
|
|
228b9ecc4d | ||
|
|
7c03469e91 | ||
|
|
c922e0645d | ||
|
|
8015cc65b8 | ||
|
|
85240fa3d5 | ||
|
|
3ed418166d | ||
|
|
b4a173d352 | ||
|
|
bd57e11f16 | ||
|
|
d65141ee92 | ||
|
|
fc12efff5e | ||
|
|
bd0879923c | ||
|
|
d2df924ba5 | ||
|
|
613c92e8c4 | ||
|
|
d8429bf305 | ||
|
|
1c8926887b | ||
|
|
7f03f371e0 | ||
|
|
273a39abb7 | ||
|
|
562b984029 | ||
|
|
74e498c5ab | ||
|
|
4c825c703b | ||
|
|
c54af65033 | ||
|
|
f80dbe9073 | ||
|
|
e9a48dca41 | ||
|
|
157c428919 | ||
|
|
a67aec366a | ||
|
|
ee12482f6e | ||
|
|
c2383fbb40 | ||
|
|
65ab14897f | ||
|
|
87ecb3c1b9 | ||
|
|
9dfbc92e92 | ||
|
|
c65303b08b | ||
|
|
fd8c960c58 | ||
|
|
7511ea0c2d | ||
|
|
4810a3cee1 | ||
|
|
a230d9f877 | ||
|
|
18e699445c | ||
|
|
4a5106c38c | ||
|
|
3afde7049e | ||
|
|
82a3ae16a6 | ||
|
|
31995f4b8b | ||
|
|
b7c444fd8f | ||
|
|
58481c842b | ||
|
|
5847ff4b7c | ||
|
|
056c255aa6 | ||
|
|
9c99b9d0ad | ||
|
|
d4a9197e60 | ||
|
|
57d7176ac9 | ||
|
|
029fa9b5e8 | ||
|
|
c38a89b48f | ||
|
|
21958442bb | ||
|
|
f92ae736b4 | ||
|
|
548714f778 | ||
|
|
1d61a7c0eb | ||
|
|
6c5a06ce5b | ||
|
|
1d4e47b832 | ||
|
|
cd9ef1c231 | ||
|
|
a1011e0668 | ||
|
|
9e7d51c36b | ||
|
|
0e826a654b | ||
|
|
40778dd494 | ||
|
|
d7b983f1ca | ||
|
|
206f6385ae | ||
|
|
18cba2d702 | ||
|
|
847850eeff | ||
|
|
107bf5a0f5 | ||
|
|
d3edde4a43 | ||
|
|
963f42628f | ||
|
|
7d83cf1dfd | ||
|
|
5bb2df98cd | ||
|
|
2796a15353 | ||
|
|
55595159be | ||
|
|
5cab0e3932 | ||
|
|
4d6c08fc73 | ||
|
|
0c147830ee | ||
|
|
b5a3a4c735 | ||
|
|
f867e8cb93 | ||
|
|
524af89c96 | ||
|
|
3df4d4783f | ||
|
|
d0e7187273 | ||
|
|
7819460377 | ||
|
|
4396214e7a | ||
|
|
697c6f3f39 | ||
|
|
0239e5a89e | ||
|
|
532fae7de5 | ||
|
|
135c4498d8 | ||
|
|
7f0e5d9c59 | ||
|
|
cf4eeafce0 | ||
|
|
8597580d93 | ||
|
|
e3643328f0 | ||
|
|
e76c8219bb | ||
|
|
650ad23e59 | ||
|
|
abc66a0c08 | ||
|
|
701e1ee5fa | ||
|
|
8031a02003 | ||
|
|
f383758c7d | ||
|
|
eeb7eddff2 | ||
|
|
1df27e2d4a | ||
|
|
66ffe63a62 | ||
|
|
a963ed20d3 | ||
|
|
c057e7a420 | ||
|
|
10bab6349a | ||
|
|
e89b612c93 | ||
|
|
2d99c61d78 | ||
|
|
ed2a816656 | ||
|
|
a73064ae46 | ||
|
|
b07ac08b69 | ||
|
|
c5793caaf3 | ||
|
|
22fadb1b15 | ||
|
|
5cd2cbb1a2 | ||
|
|
20ec9f5cc3 | ||
|
|
93db0669ff | ||
|
|
7c2eebb20c | ||
|
|
e76a63c34b | ||
|
|
80cab9ba59 | ||
|
|
c26ddd9342 | ||
|
|
78ec649af3 | ||
|
|
1ae61cc0b7 | ||
|
|
5616158ff7 | ||
|
|
554a60cf95 | ||
|
|
737a6272a9 | ||
|
|
dc7f3573fe | ||
|
|
4003faa17f | ||
|
|
4aecb05e17 | ||
|
|
f58eafd2b6 | ||
|
|
1061bc691a | ||
|
|
734813c29e | ||
|
|
2cdd0f6678 | ||
|
|
c65b30189f | ||
|
|
93db35396a | ||
|
|
3d6cf5883e | ||
|
|
3c316d1878 | ||
|
|
be6d3a460d | ||
|
|
feb93ccb48 | ||
|
|
6ad0dd1f24 | ||
|
|
1c936b4b2e | ||
|
|
3c201a9c29 | ||
|
|
5ccdc349ff | ||
|
|
a842f01e32 | ||
|
|
b3b5960725 | ||
|
|
781318397c | ||
|
|
e7e5cdac22 | ||
|
|
11bce01405 | ||
|
|
ed84b0fcb9 | ||
|
|
7f82bc9822 | ||
|
|
2d40ac0111 | ||
|
|
81ffee2e3b | ||
|
|
133e1695f6 | ||
|
|
78a8a65ae2 | ||
|
|
8e28b43ecb | ||
|
|
20062db01e | ||
|
|
42e5a15455 | ||
|
|
e61c20c66f | ||
|
|
8e4ca5fa78 | ||
|
|
8e08e863d2 | ||
|
|
6ad16c4e86 | ||
|
|
42fa077099 | ||
|
|
079d16020a | ||
|
|
fab6a42069 | ||
|
|
c461ce133e | ||
|
|
d8f3e1f1ef | ||
|
|
107b576db1 | ||
|
|
e553d50cb7 | ||
|
|
ff83a4a4f3 | ||
|
|
58ad83caef | ||
|
|
380d961ea4 | ||
|
|
ca4a336b6a | ||
|
|
5205a69041 | ||
|
|
013f3d2d4c | ||
|
|
ca3f7a7c28 | ||
|
|
b9813c9ccb | ||
|
|
7255571f36 | ||
|
|
a9e6e9d75c | ||
|
|
4bcdbc62c6 | ||
|
|
c91e92b80b | ||
|
|
ca2f2c349e | ||
|
|
420179458d | ||
|
|
20ffc23487 | ||
|
|
8de5646d07 | ||
|
|
16dbe1572a | ||
|
|
18f68cdb24 | ||
|
|
147cf544a3 | ||
|
|
a4763d8ed0 | ||
|
|
382d86dce6 | ||
|
|
2a2d05dd01 | ||
|
|
09e6617808 | ||
|
|
f9190ed915 | ||
|
|
ea7ca81f1c | ||
|
|
68e5c36909 | ||
|
|
4e167c79c1 | ||
|
|
9361487af7 | ||
|
|
c80107b870 | ||
|
|
52a1cc6549 | ||
|
|
5f34d54b42 | ||
|
|
ec4265504b | ||
|
|
3f2b140d1f | ||
|
|
4af3695301 | ||
|
|
f5368a4aab | ||
|
|
f5059b95d3 | ||
|
|
85fa0afaa8 | ||
|
|
3bcccba6d4 | ||
|
|
188c2e25a2 | ||
|
|
162622631f | ||
|
|
946a426b32 | ||
|
|
354a0f7fc0 | ||
|
|
6015a944ff | ||
|
|
e30320603a | ||
|
|
acd644025e | ||
|
|
b3e26f532d | ||
|
|
3a64b4652f | ||
|
|
56f691ca53 | ||
|
|
57c770c9ba | ||
|
|
53c3c85e57 | ||
|
|
9a02d1bfbc | ||
|
|
ffbb138986 | ||
|
|
181e9f082c | ||
|
|
912a4cb955 | ||
|
|
50a1e77500 | ||
|
|
aef32d2b95 | ||
|
|
d091ccb593 | ||
|
|
6fbbae9f0a | ||
|
|
176aa3880e | ||
|
|
fcf64c86a6 | ||
|
|
b5f6742b12 | ||
|
|
26ae92dc84 | ||
|
|
c65cdc93a7 | ||
|
|
bd85590d39 | ||
|
|
e3942b1737 | ||
|
|
2dc7fd9a45 | ||
|
|
2b7f8b6bf7 | ||
|
|
db0619718c | ||
|
|
dd19ea6322 | ||
|
|
5d656f9681 | ||
|
|
c2c50664ea | ||
|
|
058eb7dd8b | ||
|
|
7a381f3683 | ||
|
|
96b6ca4b3b | ||
|
|
21815db47d | ||
|
|
72f62b9211 | ||
|
|
0e61a4584e | ||
|
|
ca0ad17e8e | ||
|
|
20c4e03343 | ||
|
|
4ec4d8a3a6 | ||
|
|
34d1e94ba4 | ||
|
|
3ff6a2c269 | ||
|
|
2327c0a940 | ||
|
|
520629c075 | ||
|
|
48446cdac6 | ||
|
|
0e61908265 | ||
|
|
ead67942f1 | ||
|
|
43f36a1c99 | ||
|
|
bd7de108b5 | ||
|
|
ef9a490d0b | ||
|
|
4c26434f41 | ||
|
|
ffd2eccdbe | ||
|
|
214ec7d7fb | ||
|
|
269e0a1c2a | ||
|
|
21c9a63819 | ||
|
|
0121541a9a | ||
|
|
48be5390ec | ||
|
|
ca62ce8bcd | ||
|
|
4ab6d0c5ab | ||
|
|
0c12533a8e | ||
|
|
b983498bbc | ||
|
|
54871a1479 | ||
|
|
5fb911b884 | ||
|
|
8f05433ba3 | ||
|
|
55b5285e62 | ||
|
|
4a920e3f83 | ||
|
|
1979006f2c | ||
|
|
a2ac7f7c41 | ||
|
|
533930771b | ||
|
|
4beceeebf2 | ||
|
|
f17f788d0b | ||
|
|
f6c82035f8 | ||
|
|
fe9fbbfd57 | ||
|
|
e2cce91360 | ||
|
|
9981a64bcd | ||
|
|
757a942ecf | ||
|
|
6954090744 | ||
|
|
24e18473bd | ||
|
|
207e83a582 | ||
|
|
6ad1d9497c | ||
|
|
f728866645 | ||
|
|
f6f904ae39 | ||
|
|
4160909a32 | ||
|
|
c990e40d0c | ||
|
|
d4e0b6d3cf | ||
|
|
0197ae2f58 | ||
|
|
dcb94f242f | ||
|
|
ab66304c72 | ||
|
|
ee7d9e2405 | ||
|
|
146a4676d5 | ||
|
|
27da7913cb | ||
|
|
cb1cf607f5 | ||
|
|
acf94600f8 | ||
|
|
a41124cc7b | ||
|
|
0d0564b295 | ||
|
|
ba7a849c18 | ||
|
|
b3b347cd9b | ||
|
|
2efdb5b9bb | ||
|
|
c7961feb27 | ||
|
|
43c092915a | ||
|
|
720fbb4eae | ||
|
|
0b888380e5 | ||
|
|
8b4fc8c76b | ||
|
|
b9ade35828 | ||
|
|
c990992f8b | ||
|
|
4a7907f991 | ||
|
|
6f3bae96ff | ||
|
|
1a1ea44902 | ||
|
|
4c9a560b53 | ||
|
|
5cb822b295 | ||
|
|
df7b2ee4d0 | ||
|
|
6871c48c8e | ||
|
|
497458f04c | ||
|
|
a196969a93 | ||
|
|
76b65b45bc | ||
|
|
eb9935bb83 | ||
|
|
98c595696d | ||
|
|
d484e83f47 | ||
|
|
19093b462c | ||
|
|
8488352e77 | ||
|
|
38522564cf | ||
|
|
e8e15b5432 | ||
|
|
a032fc06a3 | ||
|
|
a9d55f129b | ||
|
|
84b35aa464 | ||
|
|
54342c4ee0 | ||
|
|
b89050b03c | ||
|
|
37eac1b9b7 | ||
|
|
e4b287b3c2 | ||
|
|
7cef3c4a53 | ||
|
|
6b39470890 | ||
|
|
5f184db48d | ||
|
|
96c430dd8c | ||
|
|
be662f2e67 | ||
|
|
3fdd4559b6 | ||
|
|
ecf9c0d1e2 | ||
|
|
67903c21d4 | ||
|
|
5924c8616c | ||
|
|
0f2f430b7f | ||
|
|
4a99bad8be | ||
|
|
9964fa5943 | ||
|
|
b6860a8634 | ||
|
|
cc0ef2dc0e | ||
|
|
351504dc5f | ||
|
|
b2494d8fdc | ||
|
|
aea1ea0cbf | ||
|
|
ff9f22e4bd | ||
|
|
fb13e0ab30 | ||
|
|
443685c26e | ||
|
|
bd362f1ac0 | ||
|
|
b23606ed3b | ||
|
|
2344b6367f | ||
|
|
394f15bed8 | ||
|
|
83d7422b9c | ||
|
|
a7246cf786 | ||
|
|
7abcd5b0cd | ||
|
|
a2b224df9b | ||
|
|
4542da4c38 | ||
|
|
3c92c53164 | ||
|
|
b326778219 | ||
|
|
81e16d95ac | ||
|
|
ef18bbdf7c | ||
|
|
6562a0177b | ||
|
|
275a427355 | ||
|
|
ce6a79f03d | ||
|
|
dc792c8425 | ||
|
|
680d2173d1 | ||
|
|
e95a20b971 | ||
|
|
56de06abac | ||
|
|
d66176e628 | ||
|
|
488c542cd5 | ||
|
|
0e0693bdad | ||
|
|
86267a2e38 | ||
|
|
e2171856ff | ||
|
|
3c3a37a9e8 | ||
|
|
573da1e4ff | ||
|
|
1f70446bce | ||
|
|
ff4ef15dfc | ||
|
|
926f3adb18 | ||
|
|
4b2d981cc6 | ||
|
|
93d5c5e03e | ||
|
|
475f071575 | ||
|
|
f77fa88ced | ||
|
|
7fe5c18cb8 | ||
|
|
7e16798b33 | ||
|
|
3edfb68bd7 | ||
|
|
4f307af6bd | ||
|
|
08848af908 | ||
|
|
f4e9b85ae3 | ||
|
|
73ccb0ce65 | ||
|
|
15c5ee7f2c | ||
|
|
f08be0d13f | ||
|
|
aa115e36fd | ||
|
|
cfa45013f4 | ||
|
|
cca01ae5a3 | ||
|
|
44af31f6d4 | ||
|
|
8fb076421a | ||
|
|
89f8ca1387 | ||
|
|
fddb462618 | ||
|
|
97343515a3 | ||
|
|
dcbd2aa390 | ||
|
|
12e7aaa615 | ||
|
|
50f93b87f5 | ||
|
|
b4cefbc15e | ||
|
|
4ce17c3742 | ||
|
|
5035b83ae1 | ||
|
|
dc327a3e24 | ||
|
|
4ddceb83d5 | ||
|
|
31048218af | ||
|
|
6e3a9ca380 | ||
|
|
09134f4c5f | ||
|
|
89c9271726 | ||
|
|
473f8e6b72 | ||
|
|
8310f09641 | ||
|
|
31b9123a8f | ||
|
|
cc4aed6773 | ||
|
|
a868aac579 | ||
|
|
da48eec787 | ||
|
|
4aa56a55fe | ||
|
|
c3daa1cc86 | ||
|
|
00d08d741c | ||
|
|
2f33be6b3c | ||
|
|
d54a3127a6 | ||
|
|
40ecf46b40 | ||
|
|
dd9b6a8fed | ||
|
|
194e1d5c26 | ||
|
|
9360f2a1e0 |
20
.github/dependabot.yml
vendored
20
.github/dependabot.yml
vendored
@@ -2,9 +2,29 @@ version: 2
|
||||
updates:
|
||||
- package-ecosystem: "gradle"
|
||||
directory: "/"
|
||||
registries:
|
||||
- google
|
||||
- gradlePluginPortal
|
||||
- jitpack
|
||||
- mavenCentral
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
# Workaround for https://github.com/dependabot/dependabot-core/issues/6888
|
||||
registries:
|
||||
google:
|
||||
type: maven-repository
|
||||
url: "https://dl.google.com/dl/android/maven2/"
|
||||
gradlePluginPortal:
|
||||
type: maven-repository
|
||||
url: "https://plugins.gradle.org/m2/"
|
||||
jitpack:
|
||||
type: maven-repository
|
||||
url: "https://jitpack.io/"
|
||||
mavenCentral:
|
||||
type: maven-repository
|
||||
url: "https://repo1.maven.org/maven2/"
|
||||
|
||||
6
.github/workflows/android.yml
vendored
6
.github/workflows/android.yml
vendored
@@ -29,10 +29,10 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.0.0
|
||||
- uses: actions/checkout@v4.1.1
|
||||
- name: Fail on bad translations
|
||||
run: if grep -ri "<xliff" app/src/main/res/values*/strings.xml; then echo "Invalidly escaped translations found"; exit 1; fi
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
- uses: gradle/wrapper-validation-action@v2
|
||||
- name: set up OpenJDK 17
|
||||
run: |
|
||||
sudo apt-get update
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
run: ./gradlew spotbugsRelease
|
||||
- name: Archive test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3.1.3
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
with:
|
||||
name: test-results
|
||||
path: app/build/reports
|
||||
|
||||
8
.github/workflows/changelog-to-fastlane.yml
vendored
8
.github/workflows/changelog-to-fastlane.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
permissions:
|
||||
actions: none
|
||||
checks: none
|
||||
contents: read
|
||||
contents: write
|
||||
deployments: none
|
||||
discussions: none
|
||||
id-token: none
|
||||
@@ -27,15 +27,15 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
id: checkout
|
||||
uses: actions/checkout@v4.0.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4.7.0
|
||||
uses: actions/setup-python@v5.0.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Run converter script
|
||||
run: python .scripts/changelog_to_fastlane.py
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v5.0.2
|
||||
uses: peter-evans/create-pull-request@v6.0.0
|
||||
with:
|
||||
title: "Update Fastlane changelogs"
|
||||
commit-message: "Update Fastlane changelogs"
|
||||
|
||||
7
.github/workflows/contributors-to-file.yml
vendored
7
.github/workflows/contributors-to-file.yml
vendored
@@ -25,14 +25,15 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
id: checkout
|
||||
uses: actions/checkout@v4.0.0
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Update contributors
|
||||
id: update_contributors
|
||||
uses: TheLastProject/contributors-to-file-action@v3.0.1
|
||||
uses: TheLastProject/contributors-to-file-action@v3.2.0
|
||||
with:
|
||||
file_in_repo: app/src/main/res/raw/contributors.txt
|
||||
min_commit_count: 5
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v5.0.2
|
||||
uses: peter-evans/create-pull-request@v6.0.0
|
||||
with:
|
||||
title: "Update contributors"
|
||||
commit-message: "Update contributors"
|
||||
|
||||
38
.github/workflows/generate-feature-graphic.yml
vendored
38
.github/workflows/generate-feature-graphic.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
generate-feature-graphic:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.0.0
|
||||
- uses: actions/checkout@v4.1.1
|
||||
- name: Install requirements
|
||||
run: |
|
||||
sudo apt-get update
|
||||
@@ -36,41 +36,9 @@ jobs:
|
||||
find .scripts/generate_feature_graphic/fonts -name '*.ttf' -exec cp {} "$HOME/.fonts" \;
|
||||
fc-cache
|
||||
- name: Generate featureGraphic.png for each language
|
||||
run: |
|
||||
for lang in fastlane/metadata/android/*; do
|
||||
pushd "$lang"
|
||||
# Place temporary copy for editing if needed
|
||||
cp ../../../../.scripts/generate_feature_graphic/featureGraphic.svg featureGraphic.svg
|
||||
# Extract text after 'Catima - '
|
||||
export subtext="$(grep -oP '(?<=Catima \S ).*' title.txt || true)"
|
||||
# If there is subtext, change the .svg accordingly
|
||||
if [ -n "$subtext" ]; then
|
||||
perl -pi -e 's/Loyalty Card Wallet/$ENV{subtext}/' featureGraphic.svg
|
||||
# Set correct font for language if needed (Lexend Deca has limited support)
|
||||
# We specifically need the Serif version because of the 200 weight
|
||||
case "$(basename "$lang")" in
|
||||
bg|el-GR|ru-RU|uk) sed -i "s/Lexend Deca/Noto Serif/" featureGraphic.svg ;;
|
||||
ja-JP) sed -i "s/Lexend Deca/Noto Serif CJK JP/" featureGraphic.svg ;;
|
||||
ko) sed -i "s/Lexend Deca/Noto Serif CJK KR/" featureGraphic.svg ;;
|
||||
zh-CN) sed -i "s/Lexend Deca/Noto Serif CJK SC/" featureGraphic.svg ;;
|
||||
zh-TW) sed -i "s/Lexend Deca/Noto Serif CJK TC/" featureGraphic.svg ;;
|
||||
*) ;;
|
||||
esac
|
||||
fi
|
||||
# Ensure images directory exists
|
||||
mkdir -p images
|
||||
# Generate .png
|
||||
convert featureGraphic.svg images/featureGraphic.png
|
||||
# Optimize .png
|
||||
optipng images/featureGraphic.png
|
||||
# Remove metadata (timestamps) from .png
|
||||
mat2 --inplace images/featureGraphic.png
|
||||
# Remove temporary .svg
|
||||
rm featureGraphic.svg
|
||||
popd
|
||||
done
|
||||
run: .scripts/generate_feature_graphic/generate_feature_graphic.sh
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v5.0.2
|
||||
uses: peter-evans/create-pull-request@v6.0.0
|
||||
with:
|
||||
title: "Update feature graphic"
|
||||
commit-message: "Update feature graphic"
|
||||
|
||||
33
.github/workflows/gradle-update.yml
vendored
Normal file
33
.github/workflows/gradle-update.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Gradle update
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '3 6 * * *'
|
||||
permissions:
|
||||
actions: none
|
||||
checks: none
|
||||
contents: write
|
||||
deployments: none
|
||||
discussions: none
|
||||
id-token: none
|
||||
issues: none
|
||||
packages: none
|
||||
pages: none
|
||||
pull-requests: write
|
||||
repository-projects: none
|
||||
security-events: none
|
||||
statuses: none
|
||||
jobs:
|
||||
gradle-update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.1
|
||||
- uses: obfusk/gradle-update-action@v2.0.0
|
||||
id: gradle-update
|
||||
- uses: gradle/wrapper-validation-action@v2
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6.0.0
|
||||
with:
|
||||
title: "Update Gradle to ${{ steps.gradle-update.outputs.version }}"
|
||||
commit-message: "Update Gradle to ${{ steps.gradle-update.outputs.version }}"
|
||||
branch-suffix: timestamp
|
||||
7
.github/workflows/update-locales.yml
vendored
7
.github/workflows/update-locales.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- app/src/main/res/values-*/strings.xml
|
||||
- app/src/main/res/values/settings.xml
|
||||
permissions:
|
||||
actions: none
|
||||
@@ -24,11 +25,13 @@ jobs:
|
||||
update-locales:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.0.0
|
||||
- uses: actions/checkout@v4.1.1
|
||||
- name: Add new locales
|
||||
run: .scripts/new-locales.py
|
||||
- name: Update locales
|
||||
run: .scripts/locales.py
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v5.0.2
|
||||
uses: peter-evans/create-pull-request@v6.0.0
|
||||
with:
|
||||
title: "Update locales"
|
||||
commit-message: "Update locales"
|
||||
|
||||
26
.gitignore
vendored
26
.gitignore
vendored
@@ -1,13 +1,25 @@
|
||||
# Android Studio generated (superseded/unused rules commented out)
|
||||
*.iml
|
||||
.gradle
|
||||
local.properties
|
||||
.idea/
|
||||
/local.properties
|
||||
#/.idea/caches
|
||||
#/.idea/libraries
|
||||
#/.idea/modules.xml
|
||||
#/.idea/workspace.xml
|
||||
#/.idea/navEditor.xml
|
||||
#/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
build/
|
||||
captures/
|
||||
**/release
|
||||
**/debug
|
||||
app/*.log
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
#local.properties
|
||||
|
||||
# Android extras
|
||||
/app/*.log
|
||||
/app/build
|
||||
/app/release
|
||||
/.idea
|
||||
|
||||
# Bundle
|
||||
/.bundle/
|
||||
|
||||
51
.scripts/generate_feature_graphic/generate_feature_graphic.sh
Executable file
51
.scripts/generate_feature_graphic/generate_feature_graphic.sh
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
script_location="$(dirname "$(readlink -f "$0")")"
|
||||
|
||||
for lang in "$script_location/../../fastlane/metadata/android/"*; do
|
||||
pushd "$lang"
|
||||
# Place temporary copy for editing if needed
|
||||
cp "$script_location/featureGraphic.svg" featureGraphic.svg
|
||||
if grep -q — title.txt; then
|
||||
# Try splitting title.txt on — (em dash)
|
||||
IFS='—' read -r appname subtext < title.txt
|
||||
elif grep -q – title.txt; then
|
||||
# No result, try splitting title.txt on – (en dash)
|
||||
IFS='–' read -r appname subtext < title.txt
|
||||
else
|
||||
# No result, try splitting on - (dash)
|
||||
IFS='-' read -r appname subtext < title.txt
|
||||
fi
|
||||
export appname=${appname%% }
|
||||
export subtext=${subtext## }
|
||||
# If there is subtext, change the .svg accordingly
|
||||
if [ -n "$subtext" ]; then
|
||||
perl -pi -e 's/Catima/$ENV{appname}/' featureGraphic.svg
|
||||
perl -pi -e 's/Loyalty Card Wallet/$ENV{subtext}/' featureGraphic.svg
|
||||
# Set correct font or font size for language if needed
|
||||
# (Lexend Deca has limited support and some characters are big)
|
||||
# We specifically need the Serif version because of the 200 weight
|
||||
case "$(basename "$lang")" in
|
||||
bg|el-GR|ru-RU|uk) sed -i "s/Lexend Deca/Noto Serif/" featureGraphic.svg ;;
|
||||
hi-IN) sed -i -e "s/Yesteryear/Noto Serif Devanagari/" -e "s/Lexend Deca/Noto Serif Devanagari/" featureGraphic.svg ;;
|
||||
ja-JP) sed -i "s/Lexend Deca/Noto Serif CJK JP/" featureGraphic.svg ;;
|
||||
ko) sed -i "s/Lexend Deca/Noto Serif CJK KR/" featureGraphic.svg ;;
|
||||
kn-IN) sed -i -e 's/font-size="150"/font-size="100"/' -e 's/y="285.511"/y="235.511"/' featureGraphic.svg ;;
|
||||
zh-CN) sed -i "s/Lexend Deca/Noto Serif CJK SC/" featureGraphic.svg ;;
|
||||
zh-TW) sed -i "s/Lexend Deca/Noto Serif CJK TC/" featureGraphic.svg ;;
|
||||
*) ;;
|
||||
esac
|
||||
fi
|
||||
# Ensure images directory exists
|
||||
mkdir -p images
|
||||
# Generate .png
|
||||
convert featureGraphic.svg images/featureGraphic.png
|
||||
# Optimize .png
|
||||
optipng images/featureGraphic.png
|
||||
# Remove metadata (timestamps) from .png
|
||||
mat2 --inplace images/featureGraphic.png
|
||||
# Remove temporary .svg
|
||||
rm featureGraphic.svg
|
||||
popd
|
||||
done
|
||||
@@ -19,8 +19,8 @@ res = ", ".join(f'"{loc}"' for loc in locales)
|
||||
sed = [
|
||||
"sed",
|
||||
"-i",
|
||||
f"s/resourceConfigurations .*/resourceConfigurations += [{res}]/",
|
||||
"app/build.gradle"
|
||||
f"s/resourceConfigurations .*/resourceConfigurations += listOf({res})/",
|
||||
"app/build.gradle.kts"
|
||||
]
|
||||
subprocess.run(sed, check=True)
|
||||
|
||||
|
||||
120
.scripts/new-locales.py
Executable file
120
.scripts/new-locales.py
Executable file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import glob
|
||||
import re
|
||||
|
||||
from typing import Iterator, List, Tuple
|
||||
|
||||
import requests
|
||||
|
||||
MIN_PERCENT = 90
|
||||
NOT_LANGS = ("night", "w600dp")
|
||||
REPLACE_CODES = {
|
||||
"el": "el-rGR",
|
||||
"id": "in-rID",
|
||||
"ro": "ro-rRO",
|
||||
"zh_Hans": "zh-rCN",
|
||||
"zh_Hant": "zh-rTW",
|
||||
}
|
||||
STATS_URL = "https://hosted.weblate.org/api/components/catima/catima/statistics/"
|
||||
|
||||
|
||||
def get_weblate_langs() -> List[Tuple[str, int]]:
|
||||
r = requests.get(STATS_URL, timeout=5)
|
||||
r.raise_for_status()
|
||||
results = []
|
||||
for lang in r.json()["results"]:
|
||||
if lang["code"] != "en":
|
||||
code = REPLACE_CODES.get(lang["code"], lang["code"]).replace("_", "-r")
|
||||
results.append((code, round(lang["translated_percent"])))
|
||||
return sorted(results)
|
||||
|
||||
|
||||
def get_dir_langs() -> List[str]:
|
||||
results = []
|
||||
for d in glob.glob("app/src/main/res/values-*"):
|
||||
code = d.split("-", 1)[1]
|
||||
if code not in NOT_LANGS:
|
||||
results.append(code)
|
||||
return sorted(results)
|
||||
|
||||
|
||||
def get_xml_langs() -> List[Tuple[str, bool]]:
|
||||
results = []
|
||||
in_section = False
|
||||
with open("app/src/main/res/values/settings.xml") as fh:
|
||||
for line in fh:
|
||||
if not in_section and 'name="locale_values"' in line:
|
||||
in_section = True
|
||||
elif in_section:
|
||||
if "string-array" in line:
|
||||
break
|
||||
disabled = "<!--" in line
|
||||
if m := re.search(r">(.*)<", line):
|
||||
if m[1] != "en":
|
||||
results.append((m[1], disabled))
|
||||
return sorted(results)
|
||||
|
||||
|
||||
def update_xml_langs(langs: List[Tuple[str, bool]]) -> None:
|
||||
lines: List[str] = []
|
||||
in_section = False
|
||||
with open("app/src/main/res/values/settings.xml") as fh:
|
||||
for line in fh:
|
||||
if not in_section and 'name="locale_values"' in line:
|
||||
in_section = True
|
||||
elif in_section:
|
||||
if "string-array" in line:
|
||||
in_section = False
|
||||
lines.extend(_lang_lines(langs))
|
||||
else:
|
||||
continue
|
||||
lines.append(line)
|
||||
with open("app/src/main/res/values/settings.xml", "w") as fh:
|
||||
for line in lines:
|
||||
fh.write(line)
|
||||
|
||||
|
||||
def _lang_lines(langs: List[Tuple[str, bool]]) -> Iterator[str]:
|
||||
yield " <item />\n"
|
||||
for lang, disabled in sorted(langs + [("en", False)]):
|
||||
if disabled:
|
||||
yield f" <!-- <item>{lang}</item> -->\n"
|
||||
else:
|
||||
yield f" <item>{lang}</item>\n"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
web_langs = get_weblate_langs()
|
||||
dir_langs = get_dir_langs()
|
||||
xml_langs = get_xml_langs()
|
||||
|
||||
web_codes = set(code for code, _ in web_langs)
|
||||
dir_codes = set(dir_langs)
|
||||
xml_codes = set(code for code, _ in xml_langs)
|
||||
|
||||
if diff := web_codes - dir_codes:
|
||||
print(f"WARNING: Weblate codes w/o dir: {diff}")
|
||||
if diff := xml_codes - dir_codes:
|
||||
print(f"WARNING: XML codes w/o dir: {diff}")
|
||||
|
||||
percentages = dict(web_langs)
|
||||
all_langs = xml_langs[:]
|
||||
|
||||
# add new langs as disabled
|
||||
for code in dir_codes - xml_codes:
|
||||
all_langs.append((code, True))
|
||||
|
||||
# enable disabled langs if they are at least MIN_PERCENT translated now
|
||||
updated_langs = sorted(
|
||||
(code, percentages[code] < MIN_PERCENT if disabled else disabled)
|
||||
for code, disabled in all_langs
|
||||
)
|
||||
|
||||
if updated_langs != xml_langs:
|
||||
print("Updating...")
|
||||
update_xml_langs(updated_langs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,5 +1,20 @@
|
||||
# Changelog
|
||||
|
||||
## Unreleased - 133
|
||||
|
||||
- Target Android 14
|
||||
- Open card icon in gallery on touch
|
||||
- Improve design of Photos tab in edit view
|
||||
|
||||
## v2.27.0 - 132 (2024-01-30)
|
||||
|
||||
- Refine "Add card" workflow
|
||||
- Validation flow improvements
|
||||
- Fix edge case causing invalid UI state when toggling showing archive
|
||||
- Use theme or card colour for navigation bar (Android 8.1+)
|
||||
- Updated validity and expiry date selector
|
||||
- Add option to always rotate (ignoring system settings)
|
||||
|
||||
## v2.26.0 - 131 (2023-09-14)
|
||||
|
||||
- Move "Archive mode" into "Display options" (previously "Show details") menu
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
How to Submit Patches to the Catima Project
|
||||
===============================================================================
|
||||
https://github.com/TheLastProject/Catima
|
||||
# How to Submit Patches to the Catima Project
|
||||
|
||||
This document is intended to act as a guide to help you contribute to the
|
||||
Catima project. It is not perfect, and there will always be exceptions
|
||||
Catima project. It is not perfect, and there will always be exceptions
|
||||
to the rules described here, but by following the instructions below you
|
||||
should have a much easier time getting your work merged with the upstream
|
||||
project.
|
||||
|
||||
When contributing, you certify that you agree to and have the rights to submit
|
||||
your contribution under the project's license and understand that git will
|
||||
store your name and email address in project history indefinitely.
|
||||
|
||||
## Translation Changes
|
||||
|
||||
Translation changes are managed through [Weblate](https://hosted.weblate.org/projects/catima/).
|
||||
@@ -57,44 +59,6 @@ if you can describe/include a reproducer for the problem in the description as
|
||||
well as instructions on how to test for the bug and verify that it has been
|
||||
fixed.
|
||||
|
||||
### Sign Your Work
|
||||
|
||||
The sign-off is a simple line at the end of the patch description, which
|
||||
certifies that you wrote it or otherwise have the right to pass it on as an
|
||||
open-source patch. The "Developer's Certificate of Origin" pledge is taken
|
||||
from the Linux Kernel and the rules are pretty simple:
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
|
||||
... then you just add a line to the bottom of your patch description, with
|
||||
your real name, saying:
|
||||
|
||||
Signed-off-by: Random J Developer <random@developer.example.org>
|
||||
|
||||
### Submit Patch(es) for Review
|
||||
|
||||
Finally, you will need to submit your patches so that they can be reviewed
|
||||
|
||||
88
Gemfile.lock
88
Gemfile.lock
@@ -3,25 +3,25 @@ GEM
|
||||
specs:
|
||||
CFPropertyList (3.0.6)
|
||||
rexml
|
||||
addressable (2.8.4)
|
||||
addressable (2.8.6)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
artifactory (3.0.15)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.2.0)
|
||||
aws-partitions (1.793.0)
|
||||
aws-sdk-core (3.180.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.884.0)
|
||||
aws-sdk-core (3.191.0)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (~> 1.8)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.71.0)
|
||||
aws-sdk-core (~> 3, >= 3.177.0)
|
||||
aws-sdk-kms (1.77.0)
|
||||
aws-sdk-core (~> 3, >= 3.191.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.132.0)
|
||||
aws-sdk-core (~> 3, >= 3.179.0)
|
||||
aws-sdk-s3 (1.143.0)
|
||||
aws-sdk-core (~> 3, >= 3.191.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.6)
|
||||
aws-sigv4 (1.6.0)
|
||||
aws-sigv4 (~> 1.8)
|
||||
aws-sigv4 (1.8.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
claide (1.1.0)
|
||||
@@ -32,11 +32,10 @@ GEM
|
||||
declarative (0.0.20)
|
||||
digest-crc (0.6.5)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
domain_name (0.6.20240107)
|
||||
dotenv (2.8.1)
|
||||
emoji_regex (3.2.3)
|
||||
excon (0.100.0)
|
||||
excon (0.109.0)
|
||||
faraday (1.10.3)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
@@ -65,8 +64,8 @@ GEM
|
||||
faraday-retry (1.0.3)
|
||||
faraday_middleware (1.2.0)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.2.7)
|
||||
fastlane (2.214.0)
|
||||
fastimage (2.3.0)
|
||||
fastlane (2.219.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
@@ -85,20 +84,22 @@ GEM
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-apis-androidpublisher_v3 (~> 0.3)
|
||||
google-apis-playcustomapp_v1 (~> 0.1)
|
||||
google-cloud-env (>= 1.6.0, < 2.0.0)
|
||||
google-cloud-storage (~> 1.31)
|
||||
highline (~> 2.0)
|
||||
http-cookie (~> 1.0.5)
|
||||
json (< 3.0.0)
|
||||
jwt (>= 2.1.0, < 3)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multipart-post (>= 2.0.0, < 3.0.0)
|
||||
naturally (~> 2.2)
|
||||
optparse (~> 0.1.1)
|
||||
optparse (>= 0.1.1)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
rubyzip (>= 2.0.0, < 3.0.0)
|
||||
security (= 0.1.3)
|
||||
simctl (~> 1.6.3)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
terminal-table (~> 3)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
@@ -106,9 +107,9 @@ GEM
|
||||
xcpretty (~> 0.3.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
gh_inspector (1.1.3)
|
||||
google-apis-androidpublisher_v3 (0.46.0)
|
||||
google-apis-androidpublisher_v3 (0.54.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-core (0.11.1)
|
||||
google-apis-core (0.11.3)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
httpclient (>= 2.8.1, < 3.a)
|
||||
@@ -116,31 +117,29 @@ GEM
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.a)
|
||||
rexml
|
||||
webrick
|
||||
google-apis-iamcredentials_v1 (0.17.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-playcustomapp_v1 (0.13.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-storage_v1 (0.19.0)
|
||||
google-apis-core (>= 0.9.0, < 2.a)
|
||||
google-cloud-core (1.6.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-apis-storage_v1 (0.31.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-cloud-core (1.6.1)
|
||||
google-cloud-env (>= 1.0, < 3.a)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.6.0)
|
||||
faraday (>= 0.17.3, < 3.0)
|
||||
google-cloud-errors (1.3.1)
|
||||
google-cloud-storage (1.44.0)
|
||||
google-cloud-storage (1.47.0)
|
||||
addressable (~> 2.8)
|
||||
digest-crc (~> 0.4)
|
||||
google-apis-iamcredentials_v1 (~> 0.1)
|
||||
google-apis-storage_v1 (~> 0.19.0)
|
||||
google-apis-storage_v1 (~> 0.31.0)
|
||||
google-cloud-core (~> 1.6)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (1.7.0)
|
||||
googleauth (1.8.1)
|
||||
faraday (>= 0.17.3, < 3.a)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (>= 0.16, < 2.a)
|
||||
@@ -149,20 +148,19 @@ GEM
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
jmespath (1.6.2)
|
||||
json (2.6.3)
|
||||
json (2.7.1)
|
||||
jwt (2.7.1)
|
||||
memoist (0.16.2)
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.2)
|
||||
mini_mime (1.1.5)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.3.0)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.1)
|
||||
optparse (0.1.1)
|
||||
optparse (0.4.0)
|
||||
os (1.1.4)
|
||||
plist (3.7.0)
|
||||
public_suffix (5.0.3)
|
||||
rake (13.0.6)
|
||||
plist (3.7.1)
|
||||
public_suffix (5.0.4)
|
||||
rake (13.1.0)
|
||||
representable (3.2.0)
|
||||
declarative (< 0.1.0)
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
@@ -173,7 +171,7 @@ GEM
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
security (0.1.3)
|
||||
signet (0.17.0)
|
||||
signet (0.18.0)
|
||||
addressable (~> 2.8)
|
||||
faraday (>= 0.17.5, < 3.a)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
@@ -182,21 +180,17 @@ GEM
|
||||
CFPropertyList
|
||||
naturally
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
terminal-table (3.0.2)
|
||||
unicode-display_width (>= 1.1.1, < 3)
|
||||
trailblazer-option (0.1.2)
|
||||
tty-cursor (0.7.1)
|
||||
tty-screen (0.8.1)
|
||||
tty-screen (0.8.2)
|
||||
tty-spinner (0.9.3)
|
||||
tty-cursor (~> 0.7)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.8.2)
|
||||
unicode-display_width (1.8.0)
|
||||
webrick (1.8.1)
|
||||
unicode-display_width (2.5.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.22.0)
|
||||
xcodeproj (1.24.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
|
||||
146
app/build.gradle
146
app/build.gradle
@@ -1,146 +0,0 @@
|
||||
import com.github.spotbugs.snom.SpotBugsTask
|
||||
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'com.github.spotbugs'
|
||||
}
|
||||
|
||||
spotbugs {
|
||||
ignoreFailures = false
|
||||
effort = 'max'
|
||||
excludeFilter = file("./config/spotbugs/exclude.xml")
|
||||
reportsDir = file("$buildDir/reports/spotbugs/")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk 33
|
||||
|
||||
defaultConfig {
|
||||
applicationId "me.hackerchick.catima"
|
||||
minSdk 21
|
||||
targetSdk 33
|
||||
versionCode 131
|
||||
versionName "2.26.0"
|
||||
|
||||
vectorDrawables.useSupportLibrary true
|
||||
multiDexEnabled true
|
||||
|
||||
resourceConfigurations += ["ar", "bg", "bn", "bn-rIN", "bs", "cs", "da", "de", "el-rGR", "en", "eo", "es", "es-rAR", "fi", "fr", "he-rIL", "hi", "hr", "hu", "in-rID", "is", "it", "ja", "ko", "lt", "lv", "nb-rNO", "nl", "oc", "pl", "pt", "ro-rRO", "ru", "sk", "sl", "sv", "tr", "uk", "zh-rTW", "zh-rCN"]
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
resValue "string", "app_name", "Catima"
|
||||
}
|
||||
debug {
|
||||
applicationIdSuffix ".debug"
|
||||
resValue "string", "app_name", "Catima Debug"
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
|
||||
bundle {
|
||||
language {
|
||||
enableSplit = false
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
encoding "UTF-8"
|
||||
|
||||
// Flag to enable support for the new language APIs
|
||||
coreLibraryDesugaringEnabled true
|
||||
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
|
||||
sourceSets {
|
||||
test {
|
||||
resources.srcDirs += ['src/test/res']
|
||||
}
|
||||
}
|
||||
|
||||
// Starting with Android Studio 3 Robolectric is unable to find resources.
|
||||
// The following allows it to find the resources.
|
||||
testOptions {
|
||||
unitTests {
|
||||
all {
|
||||
testLogging {
|
||||
events 'started', 'passed', 'skipped', 'failed'
|
||||
}
|
||||
}
|
||||
includeAndroidResources true
|
||||
}
|
||||
}
|
||||
lint {
|
||||
lintConfig file('lint.xml')
|
||||
}
|
||||
namespace 'protect.card_locker'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// AndroidX
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.6'
|
||||
implementation 'androidx.palette:palette:1.0.0'
|
||||
implementation 'androidx.preference:preference:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.9.0'
|
||||
implementation 'com.github.yalantis:ucrop:2.2.8'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
|
||||
|
||||
// Splash Screen
|
||||
implementation 'androidx.core:core-splashscreen:1.0.1'
|
||||
|
||||
// Third-party
|
||||
implementation 'com.journeyapps:zxing-android-embedded:4.3.0@aar'
|
||||
implementation 'com.google.zxing:core:3.5.2'
|
||||
implementation 'org.apache.commons:commons-csv:1.9.0'
|
||||
implementation 'com.jaredrummler:colorpicker:1.1.0'
|
||||
implementation 'net.lingala.zip4j:zip4j:2.11.5'
|
||||
|
||||
// SpotBugs
|
||||
implementation 'io.wcm.tooling.spotbugs:io.wcm.tooling.spotbugs.annotations:1.0.0'
|
||||
|
||||
// Testing
|
||||
testImplementation 'androidx.test:core:1.5.0'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.robolectric:robolectric:4.10.3'
|
||||
}
|
||||
|
||||
tasks.withType(SpotBugsTask) {
|
||||
|
||||
description 'Run spotbugs'
|
||||
group 'verification'
|
||||
|
||||
//classes = fileTree('build/intermediates/javac/debug/compileDebugJavaWithJavac/classes')
|
||||
//source = fileTree('src/main/java')
|
||||
//classpath = files()
|
||||
|
||||
reports {
|
||||
xml.enabled = false
|
||||
html.enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('copyRawResFiles', Copy) {
|
||||
from layout.projectDirectory.file("../CHANGELOG.md"),
|
||||
layout.projectDirectory.file("../PRIVACY.md")
|
||||
into layout.projectDirectory.dir("src/main/res/raw")
|
||||
rename { String fileName -> fileName.toLowerCase() }
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
tasks.each { task ->
|
||||
if (task != copyRawResFiles) {
|
||||
task.dependsOn(copyRawResFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
145
app/build.gradle.kts
Normal file
145
app/build.gradle.kts
Normal file
@@ -0,0 +1,145 @@
|
||||
import com.android.build.gradle.internal.tasks.factory.dependsOn
|
||||
import com.github.spotbugs.snom.SpotBugsTask
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("com.github.spotbugs")
|
||||
}
|
||||
|
||||
spotbugs {
|
||||
ignoreFailures.set(false)
|
||||
setEffort("max")
|
||||
excludeFilter.set(file("./config/spotbugs/exclude.xml"))
|
||||
reportsDir.set(layout.buildDirectory.file("reports/spotbugs/").get().asFile)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "protect.card_locker"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "me.hackerchick.catima"
|
||||
minSdk = 21
|
||||
targetSdk = 34
|
||||
versionCode = 132
|
||||
versionName = "2.27.0"
|
||||
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
multiDexEnabled = true
|
||||
|
||||
resourceConfigurations += listOf("ar", "bg", "bn", "bn-rIN", "bs", "cs", "da", "de", "el-rGR", "en", "eo", "es", "es-rAR", "fi", "fr", "he-rIL", "hi", "hr", "hu", "in-rID", "is", "it", "ja", "ko", "lt", "lv", "nb-rNO", "nl", "oc", "pl", "pt-rPT", "ro-rRO", "ru", "sk", "sl", "sv", "tr", "uk", "vi", "zh-rCN", "zh-rTW")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
debug {
|
||||
applicationIdSuffix = ".debug"
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
viewBinding = true
|
||||
}
|
||||
|
||||
bundle {
|
||||
language {
|
||||
enableSplit = false
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
encoding = "UTF-8"
|
||||
|
||||
// Flag to enable support for the new language APIs
|
||||
isCoreLibraryDesugaringEnabled = true
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
getByName("test") {
|
||||
resources.srcDirs("src/test/res")
|
||||
}
|
||||
}
|
||||
|
||||
// Starting with Android Studio 3 Robolectric is unable to find resources.
|
||||
// The following allows it to find the resources.
|
||||
testOptions.unitTests.isIncludeAndroidResources = true
|
||||
tasks.withType<Test>().configureEach {
|
||||
testLogging {
|
||||
events("started", "passed", "skipped", "failed")
|
||||
}
|
||||
}
|
||||
|
||||
lint {
|
||||
lintConfig = file("lint.xml")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
// AndroidX
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
implementation("androidx.exifinterface:exifinterface:1.3.7")
|
||||
implementation("androidx.palette:palette:1.0.0")
|
||||
implementation("androidx.preference:preference:1.2.1")
|
||||
implementation("com.google.android.material:material:1.11.0")
|
||||
implementation("com.github.yalantis:ucrop:2.2.8")
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
|
||||
|
||||
// Splash Screen
|
||||
implementation("androidx.core:core-splashscreen:1.0.1")
|
||||
|
||||
// Third-party
|
||||
implementation("com.journeyapps:zxing-android-embedded:4.3.0@aar")
|
||||
implementation("com.google.zxing:core:3.5.3")
|
||||
implementation("org.apache.commons:commons-csv:1.9.0")
|
||||
implementation("com.jaredrummler:colorpicker:1.1.0")
|
||||
implementation("net.lingala.zip4j:zip4j:2.11.5")
|
||||
|
||||
// SpotBugs
|
||||
implementation("io.wcm.tooling.spotbugs:io.wcm.tooling.spotbugs.annotations:1.0.0")
|
||||
|
||||
// Testing
|
||||
testImplementation("androidx.test:core:1.5.0")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
testImplementation("org.robolectric:robolectric:4.11.1")
|
||||
}
|
||||
|
||||
tasks.withType<SpotBugsTask>().configureEach {
|
||||
description = "Run spotbugs"
|
||||
group = "verification"
|
||||
|
||||
//classes = fileTree("build/intermediates/javac/debug/compileDebugJavaWithJavac/classes")
|
||||
//source = fileTree("src/main/java")
|
||||
//classpath = files()
|
||||
|
||||
reports.maybeCreate("xml").required.set(false)
|
||||
reports.maybeCreate("html").required.set(true)
|
||||
}
|
||||
|
||||
tasks.register("copyRawResFiles", Copy::class) {
|
||||
from(
|
||||
layout.projectDirectory.file("../CHANGELOG.md"),
|
||||
layout.projectDirectory.file("../PRIVACY.md")
|
||||
)
|
||||
into(layout.projectDirectory.dir("src/main/res/raw"))
|
||||
rename { it.lowercase() }
|
||||
}.also {
|
||||
tasks.preBuild.dependsOn(it)
|
||||
tasks.getByName<Delete>("clean") {
|
||||
val filesNamesToDelete = listOf("CHANGELOG", "PRIVACY")
|
||||
filesNamesToDelete.forEach { fileName ->
|
||||
delete(layout.projectDirectory.file("src/main/res/raw/${fileName.lowercase()}.md"))
|
||||
}
|
||||
}
|
||||
}
|
||||
2
app/proguard-rules.pro
vendored
2
app/proguard-rules.pro
vendored
@@ -2,7 +2,7 @@
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /Users/brarcher/Library/Android/sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
# directive in build.gradle.kts.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
2
app/src/debug/res/values-ar/strings.xml
Normal file
2
app/src/debug/res/values-ar/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-ast/strings.xml
Normal file
2
app/src/debug/res/values-ast/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-bg/strings.xml
Normal file
2
app/src/debug/res/values-bg/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-bn-rIN/strings.xml
Normal file
2
app/src/debug/res/values-bn-rIN/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-bn/strings.xml
Normal file
2
app/src/debug/res/values-bn/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-bs/strings.xml
Normal file
2
app/src/debug/res/values-bs/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-ca/strings.xml
Normal file
2
app/src/debug/res/values-ca/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
4
app/src/debug/res/values-cs/strings.xml
Normal file
4
app/src/debug/res/values-cs/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima Debug</string>
|
||||
</resources>
|
||||
2
app/src/debug/res/values-cy/strings.xml
Normal file
2
app/src/debug/res/values-cy/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-da/strings.xml
Normal file
2
app/src/debug/res/values-da/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
4
app/src/debug/res/values-de/strings.xml
Normal file
4
app/src/debug/res/values-de/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima Debug</string>
|
||||
</resources>
|
||||
2
app/src/debug/res/values-el/strings.xml
Normal file
2
app/src/debug/res/values-el/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-eo/strings.xml
Normal file
2
app/src/debug/res/values-eo/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-es-rAR/strings.xml
Normal file
2
app/src/debug/res/values-es-rAR/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
4
app/src/debug/res/values-es/strings.xml
Normal file
4
app/src/debug/res/values-es/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Depuración de Catima</string>
|
||||
</resources>
|
||||
2
app/src/debug/res/values-fi/strings.xml
Normal file
2
app/src/debug/res/values-fi/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
4
app/src/debug/res/values-fr/strings.xml
Normal file
4
app/src/debug/res/values-fr/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Débogage de Catima</string>
|
||||
</resources>
|
||||
2
app/src/debug/res/values-he-rIL/strings.xml
Normal file
2
app/src/debug/res/values-he-rIL/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
4
app/src/debug/res/values-hi/strings.xml
Normal file
4
app/src/debug/res/values-hi/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">कैटिमा डीबग</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-hr/strings.xml
Normal file
4
app/src/debug/res/values-hr/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima Debug</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-hu/strings.xml
Normal file
4
app/src/debug/res/values-hu/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima Debug</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-in/strings.xml
Normal file
4
app/src/debug/res/values-in/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima Debug</string>
|
||||
</resources>
|
||||
2
app/src/debug/res/values-is/strings.xml
Normal file
2
app/src/debug/res/values-is/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
4
app/src/debug/res/values-it/strings.xml
Normal file
4
app/src/debug/res/values-it/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima Debug</string>
|
||||
</resources>
|
||||
2
app/src/debug/res/values-ja/strings.xml
Normal file
2
app/src/debug/res/values-ja/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
4
app/src/debug/res/values-kn/strings.xml
Normal file
4
app/src/debug/res/values-kn/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">ಕ್ಯಾಟಿಮಾ ಡೀಬಗ್</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-ko/strings.xml
Normal file
4
app/src/debug/res/values-ko/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima 디버그</string>
|
||||
</resources>
|
||||
2
app/src/debug/res/values-lb/strings.xml
Normal file
2
app/src/debug/res/values-lb/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-lt/strings.xml
Normal file
2
app/src/debug/res/values-lt/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-lv/strings.xml
Normal file
2
app/src/debug/res/values-lv/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-ml/strings.xml
Normal file
2
app/src/debug/res/values-ml/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-mr/strings.xml
Normal file
2
app/src/debug/res/values-mr/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
4
app/src/debug/res/values-nb-rNO/strings.xml
Normal file
4
app/src/debug/res/values-nb-rNO/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima-avlusing</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-nl/strings.xml
Normal file
4
app/src/debug/res/values-nl/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima-foutopsporing</string>
|
||||
</resources>
|
||||
2
app/src/debug/res/values-oc/strings.xml
Normal file
2
app/src/debug/res/values-oc/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
4
app/src/debug/res/values-pl/strings.xml
Normal file
4
app/src/debug/res/values-pl/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima Debug</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-pt-rPT/strings.xml
Normal file
4
app/src/debug/res/values-pt-rPT/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Depuração Catima</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-ro/strings.xml
Normal file
4
app/src/debug/res/values-ro/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Depanare Catima</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-ru/strings.xml
Normal file
4
app/src/debug/res/values-ru/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Отладка Catima</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-sk/strings.xml
Normal file
4
app/src/debug/res/values-sk/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima Debug</string>
|
||||
</resources>
|
||||
2
app/src/debug/res/values-sl/strings.xml
Normal file
2
app/src/debug/res/values-sl/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
2
app/src/debug/res/values-sv/strings.xml
Normal file
2
app/src/debug/res/values-sv/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
4
app/src/debug/res/values-tr/strings.xml
Normal file
4
app/src/debug/res/values-tr/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima Hata Ayaklama</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-uk/strings.xml
Normal file
4
app/src/debug/res/values-uk/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima Debug</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-vi/strings.xml
Normal file
4
app/src/debug/res/values-vi/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Gỡ lỗi Catima</string>
|
||||
</resources>
|
||||
4
app/src/debug/res/values-zh-rCN/strings.xml
Normal file
4
app/src/debug/res/values-zh-rCN/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Catima 调试</string>
|
||||
</resources>
|
||||
2
app/src/debug/res/values-zh-rTW/strings.xml
Normal file
2
app/src/debug/res/values-zh-rTW/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
4
app/src/debug/res/values/strings.xml
Normal file
4
app/src/debug/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name">Catima Debug</string>
|
||||
</resources>
|
||||
@@ -24,6 +24,7 @@
|
||||
<application
|
||||
android:name=".LoyaltyCardLockerApplication"
|
||||
android:allowBackup="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
@@ -32,7 +33,6 @@
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.App.Starting">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@@ -111,10 +111,12 @@
|
||||
android:name=".preferences.SettingsActivity"
|
||||
android:label="@string/settings"
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
<!-- FIXME: locked screenOrientation is a workaround for https://github.com/CatimaLoyalty/Android/issues/1715, remove when https://github.com/CatimaLoyalty/Android/issues/513 is fixed -->
|
||||
<activity
|
||||
android:name=".ImportExportActivity"
|
||||
android:label="@string/importExport"
|
||||
android:exported="true"
|
||||
android:screenOrientation="locked"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
|
||||
<!-- ZIP Intent Filter -->
|
||||
|
||||
@@ -7,11 +7,11 @@ import android.view.View;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
|
||||
import protect.card_locker.databinding.AboutActivityBinding;
|
||||
|
||||
public class AboutActivity extends CatimaAppCompatActivity {
|
||||
@@ -43,7 +43,7 @@ public class AboutActivity extends CatimaAppCompatActivity {
|
||||
binding.privacy.setTag("https://catima.app/privacy-policy/");
|
||||
binding.reportError.setTag("https://github.com/CatimaLoyalty/Android/issues");
|
||||
binding.rate.setTag("https://play.google.com/store/apps/details?id=me.hackerchick.catima");
|
||||
binding.donate.setTag("https://catima.app/contribute/#donating");
|
||||
binding.donate.setTag("https://catima.app/donate");
|
||||
|
||||
boolean installedFromGooglePlay = Utils.installedFromGooglePlay(this);
|
||||
// Hide Google Play rate button if not on Google Play
|
||||
@@ -98,11 +98,7 @@ public class AboutActivity extends CatimaAppCompatActivity {
|
||||
}
|
||||
|
||||
private void showCredits() {
|
||||
new MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.credits)
|
||||
.setMessage(content.getContributorInfo())
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show();
|
||||
showHTML(R.string.credits, content.getContributorInfo(), null);
|
||||
}
|
||||
|
||||
private void showHistory(View view) {
|
||||
@@ -117,7 +113,7 @@ public class AboutActivity extends CatimaAppCompatActivity {
|
||||
showHTML(R.string.privacy_policy, content.getPrivacyInfo(), view);
|
||||
}
|
||||
|
||||
private void showHTML(@StringRes int title, final Spanned text, View view) {
|
||||
private void showHTML(@StringRes int title, final Spanned text, @Nullable View view) {
|
||||
int dialogContentPadding = getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_padding);
|
||||
TextView textView = new TextView(this);
|
||||
textView.setText(text);
|
||||
@@ -125,12 +121,21 @@ public class AboutActivity extends CatimaAppCompatActivity {
|
||||
ScrollView scrollView = new ScrollView(this);
|
||||
scrollView.addView(textView);
|
||||
scrollView.setPadding(dialogContentPadding, dialogContentPadding / 2, dialogContentPadding, 0);
|
||||
new MaterialAlertDialogBuilder(this)
|
||||
|
||||
// Create dialog
|
||||
MaterialAlertDialogBuilder materialAlertDialogBuilder = new MaterialAlertDialogBuilder(this);
|
||||
materialAlertDialogBuilder
|
||||
.setTitle(title)
|
||||
.setView(scrollView)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setNeutralButton(R.string.view_online, (dialog, which) -> openExternalBrowser(view))
|
||||
.show();
|
||||
.setPositiveButton(R.string.ok, null);
|
||||
|
||||
// Add View online button if an URL is linked to this view
|
||||
if (view != null && view.getTag() != null) {
|
||||
materialAlertDialogBuilder.setNeutralButton(R.string.view_online, (dialog, which) -> openExternalBrowser(view));
|
||||
}
|
||||
|
||||
// Show dialog
|
||||
materialAlertDialogBuilder.show();
|
||||
}
|
||||
|
||||
private void openExternalBrowser(View view) {
|
||||
|
||||
@@ -129,19 +129,19 @@ public class AboutContent {
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public String getContributorInfo() {
|
||||
public Spanned getContributorInfo() {
|
||||
StringBuilder contributorInfo = new StringBuilder();
|
||||
contributorInfo.append(getCopyright());
|
||||
contributorInfo.append("\n\n");
|
||||
contributorInfo.append("<br/><br/>");
|
||||
contributorInfo.append(context.getString(R.string.app_copyright_old));
|
||||
contributorInfo.append("\n\n");
|
||||
contributorInfo.append(HtmlCompat.fromHtml(String.format(context.getString(R.string.app_contributors), getContributors()), HtmlCompat.FROM_HTML_MODE_COMPACT));
|
||||
contributorInfo.append("\n\n");
|
||||
contributorInfo.append(HtmlCompat.fromHtml(String.format(context.getString(R.string.app_libraries), getThirdPartyLibraries()), HtmlCompat.FROM_HTML_MODE_COMPACT));
|
||||
contributorInfo.append("\n\n");
|
||||
contributorInfo.append(HtmlCompat.fromHtml(String.format(context.getString(R.string.app_resources), getUsedThirdPartyAssets()), HtmlCompat.FROM_HTML_MODE_COMPACT));
|
||||
contributorInfo.append("<br/><br/>");
|
||||
contributorInfo.append(String.format(context.getString(R.string.app_contributors), getContributors()));
|
||||
contributorInfo.append("<br/><br/>");
|
||||
contributorInfo.append(String.format(context.getString(R.string.app_libraries), getThirdPartyLibraries()));
|
||||
contributorInfo.append("<br/><br/>");
|
||||
contributorInfo.append(String.format(context.getString(R.string.app_resources), getUsedThirdPartyAssets()));
|
||||
|
||||
return contributorInfo.toString();
|
||||
return HtmlCompat.fromHtml(contributorInfo.toString(), HtmlCompat.FROM_HTML_MODE_COMPACT);
|
||||
}
|
||||
|
||||
public Spanned getHistoryInfo() {
|
||||
|
||||
@@ -12,13 +12,12 @@ import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import protect.card_locker.databinding.BarcodeSelectorActivityBinding;
|
||||
|
||||
/**
|
||||
@@ -66,10 +65,6 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
runOnUiThread(() -> {
|
||||
generateBarcodes(s.toString());
|
||||
|
||||
View noBarcodeButtonView = binding.noBarcode;
|
||||
setButtonListener(noBarcodeButtonView, s.toString());
|
||||
noBarcodeButtonView.setEnabled(s.length() > 0);
|
||||
});
|
||||
}, INPUT_DELAY);
|
||||
}
|
||||
@@ -95,17 +90,6 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity implements
|
||||
mAdapter.setBarcodes(barcodes);
|
||||
}
|
||||
|
||||
private void setButtonListener(final View button, final String cardId) {
|
||||
button.setOnClickListener(view -> {
|
||||
Log.d(TAG, "Selected no barcode");
|
||||
Intent result = new Intent();
|
||||
result.putExtra(BARCODE_FORMAT, "");
|
||||
result.putExtra(BARCODE_CONTENTS, cardId);
|
||||
BarcodeSelectorActivity.this.setResult(RESULT_OK, result);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
|
||||
@@ -15,13 +15,13 @@ import android.service.controls.actions.ControlAction;
|
||||
import android.service.controls.templates.StatelessTemplate;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Flow;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
public class CardsOnPowerScreenService extends ControlsProviderService {
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -13,6 +14,8 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
|
||||
public class CatimaAppCompatActivity extends AppCompatActivity {
|
||||
protected boolean activityOverridesNavBarColor = false;
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
// Apply chosen language
|
||||
@@ -30,20 +33,31 @@ public class CatimaAppCompatActivity extends AppCompatActivity {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
// material 3 designer does not consider status bar colors
|
||||
// XXX changing this in onCreate causes issues with the splash screen activity, so doing this here
|
||||
boolean darkMode = Utils.isDarkModeEnabled(this);
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
View decorView = getWindow().getDecorView();
|
||||
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(getWindow(), decorView);
|
||||
wic.setAppearanceLightStatusBars(!darkMode);
|
||||
getWindow().setStatusBarColor(Color.TRANSPARENT);
|
||||
} else {
|
||||
// icons are always white back then
|
||||
getWindow().setStatusBarColor(darkMode ? Color.TRANSPARENT : Color.argb(127, 0, 0, 0));
|
||||
Window window = getWindow();
|
||||
if (window != null) {
|
||||
boolean darkMode = Utils.isDarkModeEnabled(this);
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
View decorView = window.getDecorView();
|
||||
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(window, decorView);
|
||||
wic.setAppearanceLightStatusBars(!darkMode);
|
||||
window.setStatusBarColor(Color.TRANSPARENT);
|
||||
} else {
|
||||
// icons are always white back then
|
||||
window.setStatusBarColor(darkMode ? Color.TRANSPARENT : Color.argb(127, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
// XXX android 9 and below has a nasty rendering bug if the theme was patched earlier
|
||||
Utils.postPatchColors(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (!activityOverridesNavBarColor) {
|
||||
Utils.setNavigationBarColor(this, null, Utils.resolveBackgroundColor(this), !Utils.isDarkModeEnabled(this));
|
||||
}
|
||||
}
|
||||
|
||||
protected void enableToolbarBackButton() {
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
|
||||
@@ -8,14 +8,12 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import protect.card_locker.databinding.GroupLayoutBinding;
|
||||
import protect.card_locker.preferences.Settings;
|
||||
|
||||
public class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.GroupListItemViewHolder> {
|
||||
public final Context mContext;
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
@@ -16,23 +14,20 @@ import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import protect.card_locker.async.TaskHandler;
|
||||
import protect.card_locker.databinding.ImportExportActivityBinding;
|
||||
import protect.card_locker.importexport.DataFormat;
|
||||
|
||||
@@ -4,13 +4,13 @@ import android.database.Cursor;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Currency;
|
||||
import java.util.Date;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class LoyaltyCard implements Parcelable {
|
||||
public final int id;
|
||||
public final String store;
|
||||
|
||||
@@ -15,13 +15,6 @@ import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.content.ContextCompat;
|
||||
@@ -29,6 +22,13 @@ import androidx.core.graphics.BlendModeColorFilterCompat;
|
||||
import androidx.core.graphics.BlendModeCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import protect.card_locker.databinding.LoyaltyCardLayoutBinding;
|
||||
|
||||
public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder> {
|
||||
|
||||
@@ -2,8 +2,6 @@ package protect.card_locker;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -29,33 +27,34 @@ import android.view.WindowManager;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.Button;
|
||||
import android.widget.DatePicker;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.google.android.material.chip.Chip;
|
||||
import com.google.android.material.chip.ChipGroup;
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
import com.google.android.material.datepicker.CalendarConstraints;
|
||||
import com.google.android.material.datepicker.DateValidatorPointBackward;
|
||||
import com.google.android.material.datepicker.DateValidatorPointForward;
|
||||
import com.google.android.material.datepicker.MaterialDatePicker;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.jaredrummler.android.colorpicker.ColorPickerDialog;
|
||||
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;
|
||||
@@ -74,7 +73,6 @@ import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Currency;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -94,6 +92,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
private final String STATE_TAB_INDEX = "savedTab";
|
||||
private final String STATE_TEMP_CARD = "tempLoyaltyCard";
|
||||
private final String STATE_TEMP_CARD_FIELD = "tempLoyaltyCardField";
|
||||
private final String STATE_REQUESTED_IMAGE = "requestedImage";
|
||||
private final String STATE_FRONT_IMAGE_UNSAVED = "frontImageUnsaved";
|
||||
private final String STATE_BACK_IMAGE_UNSAVED = "backImageUnsaved";
|
||||
@@ -105,6 +104,9 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
private final String STATE_ICON_REMOVED = "iconRemoved";
|
||||
private final String STATE_OPEN_SET_ICON_MENU = "openSetIconMenu";
|
||||
|
||||
private static final String PICK_DATE_REQUEST_KEY = "pick_date_request";
|
||||
private static final String NEWLY_PICKED_DATE_ARGUMENT_KEY = "newly_picked_date";
|
||||
|
||||
private final String TEMP_CAMERA_IMAGE_NAME = LoyaltyCardEditActivity.class.getSimpleName() + "_camera_image.jpg";
|
||||
private final String TEMP_CROP_IMAGE_NAME = LoyaltyCardEditActivity.class.getSimpleName() + "_crop_image.png";
|
||||
private final Bitmap.CompressFormat TEMP_CROP_IMAGE_FORMAT = Bitmap.CompressFormat.PNG;
|
||||
@@ -182,6 +184,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
HashMap<String, String> currencySymbols = new HashMap<>();
|
||||
|
||||
LoyaltyCard tempLoyaltyCard;
|
||||
LoyaltyCardField tempLoyaltyCardField;
|
||||
|
||||
ActivityResultLauncher<Uri> mPhotoTakerLauncher;
|
||||
ActivityResultLauncher<Intent> mPhotoPickerLauncher;
|
||||
@@ -261,13 +264,13 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
+ ", updateLoyaltyCard=" + updateLoyaltyCard);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
|
||||
super.onSaveInstanceState(savedInstanceState);
|
||||
tabs = binding.tabs;
|
||||
savedInstanceState.putInt(STATE_TAB_INDEX, tabs.getSelectedTabPosition());
|
||||
savedInstanceState.putParcelable(STATE_TEMP_CARD, tempLoyaltyCard);
|
||||
savedInstanceState.putSerializable(STATE_TEMP_CARD_FIELD, tempLoyaltyCardField);
|
||||
savedInstanceState.putInt(STATE_REQUESTED_IMAGE, mRequestedImage);
|
||||
|
||||
Object cardImageFrontObj = cardImageFront.getTag();
|
||||
@@ -303,6 +306,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
|
||||
onRestoring = true;
|
||||
tempLoyaltyCard = savedInstanceState.getParcelable(STATE_TEMP_CARD);
|
||||
tempLoyaltyCardField = (LoyaltyCardField) savedInstanceState.getSerializable(STATE_TEMP_CARD_FIELD);
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
tabs = binding.tabs;
|
||||
tabs.selectTab(tabs.getTabAt(savedInstanceState.getInt(STATE_TAB_INDEX)));
|
||||
@@ -365,8 +369,15 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
storeFieldEdit.addTextChangedListener(new SimpleTextWatcher() {
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
updateTempState(LoyaltyCardField.store, s.toString());
|
||||
generateIcon(s.toString());
|
||||
String storeName = s.toString().trim();
|
||||
updateTempState(LoyaltyCardField.store, storeName);
|
||||
generateIcon(storeName);
|
||||
|
||||
if (storeName.length() == 0) {
|
||||
storeFieldEdit.setError(getString(R.string.field_must_not_be_empty));
|
||||
} else {
|
||||
storeFieldEdit.setError(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -381,23 +392,14 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
addDateFieldTextChangedListener(expiryField, R.string.never, R.string.chooseExpiryDate, LoyaltyCardField.expiry);
|
||||
|
||||
DatePickerFragment.registerDatePickListener(this, (textFieldToEdit, newDate) -> {
|
||||
switch (textFieldToEdit) {
|
||||
case validFrom:
|
||||
formatDateField(this, validFromField, newDate);
|
||||
updateTempState(LoyaltyCardField.validFrom, newDate);
|
||||
break;
|
||||
case expiry:
|
||||
formatDateField(this, expiryField, newDate);
|
||||
updateTempState(LoyaltyCardField.expiry, newDate);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unexpected field: " + textFieldToEdit);
|
||||
}
|
||||
});
|
||||
setMaterialDatePickerResultListener();
|
||||
|
||||
balanceField.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (!hasFocus && !onResuming && !onRestoring) {
|
||||
if (balanceField.getText().toString().isEmpty()) {
|
||||
updateTempState(LoyaltyCardField.balance, BigDecimal.valueOf(0));
|
||||
}
|
||||
|
||||
balanceField.setText(Utils.formatBalanceWithoutCurrencySymbol(tempLoyaltyCard.balance, tempLoyaltyCard.balanceType));
|
||||
}
|
||||
});
|
||||
@@ -409,10 +411,12 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
try {
|
||||
BigDecimal balance = Utils.parseBalance(s.toString(), tempLoyaltyCard.balanceType);
|
||||
updateTempState(LoyaltyCardField.balance, balance);
|
||||
balanceField.setError(null);
|
||||
validBalance = true;
|
||||
} catch (ParseException e) {
|
||||
validBalance = false;
|
||||
e.printStackTrace();
|
||||
balanceField.setError(getString(R.string.balanceParsingFailed));
|
||||
validBalance = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -488,6 +492,12 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
updateTempState(LoyaltyCardField.cardId, s.toString());
|
||||
|
||||
if (s.length() == 0) {
|
||||
cardIdFieldView.setError(getString(R.string.field_must_not_be_empty));
|
||||
} else {
|
||||
cardIdFieldView.setError(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -687,6 +697,13 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
});
|
||||
|
||||
mCropperOptions = new UCrop.Options();
|
||||
|
||||
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
askBeforeQuitIfChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ucrop 2.2.6 initial aspect ratio is glitched when 0x0 is used as the initial ratio option
|
||||
@@ -760,7 +777,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
@Override
|
||||
public void onResume() {
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
Log.i(TAG, "To view card: " + loyaltyCardId);
|
||||
@@ -933,7 +950,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
saveButton.setOnClickListener(v -> doSave());
|
||||
saveButton.bringToFront();
|
||||
|
||||
generateIcon(storeFieldEdit.getText().toString());
|
||||
generateIcon(storeFieldEdit.getText().toString().trim());
|
||||
|
||||
// It can't be null because we set it in updateTempState but SpotBugs insists it can be
|
||||
// NP_NULL_ON_SOME_PATH: Possible null pointer dereference and
|
||||
@@ -998,14 +1015,14 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
if (!lastValue.toString().equals(getString(chooseDateOptionStringId))) {
|
||||
dateField.setText(lastValue);
|
||||
}
|
||||
DialogFragment datePickerFragment = DatePickerFragment.newInstance(
|
||||
showDatePicker(
|
||||
loyaltyCardField,
|
||||
(Date) dateField.getTag(),
|
||||
// if the expiry date is being set, set date picker's minDate to the 'valid from' date
|
||||
loyaltyCardField == LoyaltyCardField.expiry ? (Date) validFromField.getTag() : null,
|
||||
// if the 'valid from' date is being set, set date picker's maxDate to the expiry date
|
||||
loyaltyCardField == LoyaltyCardField.validFrom ? (Date) expiryField.getTag() : null);
|
||||
datePickerFragment.show(getSupportFragmentManager(), "datePicker");
|
||||
loyaltyCardField == LoyaltyCardField.validFrom ? (Date) expiryField.getTag() : null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1046,11 +1063,6 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
askBeforeQuitIfChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
@@ -1352,7 +1364,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
thumbnailEditIcon.setBackgroundColor(Utils.needsDarkForeground(color) ? Color.BLACK : Color.WHITE);
|
||||
thumbnailEditIcon.setColorFilter(Utils.needsDarkForeground(color) ? Color.WHITE : Color.BLACK);
|
||||
|
||||
generateIcon(storeFieldEdit.getText().toString());
|
||||
generateIcon(storeFieldEdit.getText().toString().trim());
|
||||
}
|
||||
|
||||
// ColorPickerDialogListener callback
|
||||
@@ -1361,103 +1373,106 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
// Nothing to do, no change made
|
||||
}
|
||||
|
||||
public static class DatePickerFragment extends DialogFragment
|
||||
implements DatePickerDialog.OnDateSetListener {
|
||||
private void showDatePicker(
|
||||
LoyaltyCardField loyaltyCardField,
|
||||
@Nullable Date selectedDate,
|
||||
@Nullable Date minDate,
|
||||
@Nullable Date maxDate
|
||||
) {
|
||||
// Create a new instance of MaterialDatePicker and return it
|
||||
long startDate = minDate != null ? minDate.getTime() : getDefaultMinDateOfDatePicker();
|
||||
long endDate = maxDate != null ? maxDate.getTime() : getDefaultMaxDateOfDatePicker();
|
||||
|
||||
public interface OnDatePickListener {
|
||||
void onDatePicked(@NonNull LoyaltyCardField textFieldToEdit, @NonNull Date newDate);
|
||||
CalendarConstraints.DateValidator dateValidator;
|
||||
switch (loyaltyCardField) {
|
||||
case validFrom:
|
||||
dateValidator = DateValidatorPointBackward.before(endDate);
|
||||
break;
|
||||
case expiry:
|
||||
dateValidator = DateValidatorPointForward.from(startDate);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unexpected field: " + loyaltyCardField);
|
||||
}
|
||||
|
||||
private static final String TEXT_FIELD_TO_EDIT_ARGUMENT_KEY = "text_field_to_edit";
|
||||
private static final String CURRENT_DATE_ARGUMENT_KEY = "current_date";
|
||||
private static final String MIN_DATE_ARGUMENT_KEY = "min_date";
|
||||
private static final String MAX_DATE_ARGUMENT_KEY = "max_date";
|
||||
private static final String PICK_DATE_REQUEST_KEY = "pick_date_request";
|
||||
private static final String NEWLY_PICKED_DATE_ARGUMENT_KEY = "newly_picked_date";
|
||||
CalendarConstraints calendarConstraints = new CalendarConstraints.Builder()
|
||||
.setValidator(dateValidator)
|
||||
.setStart(startDate)
|
||||
.setEnd(endDate)
|
||||
.build();
|
||||
|
||||
LoyaltyCardField textFieldEdit;
|
||||
@Nullable
|
||||
Date minDate;
|
||||
@Nullable
|
||||
Date maxDate;
|
||||
|
||||
public static DatePickerFragment newInstance(@NonNull LoyaltyCardField textField, @Nullable Date currentDate, @Nullable Date minDate, @Nullable Date maxDate) {
|
||||
Bundle args = new Bundle();
|
||||
args.putSerializable(TEXT_FIELD_TO_EDIT_ARGUMENT_KEY, textField);
|
||||
args.putSerializable(CURRENT_DATE_ARGUMENT_KEY, currentDate);
|
||||
args.putSerializable(MIN_DATE_ARGUMENT_KEY, minDate);
|
||||
args.putSerializable(MAX_DATE_ARGUMENT_KEY, maxDate);
|
||||
DatePickerFragment fragment = new DatePickerFragment();
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
// Use the selected date as the default date in the picker
|
||||
final Calendar calendar = Calendar.getInstance();
|
||||
if (selectedDate != null) {
|
||||
calendar.setTime(selectedDate);
|
||||
}
|
||||
|
||||
public static void registerDatePickListener(@NonNull AppCompatActivity activity, @NonNull OnDatePickListener listener) {
|
||||
activity.getSupportFragmentManager().setFragmentResultListener(
|
||||
PICK_DATE_REQUEST_KEY,
|
||||
activity,
|
||||
(requestKey, result) -> listener.onDatePicked(
|
||||
(LoyaltyCardField) Objects.requireNonNull(result.getSerializable(TEXT_FIELD_TO_EDIT_ARGUMENT_KEY)),
|
||||
(Date) Objects.requireNonNull(result.getSerializable(NEWLY_PICKED_DATE_ARGUMENT_KEY))));
|
||||
}
|
||||
MaterialDatePicker<Long> materialDatePicker = MaterialDatePicker.Builder.datePicker()
|
||||
.setSelection(calendar.getTimeInMillis())
|
||||
.setCalendarConstraints(calendarConstraints)
|
||||
.build();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Bundle args = requireArguments();
|
||||
textFieldEdit = (LoyaltyCardField) args.getSerializable(TEXT_FIELD_TO_EDIT_ARGUMENT_KEY);
|
||||
minDate = (Date) args.getSerializable(MIN_DATE_ARGUMENT_KEY);
|
||||
maxDate = (Date) args.getSerializable(MAX_DATE_ARGUMENT_KEY);
|
||||
// Use the current date as the default date in the picker
|
||||
final Calendar c = Calendar.getInstance();
|
||||
|
||||
Date date = (Date) args.getSerializable(CURRENT_DATE_ARGUMENT_KEY);
|
||||
if (date != null) {
|
||||
c.setTime(date);
|
||||
// Required to handle configuration changes
|
||||
// See https://github.com/material-components/material-components-android/issues/1688
|
||||
tempLoyaltyCardField = loyaltyCardField;
|
||||
getSupportFragmentManager().addFragmentOnAttachListener((fragmentManager, fragment) -> {
|
||||
if (fragment instanceof MaterialDatePicker && Objects.equals(fragment.getTag(), PICK_DATE_REQUEST_KEY)) {
|
||||
((MaterialDatePicker<Long>) fragment).addOnPositiveButtonClickListener(selection -> {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong(NEWLY_PICKED_DATE_ARGUMENT_KEY, selection);
|
||||
getSupportFragmentManager().setFragmentResult(PICK_DATE_REQUEST_KEY, args);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
int year = c.get(Calendar.YEAR);
|
||||
int month = c.get(Calendar.MONTH);
|
||||
int day = c.get(Calendar.DAY_OF_MONTH);
|
||||
materialDatePicker.show(getSupportFragmentManager(), PICK_DATE_REQUEST_KEY);
|
||||
}
|
||||
|
||||
// Create a new instance of DatePickerDialog and return it
|
||||
DatePickerDialog datePickerDialog = new DatePickerDialog(getActivity(), this, year, month, day);
|
||||
datePickerDialog.getDatePicker().setMinDate(minDate != null ? minDate.getTime() : getDefaultMinDateOfDatePicker());
|
||||
datePickerDialog.getDatePicker().setMaxDate(maxDate != null ? maxDate.getTime() : getDefaultMaxDateOfDatePicker());
|
||||
return datePickerDialog;
|
||||
// Required to handle configuration changes
|
||||
// See https://github.com/material-components/material-components-android/issues/1688
|
||||
private void setMaterialDatePickerResultListener() {
|
||||
MaterialDatePicker<Long> fragment = (MaterialDatePicker<Long>) getSupportFragmentManager().findFragmentByTag(PICK_DATE_REQUEST_KEY);
|
||||
if (fragment != null) {
|
||||
fragment.addOnPositiveButtonClickListener(selection -> {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong(NEWLY_PICKED_DATE_ARGUMENT_KEY, selection);
|
||||
getSupportFragmentManager().setFragmentResult(PICK_DATE_REQUEST_KEY, args);
|
||||
});
|
||||
}
|
||||
|
||||
private long getDefaultMinDateOfDatePicker() {
|
||||
Calendar minDateCalendar = Calendar.getInstance();
|
||||
minDateCalendar.set(1970, 0, 1);
|
||||
return minDateCalendar.getTimeInMillis();
|
||||
}
|
||||
getSupportFragmentManager().setFragmentResultListener(
|
||||
PICK_DATE_REQUEST_KEY,
|
||||
this,
|
||||
(requestKey, result) -> {
|
||||
long selection = result.getLong(NEWLY_PICKED_DATE_ARGUMENT_KEY);
|
||||
|
||||
private long getDefaultMaxDateOfDatePicker() {
|
||||
Calendar maxDateCalendar = Calendar.getInstance();
|
||||
maxDateCalendar.set(2100, 11, 31);
|
||||
return maxDateCalendar.getTimeInMillis();
|
||||
}
|
||||
Date newDate = new Date(selection);
|
||||
switch (tempLoyaltyCardField) {
|
||||
case validFrom:
|
||||
formatDateField(LoyaltyCardEditActivity.this, validFromField, newDate);
|
||||
updateTempState(LoyaltyCardField.validFrom, newDate);
|
||||
break;
|
||||
case expiry:
|
||||
formatDateField(LoyaltyCardEditActivity.this, expiryField, newDate);
|
||||
updateTempState(LoyaltyCardField.expiry, newDate);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unexpected field: " + tempLoyaltyCardField);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void onDateSet(DatePicker view, int year, int month, int day) {
|
||||
Calendar c = new GregorianCalendar();
|
||||
c.set(Calendar.YEAR, year);
|
||||
c.set(Calendar.MONTH, month);
|
||||
c.set(Calendar.DAY_OF_MONTH, day);
|
||||
c.set(Calendar.HOUR_OF_DAY, 0);
|
||||
c.set(Calendar.MINUTE, 0);
|
||||
c.set(Calendar.SECOND, 0);
|
||||
c.set(Calendar.MILLISECOND, 0);
|
||||
private long getDefaultMinDateOfDatePicker() {
|
||||
Calendar minDateCalendar = Calendar.getInstance();
|
||||
minDateCalendar.set(1970, 0, 1);
|
||||
return minDateCalendar.getTimeInMillis();
|
||||
}
|
||||
|
||||
long unixTime = c.getTimeInMillis();
|
||||
|
||||
Date date = new Date(unixTime);
|
||||
|
||||
Bundle result = new Bundle();
|
||||
result.putSerializable(TEXT_FIELD_TO_EDIT_ARGUMENT_KEY, textFieldEdit);
|
||||
result.putSerializable(NEWLY_PICKED_DATE_ARGUMENT_KEY, date);
|
||||
getParentFragmentManager().setFragmentResult(PICK_DATE_REQUEST_KEY, result);
|
||||
}
|
||||
private long getDefaultMaxDateOfDatePicker() {
|
||||
Calendar maxDateCalendar = Calendar.getInstance();
|
||||
maxDateCalendar.set(2100, 11, 31);
|
||||
return maxDateCalendar.getTimeInMillis();
|
||||
}
|
||||
|
||||
private void doSave() {
|
||||
@@ -1471,18 +1486,41 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasError = false;
|
||||
|
||||
if (tempLoyaltyCard.store.isEmpty()) {
|
||||
Snackbar.make(storeFieldEdit, R.string.noStoreError, Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
storeFieldEdit.setError(getString(R.string.field_must_not_be_empty));
|
||||
|
||||
// Focus element
|
||||
tabs.selectTab(tabs.getTabAt(0));
|
||||
storeFieldEdit.requestFocus();
|
||||
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
if (tempLoyaltyCard.cardId.isEmpty()) {
|
||||
Snackbar.make(cardIdFieldView, R.string.noCardIdError, Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
cardIdFieldView.setError(getString(R.string.field_must_not_be_empty));
|
||||
|
||||
// Focus element if first error element
|
||||
if (!hasError) {
|
||||
tabs.selectTab(tabs.getTabAt(0));
|
||||
cardIdFieldView.requestFocus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validBalance) {
|
||||
Snackbar.make(balanceField, getString(R.string.parsingBalanceFailed, balanceField.getText().toString()), Snackbar.LENGTH_LONG).show();
|
||||
balanceField.setError(getString(R.string.balanceParsingFailed));
|
||||
|
||||
// Focus element if first error element
|
||||
if (!hasError) {
|
||||
tabs.selectTab(tabs.getTabAt(1));
|
||||
balanceField.requestFocus();
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1618,7 +1656,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements
|
||||
String cardIdString = tempLoyaltyCard.barcodeId != null ? tempLoyaltyCard.barcodeId : tempLoyaltyCard.cardId;
|
||||
CatimaBarcode barcodeFormat = tempLoyaltyCard.barcodeType;
|
||||
|
||||
if (cardIdString == null || barcodeFormat == null) {
|
||||
if (cardIdString == null || cardIdString.isEmpty() || barcodeFormat == null) {
|
||||
barcodeImageLayout.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package protect.card_locker;
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
|
||||
import protect.card_locker.preferences.Settings;
|
||||
|
||||
public class LoyaltyCardLockerApplication extends Application {
|
||||
|
||||
@@ -20,7 +20,6 @@ import android.text.method.DigitsKeyListener;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.util.Linkify;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
@@ -38,19 +37,17 @@ import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.core.graphics.BlendModeColorFilterCompat;
|
||||
import androidx.core.graphics.BlendModeCompat;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import androidx.core.widget.TextViewCompat;
|
||||
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
@@ -98,7 +95,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
ImageView barcodeRenderTarget;
|
||||
int mainImageIndex = 0;
|
||||
List<ImageType> imageTypes;
|
||||
boolean isBarcodeSupported = true;
|
||||
|
||||
static final String STATE_IMAGEINDEX = "imageIndex";
|
||||
static final String STATE_FULLSCREEN = "isFullscreen";
|
||||
@@ -113,22 +109,25 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
return;
|
||||
}
|
||||
|
||||
ImageType imageType = imageTypes.get(mainImageIndex);
|
||||
|
||||
// If the barcode is shown, switch to fullscreen layout
|
||||
if (imageTypes.get(mainImageIndex) == ImageType.BARCODE) {
|
||||
if (imageType == ImageType.BARCODE) {
|
||||
setFullscreen(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is an image, open it in the gallery.
|
||||
openCurrentMainImageInGallery();
|
||||
openImageInGallery(imageType);
|
||||
}
|
||||
|
||||
private void openCurrentMainImageInGallery() {
|
||||
ImageType wantedImageType = imageTypes.get(mainImageIndex);
|
||||
|
||||
private void openImageInGallery(ImageType imageType) {
|
||||
File file = null;
|
||||
|
||||
switch (wantedImageType) {
|
||||
switch (imageType) {
|
||||
case ICON:
|
||||
file = Utils.retrieveCardImageAsFile(this, loyaltyCardId, ImageLocationType.icon);
|
||||
break;
|
||||
case IMAGE_FRONT:
|
||||
file = Utils.retrieveCardImageAsFile(this, loyaltyCardId, ImageLocationType.front);
|
||||
break;
|
||||
@@ -176,6 +175,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
enum ImageType {
|
||||
NONE,
|
||||
ICON,
|
||||
BARCODE,
|
||||
IMAGE_FRONT,
|
||||
IMAGE_BACK
|
||||
@@ -229,7 +229,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
settings = new Settings(this);
|
||||
|
||||
String cardOrientation = settings.getCardViewOrientation();
|
||||
if (cardOrientation.equals(getString(R.string.settings_key_lock_on_opening_orientation))) {
|
||||
if (cardOrientation.equals(getString(R.string.settings_key_follow_sensor_orientation))) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
|
||||
} else if (cardOrientation.equals(getString(R.string.settings_key_lock_on_opening_orientation))) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
|
||||
} else if (cardOrientation.equals(getString(R.string.settings_key_portrait_orientation))) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
@@ -293,7 +295,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
bundle.putBoolean(LoyaltyCardEditActivity.BUNDLE_UPDATE, true);
|
||||
intent.putExtras(bundle);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
});
|
||||
binding.fabEdit.bringToFront();
|
||||
|
||||
@@ -302,7 +303,13 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
binding.bottomAppBarNextButton.setOnClickListener(view -> prevNextCard(true));
|
||||
binding.bottomAppBarUpdateBalanceButton.setOnClickListener(view -> showBalanceUpdateDialog());
|
||||
|
||||
binding.iconContainer.setOnClickListener(view -> Toast.makeText(LoyaltyCardViewActivity.this, R.string.icon_header_click_text, Toast.LENGTH_LONG).show());
|
||||
binding.iconContainer.setOnClickListener(view -> {
|
||||
if (Utils.retrieveCardImage(this, loyaltyCard.id, ImageLocationType.icon) != null) {
|
||||
openImageInGallery(ImageType.ICON);
|
||||
} else {
|
||||
Toast.makeText(LoyaltyCardViewActivity.this, R.string.icon_header_click_text, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
binding.iconContainer.setOnLongClickListener(view -> {
|
||||
Intent intent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
|
||||
Bundle bundle = new Bundle();
|
||||
@@ -324,6 +331,17 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
return true;
|
||||
});
|
||||
binding.fullscreenImage.setOnClickListener(view -> onMainImageTap());
|
||||
|
||||
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
if (isFullscreen) {
|
||||
setFullscreen(false);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private SpannableStringBuilder padSpannableString(SpannableStringBuilder spannableStringBuilder) {
|
||||
@@ -546,18 +564,24 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
protected void onResume() {
|
||||
activityOverridesNavBarColor = true;
|
||||
super.onResume();
|
||||
|
||||
Log.i(TAG, "To view card: " + loyaltyCardId);
|
||||
|
||||
// The brightness value is on a scale from [0, ..., 1], where
|
||||
// '1' is the brightest. We attempt to maximize the brightness
|
||||
// to help barcode readers scan the barcode.
|
||||
Window window = getWindow();
|
||||
if (window != null) {
|
||||
// Hide the keyboard if still shown (could be the case when returning from edit activity
|
||||
window.setSoftInputMode(
|
||||
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
|
||||
);
|
||||
|
||||
WindowManager.LayoutParams attributes = window.getAttributes();
|
||||
|
||||
// The brightness value is on a scale from [0, ..., 1], where
|
||||
// '1' is the brightest. We attempt to maximize the brightness
|
||||
// to help barcode readers scan the barcode.
|
||||
if (settings.useMaxBrightnessDisplayingBarcode()) {
|
||||
attributes.screenBrightness = 1F;
|
||||
}
|
||||
@@ -619,7 +643,11 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
int darkenedColor = ColorUtils.blendARGB(backgroundHeaderColor, Color.BLACK, 0.1f);
|
||||
binding.barcodeScaler.setProgressTintList(ColorStateList.valueOf(darkenedColor));
|
||||
binding.barcodeScaler.setThumbTintList(ColorStateList.valueOf(darkenedColor));
|
||||
|
||||
// Set bottomAppBar and system navigation bar color
|
||||
binding.bottomAppBar.setBackgroundColor(darkenedColor);
|
||||
Utils.setNavigationBarColor(null, window, darkenedColor, Utils.needsDarkForeground(darkenedColor));
|
||||
|
||||
int complementaryColor = Utils.getComplementaryColor(darkenedColor);
|
||||
binding.fabEdit.setBackgroundTintList(ColorStateList.valueOf(complementaryColor));
|
||||
Drawable editButtonIcon = binding.fabEdit.getDrawable();
|
||||
@@ -639,12 +667,15 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
fixBottomAppBarImageButtonColor(binding.bottomAppBarUpdateBalanceButton);
|
||||
setBottomAppBarButtonState();
|
||||
|
||||
boolean isBarcodeSupported;
|
||||
if (format != null && !format.isSupported()) {
|
||||
isBarcodeSupported = false;
|
||||
|
||||
Toast.makeText(this, getString(R.string.unsupportedBarcodeType), Toast.LENGTH_LONG).show();
|
||||
} else if (format == null) {
|
||||
isBarcodeSupported = false;
|
||||
} else {
|
||||
isBarcodeSupported = true;
|
||||
}
|
||||
|
||||
imageTypes = new ArrayList<>();
|
||||
@@ -698,16 +729,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
imageButton.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(backgroundNeedsDarkIcons ? Color.BLACK : Color.WHITE, BlendModeCompat.SRC_ATOP));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (isFullscreen) {
|
||||
setFullscreen(false);
|
||||
return;
|
||||
}
|
||||
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.card_view_menu, menu);
|
||||
@@ -1049,10 +1070,14 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
// Set Android to fullscreen mode
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
getWindow().setDecorFitsSystemWindows(false);
|
||||
if (getWindow().getInsetsController() != null) {
|
||||
getWindow().getInsetsController().hide(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars());
|
||||
getWindow().getInsetsController().setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
|
||||
Window window = getWindow();
|
||||
if (window != null) {
|
||||
window.setDecorFitsSystemWindows(false);
|
||||
WindowInsetsController wic = window.getInsetsController();
|
||||
if (wic != null) {
|
||||
wic.hide(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars());
|
||||
wic.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setFullscreenModeSdkLessThan30();
|
||||
@@ -1079,10 +1104,14 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
// Unset fullscreen mode
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
getWindow().setDecorFitsSystemWindows(true);
|
||||
if (getWindow().getInsetsController() != null) {
|
||||
getWindow().getInsetsController().show(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars());
|
||||
getWindow().getInsetsController().setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT);
|
||||
Window window = getWindow();
|
||||
if (window != null) {
|
||||
window.setDecorFitsSystemWindows(true);
|
||||
WindowInsetsController wic = window.getInsetsController();
|
||||
if (wic != null) {
|
||||
wic.show(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars());
|
||||
wic.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsetFullscreenModeSdkLessThan30();
|
||||
@@ -1094,19 +1123,25 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void unsetFullscreenModeSdkLessThan30() {
|
||||
getWindow().getDecorView().setSystemUiVisibility(
|
||||
getWindow().getDecorView().getSystemUiVisibility()
|
||||
& ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
& ~View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
);
|
||||
Window window = getWindow();
|
||||
if (window != null) {
|
||||
window.getDecorView().setSystemUiVisibility(
|
||||
window.getDecorView().getSystemUiVisibility()
|
||||
& ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
& ~View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void setFullscreenModeSdkLessThan30() {
|
||||
getWindow().getDecorView().setSystemUiVisibility(
|
||||
getWindow().getDecorView().getSystemUiVisibility()
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
);
|
||||
Window window = getWindow();
|
||||
if (window != null) {
|
||||
window.getDecorView().setSystemUiVisibility(
|
||||
window.getDecorView().getSystemUiVisibility()
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ package protect.card_locker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.SearchManager;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
@@ -22,6 +20,7 @@ import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
@@ -70,7 +69,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
|
||||
private View mNoGroupCardsText;
|
||||
private TabLayout groupsTabLayout;
|
||||
|
||||
private Runnable mSwapLoyaltyCardListCursor;
|
||||
private Runnable mUpdateLoyaltyCardListRunnable;
|
||||
|
||||
private ActivityResultLauncher<Intent> mBarcodeScannerLauncher;
|
||||
private ActivityResultLauncher<Intent> mSettingsLauncher;
|
||||
@@ -89,35 +88,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode inputMode, MenuItem inputItem) {
|
||||
if (inputItem.getItemId() == R.id.action_copy_to_clipboard) {
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||
|
||||
String clipboardData;
|
||||
int cardCount = mAdapter.getSelectedItemCount();
|
||||
|
||||
if (cardCount == 1) {
|
||||
clipboardData = mAdapter.getSelectedItems().get(0).cardId;
|
||||
} else {
|
||||
StringBuilder cardIds = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < cardCount; i++) {
|
||||
LoyaltyCard loyaltyCard = mAdapter.getSelectedItems().get(i);
|
||||
|
||||
cardIds.append(loyaltyCard.store + ": " + loyaltyCard.cardId);
|
||||
if (i < (cardCount - 1)) {
|
||||
cardIds.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
clipboardData = cardIds.toString();
|
||||
}
|
||||
|
||||
ClipData clip = ClipData.newPlainText(getString(R.string.card_ids_copied), clipboardData);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(MainActivity.this, cardCount > 1 ? R.string.copy_to_clipboard_multiple_toast : R.string.copy_to_clipboard_toast, Toast.LENGTH_LONG).show();
|
||||
inputMode.finish();
|
||||
return true;
|
||||
} else if (inputItem.getItemId() == R.id.action_share) {
|
||||
if (inputItem.getItemId() == R.id.action_share) {
|
||||
final ImportURIHelper importURIHelper = new ImportURIHelper(MainActivity.this);
|
||||
try {
|
||||
importURIHelper.startShareIntent(mAdapter.getSelectedItems());
|
||||
@@ -228,7 +199,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
|
||||
super.onCreate(inputSavedInstanceState);
|
||||
|
||||
binding = MainActivityBinding.inflate(getLayoutInflater());
|
||||
setTitle(R.string.app_name);
|
||||
setContentView(binding.getRoot());
|
||||
setSupportActionBar(binding.toolbar);
|
||||
groupsTabLayout = binding.groups;
|
||||
@@ -236,13 +206,8 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
|
||||
|
||||
mDatabase = new DBHelper(this).getWritableDatabase();
|
||||
|
||||
mSwapLoyaltyCardListCursor = () -> {
|
||||
Group group = null;
|
||||
if (mGroup != null) {
|
||||
group = (Group) mGroup;
|
||||
}
|
||||
|
||||
mAdapter.swapCursor(DBHelper.getLoyaltyCardCursor(mDatabase, mFilter, group, mOrder, mOrderDirection, mAdapter.showingArchivedCards() ? DBHelper.LoyaltyCardArchiveFilter.All : DBHelper.LoyaltyCardArchiveFilter.Unarchived));
|
||||
mUpdateLoyaltyCardListRunnable = () -> {
|
||||
updateLoyaltyCardList(false);
|
||||
};
|
||||
|
||||
groupsTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@@ -277,7 +242,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
|
||||
mNoGroupCardsText = contentMainBinding.noGroupCardsText;
|
||||
mCardList = contentMainBinding.list;
|
||||
|
||||
mAdapter = new LoyaltyCardCursorAdapter(this, null, this, mSwapLoyaltyCardListCursor);
|
||||
mAdapter = new LoyaltyCardCursorAdapter(this, null, this, mUpdateLoyaltyCardListRunnable);
|
||||
mCardList.setAdapter(mAdapter);
|
||||
registerForContextMenu(mCardList);
|
||||
|
||||
@@ -337,6 +302,17 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
if (mSearchView != null && !mSearchView.isIconified()) {
|
||||
mSearchView.setIconified(true);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -411,16 +387,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
|
||||
addButton.bringToFront();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (mSearchView != null && !mSearchView.isIconified()) {
|
||||
mSearchView.setIconified(true);
|
||||
return;
|
||||
}
|
||||
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
private void displayCardSetupOptions(Menu menu, boolean shouldShow) {
|
||||
for (int id : new int[]{R.id.action_search, R.id.action_display_options, R.id.action_sort}) {
|
||||
menu.findItem(id).setVisible(shouldShow);
|
||||
@@ -432,7 +398,12 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
|
||||
}
|
||||
|
||||
private void updateLoyaltyCardList(boolean updateCount) {
|
||||
mSwapLoyaltyCardListCursor.run();
|
||||
Group group = null;
|
||||
if (mGroup != null) {
|
||||
group = (Group) mGroup;
|
||||
}
|
||||
|
||||
mAdapter.swapCursor(DBHelper.getLoyaltyCardCursor(mDatabase, mFilter, group, mOrder, mOrderDirection, mAdapter.showingArchivedCards() ? DBHelper.LoyaltyCardArchiveFilter.All : DBHelper.LoyaltyCardArchiveFilter.Unarchived));
|
||||
|
||||
if (updateCount) {
|
||||
updateLoyaltyCardCount();
|
||||
@@ -611,7 +582,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
|
||||
int id = inputItem.getItemId();
|
||||
|
||||
if (id == android.R.id.home) {
|
||||
onBackPressed();
|
||||
getOnBackPressedDispatcher().onBackPressed();
|
||||
}
|
||||
|
||||
if (id == R.id.action_display_options) {
|
||||
|
||||
@@ -13,6 +13,12 @@ import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
@@ -20,11 +26,6 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import protect.card_locker.databinding.ActivityManageGroupBinding;
|
||||
|
||||
public class ManageGroupActivity extends CatimaAppCompatActivity implements ManageGroupCursorAdapter.CardAdapterListener {
|
||||
@@ -133,6 +134,13 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana
|
||||
// this setText is here because content_main.xml is reused from main activity
|
||||
noGroupCardsText.setText(getResources().getText(R.string.noGiftCardsGroup));
|
||||
updateLoyaltyCardList();
|
||||
|
||||
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
leaveWithoutSaving();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ArrayList<Integer> adapterStateToIntegerArray(HashMap<Integer, Boolean> adapterState) {
|
||||
@@ -210,14 +218,9 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
leaveWithoutSaving();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
onBackPressed();
|
||||
getOnBackPressedDispatcher().onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,22 +11,20 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import protect.card_locker.databinding.ManageGroupsActivityBinding;
|
||||
|
||||
public class ManageGroupsActivity extends CatimaAppCompatActivity implements GroupCursorAdapter.GroupAdapterListener {
|
||||
@@ -73,11 +71,6 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro
|
||||
updateGroupList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
private void updateGroupList() {
|
||||
mAdapter.swapCursor(DBHelper.getGroupCursor(mDatabase));
|
||||
|
||||
@@ -112,41 +105,16 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void setGroupNameError(EditText input) {
|
||||
String string = sanitizeAddGroupNameField(input.getText());
|
||||
|
||||
if (string.length() == 0) {
|
||||
input.setError(getString(R.string.group_name_is_empty));
|
||||
return;
|
||||
}
|
||||
|
||||
if (DBHelper.getGroup(mDatabase, string) != null) {
|
||||
input.setError(getString(R.string.group_name_already_in_use));
|
||||
return;
|
||||
}
|
||||
|
||||
input.setError(null);
|
||||
}
|
||||
|
||||
private String sanitizeAddGroupNameField(CharSequence s) {
|
||||
return s.toString().trim();
|
||||
}
|
||||
|
||||
private void createGroup() {
|
||||
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
|
||||
builder.setTitle(R.string.enter_group_name);
|
||||
final EditText input = new EditText(this);
|
||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
input.addTextChangedListener(new SimpleTextWatcher() {
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
setGroupNameError(input);
|
||||
}
|
||||
});
|
||||
setGroupNameError(input);
|
||||
|
||||
// Add spacing to EditText
|
||||
FrameLayout container = new FrameLayout(this);
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
|
||||
// Header
|
||||
builder.setTitle(R.string.enter_group_name);
|
||||
|
||||
// Layout
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
@@ -154,25 +122,51 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro
|
||||
params.leftMargin = contentPadding;
|
||||
params.topMargin = contentPadding / 2;
|
||||
params.rightMargin = contentPadding;
|
||||
|
||||
// EditText with spacing
|
||||
final EditText input = new EditText(this);
|
||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
input.setLayoutParams(params);
|
||||
container.addView(input);
|
||||
layout.addView(input);
|
||||
|
||||
builder.setView(container);
|
||||
// Set layout
|
||||
builder.setView(layout);
|
||||
|
||||
// Buttons
|
||||
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
|
||||
CharSequence error = input.getError();
|
||||
|
||||
if (error != null) {
|
||||
Toast.makeText(getApplicationContext(), error.toString(), Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
DBHelper.insertGroup(mDatabase, sanitizeAddGroupNameField(input.getText()));
|
||||
DBHelper.insertGroup(mDatabase, input.getText().toString().trim());
|
||||
updateGroupList();
|
||||
});
|
||||
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
|
||||
AlertDialog dialog = builder.create();
|
||||
|
||||
// Now that the dialog exists, we can bind something that affects the OK button
|
||||
input.addTextChangedListener(new SimpleTextWatcher() {
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
String groupName = s.toString().trim();
|
||||
|
||||
if (groupName.length() == 0) {
|
||||
input.setError(getString(R.string.group_name_is_empty));
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DBHelper.getGroup(mDatabase, groupName) != null) {
|
||||
input.setError(getString(R.string.group_name_already_in_use));
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
input.setError(null);
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
|
||||
}
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
|
||||
// Disable button (must be done **after** dialog is shown to prevent crash
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
||||
// Set focus on input field
|
||||
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
||||
input.requestFocus();
|
||||
}
|
||||
@@ -249,4 +243,4 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import static protect.card_locker.BarcodeSelectorActivity.BARCODE_CONTENTS;
|
||||
import static protect.card_locker.BarcodeSelectorActivity.BARCODE_FORMAT;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
@@ -9,6 +12,7 @@ import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.InputType;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
@@ -16,15 +20,21 @@ import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.client.android.Intents;
|
||||
import com.journeyapps.barcodescanner.BarcodeCallback;
|
||||
@@ -44,7 +54,6 @@ import protect.card_locker.databinding.ScanActivityBinding;
|
||||
* originally licensed under Apache 2.0
|
||||
*/
|
||||
public class ScanActivity extends CatimaAppCompatActivity {
|
||||
|
||||
private ScanActivityBinding binding;
|
||||
private CustomBarcodeScannerBinding customBarcodeScannerBinding;
|
||||
private static final String TAG = "Catima";
|
||||
@@ -65,6 +74,9 @@ public class ScanActivity extends CatimaAppCompatActivity {
|
||||
// can't use the pre-made contract because that launches the file manager for image type instead of gallery
|
||||
private ActivityResultLauncher<Intent> photoPickerLauncher;
|
||||
|
||||
static final String STATE_SCANNER_ACTIVE = "scannerActive";
|
||||
private boolean mScannerActive = true;
|
||||
|
||||
private void extractIntentFields(Intent intent) {
|
||||
final Bundle b = intent.getExtras();
|
||||
cardId = b != null ? b.getString(LoyaltyCardEditActivity.BUNDLE_CARDID) : null;
|
||||
@@ -87,8 +99,36 @@ public class ScanActivity extends CatimaAppCompatActivity {
|
||||
|
||||
manualAddLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> handleActivityResult(Utils.SELECT_BARCODE_REQUEST, result.getResultCode(), result.getData()));
|
||||
photoPickerLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> handleActivityResult(Utils.BARCODE_IMPORT_FROM_IMAGE_FILE, result.getResultCode(), result.getData()));
|
||||
customBarcodeScannerBinding.addFromImage.setOnClickListener(this::addFromImage);
|
||||
customBarcodeScannerBinding.addManually.setOnClickListener(this::addManually);
|
||||
customBarcodeScannerBinding.fabOtherOptions.setOnClickListener(view -> {
|
||||
setScannerActive(false);
|
||||
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ScanActivity.this);
|
||||
builder.setTitle(getString(R.string.add_a_card_in_a_different_way));
|
||||
builder.setItems(
|
||||
new CharSequence[]{
|
||||
getString(R.string.addWithoutBarcode),
|
||||
getString(R.string.addManually),
|
||||
getString(R.string.addFromImage)
|
||||
},
|
||||
(dialogInterface, i) -> {
|
||||
switch (i) {
|
||||
case 0:
|
||||
addWithoutBarcode();
|
||||
break;
|
||||
case 1:
|
||||
addManually();
|
||||
break;
|
||||
case 2:
|
||||
addFromImage();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown 'Add a card in a different way' dialog option");
|
||||
}
|
||||
}
|
||||
);
|
||||
builder.setOnCancelListener(dialogInterface -> setScannerActive(true));
|
||||
builder.show();
|
||||
});
|
||||
|
||||
barcodeScannerView = binding.zxingBarcodeScanner;
|
||||
|
||||
@@ -106,8 +146,8 @@ public class ScanActivity extends CatimaAppCompatActivity {
|
||||
public void barcodeResult(BarcodeResult result) {
|
||||
Intent scanResult = new Intent();
|
||||
Bundle scanResultBundle = new Bundle();
|
||||
scanResultBundle.putString(BarcodeSelectorActivity.BARCODE_CONTENTS, result.getText());
|
||||
scanResultBundle.putString(BarcodeSelectorActivity.BARCODE_FORMAT, result.getBarcodeFormat().name());
|
||||
scanResultBundle.putString(BARCODE_CONTENTS, result.getText());
|
||||
scanResultBundle.putString(BARCODE_FORMAT, result.getBarcodeFormat().name());
|
||||
if (addGroup != null) {
|
||||
scanResultBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, addGroup);
|
||||
}
|
||||
@@ -126,7 +166,11 @@ public class ScanActivity extends CatimaAppCompatActivity {
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
capture.onResume();
|
||||
|
||||
if (mScannerActive) {
|
||||
capture.onResume();
|
||||
}
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
|
||||
showCameraPermissionMissingText(false);
|
||||
}
|
||||
@@ -146,9 +190,18 @@ public class ScanActivity extends CatimaAppCompatActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
capture.onSaveInstanceState(outState);
|
||||
protected void onSaveInstanceState(Bundle savedInstanceState) {
|
||||
super.onSaveInstanceState(savedInstanceState);
|
||||
capture.onSaveInstanceState(savedInstanceState);
|
||||
|
||||
savedInstanceState.putBoolean(STATE_SCANNER_ACTIVE, mScannerActive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
|
||||
mScannerActive = savedInstanceState.getBoolean(STATE_SCANNER_ACTIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -190,19 +243,20 @@ public class ScanActivity extends CatimaAppCompatActivity {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void handleActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
|
||||
BarcodeValues barcodeValues = Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this);
|
||||
|
||||
if (barcodeValues.isEmpty()) {
|
||||
return;
|
||||
private void setScannerActive(boolean isActive) {
|
||||
if (isActive) {
|
||||
barcodeScannerView.resume();
|
||||
} else {
|
||||
barcodeScannerView.pause();
|
||||
}
|
||||
mScannerActive = isActive;
|
||||
}
|
||||
|
||||
private void returnResult(String barcodeContents, String barcodeFormat) {
|
||||
Intent manualResult = new Intent();
|
||||
Bundle manualResultBundle = new Bundle();
|
||||
manualResultBundle.putString(BarcodeSelectorActivity.BARCODE_CONTENTS, barcodeValues.content());
|
||||
manualResultBundle.putString(BarcodeSelectorActivity.BARCODE_FORMAT, barcodeValues.format());
|
||||
manualResultBundle.putString(BARCODE_CONTENTS, barcodeContents);
|
||||
manualResultBundle.putString(BARCODE_FORMAT, barcodeFormat);
|
||||
if (addGroup != null) {
|
||||
manualResultBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, addGroup);
|
||||
}
|
||||
@@ -211,17 +265,102 @@ public class ScanActivity extends CatimaAppCompatActivity {
|
||||
finish();
|
||||
}
|
||||
|
||||
public void addManually(View view) {
|
||||
Intent i = new Intent(getApplicationContext(), BarcodeSelectorActivity.class);
|
||||
if (cardId != null) {
|
||||
final Bundle b = new Bundle();
|
||||
b.putString("initialCardId", cardId);
|
||||
i.putExtras(b);
|
||||
private void handleActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
|
||||
BarcodeValues barcodeValues = Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this);
|
||||
|
||||
if (barcodeValues.isEmpty()) {
|
||||
setScannerActive(true);
|
||||
return;
|
||||
}
|
||||
manualAddLauncher.launch(i);
|
||||
|
||||
returnResult(barcodeValues.content(), barcodeValues.format());
|
||||
}
|
||||
|
||||
public void addFromImage(View view) {
|
||||
private void addWithoutBarcode() {
|
||||
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
|
||||
|
||||
builder.setOnCancelListener(dialogInterface -> setScannerActive(true));
|
||||
|
||||
// Header
|
||||
builder.setTitle(R.string.addWithoutBarcode);
|
||||
|
||||
// Layout
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
int contentPadding = getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_padding);
|
||||
params.leftMargin = contentPadding;
|
||||
params.topMargin = contentPadding / 2;
|
||||
params.rightMargin = contentPadding;
|
||||
|
||||
// Description
|
||||
TextView currentTextview = new TextView(this);
|
||||
currentTextview.setText(getString(R.string.enter_card_id));
|
||||
currentTextview.setLayoutParams(params);
|
||||
layout.addView(currentTextview);
|
||||
|
||||
// EditText with spacing
|
||||
final EditText input = new EditText(this);
|
||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
input.setLayoutParams(params);
|
||||
layout.addView(input);
|
||||
|
||||
// Set layout
|
||||
builder.setView(layout);
|
||||
|
||||
// Buttons
|
||||
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
|
||||
returnResult(input.getText().toString(), "");
|
||||
});
|
||||
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
|
||||
AlertDialog dialog = builder.create();
|
||||
|
||||
// Now that the dialog exists, we can bind something that affects the OK button
|
||||
input.addTextChangedListener(new SimpleTextWatcher() {
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
if (s.length() == 0) {
|
||||
input.setError(getString(R.string.card_id_must_not_be_empty));
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
||||
} else {
|
||||
input.setError(null);
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
|
||||
// Disable button (must be done **after** dialog is shown to prevent crash
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
||||
// Set focus on input field
|
||||
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
||||
input.requestFocus();
|
||||
}
|
||||
|
||||
public void addManually() {
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ScanActivity.this);
|
||||
builder.setTitle(R.string.add_manually_warning_title);
|
||||
builder.setMessage(R.string.add_manually_warning_message);
|
||||
builder.setPositiveButton(R.string.continue_, (dialog, which) -> {
|
||||
Intent i = new Intent(getApplicationContext(), BarcodeSelectorActivity.class);
|
||||
if (cardId != null) {
|
||||
final Bundle b = new Bundle();
|
||||
b.putString("initialCardId", cardId);
|
||||
i.putExtras(b);
|
||||
}
|
||||
manualAddLauncher.launch(i);
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel, (dialog, which) -> setScannerActive(true));
|
||||
builder.setOnCancelListener(dialog -> setScannerActive(true));
|
||||
builder.show();
|
||||
}
|
||||
|
||||
public void addFromImage() {
|
||||
PermissionUtils.requestStorageReadPermission(this, PERMISSION_SCAN_ADD_FROM_IMAGE);
|
||||
}
|
||||
|
||||
@@ -236,6 +375,7 @@ public class ScanActivity extends CatimaAppCompatActivity {
|
||||
try {
|
||||
photoPickerLauncher.launch(chooserIntent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
setScannerActive(true);
|
||||
Toast.makeText(getApplicationContext(), R.string.failedLaunchingPhotoPicker, Toast.LENGTH_LONG).show();
|
||||
Log.e(TAG, "No activity found to handle intent", e);
|
||||
}
|
||||
@@ -288,6 +428,7 @@ public class ScanActivity extends CatimaAppCompatActivity {
|
||||
if (granted) {
|
||||
addFromImageAfterPermission();
|
||||
} else {
|
||||
setScannerActive(true);
|
||||
Toast.makeText(this, R.string.storageReadPermissionRequired, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.core.content.pm.ShortcutInfoCompat;
|
||||
import androidx.core.content.pm.ShortcutManagerCompat;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -15,11 +20,6 @@ import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.core.content.pm.ShortcutInfoCompat;
|
||||
import androidx.core.content.pm.ShortcutManagerCompat;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
|
||||
class ShortcutHelper {
|
||||
// Android documentation says that no more than 5 shortcuts
|
||||
// are supported. However, that may be too many, as not all
|
||||
|
||||
@@ -7,19 +7,20 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
import com.google.android.material.textview.MaterialTextView;
|
||||
import com.yalantis.ucrop.UCropActivity;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
import com.google.android.material.textview.MaterialTextView;
|
||||
import com.yalantis.ucrop.UCropActivity;
|
||||
|
||||
public class UCropWrapper extends UCropActivity {
|
||||
public static final String UCROP_TOOLBAR_TYPEFACE_STYLE = "ucop_toolbar_typeface_style";
|
||||
|
||||
@@ -27,15 +28,18 @@ public class UCropWrapper extends UCropActivity {
|
||||
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
boolean darkMode = Utils.isDarkModeEnabled(this);
|
||||
Window window = getWindow();
|
||||
// setup status bar to look like the rest of the app
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
View decorView = getWindow().getDecorView();
|
||||
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(getWindow(), decorView);
|
||||
wic.setAppearanceLightStatusBars(!darkMode);
|
||||
if (window != null) {
|
||||
View decorView = window.getDecorView();
|
||||
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(window, decorView);
|
||||
wic.setAppearanceLightStatusBars(!darkMode);
|
||||
}
|
||||
} else {
|
||||
// icons are always white back then
|
||||
if (!darkMode) {
|
||||
getWindow().setStatusBarColor(ColorUtils.compositeColors(Color.argb(127, 0, 0, 0), getWindow().getStatusBarColor()));
|
||||
if (window != null && !darkMode) {
|
||||
window.setStatusBarColor(ColorUtils.compositeColors(Color.argb(127, 0, 0, 0), window.getStatusBarColor()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,16 +22,19 @@ import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RawRes;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.os.LocaleListCompat;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
import androidx.palette.graphics.Palette;
|
||||
|
||||
@@ -663,13 +666,31 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
// XXX android 9 and below has issues with patched theme where the background becomes a
|
||||
// rendering mess
|
||||
// use after views are inflated
|
||||
// Force correct color
|
||||
// Fixes OLED dark mode in MainActivity
|
||||
public static void postPatchColors(AppCompatActivity activity) {
|
||||
activity.findViewById(android.R.id.content).setBackgroundColor(resolveBackgroundColor(activity));
|
||||
}
|
||||
|
||||
// Either pass an Activity on which to call getWindow() or an existing Window (may be null) returned by that function.
|
||||
public static void setNavigationBarColor(@Nullable AppCompatActivity activity, @Nullable Window window, int color, boolean useLightBars) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||
if (window == null && activity != null) {
|
||||
window = activity.getWindow();
|
||||
}
|
||||
if (window != null) {
|
||||
View decorView = window.getDecorView();
|
||||
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(window, decorView);
|
||||
wic.setAppearanceLightNavigationBars(useLightBars);
|
||||
window.setNavigationBarColor(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int resolveBackgroundColor(AppCompatActivity activity) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
activity.getTheme().resolveAttribute(android.R.attr.colorBackground, typedValue, true);
|
||||
activity.findViewById(android.R.id.content).setBackgroundColor(typedValue.data);
|
||||
return typedValue.data;
|
||||
}
|
||||
|
||||
public static int getHeaderColorFromImage(Bitmap image, int fallback) {
|
||||
|
||||
@@ -3,12 +3,13 @@ package protect.card_locker.preferences;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.IntegerRes;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import protect.card_locker.R;
|
||||
import protect.card_locker.Utils;
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package protect.card_locker.preferences;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
@@ -56,6 +56,13 @@ public class SettingsActivity extends CatimaAppCompatActivity {
|
||||
if (savedInstanceState != null) {
|
||||
fragment.mReloadMain = savedInstanceState.getBoolean(RELOAD_MAIN_STATE);
|
||||
}
|
||||
|
||||
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
finishSettingsActivity();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,11 +83,6 @@ public class SettingsActivity extends CatimaAppCompatActivity {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
finishSettingsActivity();
|
||||
}
|
||||
|
||||
private void finishSettingsActivity() {
|
||||
if (fragment.mReloadMain) {
|
||||
Intent intent = new Intent();
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
|
||||
</vector>
|
||||
@@ -34,7 +34,7 @@
|
||||
app:layout_constraintBottom_toTopOf="@+id/barcodeIdLayout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:text="@string/enterBarcodeInstructions" />
|
||||
android:text="@string/manually_enter_barcode_instructions" />
|
||||
<LinearLayout
|
||||
android:id="@+id/barcodeIdLayout"
|
||||
android:orientation="horizontal"
|
||||
@@ -42,7 +42,7 @@
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@+id/explanationText"
|
||||
app:layout_constraintBottom_toTopOf="@+id/noBarcode"
|
||||
app:layout_constraintBottom_toTopOf="@+id/barcodes"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
<TextView android:textSize="16.0sp"
|
||||
@@ -65,21 +65,11 @@
|
||||
android:minHeight="48dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
</LinearLayout>
|
||||
<Button
|
||||
android:id="@+id/noBarcode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@+id/barcodeIdLayout"
|
||||
app:layout_constraintBottom_toTopOf="@+id/barcodes"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:text="@string/barcodeNoBarcode"
|
||||
android:enabled="false" />
|
||||
<ListView
|
||||
android:id="@+id/barcodes"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/noBarcode"
|
||||
app:layout_constraintTop_toBottomOf="@+id/barcodeIdLayout"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/fabOtherOptions"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
app:icon="@drawable/ic_baseline_unfold_more_24"
|
||||
android:text="@string/action_more_options"
|
||||
android:layout_margin="16dp" />
|
||||
|
||||
<com.journeyapps.barcodescanner.BarcodeView
|
||||
android:id="@+id/zxing_barcode_surface"
|
||||
android:layout_width="match_parent"
|
||||
@@ -33,25 +42,5 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/add_from_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/addFromImage"
|
||||
app:layout_constraintBottom_toTopOf="@+id/add_manually"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/camera_permission_denied_layout"
|
||||
app:layout_constraintVertical_bias="1.0" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/add_manually"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/addManually"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</merge>
|
||||
@@ -369,75 +369,106 @@
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<!-- Front image -->
|
||||
<LinearLayout
|
||||
android:id="@+id/frontImageHolder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="@dimen/inputPadding"
|
||||
android:paddingTop="@dimen/inputPadding">
|
||||
android:baselineAligned="false">
|
||||
|
||||
<!-- Front image -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/frontImageHolder"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="@dimen/activity_margin"
|
||||
android:layout_marginTop="@dimen/activity_margin"
|
||||
android:layout_marginEnd="@dimen/activity_margin"
|
||||
android:layout_marginBottom="@dimen/activity_margin"
|
||||
android:paddingHorizontal="@dimen/inputPadding"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardElevation="0dp">
|
||||
android:orientation="horizontal"
|
||||
android:layout_margin="5dp"
|
||||
style="?attr/materialCardViewElevatedStyle">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/frontImage"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/frontImageConstraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:minHeight="50dp"
|
||||
android:contentDescription="@string/frontImageDescription"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_camera_white"
|
||||
android:background="?attr/colorPrimary" />
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<!-- Back image -->
|
||||
<ImageView
|
||||
android:id="@+id/frontImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:minHeight="50dp"
|
||||
android:contentDescription="@string/backImageDescription"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_camera_white"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@id/frontImageDescription"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/frontImageDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/frontImageDescription"
|
||||
android:textAppearance="?attr/textAppearanceHeadlineSmall"
|
||||
android:gravity="center"
|
||||
app:layout_constraintTop_toBottomOf="@id/frontImage"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Back image -->
|
||||
<LinearLayout
|
||||
android:id="@+id/backImageHolder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="@dimen/inputPadding"
|
||||
android:paddingTop="@dimen/inputPadding">
|
||||
|
||||
<!-- Back image -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/backImageHolder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="@dimen/activity_margin"
|
||||
android:layout_marginTop="@dimen/activity_margin"
|
||||
android:layout_marginEnd="@dimen/activity_margin"
|
||||
android:layout_marginBottom="@dimen/activity_margin"
|
||||
android:paddingHorizontal="@dimen/inputPadding"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardElevation="0dp">
|
||||
android:orientation="horizontal"
|
||||
android:layout_margin="5dp"
|
||||
style="?attr/materialCardViewElevatedStyle">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/backImage"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/backImageConstraint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:minHeight="50dp"
|
||||
android:contentDescription="@string/backImageDescription"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_camera_white"
|
||||
android:background="?attr/colorPrimary" />
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<!-- Back image -->
|
||||
<ImageView
|
||||
android:id="@+id/backImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:minHeight="50dp"
|
||||
android:contentDescription="@string/backImageDescription"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_camera_white"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@id/backImageDescription"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/backImageDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/backImageDescription"
|
||||
android:textAppearance="?attr/textAppearanceHeadlineSmall"
|
||||
android:gravity="center"
|
||||
app:layout_constraintTop_toBottomOf="@id/backImage"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</LinearLayout>
|
||||
</TableLayout>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/coordinator_layout"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
@@ -9,13 +9,6 @@
|
||||
android:titleCondensed="@string/editCardTitle"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_copy_to_clipboard"
|
||||
android:icon="@drawable/ic_copy"
|
||||
android:title="@string/copy_to_clipboard"
|
||||
android:titleCondensed="@string/copy_to_clipboard"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_share"
|
||||
android:icon="@drawable/ic_share"
|
||||
|
||||
@@ -4,274 +4,53 @@ J. Lavoie
|
||||
Allan Nordhøy
|
||||
solokot
|
||||
Heimen Stoffels
|
||||
FC (Fay) Stegerman
|
||||
Oğuz Ersen
|
||||
Katharine Chui
|
||||
FC (Fay) Stegerman
|
||||
SlavekB
|
||||
mondstern
|
||||
StoyanDimitrov
|
||||
mondstern
|
||||
IllusiveMan196
|
||||
Altonss
|
||||
Michael Moroni
|
||||
Gediminas Murauskas
|
||||
GM
|
||||
Eric
|
||||
Petr Novák
|
||||
Joel A
|
||||
laralem
|
||||
Taco
|
||||
pfaffenrodt
|
||||
Eric
|
||||
Nyatsuki
|
||||
Aayush Gupta
|
||||
HudobniVolk
|
||||
Nyatsuki
|
||||
Samantaz Fox
|
||||
arno-github
|
||||
Ankit Tiwari
|
||||
Cliff Heraldo
|
||||
Sergio Paredes
|
||||
Clxff H3r4ld0
|
||||
Aayush Gupta
|
||||
Ankit Tiwari
|
||||
Milan Šalka
|
||||
Jiri Grönroos
|
||||
Balázs Meskó
|
||||
Giovanni Donisi
|
||||
Milo Ivir
|
||||
Skrripy
|
||||
huuhaa
|
||||
Projjal Moitra
|
||||
Quentin PAGÈS
|
||||
Giovanni Donisi
|
||||
Alexander Ivanov
|
||||
arshbeerSingh
|
||||
Denis Shilin
|
||||
Freddo espresso
|
||||
Ziad OUALHADJ
|
||||
Silvério Santos
|
||||
Miha Frangež
|
||||
Eryk Michalak
|
||||
Arnis Jaundžeikars
|
||||
Dan
|
||||
sr093906
|
||||
mdvhimself
|
||||
Jiri Grönroos
|
||||
Katarzyna
|
||||
echo r"0xX4H" | rev
|
||||
Magnitudee
|
||||
Olivia (Zoe)
|
||||
betsythefc
|
||||
waffshappen
|
||||
Robin
|
||||
ati3
|
||||
enolp
|
||||
Evgeniy Khramov
|
||||
Jane Kong
|
||||
Jean Mareilles
|
||||
Jean-Luc Tibaux
|
||||
José Rebelo
|
||||
K. Herbert
|
||||
Lisa A.
|
||||
Mawuena M. KODZO A.
|
||||
rudy3
|
||||
Reza
|
||||
Still / Azaka
|
||||
String E. Fighter
|
||||
Tapu
|
||||
Yurical
|
||||
rr-vesp
|
||||
yangyangdaji
|
||||
丛林意志
|
||||
alajemba-vik
|
||||
/usr/local/ΕΨΗΕΛΩΝ
|
||||
Adolfo Jayme-Barrientos
|
||||
Alessandro Mandelli
|
||||
KovalevArtem
|
||||
Artem M.
|
||||
Astrohops1
|
||||
BMN
|
||||
balaraz
|
||||
BootVirtual
|
||||
Bottan Hermawan
|
||||
zChiip
|
||||
Clonewayx
|
||||
D. Domig
|
||||
Danylo Lystopadov
|
||||
Diego
|
||||
Eudes-alencar
|
||||
Fede Pujol
|
||||
FineFindus
|
||||
francescbassas
|
||||
Jason Li
|
||||
Jesse Davids
|
||||
Kamborio
|
||||
Kis Dominik
|
||||
Lukas Grassauer
|
||||
Luna Jernberg
|
||||
Marnick L'Eau
|
||||
Michalis
|
||||
Michał
|
||||
Milo Ivir
|
||||
Mohamed A. Salah
|
||||
Yatoku
|
||||
the7thNightmare
|
||||
Quang Trung
|
||||
Rishi Agarwal
|
||||
Rosdyana Kusuma
|
||||
Sabri Ünal
|
||||
umoenks
|
||||
Simon Rusinov
|
||||
Siriusmart
|
||||
Mritunjay
|
||||
Tarik Dzambic
|
||||
Thomas Bertels
|
||||
Thomas Cruveilher
|
||||
Tian Jiale
|
||||
Tong Liu
|
||||
Tymofii Lytvynenko
|
||||
Wanath
|
||||
YounesBouhouche
|
||||
Runner
|
||||
ce i moa
|
||||
enescan201
|
||||
Frablock
|
||||
inesre
|
||||
lgasp
|
||||
notlin4
|
||||
phlostically
|
||||
pokeghost
|
||||
sal0max
|
||||
Ágata Leuck
|
||||
BmBKun
|
||||
NamHyeonjeong
|
||||
Aditya Das
|
||||
asier123123131
|
||||
Kevin Sicong Jiang
|
||||
Tomer Ben-Rachel
|
||||
Tom Sawyer
|
||||
tfuxu
|
||||
Ahmed Saleh
|
||||
Airat
|
||||
Tapwaterisokey
|
||||
sNiXx
|
||||
Angela Enogieru
|
||||
Animesh Chatterjee
|
||||
Artūras Kalenda
|
||||
Ashish Yadav
|
||||
Aya Elsaadany
|
||||
Aya
|
||||
Biren
|
||||
Booc Sylvan
|
||||
Brage Nesteby Reitan
|
||||
Cap Amr Karam
|
||||
Carlo Maria Cuoghi Barbagli
|
||||
ChaoticNeutralCzech
|
||||
ChengCheng
|
||||
CherryMonster222
|
||||
Colgrave
|
||||
Csaba
|
||||
Mylou53
|
||||
Daniel Sych
|
||||
danieluhrinyi
|
||||
Daniele Tricoli
|
||||
Kasina Dheeraj
|
||||
Donno
|
||||
Reihan
|
||||
Erik Spjelkavik
|
||||
Flav
|
||||
Franciszek Stefan
|
||||
Gael Caraballo
|
||||
Giacomo Alessandroni
|
||||
Govind S Nair
|
||||
Grzegorz
|
||||
gneiss15
|
||||
Hamustra Scans
|
||||
helzubair
|
||||
HowITsDone
|
||||
Hubert Maciejewicz
|
||||
Izzy
|
||||
Jacek
|
||||
Jacopo Gennaro Esposito
|
||||
Jean-Baptiste
|
||||
Kung-chih
|
||||
Karvjorm
|
||||
polar
|
||||
Karol Kosek
|
||||
Laura Ferraz
|
||||
Lucas da Costa
|
||||
almir992
|
||||
Manan Jhaveri
|
||||
Marco
|
||||
BRBsoup
|
||||
Mateo Gomez
|
||||
Mattia
|
||||
Md. Al-Amin
|
||||
Eryk Michalak
|
||||
Ziad OUALHADJ
|
||||
Robin Liu
|
||||
mdvhimself
|
||||
Denis Shilin
|
||||
Miha Frangež
|
||||
Silvério Santos
|
||||
ikanakova
|
||||
Virginie
|
||||
Michael Gangolf
|
||||
Milan Šalka
|
||||
3DN1M
|
||||
Minecraft boom
|
||||
Mobashir Raihan
|
||||
Moi Toi
|
||||
DiCeYMaYo
|
||||
DivideEtImpera
|
||||
Nicolas
|
||||
Nosnahc
|
||||
osamaqw
|
||||
pa4k
|
||||
pbeckmann
|
||||
Peer Beckmann
|
||||
vandman
|
||||
Piotr Strebski
|
||||
Piotr Zet
|
||||
Poorva Patidar
|
||||
Quang Nguyen
|
||||
Ratnesh
|
||||
Rohan Babbar
|
||||
Ronak Upadhyay
|
||||
Rose Liverman
|
||||
SKULD
|
||||
Sabrina
|
||||
Salem Malus
|
||||
Samarth Asthan
|
||||
tatyhub
|
||||
Shailendra Maurya
|
||||
SilverFS
|
||||
Simone Dotto
|
||||
Subhashish Anand
|
||||
Subhradeep Bera
|
||||
Swayam Khare
|
||||
SziaTomi
|
||||
Mehedi Hasan
|
||||
Tim Trek
|
||||
Titas Pažereckas
|
||||
atakujonc
|
||||
tkraljevic
|
||||
Tony C
|
||||
Vancha March
|
||||
tyap-lyap-ivprod
|
||||
Waldemar Stoczkowski
|
||||
Wiktor Kwapisiewicz
|
||||
Yevgeny M
|
||||
Yusril A
|
||||
ahmed-awad26
|
||||
Avik Kundu
|
||||
ayuyydev
|
||||
diksha-2911
|
||||
essys
|
||||
gbonaspetti
|
||||
gittyboy-cell
|
||||
huang ivan
|
||||
liva
|
||||
lucafont2
|
||||
mtrmirez
|
||||
michaelpratana
|
||||
opsik
|
||||
pesta007
|
||||
polarhun
|
||||
pooyanazari
|
||||
psa-jforestier
|
||||
sergio
|
||||
skauVictor
|
||||
080502
|
||||
Marcus
|
||||
techwebpd
|
||||
tjw123hh
|
||||
Truestorybaby
|
||||
tygyh
|
||||
unstartdev
|
||||
wmilan 17
|
||||
يوسف لطفي
|
||||
しいたけ
|
||||
元气
|
||||
JaeBeom An
|
||||
JungHee Lee
|
||||
rudy3
|
||||
Kim Seohyun
|
||||
Govind S Nair
|
||||
Freddo espresso
|
||||
arshbeerSingh
|
||||
Alexander Ivanov
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<string name="note">مذكرة</string>
|
||||
<string name="cardId">معرّف البطاقة</string>
|
||||
<string name="barcodeType">نوع الباركود</string>
|
||||
<string name="barcodeNoBarcode">لا يوجد باركود</string>
|
||||
<string name="noBarcode">لا يوجد باركود</string>
|
||||
<string name="star">أضف الي المفضلة</string>
|
||||
<string name="unstar">حذف من المفضلة</string>
|
||||
@@ -19,7 +18,6 @@
|
||||
<string name="confirm">تأكيد</string>
|
||||
<string name="deleteConfirmation">مسح هذة البطاقة نهائيا؟</string>
|
||||
<string name="ok">حسنا</string>
|
||||
<string name="copy_to_clipboard">نسخ البطاقة الشخصية الى الحافظة</string>
|
||||
<string name="share">شارك</string>
|
||||
<string name="sendLabel">ارسل…</string>
|
||||
<string name="editCardTitle">عدل البطاقة</string>
|
||||
@@ -27,10 +25,7 @@
|
||||
<string name="scanCardBarcode">مسح باركود</string>
|
||||
<string name="cardShortcut">اختصار البطاقة</string>
|
||||
<string name="noCardsMessage">اضف بطاقة أولا</string>
|
||||
<string name="card_ids_copied">البطاقة(ات) الشخصية المنسوخة</string>
|
||||
<string name="barcodeImageDescriptionWithType">صورة <xliff:g>%s</xliff:g> باركود</string>
|
||||
<string name="noStoreError">لا يوجد اسم مدخل</string>
|
||||
<string name="noCardIdError">لا يوجد بطاقة شخصية مدخلة</string>
|
||||
<string name="noCardExistsError">لا يمكن العثور على هذه البطاقة</string>
|
||||
<string name="failedParsingImportUriError">لا يمكن تحليل الرابط المستورد</string>
|
||||
<string name="importExport">استيراد/تصدير</string>
|
||||
@@ -50,8 +45,6 @@
|
||||
<string name="app_license">البرمجيات الحرة متروكة الحقوق, ترخيص +GPLv3</string>
|
||||
<string name="app_libraries">مكتبات الطرف الثالث الحرة: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="selectBarcodeTitle">اختار الباركود</string>
|
||||
<string name="enterBarcodeInstructions">أدخل بطاقة هوية ، واختر نوع الباركود أدناه ، أو \"لا يوجد باركود\".</string>
|
||||
<string name="copy_to_clipboard_toast">تم نسخ بطاقة الهوية إلى الحافظة</string>
|
||||
<string name="thumbnailDescription">صورة مصغرة</string>
|
||||
<string name="starImage">نجم مفضل</string>
|
||||
<string name="settings">اعدادات</string>
|
||||
@@ -79,7 +72,6 @@
|
||||
<string name="balance">الرصيد</string>
|
||||
<string name="currency">العملة</string>
|
||||
<string name="points">نقاط</string>
|
||||
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> لا يبدو أنه رصيد صالح.</string>
|
||||
<string name="chooseImportType">استيراد البيانات من</string>
|
||||
<string name="app_loyalty_card_keychain">سلسلة مفاتيح بطاقة الولاء</string>
|
||||
<string name="privacy_policy">سياسة الخصوصية</string>
|
||||
@@ -100,7 +92,6 @@
|
||||
<string name="setBarcodeId">قم بتعيين قيمة الباركود</string>
|
||||
<string name="unsupportedBarcodeType">لا يمكن عرض نوع الباركود هذا. قد يكون مدعومًا في إصدار أحدث من التطبيق.</string>
|
||||
<string name="wrongValueForBarcodeType">القيمة غير صالحة لنوع الباركود المحدد</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">تم نسخ بطاقات الهوية إلى الحافظة</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">أريد مشاركة بعض البطاقات معك</string>
|
||||
<string name="frontImageDescription">الصورة الأمامية</string>
|
||||
<string name="backImageDescription">الصورة الخلفية</string>
|
||||
@@ -182,9 +173,9 @@
|
||||
<item quantity="zero">مسح <xliff:g>%d</xliff:g> بطاقة</item>
|
||||
<item quantity="one">مسح <xliff:g>%d</xliff:g> بطاقة</item>
|
||||
<item quantity="two">مسح <xliff:g>%d</xliff:g> بطاقتين</item>
|
||||
<item quantity="few">مسح <xliff:g>%d</xliff:g> بطاقات</item>
|
||||
<item quantity="many">مسح <xliff:g>%d</xliff:g> بطاقات</item>
|
||||
<item quantity="other">مسح <xliff:g>%d</xliff:g> بطاقات</item>
|
||||
<item quantity="few">مسح <xliff:g>%d</xliff:g> بطائق</item>
|
||||
<item quantity="many">مسح <xliff:g>%d</xliff:g> بطاقة</item>
|
||||
<item quantity="other">مسح <xliff:g>%d</xliff:g> بطاقة</item>
|
||||
</plurals>
|
||||
<plurals name="deleteCardsConfirmation">
|
||||
<item quantity="zero">مسح هذه <xliff:g>%d</xliff:g> البطاقة نهائيا؟</item>
|
||||
@@ -208,7 +199,7 @@
|
||||
<string name="groupsList">مجموعات: <xliff:g>%s</xliff:g></string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">منع قفل الشاشة</string>
|
||||
<string name="leaveWithoutSaveTitle">خروج</string>
|
||||
<string name="editGroup">مجموعة التعديل: <xliff:g>%s</xliff:g></string>
|
||||
<string name="editGroup">تعديل المجموعه: <xliff:g>%s</xliff:g></string>
|
||||
<plurals name="groupCardCount">
|
||||
<item quantity="zero"><xliff:g>%d</xliff:g> بطاقة</item>
|
||||
<item quantity="one"><xliff:g>%d</xliff:g> بطاقة</item>
|
||||
@@ -311,4 +302,14 @@
|
||||
<string name="settings_category_title_privacy">خصوصية</string>
|
||||
<string name="show_balance">إظهار التوازن</string>
|
||||
<string name="settings_keep_screen_on_summary">تعطيل مهلة الشاشة أثناء عرض البطاقة</string>
|
||||
<string name="balanceParsingFailed">رصيد غير صالح</string>
|
||||
<string name="card_id_must_not_be_empty">يجب ألا يكون معرف البطاقة فارغا</string>
|
||||
<string name="add_a_card_in_a_different_way">أضف بطاقة بطريقة مختلفة</string>
|
||||
<string name="manually_enter_barcode_instructions">أدخل رقم الهوية أو النص الموجود على بطاقتك واضغط على الرمز الشريطي الذي يشبه الموجود على بطاقتك.</string>
|
||||
<string name="action_more_options">خيارات أخرى</string>
|
||||
<string name="enter_card_id">أدخل رقم الهوية أو النص الموجود على بطاقتك</string>
|
||||
<string name="addWithoutBarcode">إضافة بدون باركود</string>
|
||||
<string name="field_must_not_be_empty">يجب ألا يكون الحقل فارغا</string>
|
||||
<string name="app_name">كاتيما</string>
|
||||
<string name="settings_follow_sensor_orientation">التدوير دائمًا ( تجاهل إعدادات النظام)</string>
|
||||
</resources>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" xmlns:tools="http://schemas.android.com/tools">
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="storeName">Nome</string>
|
||||
<string name="note">Nota</string>
|
||||
<string name="noMatchingGiftCards">Nun hai nengún resultáu. Prueba a camudar la busca.</string>
|
||||
@@ -9,7 +9,6 @@
|
||||
<string name="confirm">Confirmar</string>
|
||||
<string name="deleteConfirmation">¿Quies desaniciar esta tarxeta permanentemente\?</string>
|
||||
<string name="importExport">Importar/Esportar</string>
|
||||
<string name="noCardIdError">Nun s\'introduxo nenguna ID</string>
|
||||
<string name="exportFailed">Num se pudo facer la esportación</string>
|
||||
<string name="importFailedTitle">La importación falló</string>
|
||||
<string name="exportOptionExplanation">Los datos escríbense nel llugar qu\'escueyas.</string>
|
||||
@@ -22,20 +21,14 @@
|
||||
</plurals>
|
||||
<string name="noGiftCards">Calca\'l botón «+» p\'amestar una tarxeta o impórtales dende\'l menú «⋮».</string>
|
||||
<string name="cardId">ID</string>
|
||||
<string name="barcodeNoBarcode">Nun hai nengún códigu de barres</string>
|
||||
<string name="save">Guardar</string>
|
||||
<string name="edit">Editar</string>
|
||||
<string name="delete">Desaniciar</string>
|
||||
<plurals name="deleteCardsTitle">
|
||||
<item quantity="one"></item>
|
||||
<item quantity="other"></item>
|
||||
</plurals>
|
||||
<string name="unstar">Quitar de Favoritos</string>
|
||||
<string name="cancel">Encaboxar</string>
|
||||
<string name="importFailed">Nun se pudo facer la importación</string>
|
||||
<string name="noCardExistsError">Nun se pudo atopar esa tarxeta</string>
|
||||
<string name="all">Too</string>
|
||||
<string name="noStoreError">Nun s\'introduxo nengún nome</string>
|
||||
<string name="sendLabel">Unviar…</string>
|
||||
<string name="editCardTitle">Editar la tarxeta</string>
|
||||
<string name="ok">D\'acuerdu</string>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<string name="unstar">Премахва от любими</string>
|
||||
<string name="star">Добавя към любими</string>
|
||||
<string name="noBarcode">Липсва щрихкод</string>
|
||||
<string name="barcodeNoBarcode">Липсва щрихкод</string>
|
||||
<string name="barcodeType">Вид на щрихкода</string>
|
||||
<string name="cardId">Номер на карта</string>
|
||||
<string name="note">Бележка</string>
|
||||
@@ -27,7 +26,6 @@
|
||||
<string name="app_license">Свободен софтуер с авторски права, лицензиран под GPLv3+</string>
|
||||
<string name="frontImageDescription">Снимка на предната страна</string>
|
||||
<string name="backImageDescription">Снимка на задната страна</string>
|
||||
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> не изглежда истинска наличност.</string>
|
||||
<string name="no">Не</string>
|
||||
<string name="yes">Да</string>
|
||||
<string name="setBackImage">Снимка на задната страна</string>
|
||||
@@ -37,15 +35,13 @@
|
||||
<string name="noCardExistsError">Картата не е намерена</string>
|
||||
<string name="updateBarcodeQuestionText">Номерът е променен. Желаете ли същата стойност да бъде приложена и към щрихкода\?</string>
|
||||
<string name="updateBarcodeQuestionTitle">Обновяване на щрихкода\?</string>
|
||||
<string name="noCardIdError">Не е въведен номер</string>
|
||||
<string name="noCardsMessage">Добавете карта</string>
|
||||
<string name="cardShortcut">Пряк път до карта</string>
|
||||
<string name="addCardTitle">Добавяне на карта</string>
|
||||
<string name="removeImage">Премахване на изображение</string>
|
||||
<string name="takePhoto">Снимане</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">Номерата са копирани в междинната памет</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Искам да споделя тези карти с вас</string>
|
||||
<string name="wrongValueForBarcodeType">Неприемлива стойност за избрания вид щрихкод</string>
|
||||
<string name="wrongValueForBarcodeType">Стойноста е неприемлива за избрания щрихкод</string>
|
||||
<string name="setBarcodeId">Задаване на стойност</string>
|
||||
<string name="sameAsCardId">Като номера</string>
|
||||
<string name="barcodeId">Стойност на щрихкода</string>
|
||||
@@ -79,7 +75,6 @@
|
||||
<string name="expiryStateSentenceExpired">Изтекла: <xliff:g>%s</xliff:g></string>
|
||||
<string name="balanceSentence">Наличност: <xliff:g>%s</xliff:g></string>
|
||||
<string name="noGroups">Докоснете бутона +, за да добавите списък.</string>
|
||||
<string name="noStoreError">Не е въведено наименование</string>
|
||||
<string name="groups">Списъци</string>
|
||||
<string name="enter_group_name">Въведете име на списъка</string>
|
||||
<string name="intent_import_card_from_url_share_text">Искам да споделя тази карта с вас</string>
|
||||
@@ -93,8 +88,6 @@
|
||||
<string name="settings">Настройки</string>
|
||||
<string name="starImage">Звезда за любимо</string>
|
||||
<string name="thumbnailDescription">Миниатюра</string>
|
||||
<string name="copy_to_clipboard_toast">Номерът е копиран в междинната памет</string>
|
||||
<string name="enterBarcodeInstructions">Въведете номер и после или изберете вида на щрихкода, или докоснете бутона „Липсва щрихкод“.</string>
|
||||
<string name="selectBarcodeTitle">Избиране на щрихкод</string>
|
||||
<string name="importOptionApplicationButton">Избиране чрез приложение</string>
|
||||
<string name="importing">Внасяне…</string>
|
||||
@@ -112,7 +105,6 @@
|
||||
<string name="scanCardBarcode">Снемане на щрихкод</string>
|
||||
<string name="editCardTitle">Редактиране на карта</string>
|
||||
<string name="share">Споделя</string>
|
||||
<string name="copy_to_clipboard">Копира номера в междинната памет</string>
|
||||
<string name="ok">Добре</string>
|
||||
<string name="importSuccessful">Данните са внесени</string>
|
||||
<string name="chooseImportType">Внасяне на данни на</string>
|
||||
@@ -201,7 +193,7 @@
|
||||
<string name="group_name_already_in_use">Има списък с това име</string>
|
||||
<string name="group_updated">Промените са запазени</string>
|
||||
<string name="selectColor">Избиране на цвят</string>
|
||||
<string name="group_name_is_empty">Името на списъка не може да е празно</string>
|
||||
<string name="group_name_is_empty">Името на списъка не трябва да е празно</string>
|
||||
<string name="group_edit">Редактиране на списък</string>
|
||||
<string name="noGiftCardsGroup">Създайте карти и ги зачислите към списък от тук.</string>
|
||||
<string name="translate_platform">в Weblate</string>
|
||||
@@ -209,7 +201,6 @@
|
||||
<string name="starred">Със звезда</string>
|
||||
<string name="showMoreInfo">Показване на информация</string>
|
||||
<string name="options">Настройки</string>
|
||||
<string name="card_ids_copied">Номерата са копирани</string>
|
||||
<plurals name="balancePoints">
|
||||
<item quantity="one"><xliff:g>%s</xliff:g> точка</item>
|
||||
<item quantity="other"><xliff:g>%s</xliff:g> точки</item>
|
||||
@@ -269,7 +260,7 @@
|
||||
<string name="show_validity">Валидност</string>
|
||||
<string name="show_name_below_image_thumbnail">Наименование</string>
|
||||
<string name="permissionReadCardsLabel">Четене на карти на Catima</string>
|
||||
<string name="permissionReadCardsDescription">Четене на картите с всички подробности, включително бележки и изображения</string>
|
||||
<string name="permissionReadCardsDescription">четене на картите на Catima с всички подробности, включително бележки и изображения</string>
|
||||
<string name="settings_allow_content_provider_read_title">Разрешаване на достъп на други приложения до данните</string>
|
||||
<string name="settings_display_barcode_max_brightness_summary">Необходимо за работата на някои скенери</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card_summary">Без заключване на екрана при преглед на карта</string>
|
||||
@@ -283,4 +274,14 @@
|
||||
<string name="show_archived_cards">Архивирани карти</string>
|
||||
<string name="view_online">Преглед</string>
|
||||
<string name="app_copyright_short">Всички права запазени © Силвия ван Ос и сътрудници</string>
|
||||
<string name="card_id_must_not_be_empty">Номера на картата не трябва да бъде празен</string>
|
||||
<string name="balanceParsingFailed">Неприемлив баланс</string>
|
||||
<string name="add_a_card_in_a_different_way">Добавяне на карта по друг начин</string>
|
||||
<string name="manually_enter_barcode_instructions">Въведете номера или текста и изберете щрихкода, който прилича на този от картата.</string>
|
||||
<string name="action_more_options">Повече</string>
|
||||
<string name="enter_card_id">Въведете номера или текста от картата</string>
|
||||
<string name="addWithoutBarcode">Добавяне на карта без щрихкод</string>
|
||||
<string name="field_must_not_be_empty">Полето не трябва да е празно</string>
|
||||
<string name="app_name">Catima</string>
|
||||
<string name="settings_follow_sensor_orientation">Винаги да се завърта (пренебрегва системната настройка)</string>
|
||||
</resources>
|
||||
@@ -4,7 +4,6 @@
|
||||
<string name="cancel">বাতিল</string>
|
||||
<string name="unstar">তারা মুক্ত</string>
|
||||
<string name="star">তারা</string>
|
||||
<string name="barcodeNoBarcode">কোনো বারকোড নেই</string>
|
||||
<string name="barcodeType">বারকোড ধরন</string>
|
||||
<string name="note">বিঃদ্রঃ</string>
|
||||
<string name="storeName">দোকানের নাম</string>
|
||||
@@ -34,7 +33,6 @@
|
||||
<string name="setBarcodeId">বারকোড আইডি সেট করুন</string>
|
||||
<string name="unsupportedBarcodeType">এই বারকোডের টাইপটি এখন দেখানো যাচ্ছে না। অ্যাপের পরের সংস্করণে হয়ত এটি সমর্থন করা যেতে পারে।</string>
|
||||
<string name="wrongValueForBarcodeType">বারকোড টাইপের জন্য ভুল মান</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">আইডিগুলি ক্লিপবোর্ডে কপি হল</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">url থেকে ইন্টেন্ট ইম্পোর্ট কার্ড একাধিক টেক্সট শেয়ার করে</string>
|
||||
<string name="frontImageDescription">সামনের চিত্র</string>
|
||||
<string name="backImageDescription">পিছনের চিত্র</string>
|
||||
@@ -69,14 +67,11 @@
|
||||
<string name="reverse">...উল্টো ক্রমে</string>
|
||||
<string name="sort_by">ক্রমানুসার</string>
|
||||
<string name="noCardExistsError">কার্ডটি খুঁজে পাওয়া গেল না</string>
|
||||
<string name="noStoreError">স্টোরেজ ত্রুটি নেই</string>
|
||||
<string name="card_ids_copied">আইডি কপি করা হয়েছে</string>
|
||||
<string name="noCardsMessage">কোন কার্ড বার্তা নেই</string>
|
||||
<string name="addCardTitle">কার্ডের শিরোনাম যোগ করুন</string>
|
||||
<string name="editCardTitle">কার্ডের শিরোনাম সম্পাদনা করুন</string>
|
||||
<string name="sendLabel">পাঠান…</string>
|
||||
<string name="share">ভাগ</string>
|
||||
<string name="copy_to_clipboard">নকল করুন ক্লিপবোর্ড এ</string>
|
||||
<string name="deleteConfirmation">এই কার্ডটি চিরকালের জন্য মুছে দেবো\?</string>
|
||||
<string name="confirm">নিশ্চিত করুন</string>
|
||||
<string name="delete">মুছে ফেলুন</string>
|
||||
@@ -100,7 +95,6 @@
|
||||
<string name="importOptionApplicationExplanation">একটি ফাইল খোলার জন্য যেকোনো অ্যাপ বা আপনার প্রিয় ফাইল ম্যানেজারটি ব্যবহার করুন।</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">মেধাস্বত্ব © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="app_license">কপিলেফট দ্বারা রক্ষা করা মুক্ত সফটওয়্যার, লাইসেন্স করা GPLv3+ এর অধীনে</string>
|
||||
<string name="enterBarcodeInstructions">আইডিটি লিখুন আর নয় নিচ থেকে একটি বারকোডের প্রকার বা \"কোনো বারকোড নেই\", নির্বাচন করুন।</string>
|
||||
<plurals name="deleteCardsConfirmation">
|
||||
<item quantity="one">এই <xliff:g>%d</xliff:g>টি কার্ড কি চিরকালের জন্য মুছে দেবো\?</item>
|
||||
<item quantity="other">এই <xliff:g>%d</xliff:g>টি কার্ড কি চিরকালের জন্য মুছে দেবো\?</item>
|
||||
@@ -128,8 +122,6 @@
|
||||
<string name="importExport">আমদানি/রপ্তানি</string>
|
||||
<string name="cardShortcut">কার্ড শর্টকাট</string>
|
||||
<string name="exportFailed">রপ্তানি করা যাচ্ছে না</string>
|
||||
<string name="copy_to_clipboard_toast">আইডি ক্লিপবোর্ডে নকল করা হল</string>
|
||||
<string name="noCardIdError">কোনো আইডি দওয়া হয়নি</string>
|
||||
<string name="importExportHelp">নিজের ডেটা অন্য কোথাও সংরক্ষণ করে রাখলে পরে সেটা অন্য ডিভাইসে সরিয়ে নিতে পারবেন।</string>
|
||||
<string name="importFailed">আমদানি করা গেল না</string>
|
||||
<string name="noGiftCardsGroup">কিছু কার্ড বানান আর এই গ্রুপে স্থির করুন।</string>
|
||||
@@ -186,7 +178,6 @@
|
||||
\nকোন তথ্য একেবারেই সংগ্রহ করা হয় না, যা যে কেউ নিশ্চিত করতে পারবেন কারন আমাদের অ্যাপ মুক্ত সফটওয়্যার।</string>
|
||||
<string name="balance">ব্যালান্স</string>
|
||||
<string name="points">পয়েন্ট</string>
|
||||
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> কোনো বৈধ ব্যালান্স মনে হচ্ছে না।</string>
|
||||
<string name="chooseImportType">এখান থেকে তথ্য আমদানি করুন</string>
|
||||
<string name="app_loyalty_card_keychain">আনুগত্য কার্ড কীচেন</string>
|
||||
<string name="privacy_policy">ব্যক্তিগত তথ্যের গোপনীয়তা নীতি</string>
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
<string name="storeName">নাম</string>
|
||||
<string name="note">বিঃদ্রঃ</string>
|
||||
<string name="star">ফেভারিটে যোগ করুন</string>
|
||||
<string name="barcodeNoBarcode">কোন বারকোড নেই</string>
|
||||
<string name="noBarcode">বারকোড নেই</string>
|
||||
<string name="unstar">পছন্দের তালিকা থেকে অপসারণ</string>
|
||||
<string name="cancel">বাতিল করুন</string>
|
||||
@@ -41,7 +40,6 @@
|
||||
<item quantity="one">এই <xliff:g>%d</xliff:g> কার্ডটি স্থায়ীভাবে মুছবেন\?</item>
|
||||
<item quantity="other">এই <xliff:g>%d</xliff:g> কার্ডগুলিকে স্থায়ীভাবে মুছবেন\?</item>
|
||||
</plurals>
|
||||
<string name="copy_to_clipboard">ক্লিপবোর্ডে আইডি কপি করুন</string>
|
||||
<string name="share">শেয়ার করুন</string>
|
||||
<string name="editCardTitle">কার্ড সম্পাদনা করুন</string>
|
||||
<string name="addCardTitle">কার্ড যোগ করুন</string>
|
||||
@@ -54,5 +52,28 @@
|
||||
<string name="noGiftCards">একটি কার্ড যোগ করতে + প্লাস বোতামে ক্লিক করুন বা ⋮ মেনু থেকে আমদানি করুন।</string>
|
||||
<string name="cardShortcut">কার্ড শর্টকাট</string>
|
||||
<string name="noCardsMessage">প্রথমে একটি কার্ড যোগ করুন</string>
|
||||
<string name="card_ids_copied">আইডি কপি করা হয়েছে</string>
|
||||
<string name="noCardExistsError">কার্ডটি খুঁজে পাওয়া যায়নি</string>
|
||||
<string name="barcodeImageDescriptionWithType">ছবি <xliff:g>%s</xliff:g> বারকোড</string>
|
||||
<string name="cameraPermissionDeniedTitle">ক্যামেরাটি ব্যবহার করা যাচ্ছে না</string>
|
||||
<string name="failedParsingImportUriError">দেওয়া URL-টি প্রক্রিয়া করা যাচ্ছে না</string>
|
||||
<string name="exporting">রপ্তানি করা হচ্ছে…</string>
|
||||
<string name="noCameraPermissionDirectToSystemSetting">বারকোড স্ক্যান করার জন্য, ক্যাটিমা কে ক্যামেরাটি ব্যবহার করার অনুমতি দিতে হবে। এইখানে টাচ করে আপনার অনুমতি সেটিংস পালটে নিন।</string>
|
||||
<string name="settings_dark_theme">অন্ধকার</string>
|
||||
<string name="exportOptionExplanation">ডেটাটি আপনার পছন্দের জায়গায় রাখা হবে।</string>
|
||||
<string name="importFailed">আমদানি করা গেল না</string>
|
||||
<string name="permissionReadCardsDescription">সমস্ত ক্যাটিমা কার্ডস এবং তার তথ্য পড়ুন, নোট্স আর ছবি সহ</string>
|
||||
<string name="importFailedTitle">আমদানি ব্যর্থ</string>
|
||||
<string name="importExportHelp">নিজের ডেটা সংরক্ষণ করে রাখলে পরে সেটা অন্য ডিভাইসে সরিয়ে নিতে পারবেন।</string>
|
||||
<string name="importExport">আমদানি/রপ্তানি</string>
|
||||
<string name="importing">আমদানি করা হচ্ছে…</string>
|
||||
<string name="exportFailed">রপ্তানি করা যাচ্ছে না</string>
|
||||
<string name="exportName">আমদানি/রপ্তানি</string>
|
||||
<string name="cameraPermissionRequired">এই কাজটির জন্য ক্যামেরা ব্যবহার করার অনুমতি লাগবে…</string>
|
||||
<string name="importSuccessfulTitle">আমদানি শেষ</string>
|
||||
<string name="exportSuccessfulTitle">রপ্তানি শেষ</string>
|
||||
<string name="permissionReadCardsLabel">কাটিমা কার্ডস পড়ুন</string>
|
||||
<string name="storageReadPermissionRequired">এই কাজটির জন্য ফোনের স্টোরেজ দেখার অনুমতি লাগবে…</string>
|
||||
<string name="exportFailedTitle">রপ্তানি ব্যর্থ</string>
|
||||
<string name="settings_card_orientation">বারকোড অভিমুখ (ওরিয়েন্টেশন)</string>
|
||||
<string name="app_name">ক্যাটিমা</string>
|
||||
</resources>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user