mirror of
https://github.com/CatimaLoyalty/Android.git
synced 2025-12-24 15:47:53 -05:00
Compare commits
641 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bc7d13d50 | ||
|
|
84fef5a615 | ||
|
|
0993f3180b | ||
|
|
f143e01685 | ||
|
|
cb5a98edad | ||
|
|
74157b2fe5 | ||
|
|
5b7d5599f9 | ||
|
|
cdfcfebd77 | ||
|
|
301fd880f5 | ||
|
|
4a4ef1b148 | ||
|
|
0bc7f4a164 | ||
|
|
5e593d0ded | ||
|
|
e958fff7b4 | ||
|
|
d81b236aa6 | ||
|
|
8be8737459 | ||
|
|
e80238bfcf | ||
|
|
211032c152 | ||
|
|
0bf50fb491 | ||
|
|
6f22e2d185 | ||
|
|
31c341663f | ||
|
|
40a68a55e2 | ||
|
|
1fd0acf6e4 | ||
|
|
127d288ace | ||
|
|
11587631a9 | ||
|
|
466b3d91d3 | ||
|
|
8f4f7524c4 | ||
|
|
f35aa2a064 | ||
|
|
c20206fe28 | ||
|
|
45de3f6616 | ||
|
|
6f42b30790 | ||
|
|
35eab50775 | ||
|
|
19d302e0a4 | ||
|
|
a17ccfa41a | ||
|
|
a22e05284c | ||
|
|
64491a1f7a | ||
|
|
472d8ae18d | ||
|
|
388db6feab | ||
|
|
5833d49fbf | ||
|
|
ffb2fadcfc | ||
|
|
5f534b9646 | ||
|
|
e011324b9f | ||
|
|
21df76a2b6 | ||
|
|
1af9789cf6 | ||
|
|
b891e05fb9 | ||
|
|
55e09b602f | ||
|
|
af4075b9e2 | ||
|
|
da0a221c85 | ||
|
|
191445b822 | ||
|
|
d890b062a9 | ||
|
|
59173443e7 | ||
|
|
5da76c9d9c | ||
|
|
f048566929 | ||
|
|
fe0f4314db | ||
|
|
8d39bd671c | ||
|
|
9ad33a047f | ||
|
|
2a78335607 | ||
|
|
d99c72982d | ||
|
|
79ced018d5 | ||
|
|
f80c79ffb1 | ||
|
|
11970004f0 | ||
|
|
a348ad62a2 | ||
|
|
22d612427f | ||
|
|
a907b28fe8 | ||
|
|
663612dce9 | ||
|
|
a55da89eb2 | ||
|
|
63ceb2589f | ||
|
|
dd981d72d7 | ||
|
|
8940a8ea77 | ||
|
|
57cfac3172 | ||
|
|
f475844bd0 | ||
|
|
4536453fdf | ||
|
|
3ee533b815 | ||
|
|
a744c19cce | ||
|
|
9cc66c5d67 | ||
|
|
3e5b018b55 | ||
|
|
f6fee780ee | ||
|
|
6971f23d0a | ||
|
|
6d33576936 | ||
|
|
b6c9b9059e | ||
|
|
000bd7b734 | ||
|
|
3dde4de775 | ||
|
|
9b867370c2 | ||
|
|
c092a04390 | ||
|
|
50d80c1a9e | ||
|
|
67e2147d33 | ||
|
|
cfe2aaaad8 | ||
|
|
88a91de63b | ||
|
|
2cdeb1af9c | ||
|
|
c815c3908f | ||
|
|
9e831924c6 | ||
|
|
cfc901855b | ||
|
|
a00a69e0c0 | ||
|
|
426acc701e | ||
|
|
d6eccd11a5 | ||
|
|
cb8275771f | ||
|
|
9252c01aa7 | ||
|
|
b4b544e342 | ||
|
|
f667fcbebe | ||
|
|
cc402c39be | ||
|
|
d5d921a1c8 | ||
|
|
d8794811a1 | ||
|
|
e56795307e | ||
|
|
6ad99d47aa | ||
|
|
2998a4d553 | ||
|
|
63db8fa0f3 | ||
|
|
ee14d9e0c5 | ||
|
|
1455265045 | ||
|
|
4f5cd87912 | ||
|
|
d5516c59a6 | ||
|
|
5654abe6e9 | ||
|
|
b17a50f9c2 | ||
|
|
87c9bb590b | ||
|
|
dc9360eb8a | ||
|
|
c8d2aa26f5 | ||
|
|
a5074eb191 | ||
|
|
9df0a8ff57 | ||
|
|
a79cf72ad7 | ||
|
|
db0134a44c | ||
|
|
5f6424778a | ||
|
|
950264105b | ||
|
|
7b2d9eb47f | ||
|
|
088ee66b5a | ||
|
|
2487edf4b2 | ||
|
|
e16d2e22ac | ||
|
|
7b335c69ba | ||
|
|
c1bd7043b1 | ||
|
|
71f3b5bc5f | ||
|
|
e2f33bf4b4 | ||
|
|
b1685ac90e | ||
|
|
394cc6b30f | ||
|
|
75e320e108 | ||
|
|
e8b38b3367 | ||
|
|
ffb24c973a | ||
|
|
d43693b1d8 | ||
|
|
b7f17181f9 | ||
|
|
10dc84820c | ||
|
|
5f0d92470e | ||
|
|
6bb4376e4d | ||
|
|
92da792378 | ||
|
|
81499cd362 | ||
|
|
fc91f1ae63 | ||
|
|
cec7bc880e | ||
|
|
4027df2119 | ||
|
|
93132961d3 | ||
|
|
638528d4fc | ||
|
|
67ef623761 | ||
|
|
cb3afe1878 | ||
|
|
e3f4aec1c5 | ||
|
|
d2f196da21 | ||
|
|
e491a960d7 | ||
|
|
f5c83793bf | ||
|
|
e334a5e454 | ||
|
|
cbbd071f4f | ||
|
|
524a6b1ffb | ||
|
|
7954adf7e3 | ||
|
|
0b31a08b9f | ||
|
|
a0884aa81c | ||
|
|
46f64d1a61 | ||
|
|
81cb6ad4fd | ||
|
|
f2f330e3e4 | ||
|
|
5b14670785 | ||
|
|
c5f68aa50f | ||
|
|
5203f89e9d | ||
|
|
8f11d73649 | ||
|
|
3d376e2a90 | ||
|
|
0e814c3359 | ||
|
|
4755cc3f7f | ||
|
|
7afbe41f95 | ||
|
|
6d4cbee499 | ||
|
|
f16a597b91 | ||
|
|
3ba0649891 | ||
|
|
297ecc371e | ||
|
|
79c8570507 | ||
|
|
8f81d2d141 | ||
|
|
325535af12 | ||
|
|
f7af4169a3 | ||
|
|
e5ec45f877 | ||
|
|
902a4e411b | ||
|
|
03ec2b4492 | ||
|
|
6a2f8a630a | ||
|
|
78e998fad9 | ||
|
|
e6ccef8ad0 | ||
|
|
acbd614b50 | ||
|
|
445e661fac | ||
|
|
d774231c05 | ||
|
|
b5d2a5dbab | ||
|
|
6ab61eb78a | ||
|
|
bbd8bb7d29 | ||
|
|
3e082b598f | ||
|
|
70510ed9d1 | ||
|
|
5da1c67dd6 | ||
|
|
dfa237958e | ||
|
|
127d53e85a | ||
|
|
7cce782143 | ||
|
|
662eb853d7 | ||
|
|
d8e58f8b38 | ||
|
|
4748e24dda | ||
|
|
5af024f482 | ||
|
|
8adc013330 | ||
|
|
4edfe962ef | ||
|
|
d80a71c852 | ||
|
|
299c9f2b4d | ||
|
|
03e3e45f07 | ||
|
|
c35c316788 | ||
|
|
d68f0c60d4 | ||
|
|
5faa28a7e7 | ||
|
|
2fffb89179 | ||
|
|
bd27ccd535 | ||
|
|
3149234f5d | ||
|
|
dcf55c93a8 | ||
|
|
3f3394c1e9 | ||
|
|
2b22dd4a1f | ||
|
|
a70710ca6a | ||
|
|
cd3baf5bd9 | ||
|
|
1138d6387e | ||
|
|
b664fd391a | ||
|
|
11cc65bae3 | ||
|
|
eaafa56503 | ||
|
|
09c6d58639 | ||
|
|
1767a009a7 | ||
|
|
a2e25512ec | ||
|
|
824b931764 | ||
|
|
0cb75fd421 | ||
|
|
36f0d814f6 | ||
|
|
2aa0c46d30 | ||
|
|
ff63dbfdaa | ||
|
|
5cacdbd192 | ||
|
|
c99bf206cc | ||
|
|
f546bb2681 | ||
|
|
bef750e047 | ||
|
|
6998599377 | ||
|
|
11164f9a73 | ||
|
|
b867795a08 | ||
|
|
9998205051 | ||
|
|
7692f19ea6 | ||
|
|
d8361cc288 | ||
|
|
93d0724c60 | ||
|
|
2c03f193f0 | ||
|
|
7028a1f4ca | ||
|
|
32d62dd9ba | ||
|
|
401fc98b4d | ||
|
|
993589427b | ||
|
|
2390568bdf | ||
|
|
50ccf6da46 | ||
|
|
44066e6599 | ||
|
|
fc9c616869 | ||
|
|
f09f35e44b | ||
|
|
f81fb0c673 | ||
|
|
b0b4e80da4 | ||
|
|
923982e449 | ||
|
|
d05c97946d | ||
|
|
504a1fd01b | ||
|
|
5efacec417 | ||
|
|
595d10fc44 | ||
|
|
2128f0a601 | ||
|
|
0b0a45da05 | ||
|
|
94fb4b4411 | ||
|
|
fc7932d3bf | ||
|
|
97a5311593 | ||
|
|
c7db676b2b | ||
|
|
f8c8b3b2e6 | ||
|
|
df4cb5b189 | ||
|
|
d2b2a53109 | ||
|
|
5107f88998 | ||
|
|
78f2e1698f | ||
|
|
6887cd098b | ||
|
|
0881d745f5 | ||
|
|
94b3a07f90 | ||
|
|
dc280b4023 | ||
|
|
edce6d6cd3 | ||
|
|
23dc47a5b9 | ||
|
|
683b4f46d9 | ||
|
|
ac021bce2a | ||
|
|
b0c34cbca0 | ||
|
|
4a0c8270ef | ||
|
|
793f1e2f87 | ||
|
|
0101b6fa25 | ||
|
|
47dff850fb | ||
|
|
fe7503c3ac | ||
|
|
5df7d8a530 | ||
|
|
ee129a3373 | ||
|
|
b979b1fc86 | ||
|
|
361ebb8b80 | ||
|
|
fd49466e0d | ||
|
|
bf8f00f877 | ||
|
|
9f0b7604cb | ||
|
|
6d151e7377 | ||
|
|
6ecc94526e | ||
|
|
1462911ffa | ||
|
|
952f7a933b | ||
|
|
b76c4ef352 | ||
|
|
48048cdb82 | ||
|
|
a555f1c41b | ||
|
|
2ab7ebb2c0 | ||
|
|
e2b0113687 | ||
|
|
dc7e9b541a | ||
|
|
b44ef7dfc0 | ||
|
|
4d1f4a64fa | ||
|
|
fd7e6e4993 | ||
|
|
b749c79a81 | ||
|
|
5d019a8e5b | ||
|
|
4e203aebfe | ||
|
|
fb2bede135 | ||
|
|
5a88909cd2 | ||
|
|
017034a788 | ||
|
|
66ff6f8199 | ||
|
|
ddccbad020 | ||
|
|
578fb068ee | ||
|
|
d624eb3842 | ||
|
|
f46fedda4b | ||
|
|
6e5ac2ca3d | ||
|
|
20de874ea1 | ||
|
|
c8a207083b | ||
|
|
ab7505c67a | ||
|
|
b26050b6bf | ||
|
|
84e9c8efd4 | ||
|
|
2811a14627 | ||
|
|
3b6d4d44b0 | ||
|
|
71bc304c51 | ||
|
|
7b0652ff11 | ||
|
|
61a3054655 | ||
|
|
54c1cc3661 | ||
|
|
ee0f9e04de | ||
|
|
ebe5289d6e | ||
|
|
15ba15c602 | ||
|
|
fd0448efc4 | ||
|
|
43fa2623d4 | ||
|
|
c1b9babf33 | ||
|
|
4c8edf9d9a | ||
|
|
ff4271f51d | ||
|
|
2424ab01cf | ||
|
|
b38dfeeed7 | ||
|
|
7912cd190f | ||
|
|
11962ad930 | ||
|
|
a8e2c65072 | ||
|
|
1b8ca5f467 | ||
|
|
46fff6da5b | ||
|
|
47e75f64ed | ||
|
|
fb95c8c9d4 | ||
|
|
66cc97214c | ||
|
|
f52423ed70 | ||
|
|
29bea052eb | ||
|
|
b683f1fce4 | ||
|
|
2ec55473a5 | ||
|
|
2fe89ffcbc | ||
|
|
7e88a10884 | ||
|
|
f260051160 | ||
|
|
b8dacc2459 | ||
|
|
b311dd99dc | ||
|
|
1d7a9843d8 | ||
|
|
03e59ad00f | ||
|
|
c083af1c76 | ||
|
|
6abb0a2a75 | ||
|
|
e672e7f1a6 | ||
|
|
852a638ea1 | ||
|
|
ec1b642614 | ||
|
|
145dac72af | ||
|
|
7d2679b2a3 | ||
|
|
ffbcd2183b | ||
|
|
b9d646868c | ||
|
|
2ce530a644 | ||
|
|
1c8e9ba1cf | ||
|
|
9a2560dbc2 | ||
|
|
f900c4299d | ||
|
|
f78494f882 | ||
|
|
b55f10b59d | ||
|
|
277ee90421 | ||
|
|
fcdde83038 | ||
|
|
12fb29ecce | ||
|
|
ae7dd63d6b | ||
|
|
48f680f7bd | ||
|
|
e3d4e393b3 | ||
|
|
81f13c255a | ||
|
|
97ce322d0c | ||
|
|
a3e876d9a2 | ||
|
|
234356f8f2 | ||
|
|
d3222f7bdc | ||
|
|
a5658e72c7 | ||
|
|
d1e1fcfabe | ||
|
|
9d6bd0770c | ||
|
|
6f76ee389b | ||
|
|
87aa74f231 | ||
|
|
a0dc80c1a5 | ||
|
|
d8dbe25a64 | ||
|
|
e3bec085df | ||
|
|
4d4b92b33f | ||
|
|
cc58c769cc | ||
|
|
37f08f6fc4 | ||
|
|
73e02e7c06 | ||
|
|
7a1b6fccc2 | ||
|
|
2473e3f91a | ||
|
|
0a6bb2805c | ||
|
|
1eecc6f065 | ||
|
|
b8b4fe4958 | ||
|
|
6dd8b6798b | ||
|
|
69d0a3f4aa | ||
|
|
ce81934890 | ||
|
|
ba06f47e3e | ||
|
|
cfc37d4af6 | ||
|
|
43cd6edda2 | ||
|
|
0bd262d82f | ||
|
|
f09bafa104 | ||
|
|
20e34ee365 | ||
|
|
7a6bd8f661 | ||
|
|
54c3765e36 | ||
|
|
4d7f563b0d | ||
|
|
4e0ecaa7be | ||
|
|
4f41d238eb | ||
|
|
7c3d021427 | ||
|
|
bfde036484 | ||
|
|
84ef4ad030 | ||
|
|
3b85fccd60 | ||
|
|
830d0f6e6a | ||
|
|
1ceede27a3 | ||
|
|
fa33cdaca4 | ||
|
|
f39fbb55a1 | ||
|
|
f3ffa0ab88 | ||
|
|
48e1fcc38e | ||
|
|
5b889c4c0c | ||
|
|
616ca77c39 | ||
|
|
59bf064783 | ||
|
|
220393c445 | ||
|
|
b976c03fb0 | ||
|
|
dad0493666 | ||
|
|
776613c507 | ||
|
|
7570d9d319 | ||
|
|
2e648d1062 | ||
|
|
5ad02ae9cc | ||
|
|
99fc568419 | ||
|
|
5f835716e0 | ||
|
|
1f6fe787eb | ||
|
|
1b08d30611 | ||
|
|
05ad33a756 | ||
|
|
b103366a10 | ||
|
|
343d37d4b8 | ||
|
|
60dc050633 | ||
|
|
96c3583393 | ||
|
|
43656dbcca | ||
|
|
7c38bbe6ab | ||
|
|
c6c6448501 | ||
|
|
7ff9da2d7f | ||
|
|
39893cc66d | ||
|
|
5110618d7d | ||
|
|
a856831ee1 | ||
|
|
c5fc6a4212 | ||
|
|
7708646c68 | ||
|
|
c84dbac020 | ||
|
|
56c2297e02 | ||
|
|
6956805e62 | ||
|
|
7736e30043 | ||
|
|
ace441f072 | ||
|
|
a37e99ce39 | ||
|
|
6b1bdbaa78 | ||
|
|
b4077a2fc3 | ||
|
|
2f660c6fec | ||
|
|
cc0511a2aa | ||
|
|
2f367efa70 | ||
|
|
bff1b54b7e | ||
|
|
010e9556b8 | ||
|
|
7c54c01dfe | ||
|
|
5709c8dbec | ||
|
|
0f434d7fe7 | ||
|
|
a2d7e70431 | ||
|
|
0c0c462372 | ||
|
|
f630539d9a | ||
|
|
7e27ddcc94 | ||
|
|
f9b61c24e9 | ||
|
|
d26a138e3e | ||
|
|
e695a4e993 | ||
|
|
8cae6aed4a | ||
|
|
56b72dd544 | ||
|
|
b935b30e00 | ||
|
|
b9a6c6248d | ||
|
|
09d8703545 | ||
|
|
6e25211f12 | ||
|
|
6f1dc74f66 | ||
|
|
61b1317fc5 | ||
|
|
129ee2d5aa | ||
|
|
2358ea1f89 | ||
|
|
87a172afd5 | ||
|
|
5a64b6996e | ||
|
|
9ba07982bf | ||
|
|
98c41ec003 | ||
|
|
bc9875e7fc | ||
|
|
b8bc7eded3 | ||
|
|
6625deadf7 | ||
|
|
c781e4ff4e | ||
|
|
b5a2508027 | ||
|
|
4916917ac9 | ||
|
|
4f9b1dae04 | ||
|
|
9b841399f7 | ||
|
|
45fdc81aa7 | ||
|
|
fdb28a3e52 | ||
|
|
a151a9334e | ||
|
|
618c7a294d | ||
|
|
f926d61213 | ||
|
|
d572add506 | ||
|
|
012da7397f | ||
|
|
92e4908ea8 | ||
|
|
a051d628ab | ||
|
|
0116346035 | ||
|
|
3049b7b0ae | ||
|
|
0c484d26ee | ||
|
|
55bea5262e | ||
|
|
f64d0dcc16 | ||
|
|
ad23a671a2 | ||
|
|
718e6b433d | ||
|
|
65e2965df2 | ||
|
|
2bf815942c | ||
|
|
b5547c5cdf | ||
|
|
371fd00606 | ||
|
|
4f2a448e7e | ||
|
|
2755641e6b | ||
|
|
3e80066a68 | ||
|
|
2e78f77be6 | ||
|
|
d042d9a7e8 | ||
|
|
c4064a2ed1 | ||
|
|
0ac0fad091 | ||
|
|
7fdad67ea4 | ||
|
|
be21bc1654 | ||
|
|
e65fb4390f | ||
|
|
9f7bd4a0bd | ||
|
|
b43817cbde | ||
|
|
da0e2ebb99 | ||
|
|
aa87f33676 | ||
|
|
4e7d4383e8 | ||
|
|
0702aa1c79 | ||
|
|
cd97f89d90 | ||
|
|
eab6c4d2bd | ||
|
|
20775cbc79 | ||
|
|
90ecb1997f | ||
|
|
64b1483fa5 | ||
|
|
8365a719d8 | ||
|
|
068e793682 | ||
|
|
2e1c72e401 | ||
|
|
3e213c6996 | ||
|
|
ec65abadc3 | ||
|
|
d24b56b5c1 | ||
|
|
b56f4e1653 | ||
|
|
efba8773c5 | ||
|
|
15339a8c44 | ||
|
|
050021de5c | ||
|
|
16cff71cfb | ||
|
|
76226a319f | ||
|
|
eed138a2fb | ||
|
|
fd202fc940 | ||
|
|
5364b57cee | ||
|
|
3136b80f26 | ||
|
|
f3471b082f | ||
|
|
9d24ef7791 | ||
|
|
6223ccd4bc | ||
|
|
a81cc27414 | ||
|
|
78481516b0 | ||
|
|
423b74273e | ||
|
|
83e0a988d9 | ||
|
|
1adea88ff1 | ||
|
|
dda912c8c5 | ||
|
|
f3b31bb306 | ||
|
|
3b31c4e05a | ||
|
|
1155108086 | ||
|
|
73bb7ded09 | ||
|
|
d8655eb631 | ||
|
|
55cddfef91 | ||
|
|
c35dc736f4 | ||
|
|
23b762a500 | ||
|
|
b9b638de45 | ||
|
|
5f57507dda | ||
|
|
852eb6612c | ||
|
|
d96aac7bbf | ||
|
|
9018479959 | ||
|
|
ce8a99e840 | ||
|
|
9236f66bc6 | ||
|
|
37b3964351 | ||
|
|
a60d902fda | ||
|
|
a97ce6f9aa | ||
|
|
a15bce04e8 | ||
|
|
34fa68f852 | ||
|
|
e5fef55fc7 | ||
|
|
c5cca1b14d | ||
|
|
f34ec1cc4b | ||
|
|
95aafa5c99 | ||
|
|
00160b0c45 | ||
|
|
a7e6d56bc9 | ||
|
|
9dc8d5e2f4 | ||
|
|
cf7cf679e0 | ||
|
|
4e7e0d9480 | ||
|
|
fbb3013b20 | ||
|
|
ca37e2aa84 | ||
|
|
e6bf60d457 | ||
|
|
35835fda34 | ||
|
|
a3133de6cf | ||
|
|
40fb10a2ec | ||
|
|
856c735ba3 | ||
|
|
16fb0df55d | ||
|
|
5658acbb07 | ||
|
|
8b5faac0e0 | ||
|
|
10be9b58ce | ||
|
|
832840be08 | ||
|
|
5806156495 | ||
|
|
0be9b908ab | ||
|
|
718d2b7567 | ||
|
|
fed9754908 | ||
|
|
c0e09ca429 | ||
|
|
4a3737b846 | ||
|
|
b4add4a0ea | ||
|
|
5aabbd629e | ||
|
|
a5ef50317d | ||
|
|
48a8cc927a | ||
|
|
cbb97d7d57 | ||
|
|
5eee344035 | ||
|
|
4c7e0c7174 | ||
|
|
37bb9c86f4 | ||
|
|
83ea6ffbf7 | ||
|
|
f4945c2cd2 | ||
|
|
24d9c7825a | ||
|
|
2aa7bb4639 | ||
|
|
110b3bcef3 | ||
|
|
f625efc76d | ||
|
|
22608a9802 | ||
|
|
abf6c1328d | ||
|
|
225058ab2b | ||
|
|
275dc6caa2 | ||
|
|
ceb7b12154 | ||
|
|
849da26198 | ||
|
|
5808c991bb | ||
|
|
e8554cb221 | ||
|
|
46092c060d | ||
|
|
736eebd45c | ||
|
|
f72db53345 | ||
|
|
b8c017259e | ||
|
|
4b4a237b9a | ||
|
|
17034e992f | ||
|
|
bf143038b0 | ||
|
|
73805ad3bb | ||
|
|
7006e35ebf | ||
|
|
fc598018b2 | ||
|
|
d01ec85c32 | ||
|
|
04ee918152 | ||
|
|
943b70647b | ||
|
|
edba5d5dca | ||
|
|
86be5d1994 |
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "gradle" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "daily"
|
||||
12
.github/workflows/android.yml
vendored
12
.github/workflows/android.yml
vendored
@@ -2,9 +2,13 @@ name: Android CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
branches:
|
||||
- master
|
||||
- staging
|
||||
- trying
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -13,6 +17,8 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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
|
||||
- name: set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
@@ -24,7 +30,7 @@ jobs:
|
||||
- name: Check lint
|
||||
run: ./gradlew lintRelease
|
||||
- name: Run unit tests
|
||||
run: ./gradlew testReleaseUnitTest
|
||||
run: ./gradlew testReleaseUnitTest || ./gradlew testReleaseUnitTest
|
||||
- name: SpotBugs
|
||||
run: ./gradlew spotbugsRelease
|
||||
- name: Archive test results
|
||||
|
||||
2
.github/workflows/autoclose-needs-info.yml
vendored
2
.github/workflows/autoclose-needs-info.yml
vendored
@@ -2,7 +2,7 @@ name: 'Close issues and PRs needing info for too long'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
@@ -10,20 +10,23 @@ on:
|
||||
- '**.webp'
|
||||
jobs:
|
||||
build:
|
||||
# Only run on Pull Requests within the same repository, and not from forks.
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
name: calibreapp/image-actions
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v2
|
||||
- name: Compress Images
|
||||
id: calibre
|
||||
uses: calibreapp/image-actions@master
|
||||
uses: calibreapp/image-actions@1.1.0
|
||||
with:
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
ignorePaths: 'app/src/test'
|
||||
compressOnly: true
|
||||
- name: Create New Pull Request If Needed
|
||||
if: steps.calibre.outputs.markdown != ''
|
||||
uses: peter-evans/create-pull-request@master
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
title: Compressed Images
|
||||
branch-suffix: timestamp
|
||||
|
||||
26
.github/workflows/changelog-to-fastlane.yml
vendored
Normal file
26
.github/workflows/changelog-to-fastlane.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Convert CHANGELOG to Fastlane
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
convert_changelog_to_fastlane:
|
||||
runs-on: ubuntu-latest
|
||||
name: Convert CHANGELOG to Fastlane
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
id: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
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@v3
|
||||
with:
|
||||
title: "Update Fastlane changelogs"
|
||||
commit-message: "Update Fastlane changelogs"
|
||||
branch-suffix: timestamp
|
||||
73
.github/workflows/codeql-analysis.yml
vendored
Normal file
73
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches:
|
||||
- master
|
||||
schedule:
|
||||
- cron: '33 1 * * 4'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'java' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
25
.github/workflows/contributors-to-file.yml
vendored
Normal file
25
.github/workflows/contributors-to-file.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Write contributors to file
|
||||
on:
|
||||
schedule:
|
||||
- cron: '3 4 * * 0'
|
||||
|
||||
jobs:
|
||||
contributors_to_file:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/master'
|
||||
name: Write contributors to file
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
id: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Update contributors
|
||||
id: update_contributors
|
||||
uses: TheLastProject/contributors-to-file-action@v2
|
||||
with:
|
||||
file_in_repo: app/src/main/res/raw/contributors.txt
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
title: "Update contributors"
|
||||
commit-message: "Update contributors"
|
||||
branch-suffix: timestamp
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ build/
|
||||
captures/
|
||||
**/release
|
||||
**/debug
|
||||
app/*.log
|
||||
|
||||
33
.scripts/changelog_to_fastlane.py
Normal file
33
.scripts/changelog_to_fastlane.py
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
changelogs = {}
|
||||
|
||||
with open('CHANGELOG.md') as changelog:
|
||||
version_code = None
|
||||
text = []
|
||||
|
||||
for line in changelog:
|
||||
if line.startswith("## "):
|
||||
if version_code != None:
|
||||
changelogs[version_code] = text
|
||||
|
||||
text = []
|
||||
match = re.match("## \S* - (\d*).*", line)
|
||||
if not match:
|
||||
raise ValueError(f"Invalid version line: {line}")
|
||||
version_code = match.group(1)
|
||||
elif line:
|
||||
# Turn Markdown [links](to_url) into links (to_url)
|
||||
text.append(re.sub(r'\[(.*?)\]\((.*?)\)', r'\1 (\2)', line))
|
||||
|
||||
for version, description in changelogs.items():
|
||||
description = "".join(description).strip()
|
||||
|
||||
if not description:
|
||||
continue
|
||||
|
||||
with open(os.path.join("fastlane", "metadata", "android", "en-US", "changelogs", f"{version}.txt"), "w") as fastlane_file:
|
||||
fastlane_file.write(description)
|
||||
383
CHANGELOG.md
383
CHANGELOG.md
@@ -1,80 +1,128 @@
|
||||
# Changelog
|
||||
|
||||
## v2.2.3 (2021-08-13)
|
||||
## Unreleased - 91
|
||||
|
||||
Changes:
|
||||
- Improved group management support
|
||||
- Support cropping images
|
||||
- Fix image data loss when saving after rotating in edit view
|
||||
- Ability to set a custom image as card icon
|
||||
|
||||
## v2.8.1 - 90 (2021-10-27)
|
||||
|
||||
- Fix dots in card view having the wrong colour when changing theme manually
|
||||
- Fix crash in card view on rotation/theme change
|
||||
- Fix flashing of cards list
|
||||
- Fix text overlaying star icon
|
||||
|
||||
## v2.8.0 - 89 (2021-10-25)
|
||||
|
||||
- Fix swiping between groups not working on an empty group
|
||||
- Allow password-protecting exports
|
||||
- Improve usage of space for QR codes
|
||||
- Save the last used zoom level per card
|
||||
- Fix a crash when swiping right after a tap
|
||||
|
||||
## v2.7.3 - 88 (2021-10-10)
|
||||
|
||||
- Fix incorrect migration making first card become invisible
|
||||
|
||||
## v2.7.2 - 87 (2021-10-09)
|
||||
|
||||
- Fix regression breaking import/export
|
||||
|
||||
## v2.7.1 - 86 (2021-10-07)
|
||||
|
||||
- Improve search with spaces
|
||||
|
||||
## v2.7.0 - 85 (2021-10-05)
|
||||
|
||||
Android 4.4 is no longer supported starting with this release. If you want to use Catima on Android 4.4, please use version 2.6.1.
|
||||
|
||||
- Improved Android 12 support
|
||||
- Improved about screen
|
||||
- Search now ignores accents
|
||||
|
||||
## v2.6.1 - 84 (2021-09-25)
|
||||
|
||||
- Minor bugfixes and improvements
|
||||
|
||||
## v2.6.0 - 83 (2021-09-19)
|
||||
|
||||
- Support for changing the sorting order
|
||||
- Prevent Out Of Memory on scanning large pictures for barcode
|
||||
|
||||
## v2.5.0 - 82 (2021-09-10)
|
||||
|
||||
- Improved support for screen readers
|
||||
- Don't crash when trying to open a video from gallery
|
||||
- Swipe support on loyalty card view screen
|
||||
- Don't reset group on back button press
|
||||
|
||||
## v2.4.0 - 81 (2021-08-29)
|
||||
|
||||
- Improve card list for landscape and tablet display
|
||||
- Add theming colour support (thanks, Subhashish Anand!)
|
||||
- Don't close scan activity on camera error (so manual entry is still possible)
|
||||
- Add all contributors to the about dialog
|
||||
|
||||
## v2.3.0 - 80 (2021-08-19)
|
||||
|
||||
- Fix images not imported from backup
|
||||
- Option to override language
|
||||
|
||||
## v2.2.3 - 79 (2021-08-13)
|
||||
|
||||
- Fix widget creating different-looking shortcut than app shortcuts
|
||||
- Replace default Android black screen with splash screen
|
||||
|
||||
## v2.2.2 (2021-08-08)
|
||||
|
||||
Changes:
|
||||
## v2.2.2 - 78 (2021-08-08)
|
||||
|
||||
- Fix crash on rotation in loyalty card edit activity
|
||||
|
||||
## v2.2.1 (2021-08-07)
|
||||
|
||||
Changes:
|
||||
## v2.2.1 - 77 (2021-08-07)
|
||||
|
||||
- Improve Stocard importer
|
||||
- Fix importing Catima export with multiline note
|
||||
- Scale card title in acceptable range
|
||||
- Animation improvements
|
||||
|
||||
## v2.2.0 (2021-08-02)
|
||||
|
||||
Changes:
|
||||
## v2.2.0 - 76 (2021-08-02)
|
||||
|
||||
- Make links in notes clickable
|
||||
- Pre-select group the user is currently in when creating a new card
|
||||
- Comma-separate group names in loyalty card view
|
||||
- Fix maximize button appearing on no barcode
|
||||
|
||||
## v2.1.0 (2021-08-01)
|
||||
|
||||
Changes:
|
||||
## v2.1.0 - 75 (2021-08-01)
|
||||
|
||||
- Fix selected colour in colour changing dialog
|
||||
- Support for deleting multiple cards at once
|
||||
- Fix possible ArithmeticException when resizing image
|
||||
- Fix fullscreen is closed when rotating device
|
||||
|
||||
## v2.0.4 (2021-07-27)
|
||||
|
||||
Changes:
|
||||
## v2.0.4 - 74 (2021-07-27)
|
||||
|
||||
- Fix shortcut creation
|
||||
- Generate card-specific shortcut icon
|
||||
- Fix ability to change loyalty card colour
|
||||
|
||||
## v2.0.3 (2021-07-25)
|
||||
|
||||
Changes:
|
||||
## v2.0.3 - 73 (2021-07-25)
|
||||
|
||||
- Fix loading photos when editing existing card
|
||||
|
||||
## v2.0.2 (2021-07-25)
|
||||
|
||||
Changes:
|
||||
## v2.0.2 - 72 (2021-07-25)
|
||||
|
||||
- Fix inability to configure photos in new loyalty card
|
||||
|
||||
## v2.0.1 (2021-07-21)
|
||||
|
||||
Changes:
|
||||
## v2.0.1 - 71 (2021-07-21)
|
||||
|
||||
- Several minor translation and UI fixes
|
||||
- Fix crash in import/sharing loyalty card on Android 6
|
||||
|
||||
## v2.0 (2021-07-14)
|
||||
|
||||
Breaking changes:
|
||||
- The backup format changed, see https://github.com/TheLastProject/Catima/wiki/Export-format
|
||||
- The URL sharing format changed, see https://github.com/TheLastProject/Catima/wiki/Card-sharing-URL-format
|
||||
|
||||
Changes:
|
||||
## v2.0 - 70 (2021-07-14)
|
||||
|
||||
- BREAKING CHANGE: The backup format changed, see https://github.com/TheLastProject/Catima/wiki/Export-format
|
||||
- BREAKING CHANGE: The URL sharing format changed, see https://github.com/TheLastProject/Catima/wiki/Card-sharing-URL-format
|
||||
- Make it possible to enable or disable the flashlight while scanning
|
||||
- Add UPC-E support
|
||||
- Support adding a front and back photo to each card
|
||||
@@ -85,26 +133,20 @@ Changes:
|
||||
- Fix Floating Action Buttons being behind other UI elements on Android 4
|
||||
- Fix loyalty card viewer appbar top margin
|
||||
|
||||
## v1.14.1 (2021-06-14)
|
||||
|
||||
Changes:
|
||||
## v1.14.1 - 69 (2021-06-14)
|
||||
|
||||
- Add missing barcode ID to export
|
||||
- Don't show update barcode dialog if value is the same as card ID
|
||||
- Add Finnish translation
|
||||
|
||||
## v1.14 (2021-06-07)
|
||||
|
||||
Changes:
|
||||
## v1.14 - 68 (2021-06-07)
|
||||
|
||||
- Support new PDF417 export from Voucher Vault
|
||||
- Support copying multiple barcodes at once
|
||||
- Support sharing multiple loyalty cards at once
|
||||
- Ask to update barcode value if card ID changes
|
||||
|
||||
## v1.13 (2021-04-10)
|
||||
|
||||
Changes:
|
||||
## v1.13 - 67 (2021-04-10)
|
||||
|
||||
- Add option to set a separate barcode value from card ID
|
||||
- Simplify font sizing configuration
|
||||
@@ -113,175 +155,125 @@ Changes:
|
||||
- Always show all barcode types in manual entry
|
||||
- Remove privacy policy first start dialog
|
||||
|
||||
## v1.12 (2021-03-30)
|
||||
|
||||
Changes:
|
||||
## v1.12 - 66 (2021-03-30)
|
||||
|
||||
- Support importing [Fidme](https://play.google.com/store/apps/details?id=fr.snapp.fidme) exports
|
||||
- Allow importing a card from a picture stored in the user's Android gallery
|
||||
- Fix multiline note cutoff
|
||||
- Change "Thank you" text on privacy dialog to "Accept" because Huawei is overly pedantic
|
||||
|
||||
## v1.11 (2021-03-21)
|
||||
|
||||
Changes:
|
||||
## v1.11 - 64 (2021-03-21)
|
||||
|
||||
- Add privacy policy dialog on first start (required by Huawei)
|
||||
|
||||
## v1.10 (2021-03-07)
|
||||
|
||||
Changes:
|
||||
## v1.10 - 63 (2021-03-07)
|
||||
|
||||
- Support importing [Voucher Vault](https://github.com/tim-smart/vouchervault/) exports
|
||||
- Option to keep the screen on while viewing a loyalty card
|
||||
- Option to suspend the lock screen while viewing a loyalty card
|
||||
|
||||
## v1.9.2 (2021-02-24)
|
||||
|
||||
Changes:
|
||||
## v1.9.2 - 62 (2021-02-24)
|
||||
|
||||
- Fix parsing balance for countries using space as separator
|
||||
|
||||
## v1.9.1 (2021-02-23)
|
||||
|
||||
Changes:
|
||||
## v1.9.1 - 61 (2021-02-23)
|
||||
|
||||
- Improve balance parsing logic
|
||||
- Fix currency decimal display on main screen
|
||||
|
||||
## v1.9 (2021-02-22)
|
||||
|
||||
Changes:
|
||||
## v1.9 - 59 (2021-02-22)
|
||||
|
||||
- Add balance support
|
||||
- Reorganize barcode tab of edit view
|
||||
|
||||
## v1.8.1 (2021-02-12)
|
||||
|
||||
Changes:
|
||||
## v1.8.1 - 58 (2021-02-12)
|
||||
|
||||
- Fix Crash on versions before Android 7
|
||||
|
||||
## v1.8 (2021-01-28)
|
||||
|
||||
Changes:
|
||||
## v1.8 - 57 (2021-01-28)
|
||||
|
||||
- Add support for scaling the barcode when moving to top to fit even more small scanners
|
||||
- Fix bottom sheet jumping after switching to fullscreen
|
||||
- Make header in loyalty card view small in landscape mode
|
||||
- Fix cards not staying in group when group gets renamed
|
||||
|
||||
## v1.7.1 (2021-01-18)
|
||||
|
||||
Changes:
|
||||
## v1.7.1 - 56 (2021-01-18)
|
||||
|
||||
- Fix crash on switching to barcode tab in edit view if there is no barcode
|
||||
|
||||
## v1.7.0 (2021-01-18)
|
||||
|
||||
Changes:
|
||||
## v1.7.0 - 55 (2021-01-18)
|
||||
|
||||
- Separate edit UI in tabs to make it feel more spacious
|
||||
- Add expiry field support
|
||||
|
||||
## v1.6.2 (2021-01-04)
|
||||
|
||||
Changes:
|
||||
## v1.6.2 - 54 (2021-01-04)
|
||||
|
||||
- Fix edit button or more info bottom sheet drawing over barcode ID
|
||||
|
||||
## v1.6.1 (2020-12-16)
|
||||
|
||||
Changes:
|
||||
## v1.6.1 - 64 (2020-12-16)
|
||||
|
||||
- Fix regression causing manual barcode entry to not be saved
|
||||
|
||||
## v1.6.0 (2020-12-15)
|
||||
|
||||
Changes:
|
||||
## v1.6.0 - 52 (2020-12-15)
|
||||
|
||||
- Automatically focus text field when creating or editing a group
|
||||
- Fix blurry icons (use SVG everywhere)
|
||||
- Always open camera but add manual scan button to camera view
|
||||
|
||||
## v1.5.1 (2020-12-03)
|
||||
|
||||
Changes:
|
||||
## v1.5.1 - 51 (2020-12-03)
|
||||
|
||||
- Fix bottomsheet background being transparent
|
||||
|
||||
## v1.5.0 (2020-12-03)
|
||||
|
||||
Changes:
|
||||
## v1.5.0 - 50 (2020-12-03)
|
||||
|
||||
- Improve contrast by always using white text on red buttons
|
||||
- Draggable bottom sheet in loyalty card view
|
||||
|
||||
## v1.4.1 (2020-12-01)
|
||||
|
||||
Changes:
|
||||
## v1.4.1 - 49 (2020-12-01)
|
||||
|
||||
- Improved translations
|
||||
- Small UI fixes
|
||||
|
||||
## v1.4.0 (2020-11-28)
|
||||
|
||||
Changes:
|
||||
## v1.4.0 - 48 (2020-11-28)
|
||||
|
||||
- Move About screen into its own activity
|
||||
- Ask user if they want to use their camera or manually enter ID on add/edit card
|
||||
- Make group ordering manual instead of forced alphabetically
|
||||
|
||||
## v1.3.0 (2020-11-22)
|
||||
|
||||
Changes:
|
||||
## v1.3.0 - 47 (2020-11-22)
|
||||
|
||||
- Always show all import/export options and show a toast on actual issues (improves compat with XPrivacyLua)
|
||||
- Ask for confirmation when leaving edit view after making changes without saving
|
||||
|
||||
## v1.2.2 (2020-11-19)
|
||||
|
||||
Changes:
|
||||
## v1.2.2 - 46 (2020-11-19)
|
||||
|
||||
- Remember active group tab between screens and sessions
|
||||
|
||||
## v1.2.1 (2020-11-17)
|
||||
|
||||
Changes:
|
||||
## v1.2.1 - 45 (2020-11-17)
|
||||
|
||||
- Fix home screen swiping triggering during vertical swipes too
|
||||
|
||||
## v1.2.0 (2020-11-17)
|
||||
|
||||
Changes:
|
||||
## v1.2.0 - 44 (2020-11-17)
|
||||
|
||||
- Add swiping between groups on the home screen
|
||||
- Fix crash with cards lacking header colour
|
||||
|
||||
## v1.1.0 (2020-11-11)
|
||||
|
||||
Changes:
|
||||
## v1.1.0 - 43 (2020-11-11)
|
||||
|
||||
- Improved edit UI
|
||||
- Removed header text colour option (now automatically generated based on brightness)
|
||||
- Updated translations
|
||||
|
||||
## v1.0.1 (2020-11-07)
|
||||
|
||||
Changes:
|
||||
## v1.0.1 - 42 (2020-11-07)
|
||||
|
||||
- Fix crash in search with no groups
|
||||
|
||||
## v1.0 (2020-11-06)
|
||||
|
||||
Changes:
|
||||
## v1.0 - 41 (2020-11-06)
|
||||
|
||||
- Added rounded edges to card icons on main overview
|
||||
- Added support for grouping entries
|
||||
|
||||
## v0.29 (2020-10-29)
|
||||
|
||||
Changes:
|
||||
## v0.29 - 40 (2020-10-29)
|
||||
|
||||
- Rebrand to Catima
|
||||
- Removed intro
|
||||
@@ -290,31 +282,23 @@ Changes:
|
||||
- Add favourites support
|
||||
- Fix disabled auto-rotate being ignored
|
||||
|
||||
## v0.28 (2020-03-09)
|
||||
|
||||
Changes:
|
||||
## v0.28 - 39 (2020-03-09)
|
||||
|
||||
- Fix barcode centering when exiting full screen ([#351](https://github.com/brarcher/loyalty-card-locker/pull/351))
|
||||
- Allow backup export location to be selected ([#352](https://github.com/brarcher/loyalty-card-locker/pull/352))
|
||||
- Update translations ([#357](https://github.com/brarcher/loyalty-card-locker/pull/357)) & ([#362](https://github.com/brarcher/loyalty-card-locker/pull/362))
|
||||
|
||||
## v0.27 (2020-01-26)
|
||||
|
||||
Changes:
|
||||
## v0.27 - 38 (2020-01-26)
|
||||
|
||||
- Tapping on a barcode now moves it to the top of the screen ([#348](https://github.com/brarcher/loyalty-card-locker/pull/348))
|
||||
- Add white space around barcodes to improve scanning in dark mode ([#328](https://github.com/brarcher/loyalty-card-locker/issues/328))
|
||||
- Fix swapped import buttons. ([#346](https://github.com/brarcher/loyalty-card-locker/pull/346))
|
||||
|
||||
## v0.26.1 (2020-01-09)
|
||||
|
||||
Changes:
|
||||
## v0.26.1 - 37 (2020-01-09)
|
||||
|
||||
- Fix issue with sharing cards without background color ([#343](https://github.com/brarcher/loyalty-card-locker/pull/343))
|
||||
|
||||
## v0.26 (2020-01-05)
|
||||
|
||||
Changes:
|
||||
## v0.26 - 36 (2020-01-05)
|
||||
|
||||
- Add ability to search for a card ([#320](https://github.com/brarcher/loyalty-card-locker/pull/320))
|
||||
- Add ability to share and receive loyalty cards ([#321](https://github.com/brarcher/loyalty-card-locker/pull/321))
|
||||
@@ -331,57 +315,41 @@ Changes:
|
||||
- Polish
|
||||
- Russian
|
||||
|
||||
## v0.25.4 (2019-10-04)
|
||||
|
||||
Changes:
|
||||
## v0.25.4 - 35 (2019-10-04)
|
||||
|
||||
- Enable app backups
|
||||
- Update French and Slovenian translations
|
||||
|
||||
## v0.25.3 (2019-03-02)
|
||||
|
||||
Changes:
|
||||
## v0.25.3 - 34 (2019-03-02)
|
||||
|
||||
- Update Russian translations
|
||||
|
||||
## v0.25.2 (2019-01-05)
|
||||
|
||||
Changes:
|
||||
## v0.25.2 - 33 (2019-01-05)
|
||||
|
||||
- Update and add translations
|
||||
|
||||
## v0.25.1 (2018-10-14)
|
||||
|
||||
Changes:
|
||||
## v0.25.1 - 32 (2018-10-14)
|
||||
|
||||
- Fix creating new card by manually entering barcode ([issue #272](https://github.com/brarcher/loyalty-card-locker/issues/272))
|
||||
|
||||
## v0.25 (2018-10-07)
|
||||
|
||||
Changes:
|
||||
## v0.25 - 31 (2018-10-07)
|
||||
|
||||
- Sort card list case insensitive ([pull #266](https://github.com/brarcher/loyalty-card-locker/pull/266))
|
||||
- Add setting to lock orientation for all cards ([pull #269](https://github.com/brarcher/loyalty-card-locker/pull/269)
|
||||
|
||||
## v0.24 (2018-07-31)
|
||||
|
||||
Changes:
|
||||
## v0.24 - 30 (2018-07-31)
|
||||
|
||||
- Add a setting to control screen brightness when displaying a barcode ([pull #259](https://github.com/brarcher/loyalty-card-locker/pull/259))
|
||||
- Add Greek translations ([pull #252](https://github.com/brarcher/loyalty-card-locker/pull/252))
|
||||
- Add Slovenian translations ([pull #260](https://github.com/brarcher/loyalty-card-locker/pull/260))
|
||||
- Update translations ([pull #260](https://github.com/brarcher/loyalty-card-locker/pull/260), [pull #254](https://github.com/brarcher/loyalty-card-locker/pull/254))
|
||||
|
||||
## v0.23.4 (2018-05-12)
|
||||
|
||||
Changes:
|
||||
## v0.23.4 - 29 (2018-05-12)
|
||||
|
||||
- Fix Spanish translations ([pull #244](https://github.com/brarcher/loyalty-card-locker/pull/244))
|
||||
- Update translations ([pull #244](https://github.com/brarcher/loyalty-card-locker/pull/244))
|
||||
|
||||
## v0.23.3 (2018-05-05)
|
||||
|
||||
Changes:
|
||||
## v0.23.3 - 28 (2018-05-05)
|
||||
|
||||
- Added translations
|
||||
- Polish ([pull #232](https://github.com/brarcher/loyalty-card-locker/pull/232))
|
||||
@@ -389,87 +357,63 @@ Changes:
|
||||
- Slovak ([pull #232](https://github.com/brarcher/loyalty-card-locker/pull/232))
|
||||
- Updated translations ([pull #239](https://github.com/brarcher/loyalty-card-locker/pull/239))
|
||||
|
||||
## v0.23.2 (2018-03-11)
|
||||
|
||||
Changes:
|
||||
## v0.23.2 - 27 (2018-03-11)
|
||||
|
||||
- Reduce min SDK from 17 to 15. ([pull #226](https://github.com/brarcher/loyalty-card-locker/pull/226))
|
||||
- Remove usage of legacy apache library, used only in unit tests but no longer needed. ([pull #225](https://github.com/brarcher/loyalty-card-locker/pull/225))
|
||||
|
||||
## v0.23.1 (2018-03-07)
|
||||
|
||||
Changes:
|
||||
## v0.23.1 - 26 (2018-03-07)
|
||||
|
||||
- Prevent crash when rendering a barcode exhausts the application's memory. ([pull #219](https://github.com/brarcher/loyalty-card-locker/pull/219))
|
||||
|
||||
## v0.23 (2018-02-28)
|
||||
|
||||
Changes:
|
||||
## v0.23 - 25 (2018-02-28)
|
||||
|
||||
- Reduce space in header when viewing a card. ([pull #213](https://github.com/brarcher/loyalty-card-locker/pull/213))
|
||||
- Disable beep when scanning a barcode. ([pull #216](https://github.com/brarcher/loyalty-card-locker/pull/216))
|
||||
|
||||
## v0.22 (2018-02-19)
|
||||
|
||||
Changes:
|
||||
## v0.22 - 24 (2018-02-19)
|
||||
|
||||
- Update translations. ([pull #208](https://github.com/brarcher/loyalty-card-locker/pull/208))
|
||||
- Barcode rendering updates: ([pull #209](https://github.com/brarcher/loyalty-card-locker/pull/209))
|
||||
- Reload card view activity when screen is rotated, so barcode image is correct size.
|
||||
- Render 1D barcodes in a larger space, allowing them to better fill the screen.
|
||||
|
||||
## v0.21 (2018-02-17)
|
||||
|
||||
Changes:
|
||||
## v0.21 - 23 (2018-02-17)
|
||||
|
||||
- Add quiet space at the start/end of barcodes. ([pull #200](https://github.com/brarcher/loyalty-card-locker/pull/200))
|
||||
- Add options to configure the colors used for the store name font and background. ([pull #203](https://github.com/brarcher/loyalty-card-locker/pull/203))
|
||||
- Add options to adjust font sizes on the card listing page and single card page. ([pull #204](https://github.com/brarcher/loyalty-card-locker/pull/204))
|
||||
|
||||
## v0.20 (2018-02-10)
|
||||
|
||||
Changes:
|
||||
## v0.20 - 22 (2018-02-10)
|
||||
|
||||
- Changes to Card view to display the note, allow the card ID to take multiple lines, and show the store name. ([pull #197](https://github.com/brarcher/loyalty-card-locker/pull/197))
|
||||
|
||||
## v0.19 (2018-02-01)
|
||||
|
||||
Changes:
|
||||
## v0.19 - 21 (2018-02-01)
|
||||
|
||||
- Improved layout for card list. ([pull #188](https://github.com/brarcher/loyalty-card-locker/pull/188))
|
||||
- Improved layout when viewing a card. ([pull #190](https://github.com/brarcher/loyalty-card-locker/pull/190))
|
||||
|
||||
## v0.18.1 (2018-01-24)
|
||||
|
||||
Changes:
|
||||
## v0.18.1 - 20 (2018-01-24)
|
||||
|
||||
- Workaround crash during install on some Android versions (likely Android 5 and below). ([pull #184](https://github.com/brarcher/loyalty-card-locker/pull/184))
|
||||
|
||||
## v0.18 (2018-01-19)
|
||||
|
||||
Changes:
|
||||
## v0.18 - 19 (2018-01-19)
|
||||
|
||||
- Fix crash when importing certain types of corrupted CSV files. ([pull #177](https://github.com/brarcher/loyalty-card-locker/pull/177))
|
||||
- Fix importing backups directly from the file system. ([pull #180](https://github.com/brarcher/loyalty-card-locker/pull/180))
|
||||
- Fix importing backups from certain types of content providers. ([pull #179](https://github.com/brarcher/loyalty-card-locker/pull/179))
|
||||
|
||||
## v0.17 (2018-01-11)
|
||||
|
||||
Changes:
|
||||
## v0.17 - 18 (2018-01-11)
|
||||
|
||||
- Fix issue on Android SDK 24+ where using the file chooser import option would cause a crash. ([pull #170](https://github.com/brarcher/loyalty-card-locker/pull/170))
|
||||
- New icon and color scheme. ([pull #171](https://github.com/brarcher/loyalty-card-locker/pull/171))
|
||||
|
||||
## v0.16 (2017-11-29)
|
||||
|
||||
Changes:
|
||||
## v0.16 - 17 (2017-11-29)
|
||||
|
||||
- Add support for adding loyalty card shortcuts from the launcher/homescreen. ([pull #161](https://github.com/brarcher/loyalty-card-locker/pull/161))
|
||||
- Remove support for adding loyalty card shortcuts from the app itself. This removes the need for the shortcut permission. ([pull #163](https://github.com/brarcher/loyalty-card-locker/pull/163))
|
||||
|
||||
## v0.15 (2017-11-25)
|
||||
|
||||
Changes:
|
||||
## v0.15 - 16 (2017-11-25)
|
||||
|
||||
- Add support for adding shortcuts to home screen when adding or editing a card. ([pull #155](https://github.com/brarcher/loyalty-card-locker/pull/155))
|
||||
- Remove widget, as it was a poor substitute for shortcuts. ([pull #155](https://github.com/brarcher/loyalty-card-locker/pull/155))
|
||||
@@ -477,37 +421,27 @@ Changes:
|
||||
- Report more accurate mime type when exporting backup data. ([pull #156](https://github.com/brarcher/loyalty-card-locker/pull/156))
|
||||
- Fix bug where a card could not be edited. ([pull #155](https://github.com/brarcher/loyalty-card-locker/pull/155))
|
||||
|
||||
## v0.14 (2017-10-26)
|
||||
|
||||
Changes:
|
||||
## v0.14 - 15 (2017-10-26)
|
||||
|
||||
- Add support for app shortcuts (Android 7.1+), where the most recently used cards will appear as shortcuts. ([pull #145](https://github.com/brarcher/loyalty-card-locker/pull/145))
|
||||
- Add a widget which works like a pinned app shortcut, to support devices which run below Android 7.1. ([pull #142](https://github.com/brarcher/loyalty-card-locker/pull/142))
|
||||
|
||||
## v0.13 (2017-07-25)
|
||||
|
||||
Changes:
|
||||
## v0.13 - 14 (2017-07-25)
|
||||
|
||||
- Add screen rotation lock menu option when displaying a card. If locked, the screen will transition to its "natural" orientation and further screen rotation will be blocked. ([pull #128](https://github.com/brarcher/loyalty-card-locker/pull/128))
|
||||
- If a card is selected from the main screen but cannot be loaded, the application fails gracefully and posts a message. ([pull #132](https://github.com/brarcher/loyalty-card-locker/pull/132))
|
||||
- Fix case where layout IDs for intro wizard could not be found. ([pull #128](https://github.com/brarcher/loyalty-card-locker/pull/128))
|
||||
|
||||
## v0.12 (2017-07-16)
|
||||
|
||||
Changes:
|
||||
## v0.12 - 13 (2017-07-16)
|
||||
|
||||
- A change in v0.11 reduced the memory usage of barcode drawing, but affected the barcode dimensions. This is now changed to maintain the barcode dimensions while reducing memory usage. ([pull #126](https://github.com/brarcher/loyalty-card-locker/pull/126))
|
||||
- Update German and French translations. ([pull #122](https://github.com/brarcher/loyalty-card-locker/pull/122), [pull #124](https://github.com/brarcher/loyalty-card-locker/pull/124), [pull #125](https://github.com/brarcher/loyalty-card-locker/pull/125))
|
||||
|
||||
## v0.11.1 (2017-06-29)
|
||||
|
||||
Changes:
|
||||
## v0.11.1 - 12 (2017-06-29)
|
||||
|
||||
- Prevent a crash when rotation the screen in the first run intro wizard.
|
||||
|
||||
## v0.11 (2017-06-26)
|
||||
|
||||
Improvements:
|
||||
## v0.11 - 11 (2017-06-26)
|
||||
|
||||
- When editing a card ID, pre-populate the existing ID to start. ([pull #94](https://github.com/brarcher/loyalty-card-locker/pull/94))
|
||||
- Limit the width of generated barcodes to reduce memory usage and out of memory errors. ([pull #103](https://github.com/brarcher/loyalty-card-locker/pull/103))
|
||||
@@ -515,15 +449,13 @@ Improvements:
|
||||
- Change the color scheme to be softer and compatible with the app icon, and change the layout when viewing a card to be cleaner. ([pull #107](https://github.com/brarcher/loyalty-card-locker/pull/107))
|
||||
- Add an intro wizard which launches on the app's first launch. ([pull #108](https://github.com/brarcher/loyalty-card-locker/pull/108))
|
||||
|
||||
## v0.10 (2017-02-12)
|
||||
|
||||
Improvements:
|
||||
## v0.10 - 10 (2017-02-12)
|
||||
|
||||
- Changed the default import/export filename. ([pull #84](https://github.com/brarcher/loyalty-card-locker/pull/84))
|
||||
- Correct string on the import/export page. ([pull #87](https://github.com/brarcher/loyalty-card-locker/pull/87))
|
||||
- Improve layout of card view page. The text should be easier to read, and is selectable with a long click. ([pull #91](https://github.com/brarcher/loyalty-card-locker/pull/91))
|
||||
|
||||
## v0.9 (2017-01-17)
|
||||
## v0.9 - 9 (2017-01-17)
|
||||
|
||||
The "Locker" part of the name was not intuitive. To help remedy this a new application icon was created by betsythefc which better represents the purpose of the application: to store loyalty cards which use barcodes. Along with this new icon the name of the application has been changed to "Loyalty Card Keychain".
|
||||
|
||||
@@ -533,55 +465,36 @@ Additional features/improvements:
|
||||
- Translations for Lithuanian added. ([pull #62](https://github.com/brarcher/loyalty-card-locker/pull/62))
|
||||
- Translations for French added. ([pull #80](https://github.com/brarcher/loyalty-card-locker/pull/80))
|
||||
|
||||
## v0.8 (2016-11-22)
|
||||
|
||||
New features/improvements:
|
||||
## v0.8 - 8 (2016-11-22)
|
||||
|
||||
- Screen brightness increased to its maximum when displaying a card, to help barcode scanners successfully capture the barcode. ([pull #54](https://github.com/brarcher/loyalty-card-locker/pull/54))
|
||||
- Add a delete confirmation when deleting a card. ([pull #55](https://github.com/brarcher/loyalty-card-locker/pull/55))
|
||||
- Add translations for German ([pull #57](https://github.com/brarcher/loyalty-card-locker/pull/57)) and Czech ([pull #58](https://github.com/brarcher/loyalty-card-locker/pull/58)).
|
||||
- Clarification change for Italian translation. ([pull #66](https://github.com/brarcher/loyalty-card-locker/pull/66))
|
||||
|
||||
## v0.7 (2016-07-14)
|
||||
|
||||
New features/improvements:
|
||||
## v0.7 - 7 (2016-07-14)
|
||||
|
||||
- Long-click of a card brings up option to copy card ID to the clipboard. ([pull #49](https://github.com/brarcher/loyalty-card-locker/issues/49))
|
||||
|
||||
Bug fixes:
|
||||
|
||||
- Back button on Input/Export view now works, moving user to main view
|
||||
|
||||
## v0.6 (2016-05-23)
|
||||
|
||||
New features/improvements:
|
||||
## v0.6 - 6 (2016-05-23)
|
||||
|
||||
- Allow user to enter barcode manually. If a user elects to enter a barcode manually, a list of all valid and supported barcode images is displayed. The user then may select the barcode image which matches what the user wants. [issue #33](https://github.com/brarcher/loyalty-card-locker/issues/33), [pull #44](https://github.com/brarcher/loyalty-card-locker/pull/44)
|
||||
|
||||
Bug fixes:
|
||||
|
||||
- Resolve issue where some displayed barcodes were blurry. ([issue #37](https://github.com/brarcher/loyalty-card-locker/issues/37))
|
||||
|
||||
## v0.5 (2016-05-16)
|
||||
|
||||
New features/improvements:
|
||||
## v0.5 - 5 (2016-05-16)
|
||||
|
||||
- An about dialog can be opened from the main screen, which gives details about the application and project on GitHub ([issue #19](https://github.com/brarcher/loyalty-card-locker/issues/19))
|
||||
- Allow loyalty card information to be imported from/exported to a CSV file in external storage ([issue #36](https://github.com/brarcher/loyalty-card-locker/issues/36), [issue #20](https://github.com/brarcher/loyalty-card-locker/issues/20))
|
||||
|
||||
## v0.4 (2016-04-09)
|
||||
|
||||
New features/improvements:
|
||||
## v0.4 - 4 (2016-04-09)
|
||||
|
||||
- Dutch translation
|
||||
- Allow name field to be editable after adding loyalty card
|
||||
- Add an optional note field
|
||||
|
||||
Bug fixes:
|
||||
|
||||
- Resolve all issues identified by FindBugs and require all FindBugs issues be resolved prior to pull request acceptance
|
||||
|
||||
## v0.3 (2016-02-11)
|
||||
## v0.3 - 3 (2016-02-11)
|
||||
|
||||
- Now officially supports the following list of 1D and 2D barcodes:
|
||||
- AZTEC
|
||||
@@ -598,13 +511,13 @@ Bug fixes:
|
||||
|
||||
- Generated barcodes are larger, easier to scan from a scanning device
|
||||
|
||||
## v0.2 (2016-02-07)
|
||||
## v0.2 - 2 (2016-02-07)
|
||||
|
||||
- Italian translations
|
||||
- Support for all 1D barcode types. (Originally only product 1D barcodes were supported)
|
||||
- Add required camera permission, which was initially missing.
|
||||
|
||||
## v0.1 (2016-01-30)
|
||||
## v0.1 - 1 (2016-01-30)
|
||||
|
||||
- Ability to create/edit/delete loyalty cards
|
||||
- Capture barcode of loyalty card using a camera
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
How to Submit Patches to the Loyalty Card Keychain Project
|
||||
How to Submit Patches to the Catima Project
|
||||
===============================================================================
|
||||
https://github.com/brarcher/budget-watch
|
||||
https://github.com/TheLastProject/Catima
|
||||
|
||||
This document is intended to act as a guide to help you contribute to the
|
||||
Loyalty Card Keychain 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.
|
||||
@@ -21,16 +21,16 @@ These are the Android lint checker, run using:
|
||||
|
||||
# ./gradlew lintRelease
|
||||
|
||||
and FindBugs, run using:
|
||||
and SpotBugs, run using:
|
||||
|
||||
# ./gradlew findbugs
|
||||
# ./gradlew spotbugsRelease
|
||||
|
||||
The final check is by testing the application on a live device and verifying
|
||||
the basic functionality works as expected.
|
||||
|
||||
## Make Sure Your Code is Tested
|
||||
|
||||
The Loyalty Card Keychain code uses a fair number of unit tests to verify that
|
||||
The Catima code uses a fair number of unit tests to verify that
|
||||
the basic functionality is working. Submissions which add functionality
|
||||
or significantly change the existing code should include additional tests
|
||||
to verify the proper operation of the proposed changes.
|
||||
@@ -85,7 +85,7 @@ your real name, saying:
|
||||
## Submit Patch(es) for Review
|
||||
|
||||
Finally, you will need to submit your patches so that they can be reviewed
|
||||
and potentially merged into the main Loyalty Card Keychain repository. The preferred
|
||||
way to do this is to submit a Pull Request to the Loyalty Card Keychain project.
|
||||
and potentially merged into the main Catima repository. The preferred
|
||||
way to do this is to submit a Pull Request to the Catima project.
|
||||
Changes need to apply cleanly onto the master branch and pass all
|
||||
unit tests and produce no errors during static analysis.
|
||||
|
||||
155
Gemfile.lock
155
Gemfile.lock
@@ -1,58 +1,75 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.2)
|
||||
CFPropertyList (3.0.3)
|
||||
addressable (2.8.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
artifactory (3.0.15)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.1.0)
|
||||
aws-partitions (1.388.0)
|
||||
aws-sdk-core (3.109.1)
|
||||
aws-eventstream (1.2.0)
|
||||
aws-partitions (1.501.0)
|
||||
aws-sdk-core (3.121.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.239.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
jmespath (~> 1.0)
|
||||
aws-sdk-kms (1.39.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sdk-kms (1.48.0)
|
||||
aws-sdk-core (~> 3, >= 3.120.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.83.1)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sdk-s3 (1.102.0)
|
||||
aws-sdk-core (~> 3, >= 3.120.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sigv4 (1.2.2)
|
||||
aws-sigv4 (~> 1.4)
|
||||
aws-sigv4 (1.4.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
claide (1.0.3)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander-fastlane (4.4.6)
|
||||
highline (~> 1.7.2)
|
||||
commander (4.6.0)
|
||||
highline (~> 2.0.0)
|
||||
declarative (0.0.20)
|
||||
declarative-option (0.1.0)
|
||||
digest-crc (0.6.1)
|
||||
rake (~> 13.0)
|
||||
digest-crc (0.6.4)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.7.6)
|
||||
emoji_regex (3.2.0)
|
||||
excon (0.78.0)
|
||||
faraday (1.1.0)
|
||||
emoji_regex (3.2.2)
|
||||
excon (0.85.0)
|
||||
faraday (1.7.2)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-httpclient (~> 1.0.1)
|
||||
faraday-net_http (~> 1.0)
|
||||
faraday-net_http_persistent (~> 1.1)
|
||||
faraday-patron (~> 1.0)
|
||||
faraday-rack (~> 1.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ruby2_keywords
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-cookie_jar (0.0.7)
|
||||
faraday (>= 0.8.0)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday_middleware (1.0.0)
|
||||
faraday-em_http (1.0.0)
|
||||
faraday-em_synchrony (1.0.0)
|
||||
faraday-excon (1.1.0)
|
||||
faraday-httpclient (1.0.1)
|
||||
faraday-net_http (1.0.1)
|
||||
faraday-net_http_persistent (1.2.0)
|
||||
faraday-patron (1.0.0)
|
||||
faraday-rack (1.0.0)
|
||||
faraday_middleware (1.1.0)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.2.0)
|
||||
fastlane (2.165.0)
|
||||
fastimage (2.2.5)
|
||||
fastlane (2.193.1)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.3, < 3.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
aws-sdk-s3 (~> 1.0)
|
||||
babosa (>= 1.0.3, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored
|
||||
commander-fastlane (>= 4.4.6, < 5.0.0)
|
||||
commander (~> 4.6)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 4.0)
|
||||
excon (>= 0.71.0, < 1.0.0)
|
||||
@@ -61,18 +78,20 @@ GEM
|
||||
faraday_middleware (~> 1.0)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-api-client (>= 0.37.0, < 0.39.0)
|
||||
google-cloud-storage (>= 1.15.0, < 2.0.0)
|
||||
highline (>= 1.7.2, < 2.0.0)
|
||||
google-apis-androidpublisher_v3 (~> 0.3)
|
||||
google-apis-playcustomapp_v1 (~> 0.1)
|
||||
google-cloud-storage (~> 1.31)
|
||||
highline (~> 2.0)
|
||||
json (< 3.0.0)
|
||||
jwt (>= 2.1.0, < 3)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multipart-post (~> 2.0.0)
|
||||
naturally (~> 2.2)
|
||||
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)
|
||||
slack-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
@@ -82,73 +101,85 @@ GEM
|
||||
xcpretty (~> 0.3.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
gh_inspector (1.1.3)
|
||||
google-api-client (0.38.0)
|
||||
google-apis-androidpublisher_v3 (0.11.0)
|
||||
google-apis-core (>= 0.4, < 2.a)
|
||||
google-apis-core (0.4.1)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (~> 0.9)
|
||||
httpclient (>= 2.8.1, < 3.0)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
httpclient (>= 2.8.1, < 3.a)
|
||||
mini_mime (~> 1.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
signet (~> 0.12)
|
||||
google-cloud-core (1.5.0)
|
||||
retriable (>= 2.0, < 4.a)
|
||||
rexml
|
||||
webrick
|
||||
google-apis-iamcredentials_v1 (0.7.0)
|
||||
google-apis-core (>= 0.4, < 2.a)
|
||||
google-apis-playcustomapp_v1 (0.5.0)
|
||||
google-apis-core (>= 0.4, < 2.a)
|
||||
google-apis-storage_v1 (0.6.0)
|
||||
google-apis-core (>= 0.4, < 2.a)
|
||||
google-cloud-core (1.6.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.4.0)
|
||||
google-cloud-env (1.5.0)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
google-cloud-errors (1.0.1)
|
||||
google-cloud-storage (1.29.1)
|
||||
google-cloud-errors (1.1.0)
|
||||
google-cloud-storage (1.34.1)
|
||||
addressable (~> 2.5)
|
||||
digest-crc (~> 0.4)
|
||||
google-api-client (~> 0.33)
|
||||
google-cloud-core (~> 1.2)
|
||||
googleauth (~> 0.9)
|
||||
google-apis-iamcredentials_v1 (~> 0.1)
|
||||
google-apis-storage_v1 (~> 0.1)
|
||||
google-cloud-core (~> 1.6)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (0.14.0)
|
||||
googleauth (0.17.1)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (~> 0.14)
|
||||
highline (1.7.10)
|
||||
http-cookie (1.0.3)
|
||||
signet (~> 0.15)
|
||||
highline (2.0.3)
|
||||
http-cookie (1.0.4)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
jmespath (1.4.0)
|
||||
json (2.3.1)
|
||||
jwt (2.2.2)
|
||||
json (2.5.1)
|
||||
jwt (2.2.3)
|
||||
memoist (0.16.2)
|
||||
mini_magick (4.10.1)
|
||||
mini_mime (1.0.2)
|
||||
mini_magick (4.11.0)
|
||||
mini_mime (1.1.1)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.0.0)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.0)
|
||||
naturally (2.2.1)
|
||||
optparse (0.1.1)
|
||||
os (1.1.1)
|
||||
plist (3.5.0)
|
||||
plist (3.6.0)
|
||||
public_suffix (4.0.6)
|
||||
rake (13.0.1)
|
||||
representable (3.0.4)
|
||||
rake (13.0.6)
|
||||
representable (3.1.1)
|
||||
declarative (< 0.1.0)
|
||||
declarative-option (< 0.2.0)
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.2.5)
|
||||
rouge (2.0.7)
|
||||
ruby2_keywords (0.0.2)
|
||||
rubyzip (2.3.0)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
security (0.1.3)
|
||||
signet (0.14.0)
|
||||
addressable (~> 2.3)
|
||||
signet (0.16.0)
|
||||
addressable (~> 2.8)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.8)
|
||||
CFPropertyList
|
||||
naturally
|
||||
slack-notifier (2.3.2)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
trailblazer-option (0.1.1)
|
||||
tty-cursor (0.7.1)
|
||||
tty-screen (0.8.1)
|
||||
tty-spinner (0.9.3)
|
||||
@@ -156,18 +187,20 @@ GEM
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
unf_ext (0.0.8)
|
||||
unicode-display_width (1.7.0)
|
||||
webrick (1.7.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.19.0)
|
||||
xcodeproj (1.21.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.3.0)
|
||||
rexml (~> 3.2.4)
|
||||
xcpretty (0.3.0)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (1.0.0)
|
||||
xcpretty-travis-formatter (1.0.1)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
|
||||
@@ -11,15 +11,15 @@ spotbugs {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "30.0.3"
|
||||
compileSdkVersion 31
|
||||
buildToolsVersion "31.0.0"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "me.hackerchick.catima"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 30
|
||||
versionCode 79
|
||||
versionName "2.2.3"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 31
|
||||
versionCode 91
|
||||
versionName "2.9.0"
|
||||
|
||||
vectorDrawables.useSupportLibrary true
|
||||
multiDexEnabled true
|
||||
@@ -37,6 +37,12 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
bundle {
|
||||
language {
|
||||
enableSplit = false
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
encoding "UTF-8"
|
||||
|
||||
@@ -75,20 +81,24 @@ android {
|
||||
dependencies {
|
||||
// AndroidX
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.3'
|
||||
implementation 'androidx.palette:palette:1.0.0'
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation 'com.github.yalantis:ucrop:2.2.7'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
// Splash Screen
|
||||
implementation 'androidx.core:core-splashscreen:1.0.0-alpha02'
|
||||
|
||||
// Third-party
|
||||
implementation 'com.journeyapps:zxing-android-embedded:4.1.0@aar'
|
||||
implementation 'com.journeyapps:zxing-android-embedded:4.3.0@aar'
|
||||
implementation 'com.google.zxing:core:3.4.1'
|
||||
implementation 'org.apache.commons:commons-csv:1.8'
|
||||
implementation 'org.apache.commons:commons-csv:1.9.0'
|
||||
implementation 'com.jaredrummler:colorpicker:1.1.0'
|
||||
implementation 'com.github.invissvenska:NumberPickerPreference:1.0.3'
|
||||
implementation 'net.lingala.zip4j:zip4j:2.8.0'
|
||||
implementation 'net.lingala.zip4j:zip4j:2.9.0'
|
||||
|
||||
// SpotBugs
|
||||
implementation 'io.wcm.tooling.spotbugs:io.wcm.tooling.spotbugs.annotations:1.0.0'
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="protect.card_locker"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="protect.card_locker">
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.CAMERA"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
@@ -17,8 +16,6 @@
|
||||
android:name="android.hardware.camera.autofocus"
|
||||
android:required="false" />
|
||||
|
||||
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
|
||||
|
||||
<application
|
||||
android:name=".LoyaltyCardLockerApplication"
|
||||
android:allowBackup="true"
|
||||
@@ -27,47 +24,64 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name="protect.card_locker.MainActivity"
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/SplashTheme">
|
||||
android:theme="@style/Theme.App.Starting">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".AboutActivity"
|
||||
android:label="@string/about"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
</activity>
|
||||
android:theme="@style/AppTheme.NoActionBar"></activity>
|
||||
<activity
|
||||
android:name=".ManageGroupsActivity"
|
||||
android:label="@string/groups"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
</activity>
|
||||
android:theme="@style/AppTheme.NoActionBar"></activity>
|
||||
<activity
|
||||
android:name=".ManageGroupActivity"
|
||||
android:label="@string/group_edit"
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
<activity
|
||||
android:name=".LoyaltyCardViewActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:exported="true"/>
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
<activity
|
||||
android:name=".LoyaltyCardEditActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:exported="true">
|
||||
<intent-filter android:label="@string/app_name">
|
||||
android:windowSoftInputMode="stateHidden">
|
||||
<intent-filter
|
||||
android:autoVerify="true"
|
||||
android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- Listen to known card sharing URIs -->
|
||||
<data android:scheme="https"
|
||||
<!-- Main card sharing URIs -->
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data
|
||||
android:host="@string/intent_import_card_from_url_host_catima_app"
|
||||
android:pathPrefix="@string/intent_import_card_from_url_path_prefix_catima_app" />
|
||||
<data android:scheme="https"
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- Old card sharing URIs -->
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data
|
||||
android:host="@string/intent_import_card_from_url_host_thelastproject"
|
||||
android:pathPrefix="@string/intent_import_card_from_url_path_prefix_thelastproject" />
|
||||
<data android:scheme="https"
|
||||
<data
|
||||
android:host="@string/intent_import_card_from_url_host_brarcher"
|
||||
android:pathPrefix="@string/intent_import_card_from_url_path_prefix_brarcher" />
|
||||
</intent-filter>
|
||||
@@ -75,37 +89,45 @@
|
||||
<activity
|
||||
android:name=".ScanActivity"
|
||||
android:label="@string/scanCardBarcode"
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
<activity
|
||||
android:name=".BarcodeSelectorActivity"
|
||||
android:label="@string/selectBarcodeTitle"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:windowSoftInputMode="stateHidden"/>
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
<activity
|
||||
android:name=".preferences.SettingsActivity"
|
||||
android:label="@string/settings"/>
|
||||
android:label="@string/settings"
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
<activity
|
||||
android:name=".ImportExportActivity"
|
||||
android:label="@string/importExport"
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
<activity
|
||||
android:name=".CardShortcutConfigure"
|
||||
android:exported="true"
|
||||
android:label="@string/cardShortcut"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.CREATE_SHORTCUT"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<action android:name="android.intent.action.CREATE_SHORTCUT" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.yalantis.ucrop.UCropActivity"
|
||||
android:theme="@style/Theme.AppCompat.NoActionBar"/>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:grantUriPermissions="true"
|
||||
android:authorities="${applicationId}"
|
||||
android:exported="false"
|
||||
android:authorities="${applicationId}">
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_provider_paths"/>
|
||||
android:resource="@xml/file_provider_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
||||
@@ -1,39 +1,64 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
|
||||
public class AboutActivity extends AppCompatActivity
|
||||
{
|
||||
public class AboutActivity extends CatimaAppCompatActivity implements View.OnClickListener {
|
||||
private static final String TAG = "Catima";
|
||||
ConstraintLayout version_history, translate, license, repo, privacy, error, credits, rate;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(R.string.about);
|
||||
setContentView(R.layout.about_activity);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
StringBuilder contributors = new StringBuilder().append("<br/>");
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.contributors), StandardCharsets.UTF_8));
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
String tmp = reader.readLine();
|
||||
|
||||
if (tmp == null || tmp.isEmpty()) {
|
||||
reader.close();
|
||||
break;
|
||||
}
|
||||
|
||||
contributors.append("<br/>");
|
||||
contributors.append(tmp);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
final List<ThirdPartyInfo> USED_LIBRARIES = new ArrayList<>();
|
||||
USED_LIBRARIES.add(new ThirdPartyInfo("Color Picker", "https://github.com/jaredrummler/ColorPicker", "Apache 2.0"));
|
||||
USED_LIBRARIES.add(new ThirdPartyInfo("Commons CSV", "https://commons.apache.org/proper/commons-csv/", "Apache 2.0"));
|
||||
@@ -46,62 +71,102 @@ public class AboutActivity extends AppCompatActivity
|
||||
USED_ASSETS.add(new ThirdPartyInfo("Android icons", "https://fonts.google.com/icons?selected=Material+Icons", "Apache 2.0"));
|
||||
|
||||
StringBuilder libs = new StringBuilder().append("<br/>");
|
||||
for (ThirdPartyInfo entry : USED_LIBRARIES)
|
||||
{
|
||||
libs.append("<br/><a href=\"").append(entry.url()).append("\">").append(entry.name()).append("</a> (").append(entry.license()).append(")<br/>");
|
||||
for (ThirdPartyInfo entry : USED_LIBRARIES) {
|
||||
libs.append("<br/><a href=\"").append(entry.url()).append("\">").append(entry.name()).append("</a> (").append(entry.license()).append(")");
|
||||
}
|
||||
|
||||
StringBuilder resources = new StringBuilder().append("<br/>");
|
||||
for (ThirdPartyInfo entry : USED_ASSETS)
|
||||
{
|
||||
resources.append("<br/><a href=\"").append(entry.url()).append("\">").append(entry.name()).append("</a> (").append(entry.license()).append(")<br/>");
|
||||
for (ThirdPartyInfo entry : USED_ASSETS) {
|
||||
resources.append("<br/><a href=\"").append(entry.url()).append("\">").append(entry.name()).append("</a> (").append(entry.license()).append(")");
|
||||
}
|
||||
|
||||
String appName = getString(R.string.app_name);
|
||||
int year = Calendar.getInstance().get(Calendar.YEAR);
|
||||
|
||||
String version = "?";
|
||||
try
|
||||
{
|
||||
try {
|
||||
PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0);
|
||||
version = pi.versionName;
|
||||
}
|
||||
catch (PackageManager.NameNotFoundException e)
|
||||
{
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, "Package name not found", e);
|
||||
}
|
||||
|
||||
TextView copyright = findViewById(R.id.credits_sub);
|
||||
copyright.setText(String.format(getString(R.string.app_copyright_fmt), year));
|
||||
TextView vHistory = findViewById(R.id.version_history_sub);
|
||||
vHistory.setText(String.format(getString(R.string.debug_version_fmt), version));
|
||||
|
||||
setTitle(String.format(getString(R.string.about_title_fmt), appName));
|
||||
|
||||
TextView aboutTextView = findViewById(R.id.aboutText);
|
||||
aboutTextView.setText(HtmlCompat.fromHtml(String.format(getString(R.string.debug_version_fmt), version) +
|
||||
"<br/><br/>" +
|
||||
String.format(getString(R.string.app_revision_fmt),
|
||||
"<a href=\"" + getString(R.string.app_revision_url) + "\">" +
|
||||
"GitHub" +
|
||||
"</a>") +
|
||||
"<br/><br/>" +
|
||||
String.format(getString(R.string.app_copyright_fmt), year) +
|
||||
"<br/><br/>" +
|
||||
getString(R.string.app_copyright_old) +
|
||||
"<br/><br/>" +
|
||||
getString(R.string.app_license) +
|
||||
"<br/><br/>" +
|
||||
String.format(getString(R.string.app_libraries), libs.toString()) +
|
||||
"<br/><br/>" +
|
||||
String.format(getString(R.string.app_resources), resources.toString()), HtmlCompat.FROM_HTML_MODE_COMPACT));
|
||||
aboutTextView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
version_history = findViewById(R.id.version_history);
|
||||
translate = findViewById(R.id.translate);
|
||||
license = findViewById(R.id.license);
|
||||
repo = findViewById(R.id.repo);
|
||||
privacy = findViewById(R.id.privacy);
|
||||
error = findViewById(R.id.report_error);
|
||||
credits = findViewById(R.id.credits);
|
||||
rate = findViewById(R.id.rate);
|
||||
|
||||
version_history.setOnClickListener(this);
|
||||
translate.setOnClickListener(this);
|
||||
license.setOnClickListener(this);
|
||||
repo.setOnClickListener(this);
|
||||
privacy.setOnClickListener(this);
|
||||
error.setOnClickListener(this);
|
||||
rate.setOnClickListener(this);
|
||||
|
||||
StringBuilder contributorInfo = new StringBuilder();
|
||||
contributorInfo.append(HtmlCompat.fromHtml(String.format(getString(R.string.app_contributors), contributors.toString()), HtmlCompat.FROM_HTML_MODE_COMPACT));
|
||||
contributorInfo.append("\n\n");
|
||||
contributorInfo.append(getString(R.string.app_copyright_old));
|
||||
contributorInfo.append("\n\n");
|
||||
contributorInfo.append(HtmlCompat.fromHtml(String.format(getString(R.string.app_libraries), libs.toString()), HtmlCompat.FROM_HTML_MODE_COMPACT));
|
||||
contributorInfo.append("\n\n");
|
||||
contributorInfo.append(HtmlCompat.fromHtml(String.format(getString(R.string.app_resources), resources.toString()), HtmlCompat.FROM_HTML_MODE_COMPACT));
|
||||
|
||||
credits.setOnClickListener(view -> new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.credits)
|
||||
.setMessage(contributorInfo.toString())
|
||||
.setPositiveButton(R.string.ok, (dialogInterface, i) -> {
|
||||
})
|
||||
.show());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
|
||||
if (id == android.R.id.home) {
|
||||
finish();
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
int id = view.getId();
|
||||
|
||||
String url;
|
||||
if (id == R.id.version_history) {
|
||||
url = "https://catima.app/changelog/";
|
||||
} else if (id == R.id.translate) {
|
||||
url = "https://hosted.weblate.org/engage/catima/";
|
||||
} else if (id == R.id.license) {
|
||||
url = "https://github.com/TheLastProject/Catima/blob/master/LICENSE";
|
||||
} else if (id == R.id.repo) {
|
||||
url = "https://github.com/TheLastProject/Catima/";
|
||||
} else if (id == R.id.privacy) {
|
||||
url = "https://catima.app/privacy-policy/";
|
||||
} else if (id == R.id.report_error) {
|
||||
url = "https://github.com/TheLastProject/Catima/issues";
|
||||
} else if (id == R.id.rate) {
|
||||
url = "https://play.google.com/store/apps/details?id=me.hackerchick.catima";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,31 +1,32 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import protect.card_locker.async.CompatCallable;
|
||||
|
||||
/**
|
||||
* This task will generate a barcode and load it into an ImageView.
|
||||
* Only a weak reference of the ImageView is kept, so this class will not
|
||||
* prevent the ImageView from being garbage collected.
|
||||
*/
|
||||
class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
{
|
||||
public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
private static final int IS_VALID = 999;
|
||||
private final Context mContext;
|
||||
private boolean isSuccesful;
|
||||
|
||||
// When drawn in a smaller window 1D barcodes for some reason end up
|
||||
@@ -36,16 +37,19 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
private final WeakReference<ImageView> imageViewReference;
|
||||
private final WeakReference<TextView> textViewReference;
|
||||
private String cardId;
|
||||
private final BarcodeFormat format;
|
||||
private final CatimaBarcode format;
|
||||
private final int imageHeight;
|
||||
private final int imageWidth;
|
||||
private final boolean showFallback;
|
||||
private final Runnable callback;
|
||||
|
||||
BarcodeImageWriterTask(ImageView imageView, String cardIdString,
|
||||
BarcodeFormat barcodeFormat, TextView textView,
|
||||
boolean showFallback, Runnable callback)
|
||||
{
|
||||
BarcodeImageWriterTask(
|
||||
Context context, ImageView imageView, String cardIdString,
|
||||
CatimaBarcode barcodeFormat, TextView textView,
|
||||
boolean showFallback, Runnable callback
|
||||
) {
|
||||
mContext = context;
|
||||
|
||||
isSuccesful = true;
|
||||
this.callback = callback;
|
||||
|
||||
@@ -58,26 +62,21 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
|
||||
final int MAX_WIDTH = getMaxWidth(format);
|
||||
|
||||
if(imageView.getWidth() < MAX_WIDTH)
|
||||
{
|
||||
if (imageView.getWidth() < MAX_WIDTH) {
|
||||
imageHeight = imageView.getHeight();
|
||||
imageWidth = imageView.getWidth();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Scale down the image to reduce the memory needed to produce it
|
||||
imageWidth = MAX_WIDTH;
|
||||
double ratio = (double)MAX_WIDTH / (double)imageView.getWidth();
|
||||
imageHeight = (int)(imageView.getHeight() * ratio);
|
||||
double ratio = (double) MAX_WIDTH / (double) imageView.getWidth();
|
||||
imageHeight = (int) (imageView.getHeight() * ratio);
|
||||
}
|
||||
|
||||
this.showFallback = showFallback;
|
||||
}
|
||||
|
||||
private int getMaxWidth(BarcodeFormat format)
|
||||
{
|
||||
switch(format)
|
||||
{
|
||||
private int getMaxWidth(CatimaBarcode format) {
|
||||
switch (format.format()) {
|
||||
// 2D barcodes
|
||||
case AZTEC:
|
||||
case DATA_MATRIX:
|
||||
@@ -104,10 +103,8 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
}
|
||||
}
|
||||
|
||||
private String getFallbackString(BarcodeFormat format)
|
||||
{
|
||||
switch(format)
|
||||
{
|
||||
private String getFallbackString(CatimaBarcode format) {
|
||||
switch (format.format()) {
|
||||
// 2D barcodes
|
||||
case AZTEC:
|
||||
return "AZTEC";
|
||||
@@ -140,23 +137,17 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap generate()
|
||||
{
|
||||
if (cardId.isEmpty())
|
||||
{
|
||||
private Bitmap generate() {
|
||||
if (cardId.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MultiFormatWriter writer = new MultiFormatWriter();
|
||||
BitMatrix bitMatrix;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
bitMatrix = writer.encode(cardId, format, imageWidth, imageHeight, null);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
try {
|
||||
try {
|
||||
bitMatrix = writer.encode(cardId, format.format(), imageWidth, imageHeight, null);
|
||||
} catch (Exception e) {
|
||||
// Cast a wider net here and catch any exception, as there are some
|
||||
// cases where an encoder may fail if the data is invalid for the
|
||||
// barcode type. If this happens, we want to fail gracefully.
|
||||
@@ -171,11 +162,9 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
|
||||
int[] pixels = new int[bitMatrixWidth * bitMatrixHeight];
|
||||
|
||||
for (int y = 0; y < bitMatrixHeight; y++)
|
||||
{
|
||||
for (int y = 0; y < bitMatrixHeight; y++) {
|
||||
int offset = y * bitMatrixWidth;
|
||||
for (int x = 0; x < bitMatrixWidth; x++)
|
||||
{
|
||||
for (int x = 0; x < bitMatrixWidth; x++) {
|
||||
int color = bitMatrix.get(x, y) ? BLACK : WHITE;
|
||||
pixels[offset + x] = color;
|
||||
}
|
||||
@@ -195,19 +184,14 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
int widthScale = imageWidth / bitMatrixHeight;
|
||||
int scalingFactor = Math.min(heightScale, widthScale);
|
||||
|
||||
if(scalingFactor > 1)
|
||||
{
|
||||
if (scalingFactor > 1) {
|
||||
bitmap = Bitmap.createScaledBitmap(bitmap, bitMatrixWidth * scalingFactor, bitMatrixHeight * scalingFactor, false);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
catch (WriterException e)
|
||||
{
|
||||
} catch (WriterException e) {
|
||||
Log.e(TAG, "Failed to generate barcode of type " + format + ": " + cardId, e);
|
||||
}
|
||||
catch(OutOfMemoryError e)
|
||||
{
|
||||
} catch (OutOfMemoryError e) {
|
||||
Log.w(TAG, "Insufficient memory to render barcode, "
|
||||
+ imageWidth + "x" + imageHeight + ", " + format.name()
|
||||
+ ", length=" + cardId.length(), e);
|
||||
@@ -216,40 +200,49 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
return null;
|
||||
}
|
||||
|
||||
public Bitmap doInBackground(Void... params)
|
||||
{
|
||||
Bitmap bitmap = generate();
|
||||
public Bitmap doInBackground(Void... params) {
|
||||
// Only do the hard tasks if we've not already been cancelled
|
||||
if (!Thread.currentThread().isInterrupted()) {
|
||||
Bitmap bitmap = generate();
|
||||
|
||||
if (bitmap == null) {
|
||||
isSuccesful = false;
|
||||
if (bitmap == null) {
|
||||
isSuccesful = false;
|
||||
|
||||
if (showFallback) {
|
||||
Log.i(TAG, "Barcode generation failed, generating fallback...");
|
||||
cardId = getFallbackString(format);
|
||||
bitmap = generate();
|
||||
if (showFallback && !Thread.currentThread().isInterrupted()) {
|
||||
Log.i(TAG, "Barcode generation failed, generating fallback...");
|
||||
cardId = getFallbackString(format);
|
||||
bitmap = generate();
|
||||
return bitmap;
|
||||
}
|
||||
} else {
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
// We've been interrupted - create a empty fallback
|
||||
Bitmap.Config config = Bitmap.Config.ARGB_8888;
|
||||
return Bitmap.createBitmap(imageWidth, imageHeight, config);
|
||||
}
|
||||
|
||||
protected void onPostExecute(Bitmap result)
|
||||
{
|
||||
public void onPostExecute(Object castResult) {
|
||||
Bitmap result = (Bitmap) castResult;
|
||||
|
||||
Log.i(TAG, "Finished generating barcode image of type " + format + ": " + cardId);
|
||||
ImageView imageView = imageViewReference.get();
|
||||
if(imageView == null)
|
||||
{
|
||||
if (imageView == null) {
|
||||
// The ImageView no longer exists, nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
String formatPrettyName = format.prettyName();
|
||||
|
||||
imageView.setTag(isSuccesful);
|
||||
|
||||
imageView.setImageBitmap(result);
|
||||
imageView.setContentDescription(mContext.getString(R.string.barcodeImageDescriptionWithType, formatPrettyName));
|
||||
TextView textView = textViewReference.get();
|
||||
|
||||
if(result != null)
|
||||
{
|
||||
if (result != null) {
|
||||
Log.i(TAG, "Displaying barcode");
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
|
||||
@@ -261,11 +254,9 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
|
||||
if (textView != null) {
|
||||
textView.setVisibility(View.VISIBLE);
|
||||
textView.setText(format.name());
|
||||
textView.setText(formatPrettyName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Log.i(TAG, "Barcode generation failed, removing image from display");
|
||||
imageView.setVisibility(View.GONE);
|
||||
if (textView != null) {
|
||||
@@ -277,4 +268,19 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreExecute() {
|
||||
// No Action
|
||||
}
|
||||
|
||||
/**
|
||||
* Provided to comply with Callable while keeping the original Syntax of AsyncTask
|
||||
*
|
||||
* @return generated Bitmap
|
||||
*/
|
||||
@Override
|
||||
public Bitmap call() {
|
||||
return doInBackground();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ package protect.card_locker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.MenuItem;
|
||||
@@ -16,16 +17,12 @@ import android.widget.Toast;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import protect.card_locker.async.TaskHandler;
|
||||
|
||||
/**
|
||||
* This activity is callable and will allow a user to enter
|
||||
@@ -33,47 +30,29 @@ import androidx.appcompat.widget.Toolbar;
|
||||
* the data. The user may then select any barcode, where its
|
||||
* data and type will be returned to the caller.
|
||||
*/
|
||||
public class BarcodeSelectorActivity extends AppCompatActivity
|
||||
{
|
||||
public class BarcodeSelectorActivity extends CatimaAppCompatActivity {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
// Result this activity will return
|
||||
public static final String BARCODE_CONTENTS = "contents";
|
||||
public static final String BARCODE_FORMAT = "format";
|
||||
|
||||
// These are all the barcode types that the zxing library
|
||||
// is able to generate a barcode for, and thus should be
|
||||
// the only barcodes which we should attempt to scan.
|
||||
public static final Collection<String> SUPPORTED_BARCODE_TYPES = Collections.unmodifiableList(
|
||||
Arrays.asList(
|
||||
BarcodeFormat.AZTEC.name(),
|
||||
BarcodeFormat.CODE_39.name(),
|
||||
BarcodeFormat.CODE_128.name(),
|
||||
BarcodeFormat.CODABAR.name(),
|
||||
BarcodeFormat.DATA_MATRIX.name(),
|
||||
BarcodeFormat.EAN_8.name(),
|
||||
BarcodeFormat.EAN_13.name(),
|
||||
BarcodeFormat.ITF.name(),
|
||||
BarcodeFormat.PDF_417.name(),
|
||||
BarcodeFormat.QR_CODE.name(),
|
||||
BarcodeFormat.UPC_A.name(),
|
||||
BarcodeFormat.UPC_E.name()
|
||||
));
|
||||
|
||||
private Map<String, Pair<Integer, Integer>> barcodeViewMap;
|
||||
private LinkedList<AsyncTask> barcodeGeneratorTasks = new LinkedList<>();
|
||||
|
||||
final private TaskHandler mTasks = new TaskHandler();
|
||||
|
||||
private final Handler typingDelayHandler = new Handler(Looper.getMainLooper());
|
||||
public static final Integer INPUT_DELAY = 250;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setTitle(R.string.selectBarcodeTitle);
|
||||
setContentView(R.layout.barcode_selector_activity);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@@ -92,26 +71,31 @@ public class BarcodeSelectorActivity extends AppCompatActivity
|
||||
barcodeViewMap.put(BarcodeFormat.UPC_E.name(), new Pair<>(R.id.upceBarcode, R.id.upceBarcodeText));
|
||||
|
||||
EditText cardId = findViewById(R.id.cardId);
|
||||
cardId.addTextChangedListener(new SimpleTextWatcher()
|
||||
{
|
||||
|
||||
cardId.addTextChangedListener(new SimpleTextWatcher() {
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count)
|
||||
{
|
||||
Log.d(TAG, "Entered text: " + s);
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Delay the input processing so we avoid overload
|
||||
typingDelayHandler.removeCallbacksAndMessages(null);
|
||||
|
||||
generateBarcodes(s.toString());
|
||||
typingDelayHandler.postDelayed(() -> {
|
||||
Log.d(TAG, "Entered text: " + s);
|
||||
|
||||
View noBarcodeButtonView = findViewById(R.id.noBarcode);
|
||||
setButtonListener(noBarcodeButtonView, s.toString());
|
||||
noBarcodeButtonView.setEnabled(s.length() > 0);
|
||||
runOnUiThread(() -> {
|
||||
generateBarcodes(s.toString());
|
||||
|
||||
View noBarcodeButtonView = findViewById(R.id.noBarcode);
|
||||
setButtonListener(noBarcodeButtonView, s.toString());
|
||||
noBarcodeButtonView.setEnabled(s.length() > 0);
|
||||
});
|
||||
}, INPUT_DELAY);
|
||||
}
|
||||
});
|
||||
|
||||
final Bundle b = getIntent().getExtras();
|
||||
final String initialCardId = b != null ? b.getString("initialCardId") : null;
|
||||
|
||||
if(initialCardId != null)
|
||||
{
|
||||
if (initialCardId != null) {
|
||||
cardId.setText(initialCardId);
|
||||
} else {
|
||||
generateBarcodes("");
|
||||
@@ -119,101 +103,74 @@ public class BarcodeSelectorActivity extends AppCompatActivity
|
||||
}
|
||||
|
||||
private void generateBarcodes(String value) {
|
||||
// Stop any async tasks which may not have been started yet
|
||||
for(AsyncTask task : barcodeGeneratorTasks)
|
||||
{
|
||||
task.cancel(false);
|
||||
}
|
||||
barcodeGeneratorTasks.clear();
|
||||
// Attempt to stop any async tasks which may not have been started yet
|
||||
// TODO this can be very much optimized by only generating Barcodes visible to the User
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.BARCODE, true, false, false);
|
||||
|
||||
// Update barcodes
|
||||
for(Map.Entry<String, Pair<Integer, Integer>> entry : barcodeViewMap.entrySet())
|
||||
{
|
||||
for (Map.Entry<String, Pair<Integer, Integer>> entry : barcodeViewMap.entrySet()) {
|
||||
ImageView image = findViewById(entry.getValue().first);
|
||||
TextView text = findViewById(entry.getValue().second);
|
||||
createBarcodeOption(image, entry.getKey(), value, text);
|
||||
}
|
||||
}
|
||||
|
||||
private void setButtonListener(final View button, final String cardId)
|
||||
{
|
||||
button.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View 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();
|
||||
}
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
private void createBarcodeOption(final ImageView image, final String formatType, final String cardId, final TextView text)
|
||||
{
|
||||
final BarcodeFormat format = BarcodeFormat.valueOf(formatType);
|
||||
if(format == null)
|
||||
{
|
||||
Log.w(TAG, "Unsupported barcode format: " + formatType);
|
||||
return;
|
||||
}
|
||||
private void createBarcodeOption(final ImageView image, final String formatType, final String cardId, final TextView text) {
|
||||
final CatimaBarcode format = CatimaBarcode.fromName(formatType);
|
||||
|
||||
image.setImageBitmap(null);
|
||||
image.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
Log.d(TAG, "Selected barcode type " + formatType);
|
||||
image.setOnClickListener(v -> {
|
||||
Log.d(TAG, "Selected barcode type " + formatType);
|
||||
|
||||
if (!((boolean) image.getTag())) {
|
||||
Toast.makeText(BarcodeSelectorActivity.this, getString(R.string.wrongValueForBarcodeType), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
Intent result = new Intent();
|
||||
result.putExtra(BARCODE_FORMAT, formatType);
|
||||
result.putExtra(BARCODE_CONTENTS, cardId);
|
||||
BarcodeSelectorActivity.this.setResult(RESULT_OK, result);
|
||||
finish();
|
||||
if (!((boolean) image.getTag())) {
|
||||
Toast.makeText(BarcodeSelectorActivity.this, getString(R.string.wrongValueForBarcodeType), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
Intent result = new Intent();
|
||||
result.putExtra(BARCODE_FORMAT, formatType);
|
||||
result.putExtra(BARCODE_CONTENTS, cardId);
|
||||
BarcodeSelectorActivity.this.setResult(RESULT_OK, result);
|
||||
finish();
|
||||
});
|
||||
|
||||
if(image.getHeight() == 0)
|
||||
{
|
||||
if (image.getHeight() == 0) {
|
||||
// The size of the ImageView is not yet available as it has not
|
||||
// yet been drawn. Wait for it to be drawn so the size is available.
|
||||
image.getViewTreeObserver().addOnGlobalLayoutListener(
|
||||
new ViewTreeObserver.OnGlobalLayoutListener()
|
||||
{
|
||||
@Override
|
||||
public void onGlobalLayout()
|
||||
{
|
||||
Log.d(TAG, "Global layout finished, type: + " + formatType + ", width: " + image.getWidth());
|
||||
image.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
Log.d(TAG, "Global layout finished, type: + " + formatType + ", width: " + image.getWidth());
|
||||
image.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
|
||||
Log.d(TAG, "Generating barcode for type " + formatType);
|
||||
BarcodeImageWriterTask task = new BarcodeImageWriterTask(image, cardId, format, text, true, null);
|
||||
barcodeGeneratorTasks.add(task);
|
||||
task.execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "Generating barcode for type " + formatType);
|
||||
|
||||
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), image, cardId, format, text, true, null);
|
||||
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Log.d(TAG, "Generating barcode for type " + formatType);
|
||||
BarcodeImageWriterTask task = new BarcodeImageWriterTask(image, cardId, format, text, true, null);
|
||||
barcodeGeneratorTasks.add(task);
|
||||
task.execute();
|
||||
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), image, cardId, format, text, true, null);
|
||||
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
if (item.getItemId() == android.R.id.home)
|
||||
{
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
return true;
|
||||
|
||||
@@ -4,14 +4,12 @@ import android.database.Cursor;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public abstract class BaseCursorAdapter<V extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<V>
|
||||
{
|
||||
public abstract class BaseCursorAdapter<V extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<V> {
|
||||
private Cursor mCursor;
|
||||
private boolean mDataValid;
|
||||
private int mRowIDColumn;
|
||||
|
||||
public BaseCursorAdapter(Cursor inputCursor)
|
||||
{
|
||||
public BaseCursorAdapter(Cursor inputCursor) {
|
||||
setHasStableIds(true);
|
||||
swapCursor(inputCursor);
|
||||
}
|
||||
@@ -19,15 +17,12 @@ public abstract class BaseCursorAdapter<V extends RecyclerView.ViewHolder> exten
|
||||
public abstract void onBindViewHolder(V inputHolder, Cursor inputCursor);
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(V inputHolder, int inputPosition)
|
||||
{
|
||||
if (!mDataValid)
|
||||
{
|
||||
public void onBindViewHolder(V inputHolder, int inputPosition) {
|
||||
if (!mDataValid) {
|
||||
throw new IllegalStateException("Cannot bind view holder when cursor is in invalid state.");
|
||||
}
|
||||
|
||||
if (!mCursor.moveToPosition(inputPosition))
|
||||
{
|
||||
if (!mCursor.moveToPosition(inputPosition)) {
|
||||
throw new IllegalStateException("Could not move cursor to position " + inputPosition + " when trying to bind view holder");
|
||||
}
|
||||
|
||||
@@ -35,49 +30,37 @@ public abstract class BaseCursorAdapter<V extends RecyclerView.ViewHolder> exten
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount()
|
||||
{
|
||||
if (mDataValid)
|
||||
{
|
||||
public int getItemCount() {
|
||||
if (mDataValid) {
|
||||
return mCursor.getCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int inputPosition)
|
||||
{
|
||||
if (!mDataValid)
|
||||
{
|
||||
public long getItemId(int inputPosition) {
|
||||
if (!mDataValid) {
|
||||
throw new IllegalStateException("Cannot lookup item id when cursor is in invalid state.");
|
||||
}
|
||||
|
||||
if (!mCursor.moveToPosition(inputPosition))
|
||||
{
|
||||
if (!mCursor.moveToPosition(inputPosition)) {
|
||||
throw new IllegalStateException("Could not move cursor to position " + inputPosition + " when trying to get an item id");
|
||||
}
|
||||
|
||||
return mCursor.getLong(mRowIDColumn);
|
||||
}
|
||||
|
||||
public void swapCursor(Cursor inputCursor)
|
||||
{
|
||||
if (inputCursor == mCursor)
|
||||
{
|
||||
public void swapCursor(Cursor inputCursor) {
|
||||
if (inputCursor == mCursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputCursor != null)
|
||||
{
|
||||
if (inputCursor != null) {
|
||||
mCursor = inputCursor;
|
||||
mDataValid = true;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
notifyItemRangeRemoved(0, getItemCount());
|
||||
mCursor = null;
|
||||
mRowIDColumn = -1;
|
||||
|
||||
@@ -19,8 +19,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
/**
|
||||
* The configuration screen for creating a shortcut.
|
||||
*/
|
||||
public class CardShortcutConfigure extends AppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener
|
||||
{
|
||||
public class CardShortcutConfigure extends AppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener {
|
||||
static final String TAG = "Catima";
|
||||
final DBHelper mDb = new DBHelper(this);
|
||||
|
||||
@@ -76,10 +75,6 @@ public class CardShortcutConfigure extends AppCompatActivity implements LoyaltyC
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIconClicked(int inputPosition) {
|
||||
onClickAction(inputPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRowClicked(int inputPosition) {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public class CatimaAppCompatActivity extends AppCompatActivity {
|
||||
|
||||
SharedPreferences pref;
|
||||
HashMap<String, Integer> supportedThemes;
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
// Apply chosen language
|
||||
super.attachBaseContext(Utils.updateBaseContextLocale(base));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resources.Theme getTheme() {
|
||||
if (supportedThemes == null) {
|
||||
supportedThemes = new HashMap<>();
|
||||
supportedThemes.put(getString(R.string.settings_key_blue_theme), R.style.AppTheme_blue);
|
||||
supportedThemes.put(getString(R.string.settings_key_brown_theme), R.style.AppTheme_brown);
|
||||
supportedThemes.put(getString(R.string.settings_key_green_theme), R.style.AppTheme_green);
|
||||
supportedThemes.put(getString(R.string.settings_key_grey_theme), R.style.AppTheme_grey);
|
||||
supportedThemes.put(getString(R.string.settings_key_magenta_theme), R.style.AppTheme_magenta);
|
||||
supportedThemes.put(getString(R.string.settings_key_pink_theme), R.style.AppTheme_pink);
|
||||
supportedThemes.put(getString(R.string.settings_key_sky_blue_theme), R.style.AppTheme_sky_blue);
|
||||
supportedThemes.put(getString(R.string.settings_key_violet_theme), R.style.AppTheme_violet);
|
||||
}
|
||||
|
||||
Resources.Theme theme = super.getTheme();
|
||||
pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||
String themeName = pref.getString(getString(R.string.setting_key_theme_color), getString(R.string.settings_key_catima_theme));
|
||||
|
||||
theme.applyStyle(Utils.mapGetOrDefault(supportedThemes, themeName, R.style.AppTheme_NoActionBar), true);
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
public int getThemeColor() {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
Resources.Theme theme = getTheme();
|
||||
theme.resolveAttribute(R.attr.colorPrimary, typedValue, true);
|
||||
return typedValue.data;
|
||||
}
|
||||
}
|
||||
90
app/src/main/java/protect/card_locker/CatimaBarcode.java
Normal file
90
app/src/main/java/protect/card_locker/CatimaBarcode.java
Normal file
@@ -0,0 +1,90 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class CatimaBarcode {
|
||||
public static final List<BarcodeFormat> barcodeFormats = Collections.unmodifiableList(Arrays.asList(
|
||||
BarcodeFormat.AZTEC,
|
||||
BarcodeFormat.CODE_39,
|
||||
BarcodeFormat.CODE_128,
|
||||
BarcodeFormat.CODABAR,
|
||||
BarcodeFormat.DATA_MATRIX,
|
||||
BarcodeFormat.EAN_8,
|
||||
BarcodeFormat.EAN_13,
|
||||
BarcodeFormat.ITF,
|
||||
BarcodeFormat.PDF_417,
|
||||
BarcodeFormat.QR_CODE,
|
||||
BarcodeFormat.UPC_A,
|
||||
BarcodeFormat.UPC_E
|
||||
));
|
||||
|
||||
public static final List<String> barcodePrettyNames = Collections.unmodifiableList(Arrays.asList(
|
||||
"Aztec",
|
||||
"Code 39",
|
||||
"Code 128",
|
||||
"Codabar",
|
||||
"Data Matrix",
|
||||
"EAN 8",
|
||||
"EAN 13",
|
||||
"ITF",
|
||||
"PDF 417",
|
||||
"QR Code",
|
||||
"UPC A",
|
||||
"UPC E"
|
||||
));
|
||||
|
||||
private final BarcodeFormat mBarcodeFormat;
|
||||
|
||||
private CatimaBarcode(BarcodeFormat barcodeFormat) {
|
||||
mBarcodeFormat = barcodeFormat;
|
||||
}
|
||||
|
||||
public static CatimaBarcode fromBarcode(BarcodeFormat barcodeFormat) {
|
||||
return new CatimaBarcode(barcodeFormat);
|
||||
}
|
||||
|
||||
public static CatimaBarcode fromName(String name) {
|
||||
return new CatimaBarcode(BarcodeFormat.valueOf(name));
|
||||
}
|
||||
|
||||
public static CatimaBarcode fromPrettyName(String prettyName) {
|
||||
try {
|
||||
return new CatimaBarcode(barcodeFormats.get(barcodePrettyNames.indexOf(prettyName)));
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException("No barcode type with pretty name " + prettyName + " known!");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSupported() {
|
||||
return barcodeFormats.contains(mBarcodeFormat);
|
||||
}
|
||||
|
||||
public boolean isSquare() {
|
||||
return mBarcodeFormat == BarcodeFormat.AZTEC
|
||||
|| mBarcodeFormat == BarcodeFormat.DATA_MATRIX
|
||||
|| mBarcodeFormat == BarcodeFormat.MAXICODE
|
||||
|| mBarcodeFormat == BarcodeFormat.QR_CODE;
|
||||
}
|
||||
|
||||
public BarcodeFormat format() {
|
||||
return mBarcodeFormat;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return mBarcodeFormat.name();
|
||||
}
|
||||
|
||||
public String prettyName() {
|
||||
int index = barcodeFormats.indexOf(mBarcodeFormat);
|
||||
|
||||
if (index == -1 || index >= barcodePrettyNames.size()) {
|
||||
return mBarcodeFormat.name();
|
||||
}
|
||||
|
||||
return barcodePrettyNames.get(index);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.journeyapps.barcodescanner.CaptureManager;
|
||||
import com.journeyapps.barcodescanner.DecoratedBarcodeView;
|
||||
|
||||
public class CatimaCaptureManager extends CaptureManager {
|
||||
private Activity activity;
|
||||
|
||||
public CatimaCaptureManager(Activity activity, DecoratedBarcodeView barcodeView) {
|
||||
super(activity, barcodeView);
|
||||
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void displayFrameworkBugMessageAndExit(String message) {
|
||||
// We don't want to exit, as we also have a enter from card image and add manually button here
|
||||
// So we show a toast instead
|
||||
Toast.makeText(activity, message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import android.database.DatabaseUtils;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.math.BigDecimal;
|
||||
@@ -18,21 +18,18 @@ import java.util.Currency;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class DBHelper extends SQLiteOpenHelper
|
||||
{
|
||||
public class DBHelper extends SQLiteOpenHelper {
|
||||
public static final String DATABASE_NAME = "Catima.db";
|
||||
public static final int ORIGINAL_DATABASE_VERSION = 1;
|
||||
public static final int DATABASE_VERSION = 10;
|
||||
public static final int DATABASE_VERSION = 14;
|
||||
|
||||
public static class LoyaltyCardDbGroups
|
||||
{
|
||||
public static class LoyaltyCardDbGroups {
|
||||
public static final String TABLE = "groups";
|
||||
public static final String ID = "_id";
|
||||
public static final String ORDER = "orderId";
|
||||
}
|
||||
|
||||
public static class LoyaltyCardDbIds
|
||||
{
|
||||
public static class LoyaltyCardDbIds {
|
||||
public static final String TABLE = "cards";
|
||||
public static final String ID = "_id";
|
||||
public static final String STORE = "store";
|
||||
@@ -46,35 +43,52 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
public static final String BARCODE_ID = "barcodeid";
|
||||
public static final String BARCODE_TYPE = "barcodetype";
|
||||
public static final String STAR_STATUS = "starstatus";
|
||||
public static final String LAST_USED = "lastused";
|
||||
public static final String ZOOM_LEVEL = "zoomlevel";
|
||||
}
|
||||
|
||||
public static class LoyaltyCardDbIdsGroups
|
||||
{
|
||||
public static class LoyaltyCardDbIdsGroups {
|
||||
public static final String TABLE = "cardsGroups";
|
||||
public static final String cardID = "cardId";
|
||||
public static final String groupID = "groupId";
|
||||
}
|
||||
|
||||
public static class LoyaltyCardDbFTS {
|
||||
public static final String TABLE = "fts";
|
||||
public static final String ID = "rowid"; // This should NEVER be changed
|
||||
public static final String STORE = "store";
|
||||
public static final String NOTE = "note";
|
||||
}
|
||||
|
||||
public enum LoyaltyCardOrder {
|
||||
Alpha,
|
||||
LastUsed,
|
||||
Expiry
|
||||
}
|
||||
|
||||
public enum LoyaltyCardOrderDirection {
|
||||
Ascending,
|
||||
Descending
|
||||
}
|
||||
|
||||
private Context mContext;
|
||||
|
||||
public DBHelper(Context context)
|
||||
{
|
||||
public DBHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db)
|
||||
{
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
// create table for card groups
|
||||
db.execSQL("create table " + LoyaltyCardDbGroups.TABLE + "(" +
|
||||
db.execSQL("CREATE TABLE " + LoyaltyCardDbGroups.TABLE + "(" +
|
||||
LoyaltyCardDbGroups.ID + " TEXT primary key not null," +
|
||||
LoyaltyCardDbGroups.ORDER + " INTEGER DEFAULT '0')");
|
||||
|
||||
// create table for cards
|
||||
// Balance is TEXT and not REAL to be able to store a BigDecimal without precision loss
|
||||
db.execSQL("create table " + LoyaltyCardDbIds.TABLE + "(" +
|
||||
db.execSQL("CREATE TABLE " + LoyaltyCardDbIds.TABLE + "(" +
|
||||
LoyaltyCardDbIds.ID + " INTEGER primary key autoincrement," +
|
||||
LoyaltyCardDbIds.STORE + " TEXT not null," +
|
||||
LoyaltyCardDbIds.NOTE + " TEXT not null," +
|
||||
@@ -85,82 +99,75 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
LoyaltyCardDbIds.CARD_ID + " TEXT not null," +
|
||||
LoyaltyCardDbIds.BARCODE_ID + " TEXT," +
|
||||
LoyaltyCardDbIds.BARCODE_TYPE + " TEXT," +
|
||||
LoyaltyCardDbIds.STAR_STATUS + " INTEGER DEFAULT '0')");
|
||||
LoyaltyCardDbIds.STAR_STATUS + " INTEGER DEFAULT '0'," +
|
||||
LoyaltyCardDbIds.LAST_USED + " INTEGER DEFAULT '0', " +
|
||||
LoyaltyCardDbIds.ZOOM_LEVEL + " INTEGER DEFAULT '100' )");
|
||||
|
||||
// create associative table for cards in groups
|
||||
db.execSQL("create table " + LoyaltyCardDbIdsGroups.TABLE + "(" +
|
||||
db.execSQL("CREATE TABLE " + LoyaltyCardDbIdsGroups.TABLE + "(" +
|
||||
LoyaltyCardDbIdsGroups.cardID + " INTEGER," +
|
||||
LoyaltyCardDbIdsGroups.groupID + " TEXT," +
|
||||
"primary key (" + LoyaltyCardDbIdsGroups.cardID + "," + LoyaltyCardDbIdsGroups.groupID +"))");
|
||||
"primary key (" + LoyaltyCardDbIdsGroups.cardID + "," + LoyaltyCardDbIdsGroups.groupID + "))");
|
||||
|
||||
// create FTS search table
|
||||
db.execSQL("CREATE VIRTUAL TABLE " + LoyaltyCardDbFTS.TABLE + " USING fts4(" +
|
||||
LoyaltyCardDbFTS.STORE + ", " + LoyaltyCardDbFTS.NOTE + ", " +
|
||||
"tokenize=unicode61);");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
|
||||
{
|
||||
// Upgrade from version 1 to version 2
|
||||
if(oldVersion < 2 && newVersion >= 2)
|
||||
{
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion < 2 && newVersion >= 2) {
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.NOTE + " TEXT not null default ''");
|
||||
}
|
||||
|
||||
// Upgrade from version 2 to version 3
|
||||
if(oldVersion < 3 && newVersion >= 3)
|
||||
{
|
||||
if (oldVersion < 3 && newVersion >= 3) {
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.HEADER_COLOR + " INTEGER");
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.HEADER_TEXT_COLOR + " INTEGER");
|
||||
}
|
||||
|
||||
// Upgrade from version 3 to version 4
|
||||
if(oldVersion < 4 && newVersion >= 4)
|
||||
{
|
||||
if (oldVersion < 4 && newVersion >= 4) {
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.STAR_STATUS + " INTEGER DEFAULT '0'");
|
||||
}
|
||||
|
||||
// Upgrade from version 4 to version 5
|
||||
if(oldVersion < 5 && newVersion >= 5)
|
||||
{
|
||||
db.execSQL("create table " + LoyaltyCardDbGroups.TABLE + "(" +
|
||||
if (oldVersion < 5 && newVersion >= 5) {
|
||||
db.execSQL("CREATE TABLE " + LoyaltyCardDbGroups.TABLE + "(" +
|
||||
LoyaltyCardDbGroups.ID + " TEXT primary key not null)");
|
||||
|
||||
db.execSQL("create table " + LoyaltyCardDbIdsGroups.TABLE + "(" +
|
||||
db.execSQL("CREATE TABLE " + LoyaltyCardDbIdsGroups.TABLE + "(" +
|
||||
LoyaltyCardDbIdsGroups.cardID + " INTEGER," +
|
||||
LoyaltyCardDbIdsGroups.groupID + " TEXT," +
|
||||
"primary key (" + LoyaltyCardDbIdsGroups.cardID + "," + LoyaltyCardDbIdsGroups.groupID +"))");
|
||||
"primary key (" + LoyaltyCardDbIdsGroups.cardID + "," + LoyaltyCardDbIdsGroups.groupID + "))");
|
||||
}
|
||||
|
||||
// Upgrade from version 5 to 6
|
||||
if(oldVersion < 6 && newVersion >= 6)
|
||||
{
|
||||
if (oldVersion < 6 && newVersion >= 6) {
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbGroups.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbGroups.ORDER + " INTEGER DEFAULT '0'");
|
||||
}
|
||||
|
||||
if(oldVersion < 7 && newVersion >= 7)
|
||||
{
|
||||
if (oldVersion < 7 && newVersion >= 7) {
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.EXPIRY + " INTEGER");
|
||||
}
|
||||
|
||||
if(oldVersion < 8 && newVersion >= 8)
|
||||
{
|
||||
if (oldVersion < 8 && newVersion >= 8) {
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.BALANCE + " TEXT not null DEFAULT '0'");
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.BALANCE_TYPE + " TEXT");
|
||||
}
|
||||
|
||||
if(oldVersion < 9 && newVersion >= 9)
|
||||
{
|
||||
if (oldVersion < 9 && newVersion >= 9) {
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.BARCODE_ID + " TEXT");
|
||||
}
|
||||
|
||||
if(oldVersion < 10 && newVersion >= 10)
|
||||
{
|
||||
if (oldVersion < 10 && newVersion >= 10) {
|
||||
// SQLite doesn't support modify column
|
||||
// So we need to create a temp column to make barcode type nullable
|
||||
// Let's drop header text colour too while we're at it
|
||||
@@ -208,7 +215,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
|
||||
db.execSQL("DROP TABLE " + LoyaltyCardDbIds.TABLE);
|
||||
|
||||
db.execSQL("create table " + LoyaltyCardDbIds.TABLE + "(" +
|
||||
db.execSQL("CREATE TABLE " + LoyaltyCardDbIds.TABLE + "(" +
|
||||
LoyaltyCardDbIds.ID + " INTEGER primary key autoincrement," +
|
||||
LoyaltyCardDbIds.STORE + " TEXT not null," +
|
||||
LoyaltyCardDbIds.NOTE + " TEXT not null," +
|
||||
@@ -252,15 +259,106 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
if (oldVersion < 11 && newVersion >= 11) {
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.LAST_USED + " INTEGER DEFAULT '0'");
|
||||
}
|
||||
|
||||
if (oldVersion < 12 && newVersion >= 12) {
|
||||
db.execSQL("CREATE VIRTUAL TABLE " + LoyaltyCardDbFTS.TABLE + " USING fts4(" +
|
||||
LoyaltyCardDbFTS.STORE + ", " + LoyaltyCardDbFTS.NOTE + ", " +
|
||||
"tokenize=unicode61);");
|
||||
|
||||
Cursor cursor = db.rawQuery("SELECT * FROM " + LoyaltyCardDbIds.TABLE + ";", null, null);
|
||||
|
||||
cursor.moveToFirst();
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
int id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID));
|
||||
String store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE));
|
||||
String note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE));
|
||||
insertFTS(db, id, store, note);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldVersion < 13 && newVersion >= 13) {
|
||||
db.execSQL("DELETE FROM " + LoyaltyCardDbFTS.TABLE + ";");
|
||||
|
||||
Cursor cursor = db.rawQuery("SELECT * FROM " + LoyaltyCardDbIds.TABLE + ";", null, null);
|
||||
|
||||
if (cursor.moveToFirst()) {
|
||||
int id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID));
|
||||
String store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE));
|
||||
String note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE));
|
||||
insertFTS(db, id, store, note);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID));
|
||||
store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE));
|
||||
note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE));
|
||||
insertFTS(db, id, store, note);
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
if (oldVersion < 14 && newVersion >= 14) {
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.ZOOM_LEVEL + " INTEGER DEFAULT '100' ");
|
||||
}
|
||||
}
|
||||
|
||||
private ContentValues generateFTSContentValues(final int id, final String store, final String note) {
|
||||
// FTS on Android is severely limited and can only search for word starting with a certain string
|
||||
// So for each word, we grab every single substring
|
||||
// This makes it possible to find Décathlon by searching both de and cat, for example
|
||||
|
||||
ContentValues ftsContentValues = new ContentValues();
|
||||
|
||||
StringBuilder storeString = new StringBuilder();
|
||||
for (String word : store.split(" ")) {
|
||||
for (int i = 0; i < word.length(); i++) {
|
||||
storeString.append(word);
|
||||
storeString.append(" ");
|
||||
word = word.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder noteString = new StringBuilder();
|
||||
for (String word : note.split(" ")) {
|
||||
for (int i = 0; i < word.length(); i++) {
|
||||
noteString.append(word);
|
||||
noteString.append(" ");
|
||||
word = word.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
ftsContentValues.put(LoyaltyCardDbFTS.ID, id);
|
||||
ftsContentValues.put(LoyaltyCardDbFTS.STORE, storeString.toString());
|
||||
ftsContentValues.put(LoyaltyCardDbFTS.NOTE, noteString.toString());
|
||||
|
||||
return ftsContentValues;
|
||||
}
|
||||
|
||||
private void insertFTS(final SQLiteDatabase db, final int id, final String store, final String note) {
|
||||
db.insert(LoyaltyCardDbFTS.TABLE, null, generateFTSContentValues(id, store, note));
|
||||
}
|
||||
|
||||
private void updateFTS(final SQLiteDatabase db, final int id, final String store, final String note) {
|
||||
db.update(LoyaltyCardDbFTS.TABLE, generateFTSContentValues(id, store, note),
|
||||
whereAttrs(LoyaltyCardDbFTS.ID), withArgs(id));
|
||||
}
|
||||
|
||||
public long insertLoyaltyCard(final String store, final String note, final Date expiry,
|
||||
final BigDecimal balance, final Currency balanceType,
|
||||
final String cardId, final String barcodeId,
|
||||
final BarcodeFormat barcodeType, final Integer headerColor,
|
||||
final int starStatus)
|
||||
{
|
||||
final CatimaBarcode barcodeType, final Integer headerColor,
|
||||
final int starStatus, final Long lastUsed) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
db.beginTransaction();
|
||||
|
||||
// Card
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(LoyaltyCardDbIds.STORE, store);
|
||||
contentValues.put(LoyaltyCardDbIds.NOTE, note);
|
||||
@@ -269,18 +367,30 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
contentValues.put(LoyaltyCardDbIds.BALANCE_TYPE, balanceType != null ? balanceType.getCurrencyCode() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.CARD_ID, cardId);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_ID, barcodeId);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType != null ? barcodeType.toString() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType != null ? barcodeType.name() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.HEADER_COLOR, headerColor);
|
||||
contentValues.put(LoyaltyCardDbIds.STAR_STATUS, starStatus);
|
||||
return db.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
|
||||
contentValues.put(LoyaltyCardDbIds.LAST_USED, lastUsed != null ? lastUsed : Utils.getUnixTime());
|
||||
long id = db.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
|
||||
|
||||
// FTS
|
||||
insertFTS(db, (int) id, store, note);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
public long insertLoyaltyCard(final SQLiteDatabase db, final String store,
|
||||
final String note, final Date expiry, final BigDecimal balance,
|
||||
final Currency balanceType, final String cardId,
|
||||
final String barcodeId, final BarcodeFormat barcodeType,
|
||||
final Integer headerColor, final int starStatus)
|
||||
{
|
||||
final String note, final Date expiry, final BigDecimal balance,
|
||||
final Currency balanceType, final String cardId,
|
||||
final String barcodeId, final CatimaBarcode barcodeType,
|
||||
final Integer headerColor, final int starStatus,
|
||||
final Long lastUsed) {
|
||||
db.beginTransaction();
|
||||
|
||||
// Card
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(LoyaltyCardDbIds.STORE, store);
|
||||
contentValues.put(LoyaltyCardDbIds.NOTE, note);
|
||||
@@ -289,18 +399,30 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
contentValues.put(LoyaltyCardDbIds.BALANCE_TYPE, balanceType != null ? balanceType.getCurrencyCode() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.CARD_ID, cardId);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_ID, barcodeId);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType != null ? barcodeType.toString() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType != null ? barcodeType.name() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.HEADER_COLOR, headerColor);
|
||||
contentValues.put(LoyaltyCardDbIds.STAR_STATUS,starStatus);
|
||||
return db.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
|
||||
contentValues.put(LoyaltyCardDbIds.STAR_STATUS, starStatus);
|
||||
contentValues.put(LoyaltyCardDbIds.LAST_USED, lastUsed != null ? lastUsed : Utils.getUnixTime());
|
||||
long id = db.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
|
||||
|
||||
// FTS
|
||||
insertFTS(db, (int) id, store, note);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
public long insertLoyaltyCard(final SQLiteDatabase db, final int id, final String store,
|
||||
final String note, final Date expiry, final BigDecimal balance,
|
||||
final Currency balanceType, final String cardId,
|
||||
final String barcodeId, final BarcodeFormat barcodeType,
|
||||
final Integer headerColor, final int starStatus)
|
||||
{
|
||||
final String note, final Date expiry, final BigDecimal balance,
|
||||
final Currency balanceType, final String cardId,
|
||||
final String barcodeId, final CatimaBarcode barcodeType,
|
||||
final Integer headerColor, final int starStatus,
|
||||
final Long lastUsed) {
|
||||
db.beginTransaction();
|
||||
|
||||
// Card
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(LoyaltyCardDbIds.ID, id);
|
||||
contentValues.put(LoyaltyCardDbIds.STORE, store);
|
||||
@@ -310,19 +432,30 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
contentValues.put(LoyaltyCardDbIds.BALANCE_TYPE, balanceType != null ? balanceType.getCurrencyCode() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.CARD_ID, cardId);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_ID, barcodeId);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType != null ? barcodeType.toString() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType != null ? barcodeType.name() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.HEADER_COLOR, headerColor);
|
||||
contentValues.put(LoyaltyCardDbIds.STAR_STATUS,starStatus);
|
||||
return db.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
|
||||
contentValues.put(LoyaltyCardDbIds.STAR_STATUS, starStatus);
|
||||
contentValues.put(LoyaltyCardDbIds.LAST_USED, lastUsed != null ? lastUsed : Utils.getUnixTime());
|
||||
db.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
|
||||
|
||||
// FTS
|
||||
insertFTS(db, id, store, note);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean updateLoyaltyCard(final int id, final String store, final String note,
|
||||
final Date expiry, final BigDecimal balance,
|
||||
final Currency balanceType, final String cardId,
|
||||
final String barcodeId, final BarcodeFormat barcodeType,
|
||||
final Integer headerColor)
|
||||
{
|
||||
final String barcodeId, final CatimaBarcode barcodeType,
|
||||
final Integer headerColor) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
db.beginTransaction();
|
||||
|
||||
// Card
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(LoyaltyCardDbIds.STORE, store);
|
||||
contentValues.put(LoyaltyCardDbIds.NOTE, note);
|
||||
@@ -331,33 +464,59 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
contentValues.put(LoyaltyCardDbIds.BALANCE_TYPE, balanceType != null ? balanceType.getCurrencyCode() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.CARD_ID, cardId);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_ID, barcodeId);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType != null ? barcodeType.toString() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType != null ? barcodeType.name() : null);
|
||||
contentValues.put(LoyaltyCardDbIds.HEADER_COLOR, headerColor);
|
||||
int rowsUpdated = db.update(LoyaltyCardDbIds.TABLE, contentValues,
|
||||
whereAttrs(LoyaltyCardDbIds.ID), withArgs(id));
|
||||
|
||||
// FTS
|
||||
updateFTS(db, id, store, note);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
return (rowsUpdated == 1);
|
||||
}
|
||||
|
||||
public boolean updateLoyaltyCardStarStatus(final int id, final int starStatus)
|
||||
{
|
||||
public boolean updateLoyaltyCardStarStatus(final int id, final int starStatus) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(LoyaltyCardDbIds.STAR_STATUS,starStatus);
|
||||
contentValues.put(LoyaltyCardDbIds.STAR_STATUS, starStatus);
|
||||
int rowsUpdated = db.update(LoyaltyCardDbIds.TABLE, contentValues,
|
||||
whereAttrs(LoyaltyCardDbIds.ID),
|
||||
withArgs(id));
|
||||
return (rowsUpdated == 1);
|
||||
}
|
||||
|
||||
public LoyaltyCard getLoyaltyCard(final int id)
|
||||
{
|
||||
public boolean updateLoyaltyCardLastUsed(final int id) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(LoyaltyCardDbIds.LAST_USED, System.currentTimeMillis() / 1000);
|
||||
int rowsUpdated = db.update(LoyaltyCardDbIds.TABLE, contentValues,
|
||||
whereAttrs(LoyaltyCardDbIds.ID),
|
||||
withArgs(id));
|
||||
return (rowsUpdated == 1);
|
||||
}
|
||||
|
||||
public boolean updateLoyaltyCardZoomLevel(int loyaltyCardId, int zoomLevel) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(LoyaltyCardDbIds.ZOOM_LEVEL, zoomLevel);
|
||||
Log.d("updateLoyaltyCardZLevel", "Card Id = " + loyaltyCardId + " Zoom level= " + zoomLevel);
|
||||
int rowsUpdated = db.update(LoyaltyCardDbIds.TABLE, contentValues,
|
||||
whereAttrs(LoyaltyCardDbIds.ID),
|
||||
withArgs(loyaltyCardId));
|
||||
Log.d("updateLoyaltyCardZLevel", "Rows changed = " + rowsUpdated);
|
||||
return (rowsUpdated == 1);
|
||||
}
|
||||
|
||||
public LoyaltyCard getLoyaltyCard(final int id) {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
Cursor data = db.query(LoyaltyCardDbIds.TABLE, null, whereAttrs(LoyaltyCardDbIds.ID), withArgs(id), null, null, null);
|
||||
|
||||
LoyaltyCard card = null;
|
||||
|
||||
if(data.getCount() == 1)
|
||||
{
|
||||
if (data.getCount() == 1) {
|
||||
data.moveToFirst();
|
||||
card = LoyaltyCard.toLoyaltyCard(data);
|
||||
}
|
||||
@@ -367,8 +526,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
return card;
|
||||
}
|
||||
|
||||
public List<Group> getLoyaltyCardGroups(final int id)
|
||||
{
|
||||
public List<Group> getLoyaltyCardGroups(final int id) {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
Cursor data = db.rawQuery("select * from " + LoyaltyCardDbGroups.TABLE + " g " +
|
||||
" LEFT JOIN " + LoyaltyCardDbIdsGroups.TABLE + " ig ON ig." + LoyaltyCardDbIdsGroups.groupID + " = g." + LoyaltyCardDbGroups.ID +
|
||||
@@ -393,8 +551,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
return groups;
|
||||
}
|
||||
|
||||
public void setLoyaltyCardGroups(final int id, List<Group> groups)
|
||||
{
|
||||
public void setLoyaltyCardGroups(final int id, List<Group> groups) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
|
||||
// First delete lookup table entries associated with this card
|
||||
@@ -411,8 +568,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoyaltyCardGroups(final SQLiteDatabase db, final int id, List<Group> groups)
|
||||
{
|
||||
public void setLoyaltyCardGroups(final SQLiteDatabase db, final int id, List<Group> groups) {
|
||||
// First delete lookup table entries associated with this card
|
||||
db.delete(LoyaltyCardDbIdsGroups.TABLE,
|
||||
whereAttrs(LoyaltyCardDbIdsGroups.cardID),
|
||||
@@ -427,8 +583,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
}
|
||||
}
|
||||
|
||||
public boolean deleteLoyaltyCard(final int id)
|
||||
{
|
||||
public boolean deleteLoyaltyCard(final int id) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
// Delete card
|
||||
int rowsDeleted = db.delete(LoyaltyCardDbIds.TABLE,
|
||||
@@ -440,19 +595,24 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
whereAttrs(LoyaltyCardDbIdsGroups.cardID),
|
||||
withArgs(id));
|
||||
|
||||
// Delete FTS table entries
|
||||
db.delete(LoyaltyCardDbFTS.TABLE,
|
||||
whereAttrs(LoyaltyCardDbFTS.ID),
|
||||
withArgs(id));
|
||||
|
||||
// Also wipe card images associated with this card
|
||||
try {
|
||||
Utils.saveCardImage(mContext, null, id, true);
|
||||
Utils.saveCardImage(mContext, null, id, false);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
for (ImageLocationType imageLocationType : ImageLocationType.values()) {
|
||||
try {
|
||||
Utils.saveCardImage(mContext, null, id, imageLocationType);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return (rowsDeleted == 1);
|
||||
}
|
||||
|
||||
public Cursor getLoyaltyCardCursor()
|
||||
{
|
||||
public Cursor getLoyaltyCardCursor() {
|
||||
// An empty string will match everything
|
||||
return getLoyaltyCardCursor("");
|
||||
}
|
||||
@@ -463,8 +623,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
* @param filter
|
||||
* @return Cursor
|
||||
*/
|
||||
public Cursor getLoyaltyCardCursor(final String filter)
|
||||
{
|
||||
public Cursor getLoyaltyCardCursor(final String filter) {
|
||||
return getLoyaltyCardCursor(filter, null);
|
||||
}
|
||||
|
||||
@@ -475,10 +634,19 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
* @param group
|
||||
* @return Cursor
|
||||
*/
|
||||
public Cursor getLoyaltyCardCursor(final String filter, Group group)
|
||||
{
|
||||
String actualFilter = String.format("%%%s%%", filter);
|
||||
String[] selectionArgs = { actualFilter, actualFilter };
|
||||
public Cursor getLoyaltyCardCursor(final String filter, Group group) {
|
||||
return getLoyaltyCardCursor(filter, group, LoyaltyCardOrder.Alpha, LoyaltyCardOrderDirection.Ascending);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cursor to all loyalty cards with the filter text in either the store or note in a certain group sorted as requested.
|
||||
*
|
||||
* @param filter
|
||||
* @param group
|
||||
* @param order
|
||||
* @return Cursor
|
||||
*/
|
||||
public Cursor getLoyaltyCardCursor(String filter, Group group, LoyaltyCardOrder order, LoyaltyCardOrderDirection direction) {
|
||||
StringBuilder groupFilter = new StringBuilder();
|
||||
String limitString = "";
|
||||
|
||||
@@ -492,7 +660,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
groupFilter.append("AND (");
|
||||
|
||||
for (int i = 0; i < allowedIds.size(); i++) {
|
||||
groupFilter.append(LoyaltyCardDbIds.ID + " = ").append(allowedIds.get(i));
|
||||
groupFilter.append(LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.ID + " = ").append(allowedIds.get(i));
|
||||
if (i != allowedIds.size() - 1) {
|
||||
groupFilter.append(" OR ");
|
||||
}
|
||||
@@ -503,34 +671,28 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
}
|
||||
}
|
||||
|
||||
return db.rawQuery("select * from " + LoyaltyCardDbIds.TABLE +
|
||||
" WHERE (" + LoyaltyCardDbIds.STORE + " LIKE ? " +
|
||||
" OR " + LoyaltyCardDbIds.NOTE + " LIKE ? )" +
|
||||
groupFilter.toString() +
|
||||
" ORDER BY " + LoyaltyCardDbIds.STAR_STATUS + " DESC," + LoyaltyCardDbIds.STORE + " COLLATE NOCASE ASC " +
|
||||
limitString, selectionArgs, null);
|
||||
}
|
||||
String orderField = getFieldForOrder(order);
|
||||
|
||||
public int getLoyaltyCardCount()
|
||||
{
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
return (int) DatabaseUtils.queryNumEntries(db, LoyaltyCardDbIds.TABLE);
|
||||
return db.rawQuery("SELECT " + LoyaltyCardDbIds.TABLE + ".* FROM " + LoyaltyCardDbIds.TABLE +
|
||||
" JOIN " + LoyaltyCardDbFTS.TABLE +
|
||||
" ON " + LoyaltyCardDbFTS.TABLE + "." + LoyaltyCardDbFTS.ID + " = " + LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.ID +
|
||||
(filter.trim().isEmpty() ? " " : " AND " + LoyaltyCardDbFTS.TABLE + " MATCH ? ") +
|
||||
groupFilter.toString() +
|
||||
" ORDER BY " + LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.STAR_STATUS + " DESC, " +
|
||||
" (CASE WHEN " + LoyaltyCardDbIds.TABLE + "." + orderField + " IS NULL THEN 1 ELSE 0 END), " +
|
||||
LoyaltyCardDbIds.TABLE + "." + orderField + " COLLATE NOCASE " + getDbDirection(order, direction) + ", " +
|
||||
LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.STORE + " COLLATE NOCASE ASC " +
|
||||
limitString, filter.trim().isEmpty() ? null : new String[]{TextUtils.join("* ", filter.split(" ")) + '*'}, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of loyalty cards with the filter text in either the store or note.
|
||||
* Returns the amount of loyalty cards.
|
||||
*
|
||||
* @param filter
|
||||
* @return Integer
|
||||
*/
|
||||
public int getLoyaltyCardCount(String filter)
|
||||
{
|
||||
String actualFilter = String.format("%%%s%%", filter);
|
||||
|
||||
public int getLoyaltyCardCount() {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
return (int) DatabaseUtils.queryNumEntries(db, LoyaltyCardDbIds.TABLE,
|
||||
LoyaltyCardDbIds.STORE + " LIKE ? " +
|
||||
" OR " + LoyaltyCardDbIds.NOTE + " LIKE ? ", withArgs(actualFilter, actualFilter));
|
||||
return (int) DatabaseUtils.queryNumEntries(db, LoyaltyCardDbIds.TABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -538,8 +700,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
*
|
||||
* @return Cursor
|
||||
*/
|
||||
public Cursor getGroupCursor()
|
||||
{
|
||||
public Cursor getGroupCursor() {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
|
||||
return db.rawQuery("select * from " + LoyaltyCardDbGroups.TABLE +
|
||||
@@ -547,29 +708,29 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
}
|
||||
|
||||
public List<Group> getGroups() {
|
||||
try(Cursor data = getGroupCursor()) {
|
||||
List<Group> groups = new ArrayList<>();
|
||||
Cursor data = getGroupCursor();
|
||||
|
||||
if (!data.moveToFirst()) {
|
||||
return groups;
|
||||
}
|
||||
|
||||
groups.add(Group.toGroup(data));
|
||||
while (data.moveToNext()) {
|
||||
groups.add(Group.toGroup(data));
|
||||
}
|
||||
List<Group> groups = new ArrayList<>();
|
||||
|
||||
if (!data.moveToFirst()) {
|
||||
data.close();
|
||||
return groups;
|
||||
}
|
||||
|
||||
groups.add(Group.toGroup(data));
|
||||
while (data.moveToNext()) {
|
||||
groups.add(Group.toGroup(data));
|
||||
}
|
||||
|
||||
data.close();
|
||||
return groups;
|
||||
}
|
||||
|
||||
public void reorderGroups(final List<Group> groups)
|
||||
{
|
||||
public void reorderGroups(final List<Group> groups) {
|
||||
Integer order = 0;
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
|
||||
for (Group group : groups)
|
||||
{
|
||||
for (Group group : groups) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(LoyaltyCardDbGroups.ORDER, order);
|
||||
|
||||
@@ -581,15 +742,13 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
}
|
||||
}
|
||||
|
||||
public Group getGroup(final String groupName)
|
||||
{
|
||||
public Group getGroup(final String groupName) {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
Cursor data = db.query(LoyaltyCardDbGroups.TABLE, null,
|
||||
whereAttrs(LoyaltyCardDbGroups.ID), withArgs(groupName), null, null, null);
|
||||
|
||||
Group group = null;
|
||||
if(data.getCount() == 1)
|
||||
{
|
||||
if (data.getCount() == 1) {
|
||||
data.moveToFirst();
|
||||
group = Group.toGroup(data);
|
||||
}
|
||||
@@ -598,14 +757,12 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
return group;
|
||||
}
|
||||
|
||||
public int getGroupCount()
|
||||
{
|
||||
public int getGroupCount() {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
return (int) DatabaseUtils.queryNumEntries(db, LoyaltyCardDbGroups.TABLE);
|
||||
}
|
||||
|
||||
public List<Integer> getGroupCardIds(final String groupName)
|
||||
{
|
||||
public List<Integer> getGroupCardIds(final String groupName) {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
Cursor data = db.query(LoyaltyCardDbIdsGroups.TABLE, withArgs(LoyaltyCardDbIdsGroups.cardID),
|
||||
whereAttrs(LoyaltyCardDbIdsGroups.groupID), withArgs(groupName), null, null, null);
|
||||
@@ -626,8 +783,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
return cardIds;
|
||||
}
|
||||
|
||||
public long insertGroup(final String name)
|
||||
{
|
||||
public long insertGroup(final String name) {
|
||||
if (name.isEmpty()) return -1;
|
||||
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
@@ -637,8 +793,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
return db.insert(LoyaltyCardDbGroups.TABLE, null, contentValues);
|
||||
}
|
||||
|
||||
public boolean insertGroup(final SQLiteDatabase db, final String name)
|
||||
{
|
||||
public boolean insertGroup(final SQLiteDatabase db, final String name) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(LoyaltyCardDbGroups.ID, name);
|
||||
contentValues.put(LoyaltyCardDbGroups.ORDER, getGroupCount());
|
||||
@@ -646,8 +801,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
return newId != -1;
|
||||
}
|
||||
|
||||
public boolean updateGroup(final String groupName, final String newName)
|
||||
{
|
||||
public boolean updateGroup(final String groupName, final String newName) {
|
||||
if (newName.isEmpty()) return false;
|
||||
|
||||
boolean success = false;
|
||||
@@ -683,8 +837,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
return success;
|
||||
}
|
||||
|
||||
public boolean deleteGroup(final String groupName)
|
||||
{
|
||||
public boolean deleteGroup(final String groupName) {
|
||||
boolean success = false;
|
||||
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
@@ -715,8 +868,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
return success;
|
||||
}
|
||||
|
||||
public int getGroupCardCount(final String groupName)
|
||||
{
|
||||
public int getGroupCardCount(final String groupName) {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
|
||||
return (int) DatabaseUtils.queryNumEntries(db, LoyaltyCardDbIdsGroups.TABLE,
|
||||
@@ -739,4 +891,29 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
.map(String::valueOf)
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
private String getFieldForOrder(LoyaltyCardOrder order) {
|
||||
if (order == LoyaltyCardOrder.Alpha) {
|
||||
return LoyaltyCardDbIds.STORE;
|
||||
}
|
||||
|
||||
if (order == LoyaltyCardOrder.LastUsed) {
|
||||
return LoyaltyCardDbIds.LAST_USED;
|
||||
}
|
||||
|
||||
if (order == LoyaltyCardOrder.Expiry) {
|
||||
return LoyaltyCardDbIds.EXPIRY;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown order " + order);
|
||||
}
|
||||
|
||||
private String getDbDirection(LoyaltyCardOrder order, LoyaltyCardOrderDirection direction) {
|
||||
if (order == LoyaltyCardOrder.LastUsed) {
|
||||
// We want the default sorting to put the most recently used first
|
||||
return direction == LoyaltyCardOrderDirection.Descending ? "ASC" : "DESC";
|
||||
}
|
||||
|
||||
return direction == LoyaltyCardOrderDirection.Ascending ? "ASC" : "DESC";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,12 @@ package protect.card_locker;
|
||||
* encountered with the format of data being
|
||||
* imported or exported.
|
||||
*/
|
||||
public class FormatException extends Exception
|
||||
{
|
||||
public FormatException(String message)
|
||||
{
|
||||
public class FormatException extends Exception {
|
||||
public FormatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public FormatException(String message, Exception rootCause)
|
||||
{
|
||||
public FormatException(String message, Exception rootCause) {
|
||||
super(message, rootCause);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ package protect.card_locker;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
public class Group
|
||||
{
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class Group {
|
||||
public final String _id;
|
||||
public final int order;
|
||||
|
||||
@@ -12,11 +13,28 @@ public class Group
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public static Group toGroup(Cursor cursor)
|
||||
{
|
||||
public static Group toGroup(Cursor cursor) {
|
||||
String _id = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.ID));
|
||||
int order = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.ORDER));
|
||||
|
||||
return new Group(_id, order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Group)) {
|
||||
return false;
|
||||
}
|
||||
Group anotherGroup = (Group) obj;
|
||||
return _id.equals(anotherGroup._id) && order == anotherGroup.order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
String combined = _id + "_" + order;
|
||||
return combined.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@ import androidx.appcompat.widget.AppCompatImageButton;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import protect.card_locker.preferences.Settings;
|
||||
|
||||
class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.GroupListItemViewHolder>
|
||||
{
|
||||
class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.GroupListItemViewHolder> {
|
||||
Settings mSettings;
|
||||
private Cursor mCursor;
|
||||
private final Context mContext;
|
||||
@@ -39,14 +38,12 @@ class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.GroupListI
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public GroupCursorAdapter.GroupListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType)
|
||||
{
|
||||
public GroupCursorAdapter.GroupListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType) {
|
||||
View itemView = LayoutInflater.from(inputParent.getContext()).inflate(R.layout.group_layout, inputParent, false);
|
||||
return new GroupCursorAdapter.GroupListItemViewHolder(itemView);
|
||||
return new GroupListItemViewHolder(itemView);
|
||||
}
|
||||
|
||||
public Cursor getCursor()
|
||||
{
|
||||
public Cursor getCursor() {
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
@@ -64,24 +61,24 @@ class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.GroupListI
|
||||
applyClickEvents(inputHolder);
|
||||
}
|
||||
|
||||
private void applyClickEvents(GroupListItemViewHolder inputHolder)
|
||||
{
|
||||
private void applyClickEvents(GroupListItemViewHolder inputHolder) {
|
||||
inputHolder.mMoveDown.setOnClickListener(view -> mListener.onMoveDownButtonClicked(inputHolder.itemView));
|
||||
inputHolder.mMoveUp.setOnClickListener(view -> mListener.onMoveUpButtonClicked(inputHolder.itemView));
|
||||
inputHolder.mEdit.setOnClickListener(view -> mListener.onEditButtonClicked(inputHolder.itemView));
|
||||
inputHolder.mDelete.setOnClickListener(view -> mListener.onDeleteButtonClicked(inputHolder.itemView));
|
||||
}
|
||||
|
||||
public interface GroupAdapterListener
|
||||
{
|
||||
public interface GroupAdapterListener {
|
||||
void onMoveDownButtonClicked(View view);
|
||||
|
||||
void onMoveUpButtonClicked(View view);
|
||||
|
||||
void onEditButtonClicked(View view);
|
||||
|
||||
void onDeleteButtonClicked(View view);
|
||||
}
|
||||
|
||||
public class GroupListItemViewHolder extends RecyclerView.ViewHolder
|
||||
{
|
||||
public static class GroupListItemViewHolder extends RecyclerView.ViewHolder {
|
||||
public TextView mName, mCardCount;
|
||||
public AppCompatImageButton mMoveUp, mMoveDown, mEdit, mDelete;
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package protect.card_locker;
|
||||
|
||||
public enum ImageLocationType {
|
||||
front,
|
||||
back,
|
||||
icon
|
||||
}
|
||||
@@ -6,20 +6,21 @@ import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
@@ -27,15 +28,14 @@ import java.util.List;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import protect.card_locker.async.TaskHandler;
|
||||
import protect.card_locker.importexport.DataFormat;
|
||||
import protect.card_locker.importexport.ImportExportResult;
|
||||
|
||||
public class ImportExportActivity extends AppCompatActivity
|
||||
{
|
||||
public class ImportExportActivity extends CatimaAppCompatActivity {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
private static final int PERMISSIONS_EXTERNAL_STORAGE = 1;
|
||||
@@ -47,17 +47,19 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
private String importAlertTitle;
|
||||
private String importAlertMessage;
|
||||
private DataFormat importDataFormat;
|
||||
private String exportPassword;
|
||||
|
||||
final private TaskHandler mTasks = new TaskHandler();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(R.string.importExport);
|
||||
setContentView(R.layout.import_export_activity);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@@ -66,12 +68,11 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
|
||||
if (ContextCompat.checkSelfPermission(ImportExportActivity.this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
|
||||
ContextCompat.checkSelfPermission(ImportExportActivity.this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
ContextCompat.checkSelfPermission(ImportExportActivity.this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(ImportExportActivity.this,
|
||||
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
PERMISSIONS_EXTERNAL_STORAGE);
|
||||
}
|
||||
|
||||
@@ -82,12 +83,31 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
intentCreateDocumentAction.putExtra(Intent.EXTRA_TITLE, "catima.zip");
|
||||
|
||||
Button exportButton = findViewById(R.id.exportButton);
|
||||
exportButton.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
exportButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
chooseFileWithIntent(intentCreateDocumentAction, CHOOSE_EXPORT_LOCATION);
|
||||
public void onClick(View v) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ImportExportActivity.this);
|
||||
builder.setTitle(R.string.exportPassword);
|
||||
|
||||
FrameLayout container = new FrameLayout(ImportExportActivity.this);
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
params.leftMargin = 50;
|
||||
params.rightMargin = 50;
|
||||
|
||||
final EditText input = new EditText(ImportExportActivity.this);
|
||||
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
input.setLayoutParams(params);
|
||||
input.setHint(R.string.exportPasswordHint);
|
||||
|
||||
container.addView(input);
|
||||
builder.setView(container);
|
||||
builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> {
|
||||
exportPassword = input.getText().toString();
|
||||
chooseFileWithIntent(intentCreateDocumentAction, CHOOSE_EXPORT_LOCATION);
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel, (dialogInterface, i) -> dialogInterface.cancel());
|
||||
builder.show();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -97,11 +117,9 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
intentGetContentAction.setType("*/*");
|
||||
|
||||
Button importFilesystem = findViewById(R.id.importOptionFilesystemButton);
|
||||
importFilesystem.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
importFilesystem.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
public void onClick(View v) {
|
||||
chooseImportType(intentGetContentAction);
|
||||
}
|
||||
});
|
||||
@@ -110,11 +128,9 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
final Intent intentPickAction = new Intent(Intent.ACTION_PICK);
|
||||
|
||||
Button importApplication = findViewById(R.id.importOptionApplicationButton);
|
||||
importApplication.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
importApplication.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
public void onClick(View v) {
|
||||
chooseImportType(intentPickAction);
|
||||
}
|
||||
});
|
||||
@@ -176,47 +192,57 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
.setTitle(importAlertTitle)
|
||||
.setMessage(importAlertMessage)
|
||||
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
chooseFileWithIntent(baseIntent, IMPORT);
|
||||
}
|
||||
})
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
chooseFileWithIntent(baseIntent, IMPORT);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void startImport(final InputStream target, final Uri targetUri, final DataFormat dataFormat, final char[] password)
|
||||
{
|
||||
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener()
|
||||
{
|
||||
private void startImport(final InputStream target, final Uri targetUri, final DataFormat dataFormat, final char[] password, final boolean closeWhenDone) {
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.IMPORT, true, false, false);
|
||||
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener() {
|
||||
@Override
|
||||
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat)
|
||||
{
|
||||
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat) {
|
||||
onImportComplete(result, targetUri, dataFormat);
|
||||
if (closeWhenDone) {
|
||||
try {
|
||||
target.close();
|
||||
} catch (IOException ioException) {
|
||||
ioException.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
importExporter = new ImportExportTask(ImportExportActivity.this,
|
||||
dataFormat, target, password, listener);
|
||||
importExporter.execute();
|
||||
mTasks.executeTask(TaskHandler.TYPE.IMPORT, importExporter);
|
||||
}
|
||||
|
||||
private void startExport(final OutputStream target, final Uri targetUri)
|
||||
{
|
||||
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener()
|
||||
{
|
||||
private void startExport(final OutputStream target, final Uri targetUri, char[] password, final boolean closeWhenDone) {
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.EXPORT, true, false, false);
|
||||
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener() {
|
||||
@Override
|
||||
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat)
|
||||
{
|
||||
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat) {
|
||||
onExportComplete(result, targetUri);
|
||||
if (closeWhenDone) {
|
||||
try {
|
||||
target.close();
|
||||
} catch (IOException ioException) {
|
||||
ioException.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
importExporter = new ImportExportTask(ImportExportActivity.this,
|
||||
DataFormat.Catima, target, listener);
|
||||
importExporter.execute();
|
||||
DataFormat.Catima, target, password, listener);
|
||||
mTasks.executeTask(TaskHandler.TYPE.EXPORT, importExporter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -244,22 +270,17 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy()
|
||||
{
|
||||
if(importExporter != null && importExporter.getStatus() != AsyncTask.Status.RUNNING)
|
||||
{
|
||||
importExporter.cancel(true);
|
||||
}
|
||||
protected void onDestroy() {
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.IMPORT, true, false, false);
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.EXPORT, true, false, false);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
|
||||
if(id == android.R.id.home)
|
||||
{
|
||||
if (id == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
@@ -293,13 +314,10 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
|
||||
int messageId;
|
||||
|
||||
if (result == ImportExportResult.Success)
|
||||
{
|
||||
if (result == ImportExportResult.Success) {
|
||||
builder.setTitle(R.string.importSuccessfulTitle);
|
||||
messageId = R.string.importSuccessful;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
builder.setTitle(R.string.importFailedTitle);
|
||||
messageId = R.string.importFailed;
|
||||
}
|
||||
@@ -307,11 +325,9 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
final String message = getResources().getString(messageId);
|
||||
|
||||
builder.setMessage(message);
|
||||
builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener()
|
||||
{
|
||||
builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
@@ -319,19 +335,15 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
private void onExportComplete(ImportExportResult result, final Uri path)
|
||||
{
|
||||
private void onExportComplete(ImportExportResult result, final Uri path) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
|
||||
int messageId;
|
||||
|
||||
if(result == ImportExportResult.Success)
|
||||
{
|
||||
if (result == ImportExportResult.Success) {
|
||||
builder.setTitle(R.string.exportSuccessfulTitle);
|
||||
messageId = R.string.exportSuccessful;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
builder.setTitle(R.string.exportFailedTitle);
|
||||
messageId = R.string.exportFailed;
|
||||
}
|
||||
@@ -341,8 +353,7 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
builder.setMessage(message);
|
||||
builder.setNeutralButton(R.string.ok, (dialog, which) -> dialog.dismiss());
|
||||
|
||||
if(result == ImportExportResult.Success)
|
||||
{
|
||||
if (result == ImportExportResult.Success) {
|
||||
final CharSequence sendLabel = ImportExportActivity.this.getResources().getText(R.string.sendLabel);
|
||||
|
||||
builder.setPositiveButton(sendLabel, (dialog, which) -> {
|
||||
@@ -363,87 +374,64 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
private void chooseFileWithIntent(Intent intent, int requestCode)
|
||||
{
|
||||
try
|
||||
{
|
||||
private void chooseFileWithIntent(Intent intent, int requestCode) {
|
||||
try {
|
||||
startActivityForResult(intent, requestCode);
|
||||
}
|
||||
catch (ActivityNotFoundException e)
|
||||
{
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(getApplicationContext(), R.string.failedOpeningFileManager, Toast.LENGTH_LONG).show();
|
||||
Log.e(TAG, "No activity found to handle intent", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void activityResultParser(int requestCode, int resultCode, Uri uri, char[] password) {
|
||||
if (resultCode != RESULT_OK)
|
||||
{
|
||||
if (resultCode != RESULT_OK) {
|
||||
Log.w(TAG, "Failed onActivityResult(), result=" + resultCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if(uri == null)
|
||||
{
|
||||
if (uri == null) {
|
||||
Log.e(TAG, "Activity returned a NULL URI");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (requestCode == CHOOSE_EXPORT_LOCATION)
|
||||
{
|
||||
try {
|
||||
if (requestCode == CHOOSE_EXPORT_LOCATION) {
|
||||
|
||||
OutputStream writer;
|
||||
if (uri.getScheme() != null)
|
||||
{
|
||||
if (uri.getScheme() != null) {
|
||||
writer = getContentResolver().openOutputStream(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
writer = new FileOutputStream(new File(uri.toString()));
|
||||
}
|
||||
|
||||
Log.e(TAG, "Starting file export with: " + uri.toString());
|
||||
startExport(writer, uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
startExport(writer, uri, exportPassword.toCharArray(), true);
|
||||
} else {
|
||||
InputStream reader;
|
||||
if(uri.getScheme() != null)
|
||||
{
|
||||
if (uri.getScheme() != null) {
|
||||
reader = getContentResolver().openInputStream(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
reader = new FileInputStream(new File(uri.toString()));
|
||||
}
|
||||
|
||||
Log.e(TAG, "Starting file import with: " + uri.toString());
|
||||
|
||||
startImport(reader, uri, importDataFormat, password);
|
||||
startImport(reader, uri, importDataFormat, password, true);
|
||||
}
|
||||
}
|
||||
catch(FileNotFoundException e)
|
||||
{
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to import/export file: " + uri.toString(), e);
|
||||
if (requestCode == CHOOSE_EXPORT_LOCATION)
|
||||
{
|
||||
if (requestCode == CHOOSE_EXPORT_LOCATION) {
|
||||
onExportComplete(ImportExportResult.GenericFailure, uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
onImportComplete(ImportExportResult.GenericFailure, uri, importDataFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if(data == null)
|
||||
{
|
||||
if (data == null) {
|
||||
Log.e(TAG, "Activity returned NULL data");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -13,13 +12,13 @@ import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import protect.card_locker.async.CompatCallable;
|
||||
import protect.card_locker.importexport.DataFormat;
|
||||
import protect.card_locker.importexport.ImportExportResult;
|
||||
import protect.card_locker.importexport.MultiFormatExporter;
|
||||
import protect.card_locker.importexport.MultiFormatImporter;
|
||||
|
||||
class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
{
|
||||
public class ImportExportTask implements CompatCallable<ImportExportResult> {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
private Activity activity;
|
||||
@@ -35,14 +34,14 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
/**
|
||||
* Constructor which will setup a task for exporting to the given file
|
||||
*/
|
||||
ImportExportTask(Activity activity, DataFormat format, OutputStream output,
|
||||
TaskCompleteListener listener)
|
||||
{
|
||||
ImportExportTask(Activity activity, DataFormat format, OutputStream output, char[] password,
|
||||
TaskCompleteListener listener) {
|
||||
super();
|
||||
this.activity = activity;
|
||||
this.doImport = false;
|
||||
this.format = format;
|
||||
this.outputStream = output;
|
||||
this.password = password;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@@ -50,8 +49,7 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
* Constructor which will setup a task for importing from the given InputStream.
|
||||
*/
|
||||
ImportExportTask(Activity activity, DataFormat format, InputStream input, char[] password,
|
||||
TaskCompleteListener listener)
|
||||
{
|
||||
TaskCompleteListener listener) {
|
||||
super();
|
||||
this.activity = activity;
|
||||
this.doImport = true;
|
||||
@@ -61,8 +59,7 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
private ImportExportResult performImport(Context context, InputStream stream, DBHelper db, char[] password)
|
||||
{
|
||||
private ImportExportResult performImport(Context context, InputStream stream, DBHelper db, char[] password) {
|
||||
ImportExportResult importResult = MultiFormatImporter.importData(context, db, stream, format, password);
|
||||
|
||||
Log.i(TAG, "Import result: " + importResult.name());
|
||||
@@ -70,18 +67,14 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
return importResult;
|
||||
}
|
||||
|
||||
private ImportExportResult performExport(Context context, OutputStream stream, DBHelper db)
|
||||
{
|
||||
private ImportExportResult performExport(Context context, OutputStream stream, DBHelper db, char[] password) {
|
||||
ImportExportResult result = ImportExportResult.GenericFailure;
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8);
|
||||
result = MultiFormatExporter.exportData(context, db, stream, format);
|
||||
result = MultiFormatExporter.exportData(context, db, stream, format, password);
|
||||
writer.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to export file", e);
|
||||
}
|
||||
|
||||
@@ -90,55 +83,55 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void onPreExecute()
|
||||
{
|
||||
public void onPreExecute() {
|
||||
progress = new ProgressDialog(activity);
|
||||
progress.setTitle(doImport ? R.string.importing : R.string.exporting);
|
||||
|
||||
progress.setOnDismissListener(new DialogInterface.OnDismissListener()
|
||||
{
|
||||
progress.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog)
|
||||
{
|
||||
ImportExportTask.this.cancel(true);
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
ImportExportTask.this.stop();
|
||||
}
|
||||
});
|
||||
|
||||
progress.show();
|
||||
}
|
||||
|
||||
protected ImportExportResult doInBackground(Void... nothing)
|
||||
{
|
||||
protected ImportExportResult doInBackground(Void... nothing) {
|
||||
final DBHelper db = new DBHelper(activity);
|
||||
ImportExportResult result;
|
||||
|
||||
if(doImport)
|
||||
{
|
||||
if (doImport) {
|
||||
result = performImport(activity.getApplicationContext(), inputStream, db, password);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = performExport(activity.getApplicationContext(), outputStream, db);
|
||||
} else {
|
||||
result = performExport(activity.getApplicationContext(), outputStream, db, password);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void onPostExecute(ImportExportResult result)
|
||||
{
|
||||
listener.onTaskComplete(result, format);
|
||||
public void onPostExecute(Object castResult) {
|
||||
listener.onTaskComplete((ImportExportResult) castResult, format);
|
||||
|
||||
progress.dismiss();
|
||||
Log.i(TAG, (doImport ? "Import" : "Export") + " Complete");
|
||||
}
|
||||
|
||||
protected void onCancelled()
|
||||
{
|
||||
protected void onCancelled() {
|
||||
progress.dismiss();
|
||||
Log.i(TAG, (doImport ? "Import" : "Export") + " Cancelled");
|
||||
}
|
||||
interface TaskCompleteListener
|
||||
{
|
||||
|
||||
protected void stop() {
|
||||
// Whelp
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportExportResult call() {
|
||||
return doInBackground();
|
||||
}
|
||||
|
||||
interface TaskCompleteListener {
|
||||
void onTaskComplete(ImportExportResult result, DataFormat format);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
@@ -57,13 +55,13 @@ public class ImportURIHelper {
|
||||
}
|
||||
|
||||
public LoyaltyCard parse(Uri uri) throws InvalidObjectException {
|
||||
if(!isImportUri(uri)) {
|
||||
if (!isImportUri(uri)) {
|
||||
throw new InvalidObjectException("Not an import URI");
|
||||
}
|
||||
|
||||
try {
|
||||
// These values are allowed to be null
|
||||
BarcodeFormat barcodeType = null;
|
||||
CatimaBarcode barcodeType = null;
|
||||
Date expiry = null;
|
||||
BigDecimal balance = new BigDecimal("0");
|
||||
Currency balanceType = null;
|
||||
@@ -92,37 +90,33 @@ public class ImportURIHelper {
|
||||
String note = kv.get(NOTE);
|
||||
String cardId = kv.get(CARD_ID);
|
||||
String barcodeId = kv.get(BARCODE_ID);
|
||||
if (store == null || note == null || cardId == null) throw new InvalidObjectException("Not a valid import URI: " + uri.toString());
|
||||
if (store == null || note == null || cardId == null)
|
||||
throw new InvalidObjectException("Not a valid import URI: " + uri.toString());
|
||||
|
||||
String unparsedBarcodeType = kv.get(BARCODE_TYPE);
|
||||
if(unparsedBarcodeType != null && !unparsedBarcodeType.equals(""))
|
||||
{
|
||||
barcodeType = BarcodeFormat.valueOf(unparsedBarcodeType);
|
||||
if (unparsedBarcodeType != null && !unparsedBarcodeType.equals("")) {
|
||||
barcodeType = CatimaBarcode.fromName(unparsedBarcodeType);
|
||||
}
|
||||
|
||||
String unparsedBalance = kv.get(BALANCE);
|
||||
if(unparsedBalance != null && !unparsedBalance.equals(""))
|
||||
{
|
||||
if (unparsedBalance != null && !unparsedBalance.equals("")) {
|
||||
balance = new BigDecimal(unparsedBalance);
|
||||
}
|
||||
String unparsedBalanceType = kv.get(BALANCE_TYPE);
|
||||
if (unparsedBalanceType != null && !unparsedBalanceType.equals(""))
|
||||
{
|
||||
if (unparsedBalanceType != null && !unparsedBalanceType.equals("")) {
|
||||
balanceType = Currency.getInstance(unparsedBalanceType);
|
||||
}
|
||||
String unparsedExpiry = kv.get(EXPIRY);
|
||||
if(unparsedExpiry != null && !unparsedExpiry.equals(""))
|
||||
{
|
||||
if (unparsedExpiry != null && !unparsedExpiry.equals("")) {
|
||||
expiry = new Date(Long.parseLong(unparsedExpiry));
|
||||
}
|
||||
|
||||
String unparsedHeaderColor = kv.get(HEADER_COLOR);
|
||||
if(unparsedHeaderColor != null)
|
||||
{
|
||||
if (unparsedHeaderColor != null) {
|
||||
headerColor = Integer.parseInt(unparsedHeaderColor);
|
||||
}
|
||||
|
||||
return new LoyaltyCard(-1, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, 0);
|
||||
return new LoyaltyCard(-1, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, 0, Utils.getUnixTime(), 100);
|
||||
} catch (NullPointerException | NumberFormatException | UnsupportedEncodingException ex) {
|
||||
throw new InvalidObjectException("Not a valid import URI");
|
||||
}
|
||||
@@ -159,14 +153,14 @@ public class ImportURIHelper {
|
||||
fragment = appendFragment(fragment, EXPIRY, String.valueOf(loyaltyCard.expiry.getTime()));
|
||||
}
|
||||
fragment = appendFragment(fragment, CARD_ID, loyaltyCard.cardId);
|
||||
if(loyaltyCard.barcodeId != null) {
|
||||
if (loyaltyCard.barcodeId != null) {
|
||||
fragment = appendFragment(fragment, BARCODE_ID, loyaltyCard.barcodeId);
|
||||
}
|
||||
|
||||
if(loyaltyCard.barcodeType != null) {
|
||||
fragment = appendFragment(fragment, BARCODE_TYPE, loyaltyCard.barcodeType.toString());
|
||||
if (loyaltyCard.barcodeType != null) {
|
||||
fragment = appendFragment(fragment, BARCODE_TYPE, loyaltyCard.barcodeType.name());
|
||||
}
|
||||
if(loyaltyCard.headerColor != null) {
|
||||
if (loyaltyCard.headerColor != null) {
|
||||
fragment = appendFragment(fragment, HEADER_COLOR, loyaltyCard.headerColor.toString());
|
||||
}
|
||||
// Star status will not be exported
|
||||
|
||||
@@ -18,8 +18,7 @@ import android.text.TextPaint;
|
||||
* alphabet or digit, if there is no letter or digit available, a default image
|
||||
* is shown instead.
|
||||
*/
|
||||
class LetterBitmap
|
||||
{
|
||||
class LetterBitmap {
|
||||
|
||||
/**
|
||||
* The number of available tile colors
|
||||
@@ -37,39 +36,32 @@ class LetterBitmap
|
||||
/**
|
||||
* Constructor for <code>LetterTileProvider</code>
|
||||
*
|
||||
* @param context The {@link Context} to use
|
||||
* @param displayName The name used to create the letter for the tile
|
||||
* @param key The key used to generate the background color for the tile
|
||||
* @param context The {@link Context} to use
|
||||
* @param displayName The name used to create the letter for the tile
|
||||
* @param key The key used to generate the background color for the tile
|
||||
* @param tileLetterFontSize The font size used to display the letter
|
||||
* @param width The desired width of the tile
|
||||
* @param height The desired height of the tile
|
||||
* @param backgroundColor (optional) color to use for background.
|
||||
* @param textColor (optional) color to use for text.
|
||||
* @param width The desired width of the tile
|
||||
* @param height The desired height of the tile
|
||||
* @param backgroundColor (optional) color to use for background.
|
||||
* @param textColor (optional) color to use for text.
|
||||
*/
|
||||
public LetterBitmap(Context context, String displayName, String key, int tileLetterFontSize,
|
||||
int width, int height, Integer backgroundColor, Integer textColor)
|
||||
{
|
||||
int width, int height, Integer backgroundColor, Integer textColor) {
|
||||
TextPaint paint = new TextPaint();
|
||||
paint.setTypeface(Typeface.create("sans-serif-light", Typeface.BOLD));
|
||||
|
||||
if(textColor != null)
|
||||
{
|
||||
if (textColor != null) {
|
||||
paint.setColor(textColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
paint.setColor(Color.WHITE);
|
||||
}
|
||||
|
||||
paint.setTextAlign(Paint.Align.CENTER);
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
if(backgroundColor == null)
|
||||
{
|
||||
if (backgroundColor == null) {
|
||||
mColor = getDefaultColor(context, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
mColor = backgroundColor;
|
||||
}
|
||||
|
||||
@@ -80,7 +72,7 @@ class LetterBitmap
|
||||
c.setBitmap(mBitmap);
|
||||
c.drawColor(mColor);
|
||||
|
||||
char [] firstCharArray = new char[1];
|
||||
char[] firstCharArray = new char[1];
|
||||
firstCharArray[0] = firstChar.toUpperCase().charAt(0);
|
||||
paint.setTextSize(tileLetterFontSize);
|
||||
|
||||
@@ -97,16 +89,14 @@ class LetterBitmap
|
||||
* alphabet or digit, if there is no letter or digit available, a
|
||||
* default image is shown instead
|
||||
*/
|
||||
public Bitmap getLetterTile()
|
||||
{
|
||||
public Bitmap getLetterTile() {
|
||||
return mBitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return background color used for letter title.
|
||||
*/
|
||||
public int getBackgroundColor()
|
||||
{
|
||||
public int getBackgroundColor() {
|
||||
return mColor;
|
||||
}
|
||||
|
||||
@@ -115,8 +105,7 @@ class LetterBitmap
|
||||
* @return A new or previously chosen color for <code>key</code> used as the
|
||||
* tile background color
|
||||
*/
|
||||
private static int pickColor(String key, TypedArray colors)
|
||||
{
|
||||
private static int pickColor(String key, TypedArray colors) {
|
||||
// String.hashCode() is not supposed to change across java versions, so
|
||||
// this should guarantee the same key always maps to the same color
|
||||
final int color = Math.abs(key.hashCode()) % NUM_OF_TILE_COLORS;
|
||||
@@ -127,8 +116,7 @@ class LetterBitmap
|
||||
* Determine the color which the letter tile will use if no default
|
||||
* color is provided.
|
||||
*/
|
||||
public static int getDefaultColor(Context context, String key)
|
||||
{
|
||||
public static int getDefaultColor(Context context, String key) {
|
||||
final Resources res = context.getResources();
|
||||
|
||||
TypedArray colors = res.obtainTypedArray(R.array.letter_tile_colors);
|
||||
|
||||
@@ -4,8 +4,6 @@ import android.database.Cursor;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Currency;
|
||||
import java.util.Date;
|
||||
@@ -25,18 +23,19 @@ public class LoyaltyCard implements Parcelable {
|
||||
public final String barcodeId;
|
||||
|
||||
@Nullable
|
||||
public final BarcodeFormat barcodeType;
|
||||
public final CatimaBarcode barcodeType;
|
||||
|
||||
@Nullable
|
||||
public final Integer headerColor;
|
||||
|
||||
public final int starStatus;
|
||||
public final long lastUsed;
|
||||
public int zoomLevel;
|
||||
|
||||
public LoyaltyCard(final int id, final String store, final String note, final Date expiry,
|
||||
final BigDecimal balance, final Currency balanceType, final String cardId,
|
||||
@Nullable final String barcodeId, @Nullable final BarcodeFormat barcodeType, @Nullable final Integer headerColor,
|
||||
final int starStatus)
|
||||
{
|
||||
@Nullable final String barcodeId, @Nullable final CatimaBarcode barcodeType,
|
||||
@Nullable final Integer headerColor, final int starStatus, final long lastUsed, final int zoomLevel) {
|
||||
this.id = id;
|
||||
this.store = store;
|
||||
this.note = note;
|
||||
@@ -48,6 +47,8 @@ public class LoyaltyCard implements Parcelable {
|
||||
this.barcodeType = barcodeType;
|
||||
this.headerColor = headerColor;
|
||||
this.starStatus = starStatus;
|
||||
this.lastUsed = lastUsed;
|
||||
this.zoomLevel = zoomLevel;
|
||||
}
|
||||
|
||||
protected LoyaltyCard(Parcel in) {
|
||||
@@ -61,10 +62,12 @@ public class LoyaltyCard implements Parcelable {
|
||||
cardId = in.readString();
|
||||
barcodeId = in.readString();
|
||||
String tmpBarcodeType = in.readString();
|
||||
barcodeType = !tmpBarcodeType.isEmpty() ? BarcodeFormat.valueOf(tmpBarcodeType) : null;
|
||||
barcodeType = !tmpBarcodeType.isEmpty() ? CatimaBarcode.fromName(tmpBarcodeType) : null;
|
||||
int tmpHeaderColor = in.readInt();
|
||||
headerColor = tmpHeaderColor != -1 ? tmpHeaderColor : null;
|
||||
starStatus = in.readInt();
|
||||
lastUsed = in.readLong();
|
||||
zoomLevel = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,13 +80,14 @@ public class LoyaltyCard implements Parcelable {
|
||||
parcel.writeValue(balanceType);
|
||||
parcel.writeString(cardId);
|
||||
parcel.writeString(barcodeId);
|
||||
parcel.writeString(barcodeType != null ? barcodeType.toString() : "");
|
||||
parcel.writeString(barcodeType != null ? barcodeType.name() : "");
|
||||
parcel.writeInt(headerColor != null ? headerColor : -1);
|
||||
parcel.writeInt(starStatus);
|
||||
parcel.writeLong(lastUsed);
|
||||
parcel.writeInt(zoomLevel);
|
||||
}
|
||||
|
||||
public static LoyaltyCard toLoyaltyCard(Cursor cursor)
|
||||
{
|
||||
public static LoyaltyCard toLoyaltyCard(Cursor cursor) {
|
||||
int id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID));
|
||||
String store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE));
|
||||
String note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE));
|
||||
@@ -92,37 +96,35 @@ public class LoyaltyCard implements Parcelable {
|
||||
String cardId = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.CARD_ID));
|
||||
String barcodeId = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_ID));
|
||||
int starred = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STAR_STATUS));
|
||||
long lastUsed = cursor.getLong(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.LAST_USED));
|
||||
int zoomLevel = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ZOOM_LEVEL));
|
||||
|
||||
int barcodeTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_TYPE);
|
||||
int balanceTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BALANCE_TYPE);
|
||||
int headerColorColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.HEADER_COLOR);
|
||||
|
||||
BarcodeFormat barcodeType = null;
|
||||
CatimaBarcode barcodeType = null;
|
||||
Currency balanceType = null;
|
||||
Date expiry = null;
|
||||
Integer headerColor = null;
|
||||
|
||||
if (cursor.isNull(barcodeTypeColumn) == false)
|
||||
{
|
||||
barcodeType = BarcodeFormat.valueOf(cursor.getString(barcodeTypeColumn));
|
||||
if (cursor.isNull(barcodeTypeColumn) == false) {
|
||||
barcodeType = CatimaBarcode.fromName(cursor.getString(barcodeTypeColumn));
|
||||
}
|
||||
|
||||
if (cursor.isNull(balanceTypeColumn) == false)
|
||||
{
|
||||
if (cursor.isNull(balanceTypeColumn) == false) {
|
||||
balanceType = Currency.getInstance(cursor.getString(balanceTypeColumn));
|
||||
}
|
||||
|
||||
if(expiryLong > 0)
|
||||
{
|
||||
if (expiryLong > 0) {
|
||||
expiry = new Date(expiryLong);
|
||||
}
|
||||
|
||||
if(cursor.isNull(headerColorColumn) == false)
|
||||
{
|
||||
if (cursor.isNull(headerColorColumn) == false) {
|
||||
headerColor = cursor.getInt(headerColorColumn);
|
||||
}
|
||||
|
||||
return new LoyaltyCard(id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starred);
|
||||
return new LoyaltyCard(id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starred, lastUsed, zoomLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,43 +1,47 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.graphics.BlendModeColorFilterCompat;
|
||||
import androidx.core.graphics.BlendModeCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import protect.card_locker.preferences.Settings;
|
||||
|
||||
public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder>
|
||||
{
|
||||
private static int mCurrentSelectedIndex = -1;
|
||||
public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder> {
|
||||
private int mCurrentSelectedIndex = -1;
|
||||
private Cursor mCursor;
|
||||
Settings mSettings;
|
||||
boolean mDarkModeEnabled;
|
||||
private Context mContext;
|
||||
private CardAdapterListener mListener;
|
||||
private SparseBooleanArray mSelectedItems;
|
||||
private SparseBooleanArray mAnimationItemsIndex;
|
||||
protected SparseBooleanArray mSelectedItems;
|
||||
protected SparseBooleanArray mAnimationItemsIndex;
|
||||
private boolean mReverseAllAnimations = false;
|
||||
|
||||
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener)
|
||||
{
|
||||
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener) {
|
||||
super(inputCursor);
|
||||
setHasStableIds(true);
|
||||
mSettings = new Settings(inputContext);
|
||||
@@ -46,7 +50,7 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
mSelectedItems = new SparseBooleanArray();
|
||||
mAnimationItemsIndex = new SparseBooleanArray();
|
||||
|
||||
mDarkModeEnabled = MainActivity.isDarkModeEnabled(inputContext);
|
||||
mDarkModeEnabled = Utils.isDarkModeEnabled(inputContext);
|
||||
|
||||
swapCursor(mCursor);
|
||||
}
|
||||
@@ -58,20 +62,32 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoyaltyCardListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType)
|
||||
{
|
||||
public LoyaltyCardListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType) {
|
||||
View itemView = LayoutInflater.from(inputParent.getContext()).inflate(R.layout.loyalty_card_layout, inputParent, false);
|
||||
return new LoyaltyCardListItemViewHolder(itemView);
|
||||
return new LoyaltyCardListItemViewHolder(itemView, mListener);
|
||||
}
|
||||
|
||||
public Cursor getCursor()
|
||||
{
|
||||
public Cursor getCursor() {
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
public void onBindViewHolder(LoyaltyCardListItemViewHolder inputHolder, Cursor inputCursor) {
|
||||
// Invisible until we want to show something more
|
||||
inputHolder.mDivider.setVisibility(View.GONE);
|
||||
|
||||
// remove outline shadow
|
||||
inputHolder.mThumbnailContainer.setOutlineProvider(new ViewOutlineProvider() {
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
|
||||
outline.setAlpha(0f);
|
||||
}
|
||||
});
|
||||
|
||||
int size = mSettings.getFontSizeMax(mSettings.getSmallFont());
|
||||
|
||||
if (mDarkModeEnabled) {
|
||||
inputHolder.mStarIcon.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
|
||||
inputHolder.mStarIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP));
|
||||
}
|
||||
|
||||
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(inputCursor);
|
||||
@@ -81,45 +97,96 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
if (!loyaltyCard.note.isEmpty()) {
|
||||
inputHolder.mNoteField.setVisibility(View.VISIBLE);
|
||||
inputHolder.mNoteField.setText(loyaltyCard.note);
|
||||
inputHolder.mNoteField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
|
||||
inputHolder.mNoteField.setTextSize(size);
|
||||
} else {
|
||||
inputHolder.mNoteField.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (!loyaltyCard.balance.equals(new BigDecimal("0"))) {
|
||||
int drawableSize = dpToPx((size * 24) / 14, mContext);
|
||||
inputHolder.mDivider.setVisibility(View.VISIBLE);
|
||||
inputHolder.mBalanceField.setVisibility(View.VISIBLE);
|
||||
inputHolder.mBalanceField.setText(mContext.getString(R.string.balanceSentence, Utils.formatBalance(mContext, loyaltyCard.balance, loyaltyCard.balanceType)));
|
||||
inputHolder.mBalanceField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
|
||||
Drawable balanceIcon = inputHolder.mBalanceField.getCompoundDrawables()[0];
|
||||
balanceIcon.setBounds(0, 0, drawableSize, drawableSize);
|
||||
inputHolder.mBalanceField.setCompoundDrawablesRelative(balanceIcon, null, null, null);
|
||||
if (mDarkModeEnabled) {
|
||||
balanceIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP));
|
||||
}
|
||||
inputHolder.mBalanceField.setText(Utils.formatBalance(mContext, loyaltyCard.balance, loyaltyCard.balanceType));
|
||||
inputHolder.mBalanceField.setTextSize(size);
|
||||
} else {
|
||||
inputHolder.mBalanceField.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (loyaltyCard.expiry != null)
|
||||
{
|
||||
if (loyaltyCard.expiry != null) {
|
||||
int drawableSize = dpToPx((size * 24) / 14, mContext);
|
||||
inputHolder.mDivider.setVisibility(View.VISIBLE);
|
||||
inputHolder.mExpiryField.setVisibility(View.VISIBLE);
|
||||
int expiryString = R.string.expiryStateSentence;
|
||||
if(Utils.hasExpired(loyaltyCard.expiry)) {
|
||||
expiryString = R.string.expiryStateSentenceExpired;
|
||||
inputHolder.mExpiryField.setTextColor(mContext.getResources().getColor(R.color.alert));
|
||||
Drawable expiryIcon = inputHolder.mExpiryField.getCompoundDrawables()[0];
|
||||
expiryIcon.setBounds(0, 0, drawableSize, drawableSize);
|
||||
inputHolder.mExpiryField.setCompoundDrawablesRelative(expiryIcon, null, null, null);
|
||||
if (Utils.hasExpired(loyaltyCard.expiry)) {
|
||||
expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.RED, BlendModeCompat.SRC_ATOP));
|
||||
inputHolder.mExpiryField.setTextColor(Color.RED);
|
||||
} else if (mDarkModeEnabled) {
|
||||
expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP));
|
||||
}
|
||||
inputHolder.mExpiryField.setText(mContext.getString(expiryString, DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.expiry)));
|
||||
inputHolder.mExpiryField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
|
||||
inputHolder.mExpiryField.setText(DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.expiry));
|
||||
inputHolder.mExpiryField.setTextSize(size);
|
||||
} else {
|
||||
inputHolder.mExpiryField.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
inputHolder.mStarIcon.setVisibility((loyaltyCard.starStatus != 0) ? View.VISIBLE : View.GONE);
|
||||
inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, loyaltyCard.store, loyaltyCard.headerColor).getLetterTile());
|
||||
Bitmap cardIcon = Utils.retrieveCardImage(mContext, loyaltyCard.id, ImageLocationType.icon);
|
||||
if (cardIcon != null) {
|
||||
inputHolder.mCardIcon.setImageBitmap(cardIcon);
|
||||
inputHolder.mCardIcon.setBackgroundColor(Color.TRANSPARENT);
|
||||
} else {
|
||||
inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, loyaltyCard.store, loyaltyCard.headerColor).getLetterTile());
|
||||
if (loyaltyCard.headerColor != null) {
|
||||
inputHolder.mCardIcon.setBackgroundColor(loyaltyCard.headerColor);
|
||||
}
|
||||
}
|
||||
|
||||
inputHolder.mStarIcon.setVisibility(loyaltyCard.starStatus != 0 ? View.VISIBLE : View.GONE);
|
||||
int imageSize = dpToPx((size * 46) / 14, mContext);
|
||||
inputHolder.mCardIcon.getLayoutParams().height = imageSize;
|
||||
inputHolder.mCardIcon.getLayoutParams().width = imageSize;
|
||||
inputHolder.mStarIcon.getLayoutParams().height = imageSize;
|
||||
inputHolder.mStarIcon.getLayoutParams().width = imageSize;
|
||||
inputHolder.mTickIcon.getLayoutParams().height = imageSize;
|
||||
inputHolder.mTickIcon.getLayoutParams().width = imageSize;
|
||||
|
||||
/* Changing Padding and Mragin of different views according to font size
|
||||
* Views Included:
|
||||
* a) InformationContainer padding
|
||||
* b) Store left padding
|
||||
* c) Divider Margin
|
||||
* d) note top margin
|
||||
* e) row margin
|
||||
* */
|
||||
int marginPaddingSize = dpToPx((size * 16) / 14, mContext);
|
||||
inputHolder.mInformationContainer.setPadding(marginPaddingSize, marginPaddingSize, marginPaddingSize, marginPaddingSize);
|
||||
inputHolder.mStoreField.setPadding(marginPaddingSize, 0, 0, 0);
|
||||
LinearLayout.LayoutParams lpDivider = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
lpDivider.setMargins(0, marginPaddingSize, 0, marginPaddingSize);
|
||||
inputHolder.mDivider.setLayoutParams(lpDivider);
|
||||
LinearLayout.LayoutParams lpNoteField = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
lpNoteField.setMargins(0, marginPaddingSize / 2, 0, 0);
|
||||
inputHolder.mNoteField.setLayoutParams(lpNoteField);
|
||||
LinearLayout.LayoutParams lpRow = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
lpRow.setMargins(marginPaddingSize / 2, marginPaddingSize / 2, marginPaddingSize / 2, marginPaddingSize / 2);
|
||||
inputHolder.mRow.setLayoutParams(lpRow);
|
||||
|
||||
inputHolder.itemView.setActivated(mSelectedItems.get(inputCursor.getPosition(), false));
|
||||
applyIconAnimation(inputHolder, inputCursor.getPosition());
|
||||
applyClickEvents(inputHolder, inputCursor.getPosition());
|
||||
|
||||
}
|
||||
|
||||
private void applyClickEvents(LoyaltyCardListItemViewHolder inputHolder, final int inputPosition)
|
||||
{
|
||||
inputHolder.mThumbnailContainer.setOnClickListener(inputView -> mListener.onIconClicked(inputPosition));
|
||||
private void applyClickEvents(LoyaltyCardListItemViewHolder inputHolder, final int inputPosition) {
|
||||
inputHolder.mRow.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition));
|
||||
inputHolder.mInformationContainer.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition));
|
||||
|
||||
@@ -136,85 +203,68 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
});
|
||||
}
|
||||
|
||||
private void applyIconAnimation(LoyaltyCardListItemViewHolder inputHolder, int inputPosition)
|
||||
{
|
||||
if (mSelectedItems.get(inputPosition, false))
|
||||
{
|
||||
private void applyIconAnimation(LoyaltyCardListItemViewHolder inputHolder, int inputPosition) {
|
||||
if (mSelectedItems.get(inputPosition, false)) {
|
||||
inputHolder.mThumbnailFrontContainer.setVisibility(View.GONE);
|
||||
resetIconYAxis(inputHolder.mThumbnailBackContainer);
|
||||
inputHolder.mThumbnailBackContainer.setVisibility(View.VISIBLE);
|
||||
inputHolder.mThumbnailBackContainer.setAlpha(1);
|
||||
if (mCurrentSelectedIndex == inputPosition)
|
||||
{
|
||||
if (mCurrentSelectedIndex == inputPosition) {
|
||||
LoyaltyCardAnimator.flipView(mContext, inputHolder.mThumbnailBackContainer, inputHolder.mThumbnailFrontContainer, true);
|
||||
resetCurrentIndex();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
inputHolder.mThumbnailBackContainer.setVisibility(View.GONE);
|
||||
resetIconYAxis(inputHolder.mThumbnailFrontContainer);
|
||||
inputHolder.mThumbnailFrontContainer.setVisibility(View.VISIBLE);
|
||||
inputHolder.mThumbnailFrontContainer.setAlpha(1);
|
||||
if ((mReverseAllAnimations && mAnimationItemsIndex.get(inputPosition, false)) || mCurrentSelectedIndex == inputPosition)
|
||||
{
|
||||
if ((mReverseAllAnimations && mAnimationItemsIndex.get(inputPosition, false)) || mCurrentSelectedIndex == inputPosition) {
|
||||
LoyaltyCardAnimator.flipView(mContext, inputHolder.mThumbnailBackContainer, inputHolder.mThumbnailFrontContainer, false);
|
||||
resetCurrentIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resetIconYAxis(View inputView)
|
||||
{
|
||||
if (inputView.getRotationY() != 0)
|
||||
{
|
||||
private void resetIconYAxis(View inputView) {
|
||||
if (inputView.getRotationY() != 0) {
|
||||
inputView.setRotationY(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetAnimationIndex()
|
||||
{
|
||||
public void resetAnimationIndex() {
|
||||
mReverseAllAnimations = false;
|
||||
mAnimationItemsIndex.clear();
|
||||
}
|
||||
|
||||
@SuppressFBWarnings("ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD")
|
||||
public void toggleSelection(int inputPosition)
|
||||
{
|
||||
|
||||
public void toggleSelection(int inputPosition) {
|
||||
mCurrentSelectedIndex = inputPosition;
|
||||
if (mSelectedItems.get(inputPosition, false))
|
||||
{
|
||||
if (mSelectedItems.get(inputPosition, false)) {
|
||||
mSelectedItems.delete(inputPosition);
|
||||
mAnimationItemsIndex.delete(inputPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
mSelectedItems.put(inputPosition, true);
|
||||
mAnimationItemsIndex.put(inputPosition, true);
|
||||
}
|
||||
notifyItemChanged(inputPosition);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void clearSelections()
|
||||
{
|
||||
public void clearSelections() {
|
||||
mReverseAllAnimations = true;
|
||||
mSelectedItems.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public int getSelectedItemCount()
|
||||
{
|
||||
public int getSelectedItemCount() {
|
||||
return mSelectedItems.size();
|
||||
}
|
||||
|
||||
public ArrayList<LoyaltyCard> getSelectedItems()
|
||||
{
|
||||
public ArrayList<LoyaltyCard> getSelectedItems() {
|
||||
|
||||
ArrayList<LoyaltyCard> result = new ArrayList<>();
|
||||
|
||||
int i;
|
||||
for(i = 0; i < mSelectedItems.size(); i++)
|
||||
{
|
||||
for (i = 0; i < mSelectedItems.size(); i++) {
|
||||
mCursor.moveToPosition(mSelectedItems.keyAt(i));
|
||||
result.add(LoyaltyCard.toLoyaltyCard(mCursor));
|
||||
}
|
||||
@@ -222,33 +272,31 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
return result;
|
||||
}
|
||||
|
||||
private void resetCurrentIndex()
|
||||
{
|
||||
private void resetCurrentIndex() {
|
||||
mCurrentSelectedIndex = -1;
|
||||
}
|
||||
|
||||
public interface CardAdapterListener
|
||||
{
|
||||
void onIconClicked(int inputPosition);
|
||||
public interface CardAdapterListener {
|
||||
void onRowClicked(int inputPosition);
|
||||
|
||||
void onRowLongClicked(int inputPosition);
|
||||
}
|
||||
|
||||
public class LoyaltyCardListItemViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener
|
||||
{
|
||||
public static class LoyaltyCardListItemViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public TextView mStoreField, mNoteField, mBalanceField, mExpiryField;
|
||||
public LinearLayout mInformationContainer;
|
||||
public ImageView mCardIcon, mStarIcon;
|
||||
public CardView mThumbnailContainer;
|
||||
public ConstraintLayout mRow;
|
||||
public ImageView mCardIcon, mStarIcon, mTickIcon;
|
||||
public MaterialCardView mRow;
|
||||
public View mDivider;
|
||||
public RelativeLayout mThumbnailFrontContainer, mThumbnailBackContainer;
|
||||
public MaterialCardView mThumbnailContainer;
|
||||
|
||||
public LoyaltyCardListItemViewHolder(View inputView)
|
||||
{
|
||||
public LoyaltyCardListItemViewHolder(View inputView, CardAdapterListener inputListener) {
|
||||
super(inputView);
|
||||
mThumbnailContainer = inputView.findViewById(R.id.thumbnail_container);
|
||||
mRow = inputView.findViewById(R.id.row);
|
||||
mDivider = inputView.findViewById(R.id.info_divider);
|
||||
mThumbnailContainer = inputView.findViewById(R.id.thumbnail_container);
|
||||
mThumbnailFrontContainer = inputView.findViewById(R.id.thumbnail_front);
|
||||
mThumbnailBackContainer = inputView.findViewById(R.id.thumbnail_back);
|
||||
mInformationContainer = inputView.findViewById(R.id.information_container);
|
||||
@@ -258,15 +306,18 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
mExpiryField = inputView.findViewById(R.id.expiry);
|
||||
mCardIcon = inputView.findViewById(R.id.thumbnail);
|
||||
mStarIcon = inputView.findViewById(R.id.star);
|
||||
inputView.setOnLongClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View inputView)
|
||||
{
|
||||
mListener.onRowLongClicked(getAdapterPosition());
|
||||
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
return true;
|
||||
mTickIcon = inputView.findViewById(R.id.selected_thumbnail);
|
||||
inputView.setOnLongClickListener(view -> {
|
||||
inputListener.onRowClicked(getAdapterPosition());
|
||||
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int dpToPx(int dp, Context mContext) {
|
||||
Resources r = mContext.getResources();
|
||||
int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());
|
||||
return px;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,17 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.multidex.MultiDexApplication;
|
||||
import protect.card_locker.preferences.Settings;
|
||||
|
||||
public class LoyaltyCardLockerApplication extends MultiDexApplication {
|
||||
public class LoyaltyCardLockerApplication extends Application {
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
Settings settings = new Settings(getApplicationContext());
|
||||
Settings settings = new Settings(this);
|
||||
AppCompatDelegate.setDefaultNightMode(settings.getTheme());
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,9 +6,8 @@ import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.database.CursorIndexOutOfBoundsException;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
@@ -16,27 +15,26 @@ import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.core.splashscreen.SplashScreen;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import protect.card_locker.preferences.SettingsActivity;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener, GestureDetector.OnGestureListener
|
||||
{
|
||||
public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener, GestureDetector.OnGestureListener {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
private final DBHelper mDB = new DBHelper(this);
|
||||
@@ -45,13 +43,16 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
private Menu mMenu;
|
||||
private GestureDetector mGestureDetector;
|
||||
protected String mFilter = "";
|
||||
protected Object mGroup = null;
|
||||
protected DBHelper.LoyaltyCardOrder mOrder = DBHelper.LoyaltyCardOrder.Alpha;
|
||||
protected DBHelper.LoyaltyCardOrderDirection mOrderDirection = DBHelper.LoyaltyCardOrderDirection.Ascending;
|
||||
protected int selectedTab = 0;
|
||||
private RecyclerView mCardList;
|
||||
private View mHelpText;
|
||||
private View mNoMatchingCardsText;
|
||||
private View mNoGroupCardsText;
|
||||
|
||||
private ActionMode.Callback mCurrentActionModeCallback = new ActionMode.Callback()
|
||||
{
|
||||
private ActionMode.Callback mCurrentActionModeCallback = new ActionMode.Callback() {
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode inputMode, Menu inputMenu) {
|
||||
inputMode.getMenuInflater().inflate(R.menu.card_longclick_menu, inputMenu);
|
||||
@@ -59,8 +60,7 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode inputMode, Menu inputMenu)
|
||||
{
|
||||
public boolean onPrepareActionMode(ActionMode inputMode, Menu inputMenu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
}
|
||||
inputMode.finish();
|
||||
return true;
|
||||
} else if(inputItem.getItemId() == R.id.action_edit) {
|
||||
} else if (inputItem.getItemId() == R.id.action_edit) {
|
||||
if (mAdapter.getSelectedItemCount() != 1) {
|
||||
throw new IllegalArgumentException("Cannot edit more than 1 card at a time");
|
||||
}
|
||||
@@ -117,7 +117,7 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
startActivity(intent);
|
||||
inputMode.finish();
|
||||
return true;
|
||||
} else if(inputItem.getItemId() == R.id.action_delete) {
|
||||
} else if (inputItem.getItemId() == R.id.action_delete) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
|
||||
// The following may seem weird, but it is necessary to give translators enough flexibility.
|
||||
// For example, in Russian, Android's plural quantity "one" actually refers to "any number ending on 1 but not ending in 11".
|
||||
@@ -143,8 +143,9 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
}
|
||||
|
||||
TabLayout.Tab tab = ((TabLayout) findViewById(R.id.groups)).getTabAt(selectedTab);
|
||||
mGroup = tab != null ? tab.getTag() : null;
|
||||
|
||||
updateLoyaltyCardList(mFilter, tab != null ? tab.getTag() : null);
|
||||
updateLoyaltyCardList();
|
||||
|
||||
dialog.dismiss();
|
||||
});
|
||||
@@ -159,15 +160,12 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode inputMode)
|
||||
{
|
||||
public void onDestroyActionMode(ActionMode inputMode) {
|
||||
mAdapter.clearSelections();
|
||||
mCurrentActionMode = null;
|
||||
mCardList.post(new Runnable()
|
||||
{
|
||||
mCardList.post(new Runnable() {
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
public void run() {
|
||||
mAdapter.resetAnimationIndex();
|
||||
}
|
||||
});
|
||||
@@ -175,10 +173,10 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle inputSavedInstanceState)
|
||||
{
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
protected void onCreate(Bundle inputSavedInstanceState) {
|
||||
super.onCreate(inputSavedInstanceState);
|
||||
SplashScreen.installSplashScreen(this);
|
||||
setTitle(R.string.app_name);
|
||||
setContentView(R.layout.main_activity);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
@@ -188,14 +186,15 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
selectedTab = tab.getPosition();
|
||||
updateLoyaltyCardList(mFilter, tab.getTag());
|
||||
|
||||
Log.d("onTabSelected", "Tab Position " + tab.getPosition());
|
||||
mGroup = tab.getTag();
|
||||
updateLoyaltyCardList();
|
||||
// Store active tab in Shared Preference to restore next app launch
|
||||
SharedPreferences activeTabPref = getApplicationContext().getSharedPreferences(
|
||||
getString(R.string.sharedpreference_active_tab),
|
||||
Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor activeTabPrefEditor = activeTabPref.edit();
|
||||
activeTabPrefEditor.putInt(getString(R.string.sharedpreference_active_tab), selectedTab);
|
||||
activeTabPrefEditor.putInt(getString(R.string.sharedpreference_active_tab), tab.getPosition());
|
||||
activeTabPrefEditor.apply();
|
||||
}
|
||||
|
||||
@@ -212,31 +211,24 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
|
||||
mGestureDetector = new GestureDetector(this, this);
|
||||
|
||||
View.OnTouchListener gestureTouchListener = new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(final View v, final MotionEvent event){
|
||||
return mGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
};
|
||||
View.OnTouchListener gestureTouchListener = (v, event) -> mGestureDetector.onTouchEvent(event);
|
||||
|
||||
mHelpText = findViewById(R.id.helpText);
|
||||
mNoMatchingCardsText = findViewById(R.id.noMatchingCardsText);
|
||||
mNoGroupCardsText = findViewById(R.id.noGroupCardsText);
|
||||
mCardList = findViewById(R.id.list);
|
||||
|
||||
mHelpText.setOnTouchListener(gestureTouchListener);
|
||||
mNoMatchingCardsText.setOnTouchListener(gestureTouchListener);
|
||||
mCardList.setOnTouchListener(gestureTouchListener);
|
||||
|
||||
// Init card list
|
||||
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
|
||||
mCardList.setLayoutManager(mLayoutManager);
|
||||
mCardList.setItemAnimator(new DefaultItemAnimator());
|
||||
mNoGroupCardsText.setOnTouchListener(gestureTouchListener);
|
||||
|
||||
mAdapter = new LoyaltyCardCursorAdapter(this, null, this);
|
||||
mCardList.setAdapter(mAdapter);
|
||||
registerForContextMenu(mCardList);
|
||||
|
||||
updateLoyaltyCardList(mFilter, null);
|
||||
mGroup = null;
|
||||
updateLoyaltyCardList();
|
||||
|
||||
/*
|
||||
* This was added for Huawei, but Huawei is just too much of a fucking pain.
|
||||
@@ -271,22 +263,18 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume()
|
||||
{
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if(mCurrentActionMode != null)
|
||||
{
|
||||
if (mCurrentActionMode != null) {
|
||||
mAdapter.clearSelections();
|
||||
mCurrentActionMode.finish();
|
||||
}
|
||||
|
||||
if (mMenu != null)
|
||||
{
|
||||
if (mMenu != null) {
|
||||
SearchView searchView = (SearchView) mMenu.findItem(R.id.action_search).getActionView();
|
||||
|
||||
if (!searchView.isIconified())
|
||||
{
|
||||
if (!searchView.isIconified()) {
|
||||
mFilter = searchView.getQuery().toString();
|
||||
}
|
||||
}
|
||||
@@ -295,13 +283,21 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
TabLayout groupsTabLayout = findViewById(R.id.groups);
|
||||
updateTabGroups(groupsTabLayout);
|
||||
|
||||
// Restore active tab from Shared Preference
|
||||
// Restore settings from Shared Preference
|
||||
SharedPreferences activeTabPref = getApplicationContext().getSharedPreferences(
|
||||
getString(R.string.sharedpreference_active_tab),
|
||||
Context.MODE_PRIVATE);
|
||||
selectedTab = activeTabPref.getInt(getString(R.string.sharedpreference_active_tab), 0);
|
||||
SharedPreferences sortPref = getApplicationContext().getSharedPreferences(
|
||||
getString(R.string.sharedpreference_sort),
|
||||
Context.MODE_PRIVATE);
|
||||
try {
|
||||
mOrder = DBHelper.LoyaltyCardOrder.valueOf(sortPref.getString(getString(R.string.sharedpreference_sort_order), null));
|
||||
mOrderDirection = DBHelper.LoyaltyCardOrderDirection.valueOf(sortPref.getString(getString(R.string.sharedpreference_sort_direction), null));
|
||||
} catch (IllegalArgumentException | NullPointerException ignored) {
|
||||
}
|
||||
|
||||
Object group = null;
|
||||
mGroup = null;
|
||||
|
||||
if (groupsTabLayout.getTabCount() != 0) {
|
||||
TabLayout.Tab tab = groupsTabLayout.getTabAt(selectedTab);
|
||||
@@ -311,9 +307,9 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
|
||||
groupsTabLayout.selectTab(tab);
|
||||
assert tab != null;
|
||||
group = tab.getTag();
|
||||
mGroup = tab.getTag();
|
||||
}
|
||||
updateLoyaltyCardList(mFilter, group);
|
||||
updateLoyaltyCardList();
|
||||
// End of active tab logic
|
||||
|
||||
FloatingActionButton addButton = findViewById(R.id.fabAdd);
|
||||
@@ -337,19 +333,18 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
// We're coming back from another view so clear the search
|
||||
// We only do this now to prevent a flash of all entries right after picking one
|
||||
mFilter = "";
|
||||
if (mMenu != null)
|
||||
{
|
||||
if (mMenu != null) {
|
||||
MenuItem searchItem = mMenu.findItem(R.id.action_search);
|
||||
searchItem.collapseActionView();
|
||||
}
|
||||
ActivityCompat.recreate(this);
|
||||
updateLoyaltyCardList();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BarcodeValues barcodeValues = Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this);
|
||||
|
||||
if(!barcodeValues.isEmpty()) {
|
||||
if (!barcodeValues.isEmpty()) {
|
||||
Intent newIntent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
|
||||
Bundle newBundle = new Bundle();
|
||||
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_BARCODETYPE, barcodeValues.format());
|
||||
@@ -364,61 +359,53 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed()
|
||||
{
|
||||
if (mMenu == null)
|
||||
{
|
||||
super.onBackPressed();
|
||||
return;
|
||||
}
|
||||
public void onBackPressed() {
|
||||
if (mMenu != null) {
|
||||
SearchView searchView = (SearchView) mMenu.findItem(R.id.action_search).getActionView();
|
||||
|
||||
SearchView searchView = (SearchView) mMenu.findItem(R.id.action_search).getActionView();
|
||||
|
||||
if (!searchView.isIconified())
|
||||
{
|
||||
searchView.setIconified(true);
|
||||
} else {
|
||||
TabLayout groupsTabLayout = findViewById(R.id.groups);
|
||||
|
||||
if (groupsTabLayout.getVisibility() == View.VISIBLE && selectedTab != 0) {
|
||||
selectedTab = 0;
|
||||
groupsTabLayout.selectTab(groupsTabLayout.getTabAt(0));
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
if (!searchView.isIconified()) {
|
||||
searchView.setIconified(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
private void updateLoyaltyCardList(String filterText, Object tag)
|
||||
{
|
||||
private void updateLoyaltyCardList() {
|
||||
Group group = null;
|
||||
if (tag != null) {
|
||||
group = (Group) tag;
|
||||
if (mGroup != null) {
|
||||
group = (Group) mGroup;
|
||||
}
|
||||
|
||||
mAdapter.swapCursor(mDB.getLoyaltyCardCursor(filterText, group));
|
||||
mAdapter.swapCursor(mDB.getLoyaltyCardCursor(mFilter, group, mOrder, mOrderDirection));
|
||||
|
||||
if(mDB.getLoyaltyCardCount() > 0)
|
||||
{
|
||||
if (mDB.getLoyaltyCardCount() > 0) {
|
||||
// We want the cardList to be visible regardless of the filtered match count
|
||||
// to ensure that the noMatchingCardsText doesn't end up being shown below
|
||||
// the keyboard
|
||||
mCardList.setVisibility(View.VISIBLE);
|
||||
mHelpText.setVisibility(View.GONE);
|
||||
if(mAdapter.getItemCount() > 0)
|
||||
{
|
||||
mNoGroupCardsText.setVisibility(View.GONE);
|
||||
if (mAdapter.getItemCount() > 0) {
|
||||
mCardList.setVisibility(View.VISIBLE);
|
||||
mNoMatchingCardsText.setVisibility(View.GONE);
|
||||
} else {
|
||||
mCardList.setVisibility(View.GONE);
|
||||
if (!mFilter.isEmpty()) {
|
||||
// Actual Empty Search Result
|
||||
mNoMatchingCardsText.setVisibility(View.VISIBLE);
|
||||
mNoGroupCardsText.setVisibility(View.GONE);
|
||||
} else {
|
||||
// Group Tab with no Group Cards
|
||||
mNoMatchingCardsText.setVisibility(View.GONE);
|
||||
mNoGroupCardsText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mNoMatchingCardsText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
mCardList.setVisibility(View.GONE);
|
||||
mHelpText.setVisibility(View.VISIBLE);
|
||||
mNoMatchingCardsText.setVisibility(View.GONE);
|
||||
mNoGroupCardsText.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (mCurrentActionMode != null) {
|
||||
@@ -426,8 +413,7 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTabGroups(TabLayout groupsTabLayout)
|
||||
{
|
||||
public void updateTabGroups(TabLayout groupsTabLayout) {
|
||||
final DBHelper db = new DBHelper(this);
|
||||
|
||||
List<Group> newGroups = db.getGroups();
|
||||
@@ -455,24 +441,14 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
groupsTabLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void openPrivacyPolicy() {
|
||||
Intent browserIntent = new Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse("https://catima.app/privacy-policy")
|
||||
);
|
||||
startActivity(browserIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu inputMenu)
|
||||
{
|
||||
public boolean onCreateOptionsMenu(Menu inputMenu) {
|
||||
this.mMenu = inputMenu;
|
||||
|
||||
getMenuInflater().inflate(R.menu.main_menu, inputMenu);
|
||||
|
||||
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
|
||||
if (searchManager != null)
|
||||
{
|
||||
if (searchManager != null) {
|
||||
SearchView searchView = (SearchView) inputMenu.findItem(R.id.action_search).getActionView();
|
||||
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
|
||||
searchView.setSubmitButtonEnabled(false);
|
||||
@@ -482,26 +458,21 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
return false;
|
||||
});
|
||||
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener()
|
||||
{
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query)
|
||||
{
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText)
|
||||
{
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
mFilter = newText;
|
||||
|
||||
TabLayout groupsTabLayout = findViewById(R.id.groups);
|
||||
TabLayout.Tab currentTab = groupsTabLayout.getTabAt(groupsTabLayout.getSelectedTabPosition());
|
||||
mGroup = currentTab != null ? currentTab.getTag() : null;
|
||||
|
||||
updateLoyaltyCardList(
|
||||
mFilter,
|
||||
currentTab != null ? currentTab.getTag() : null
|
||||
);
|
||||
updateLoyaltyCardList();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -511,39 +482,67 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem inputItem)
|
||||
{
|
||||
public boolean onOptionsItemSelected(MenuItem inputItem) {
|
||||
int id = inputItem.getItemId();
|
||||
|
||||
if (id == R.id.action_manage_groups)
|
||||
{
|
||||
if (id == R.id.action_sort) {
|
||||
TabLayout.Tab tab = ((TabLayout) findViewById(R.id.groups)).getTabAt(selectedTab);
|
||||
AtomicInteger currentIndex = new AtomicInteger();
|
||||
List<DBHelper.LoyaltyCardOrder> loyaltyCardOrders = Arrays.asList(DBHelper.LoyaltyCardOrder.values());
|
||||
for (int i = 0; i < loyaltyCardOrders.size(); i++) {
|
||||
if (mOrder == loyaltyCardOrders.get(i)) {
|
||||
currentIndex.set(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
|
||||
builder.setTitle(R.string.sort_by);
|
||||
|
||||
final View customLayout = getLayoutInflater().inflate(R.layout.sorting_option, null);
|
||||
builder.setView(customLayout);
|
||||
|
||||
CheckBox ch = (CheckBox) customLayout.findViewById(R.id.checkBox_reverse);
|
||||
ch.setChecked(mOrderDirection == DBHelper.LoyaltyCardOrderDirection.Descending);
|
||||
|
||||
builder.setSingleChoiceItems(R.array.sort_types_array, currentIndex.get(), (dialog, which) -> currentIndex.set(which));
|
||||
|
||||
builder.setPositiveButton(R.string.sort, (dialog, which) -> {
|
||||
if (ch.isChecked()) {
|
||||
setSort(loyaltyCardOrders.get(currentIndex.get()), DBHelper.LoyaltyCardOrderDirection.Descending);
|
||||
} else {
|
||||
setSort(loyaltyCardOrders.get(currentIndex.get()), DBHelper.LoyaltyCardOrderDirection.Ascending);
|
||||
}
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (id == R.id.action_manage_groups) {
|
||||
Intent i = new Intent(getApplicationContext(), ManageGroupsActivity.class);
|
||||
startActivityForResult(i, Utils.MAIN_REQUEST);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (id == R.id.action_import_export)
|
||||
{
|
||||
if (id == R.id.action_import_export) {
|
||||
Intent i = new Intent(getApplicationContext(), ImportExportActivity.class);
|
||||
startActivityForResult(i, Utils.MAIN_REQUEST);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (id == R.id.action_settings)
|
||||
{
|
||||
if (id == R.id.action_settings) {
|
||||
Intent i = new Intent(getApplicationContext(), SettingsActivity.class);
|
||||
startActivityForResult(i, Utils.MAIN_REQUEST);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(id == R.id.action_privacy_policy)
|
||||
{
|
||||
openPrivacyPolicy();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (id == R.id.action_about)
|
||||
{
|
||||
if (id == R.id.action_about) {
|
||||
Intent i = new Intent(getApplicationContext(), AboutActivity.class);
|
||||
startActivityForResult(i, Utils.MAIN_REQUEST);
|
||||
return true;
|
||||
@@ -552,11 +551,22 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
return super.onOptionsItemSelected(inputItem);
|
||||
}
|
||||
|
||||
protected static boolean isDarkModeEnabled(Context inputContext)
|
||||
{
|
||||
Configuration config = inputContext.getResources().getConfiguration();
|
||||
int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
return (currentNightMode == Configuration.UI_MODE_NIGHT_YES);
|
||||
private void setSort(DBHelper.LoyaltyCardOrder order, DBHelper.LoyaltyCardOrderDirection direction) {
|
||||
// Update values
|
||||
mOrder = order;
|
||||
mOrderDirection = direction;
|
||||
|
||||
// Store in Shared Preference to restore next app launch
|
||||
SharedPreferences sortPref = getApplicationContext().getSharedPreferences(
|
||||
getString(R.string.sharedpreference_sort),
|
||||
Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor sortPrefEditor = sortPref.edit();
|
||||
sortPrefEditor.putString(getString(R.string.sharedpreference_sort_order), order.name());
|
||||
sortPrefEditor.putString(getString(R.string.sharedpreference_sort_direction), direction.name());
|
||||
sortPrefEditor.apply();
|
||||
|
||||
// Update card list
|
||||
updateLoyaltyCardList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -584,6 +594,12 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
mGestureDetector.onTouchEvent(ev);
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
Log.d(TAG, "On fling");
|
||||
@@ -599,9 +615,10 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
}
|
||||
|
||||
Integer currentTab = groupsTabLayout.getSelectedTabPosition();
|
||||
|
||||
Log.d("onFling", "Current Tab " + currentTab);
|
||||
// Swipe right
|
||||
if (velocityX < -150) {
|
||||
Log.d("onFling", "Right Swipe detected " + velocityX);
|
||||
Integer nextTab = currentTab + 1;
|
||||
|
||||
if (nextTab == groupsTabLayout.getTabCount()) {
|
||||
@@ -615,6 +632,7 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
|
||||
// Swipe left
|
||||
if (velocityX > 150) {
|
||||
Log.d("onFling", "Left Swipe detected " + velocityX);
|
||||
Integer nextTab = currentTab - 1;
|
||||
|
||||
if (nextTab < 0) {
|
||||
@@ -630,22 +648,18 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRowLongClicked(int inputPosition)
|
||||
{
|
||||
public void onRowLongClicked(int inputPosition) {
|
||||
enableActionMode(inputPosition);
|
||||
}
|
||||
|
||||
private void enableActionMode(int inputPosition)
|
||||
{
|
||||
if (mCurrentActionMode == null)
|
||||
{
|
||||
private void enableActionMode(int inputPosition) {
|
||||
if (mCurrentActionMode == null) {
|
||||
mCurrentActionMode = startSupportActionMode(mCurrentActionModeCallback);
|
||||
}
|
||||
toggleSelection(inputPosition);
|
||||
}
|
||||
|
||||
private void toggleSelection(int inputPosition)
|
||||
{
|
||||
private void toggleSelection(int inputPosition) {
|
||||
mAdapter.toggleSelection(inputPosition);
|
||||
int count = mAdapter.getSelectedItemCount();
|
||||
|
||||
@@ -667,29 +681,29 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIconClicked(int inputPosition)
|
||||
{
|
||||
if (mCurrentActionMode == null)
|
||||
{
|
||||
mCurrentActionMode = startSupportActionMode(mCurrentActionModeCallback);
|
||||
}
|
||||
|
||||
toggleSelection(inputPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRowClicked(int inputPosition)
|
||||
{
|
||||
if (mAdapter.getSelectedItemCount() > 0)
|
||||
{
|
||||
public void onRowClicked(int inputPosition) {
|
||||
if (mAdapter.getSelectedItemCount() > 0) {
|
||||
enableActionMode(inputPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Cursor selected = mAdapter.getCursor();
|
||||
selected.moveToPosition(inputPosition);
|
||||
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
|
||||
// FIXME
|
||||
//
|
||||
// There is a really nasty edge case that can happen when someone taps a card but right
|
||||
// after it swipes (very small window, hard to reproduce). The cursor gets replaced and
|
||||
// may not have a card at the ID number that is returned from onRowClicked.
|
||||
//
|
||||
// The proper fix, obviously, would involve makes sure an onFling can't happen while a
|
||||
// click is being processed. Sadly, I have not yet found a way to make that possible.
|
||||
LoyaltyCard loyaltyCard;
|
||||
try {
|
||||
loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
|
||||
} catch (CursorIndexOutOfBoundsException e) {
|
||||
Log.w(TAG, "Prevented crash from tap + swipe on ID " + inputPosition + ": " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
Intent i = new Intent(this, LoyaltyCardViewActivity.class);
|
||||
i.setAction("");
|
||||
@@ -702,4 +716,4 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
|
||||
startActivityForResult(i, Utils.MAIN_REQUEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
216
app/src/main/java/protect/card_locker/ManageGroupActivity.java
Normal file
216
app/src/main/java/protect/card_locker/ManageGroupActivity.java
Normal file
@@ -0,0 +1,216 @@
|
||||
package protect.card_locker;
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class ManageGroupActivity extends CatimaAppCompatActivity implements ManageGroupCursorAdapter.CardAdapterListener {
|
||||
|
||||
private final DBHelper mDB = new DBHelper(this);
|
||||
private ManageGroupCursorAdapter mAdapter;
|
||||
|
||||
private final String SAVE_INSTANCE_ADAPTER_STATE = "adapterState";
|
||||
private final String SAVE_INSTANCE_CURRENT_GROUP_NAME = "currentGroupName";
|
||||
|
||||
protected Group mGroup = null;
|
||||
private RecyclerView mCardList;
|
||||
private TextView mHelpText;
|
||||
private EditText mGroupNameText;
|
||||
|
||||
private boolean mGroupNameNotInUse;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle inputSavedInstanceState) {
|
||||
super.onCreate(inputSavedInstanceState);
|
||||
setContentView(R.layout.activity_manage_group);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
mHelpText = findViewById(R.id.helpText);
|
||||
mCardList = findViewById(R.id.list);
|
||||
FloatingActionButton saveButton = findViewById(R.id.fabSave);
|
||||
|
||||
mGroupNameText = findViewById(R.id.editTextGroupName);
|
||||
|
||||
mGroupNameText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
mGroupNameNotInUse = true;
|
||||
mGroupNameText.setError(null);
|
||||
String currentGroupName = mGroupNameText.getText().toString().trim();
|
||||
if (currentGroupName.length() == 0) {
|
||||
mGroupNameText.setError(getResources().getText(R.string.group_name_is_empty));
|
||||
return;
|
||||
}
|
||||
if (!mGroup._id.equals(currentGroupName)) {
|
||||
if (mDB.getGroup(currentGroupName) != null) {
|
||||
mGroupNameNotInUse = false;
|
||||
mGroupNameText.setError(getResources().getText(R.string.group_name_already_in_use));
|
||||
} else {
|
||||
mGroupNameNotInUse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Intent intent = getIntent();
|
||||
String groupId = intent.getStringExtra("group");
|
||||
if (groupId == null) {
|
||||
throw (new IllegalArgumentException("this activity expects a group loaded into it's intent"));
|
||||
}
|
||||
Log.d("groupId", "groupId: " + groupId);
|
||||
mGroup = mDB.getGroup(groupId);
|
||||
if (mGroup == null) {
|
||||
throw (new IllegalArgumentException("cannot load group " + groupId + " from database"));
|
||||
}
|
||||
mGroupNameText.setText(mGroup._id);
|
||||
setTitle(getString(R.string.editGroup, mGroup._id));
|
||||
mAdapter = new ManageGroupCursorAdapter(this, null, this, mGroup);
|
||||
mCardList.setAdapter(mAdapter);
|
||||
registerForContextMenu(mCardList);
|
||||
|
||||
if (inputSavedInstanceState != null) {
|
||||
mAdapter.importInGroupState(integerArrayToAdapterState(inputSavedInstanceState.getIntegerArrayList(SAVE_INSTANCE_ADAPTER_STATE)));
|
||||
mGroupNameText.setText(inputSavedInstanceState.getString(SAVE_INSTANCE_CURRENT_GROUP_NAME));
|
||||
}
|
||||
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar == null) {
|
||||
throw (new RuntimeException("mActionBar is not expected to be null here"));
|
||||
}
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setDisplayShowHomeEnabled(true);
|
||||
|
||||
saveButton.setOnClickListener(v -> {
|
||||
String currentGroupName = mGroupNameText.getText().toString().trim();
|
||||
if (!currentGroupName.equals(mGroup._id)) {
|
||||
if (currentGroupName.length() == 0) {
|
||||
Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if (!mGroupNameNotInUse) {
|
||||
Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mAdapter.commitToDatabase();
|
||||
if (!currentGroupName.equals(mGroup._id)) {
|
||||
mDB.updateGroup(mGroup._id, currentGroupName);
|
||||
}
|
||||
Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
});
|
||||
// this setText is here because content_main.xml is reused from main activity
|
||||
mHelpText.setText(getResources().getText(R.string.noGiftCardsGroup));
|
||||
updateLoyaltyCardList();
|
||||
}
|
||||
|
||||
private ArrayList<Integer> adapterStateToIntegerArray(HashMap<Integer, Boolean> adapterState) {
|
||||
ArrayList<Integer> ret = new ArrayList<>(adapterState.size() * 2);
|
||||
for (Map.Entry<Integer, Boolean> entry : adapterState.entrySet()) {
|
||||
ret.add(entry.getKey());
|
||||
ret.add(entry.getValue() ? 1 : 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private HashMap<Integer, Boolean> integerArrayToAdapterState(ArrayList<Integer> in) {
|
||||
HashMap<Integer, Boolean> ret = new HashMap<>();
|
||||
if (in.size() % 2 != 0) {
|
||||
throw (new RuntimeException("failed restoring adapterState from integer array list"));
|
||||
}
|
||||
for (int i = 0; i < in.size(); i += 2) {
|
||||
ret.put(in.get(i), in.get(i + 1) == 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
outState.putIntegerArrayList(SAVE_INSTANCE_ADAPTER_STATE, adapterStateToIntegerArray(mAdapter.exportInGroupState()));
|
||||
outState.putString(SAVE_INSTANCE_CURRENT_GROUP_NAME, mGroupNameText.getText().toString());
|
||||
}
|
||||
|
||||
private void updateLoyaltyCardList() {
|
||||
mAdapter.swapCursor(mDB.getLoyaltyCardCursor());
|
||||
|
||||
if (mAdapter.getCountFromCursor() == 0) {
|
||||
mCardList.setVisibility(View.GONE);
|
||||
mHelpText.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mCardList.setVisibility(View.VISIBLE);
|
||||
mHelpText.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void leaveWithoutSaving() {
|
||||
if (hasChanged()) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ManageGroupActivity.this);
|
||||
builder.setTitle(R.string.leaveWithoutSaveTitle);
|
||||
builder.setMessage(R.string.leaveWithoutSaveConfirmation);
|
||||
builder.setPositiveButton(R.string.confirm, (dialog, which) -> finish());
|
||||
builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
leaveWithoutSaving();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasChanged() {
|
||||
return mAdapter.hasChanged() || !mGroup._id.equals(mGroupNameText.getText().toString().trim());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRowLongClicked(int inputPosition) {
|
||||
// do nothing for now
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRowClicked(int inputPosition) {
|
||||
mAdapter.toggleSelection(inputPosition);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ManageGroupCursorAdapter extends LoyaltyCardCursorAdapter {
|
||||
private HashMap<Integer, Integer> mIndexCardMap;
|
||||
private HashMap<Integer, Boolean> mInGroupOverlay;
|
||||
private HashMap<Integer, Boolean> mIsLoyaltyCardInGroupCache;
|
||||
private HashMap<Integer, List<Group>> mGetGroupCache;
|
||||
final private Group mGroup;
|
||||
final private DBHelper mDb;
|
||||
|
||||
public ManageGroupCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener, Group group) {
|
||||
super(inputContext, inputCursor, inputListener);
|
||||
mGroup = new Group(group._id, group.order);
|
||||
mInGroupOverlay = new HashMap<>();
|
||||
mDb = new DBHelper(inputContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swapCursor(Cursor inputCursor) {
|
||||
super.swapCursor(inputCursor);
|
||||
mIndexCardMap = new HashMap<>();
|
||||
mIsLoyaltyCardInGroupCache = new HashMap<>();
|
||||
mGetGroupCache = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(LoyaltyCardListItemViewHolder inputHolder, Cursor inputCursor) {
|
||||
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(inputCursor);
|
||||
Boolean overlayValue = mInGroupOverlay.get(loyaltyCard.id);
|
||||
if ((overlayValue != null ? overlayValue : isLoyaltyCardInGroup(loyaltyCard.id))) {
|
||||
mAnimationItemsIndex.put(inputCursor.getPosition(), true);
|
||||
mSelectedItems.put(inputCursor.getPosition(), true);
|
||||
}
|
||||
mIndexCardMap.put(inputCursor.getPosition(), loyaltyCard.id);
|
||||
super.onBindViewHolder(inputHolder, inputCursor);
|
||||
}
|
||||
|
||||
private List<Group> getGroups(int cardId) {
|
||||
List<Group> cache = mGetGroupCache.get(cardId);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
}
|
||||
List<Group> groups = mDb.getLoyaltyCardGroups(cardId);
|
||||
mGetGroupCache.put(cardId, groups);
|
||||
return groups;
|
||||
}
|
||||
|
||||
private boolean isLoyaltyCardInGroup(int cardId) {
|
||||
Boolean cache = mIsLoyaltyCardInGroupCache.get(cardId);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
}
|
||||
List<Group> groups = getGroups(cardId);
|
||||
if (groups.contains(mGroup)) {
|
||||
mIsLoyaltyCardInGroupCache.put(cardId, true);
|
||||
return true;
|
||||
}
|
||||
mIsLoyaltyCardInGroupCache.put(cardId, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toggleSelection(int inputPosition) {
|
||||
super.toggleSelection(inputPosition);
|
||||
Integer cardId = mIndexCardMap.get(inputPosition);
|
||||
if (cardId == null) {
|
||||
throw (new RuntimeException("cardId should not be null here"));
|
||||
}
|
||||
Boolean overlayValue = mInGroupOverlay.get(cardId);
|
||||
if (overlayValue == null) {
|
||||
mInGroupOverlay.put(cardId, !isLoyaltyCardInGroup(cardId));
|
||||
} else {
|
||||
mInGroupOverlay.remove(cardId);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasChanged() {
|
||||
return mInGroupOverlay.size() > 0;
|
||||
}
|
||||
|
||||
public void commitToDatabase() {
|
||||
for (Map.Entry<Integer, Boolean> entry : mInGroupOverlay.entrySet()) {
|
||||
int cardId = entry.getKey();
|
||||
List<Group> groups = getGroups(cardId);
|
||||
if (entry.getValue()) {
|
||||
groups.add(mGroup);
|
||||
} else {
|
||||
groups.remove(mGroup);
|
||||
}
|
||||
mDb.setLoyaltyCardGroups(cardId, groups);
|
||||
}
|
||||
}
|
||||
|
||||
public void importInGroupState(HashMap<Integer, Boolean> cardIdInGroupMap) {
|
||||
mInGroupOverlay = new HashMap<>(cardIdInGroupMap);
|
||||
}
|
||||
|
||||
public HashMap<Integer, Boolean> exportInGroupState() {
|
||||
return new HashMap<>(mInGroupOverlay);
|
||||
}
|
||||
|
||||
public int getCountFromCursor() {
|
||||
return super.getCursor().getCount();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
@@ -9,6 +10,7 @@ import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
@@ -16,14 +18,12 @@ import java.util.List;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class ManageGroupsActivity extends AppCompatActivity implements GroupCursorAdapter.GroupAdapterListener
|
||||
{
|
||||
public class ManageGroupsActivity extends CatimaAppCompatActivity implements GroupCursorAdapter.GroupAdapterListener {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
private final DBHelper mDb = new DBHelper(this);
|
||||
@@ -32,15 +32,14 @@ public class ManageGroupsActivity extends AppCompatActivity implements GroupCurs
|
||||
GroupCursorAdapter mAdapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(R.string.groups);
|
||||
setContentView(R.layout.manage_groups_activity);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
}
|
||||
@@ -72,8 +71,7 @@ public class ManageGroupsActivity extends AppCompatActivity implements GroupCurs
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
private void updateGroupList()
|
||||
{
|
||||
private void updateGroupList() {
|
||||
mAdapter.swapCursor(mDb.getGroupCursor());
|
||||
|
||||
if (mDb.getGroupCount() == 0) {
|
||||
@@ -87,8 +85,7 @@ public class ManageGroupsActivity extends AppCompatActivity implements GroupCurs
|
||||
mHelpText.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void invalidateHomescreenActiveTab()
|
||||
{
|
||||
private void invalidateHomescreenActiveTab() {
|
||||
SharedPreferences activeTabPref = getApplicationContext().getSharedPreferences(
|
||||
getString(R.string.sharedpreference_active_tab),
|
||||
Context.MODE_PRIVATE);
|
||||
@@ -98,8 +95,7 @@ public class ManageGroupsActivity extends AppCompatActivity implements GroupCurs
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
|
||||
if (id == android.R.id.home) {
|
||||
@@ -110,14 +106,23 @@ public class ManageGroupsActivity extends AppCompatActivity implements GroupCurs
|
||||
}
|
||||
|
||||
private void createGroup() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AlertDialogTheme);
|
||||
builder.setTitle(R.string.enter_group_name);
|
||||
final EditText input = new EditText(this);
|
||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
builder.setView(input);
|
||||
|
||||
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
|
||||
mDb.insertGroup(input.getText().toString());
|
||||
String inputString = input.getText().toString().trim();
|
||||
if (inputString.length() == 0) {
|
||||
Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if (mDb.getGroup(inputString) != null) {
|
||||
Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
mDb.insertGroup(inputString);
|
||||
updateGroupList();
|
||||
});
|
||||
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
|
||||
@@ -176,25 +181,9 @@ public class ManageGroupsActivity extends AppCompatActivity implements GroupCurs
|
||||
|
||||
@Override
|
||||
public void onEditButtonClicked(View view) {
|
||||
final String groupName = getGroupName(view);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.enter_group_name);
|
||||
final EditText input = new EditText(this);
|
||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
input.setText(groupName);
|
||||
builder.setView(input);
|
||||
|
||||
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
|
||||
String newGroupName = input.getText().toString();
|
||||
mDb.updateGroup(groupName, newGroupName);
|
||||
updateGroupList();
|
||||
});
|
||||
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
||||
input.requestFocus();
|
||||
Intent intent = new Intent(this, ManageGroupActivity.class);
|
||||
intent.putExtra("group", getGroupName(view));
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,6 +9,7 @@ import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.zxing.ResultPoint;
|
||||
import com.google.zxing.client.android.Intents;
|
||||
@@ -20,16 +21,15 @@ import com.journeyapps.barcodescanner.DecoratedBarcodeView;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
/**
|
||||
* Custom Scannner Activity extending from Activity to display a custom layout form scanner view.
|
||||
*
|
||||
* <p>
|
||||
* Based on https://github.com/journeyapps/zxing-android-embedded/blob/0fdfbce9fb3285e985bad9971c5f7c0a7a334e7b/sample/src/main/java/example/zxing/CustomScannerActivity.java
|
||||
* originally licensed under Apache 2.0
|
||||
*/
|
||||
public class ScanActivity extends AppCompatActivity {
|
||||
public class ScanActivity extends CatimaAppCompatActivity {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
private CaptureManager capture;
|
||||
@@ -49,12 +49,12 @@ public class ScanActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(R.string.scanCardBarcode);
|
||||
setContentView(R.layout.scan_activity);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class ScanActivity extends AppCompatActivity {
|
||||
|
||||
// Even though we do the actual decoding with the barcodeScannerView
|
||||
// CaptureManager needs to be running to show the camera and scanning bar
|
||||
capture = new CaptureManager(this, barcodeScannerView);
|
||||
capture = new CatimaCaptureManager(this, barcodeScannerView);
|
||||
Intent captureIntent = new Intent();
|
||||
Bundle captureIntentBundle = new Bundle();
|
||||
captureIntentBundle.putBoolean(Intents.Scan.BEEP_ENABLED, false);
|
||||
@@ -80,7 +80,7 @@ public class ScanActivity extends AppCompatActivity {
|
||||
Intent scanResult = new Intent();
|
||||
Bundle scanResultBundle = new Bundle();
|
||||
scanResultBundle.putString(BarcodeSelectorActivity.BARCODE_CONTENTS, result.getText());
|
||||
scanResultBundle.putString(BarcodeSelectorActivity.BARCODE_FORMAT, result.getBarcodeFormat().toString());
|
||||
scanResultBundle.putString(BarcodeSelectorActivity.BARCODE_FORMAT, result.getBarcodeFormat().name());
|
||||
if (addGroup != null) {
|
||||
scanResultBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, addGroup);
|
||||
}
|
||||
@@ -126,8 +126,7 @@ public class ScanActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
|
||||
getMenuInflater().inflate(R.menu.scan_menu, menu);
|
||||
}
|
||||
@@ -138,15 +137,12 @@ public class ScanActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
if (item.getItemId() == android.R.id.home)
|
||||
{
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_toggle_flashlight)
|
||||
{
|
||||
} else if (item.getItemId() == R.id.action_toggle_flashlight) {
|
||||
if (torch) {
|
||||
torch = false;
|
||||
barcodeScannerView.setTorchOff();
|
||||
@@ -164,11 +160,17 @@ public class ScanActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent)
|
||||
{
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
|
||||
BarcodeValues barcodeValues = Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this);
|
||||
BarcodeValues barcodeValues;
|
||||
|
||||
try {
|
||||
barcodeValues = Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this);
|
||||
} catch (NullPointerException e) {
|
||||
Toast.makeText(this, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!barcodeValues.isEmpty()) {
|
||||
Intent manualResult = new Intent();
|
||||
|
||||
@@ -3,8 +3,11 @@ package protect.card_locker;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
@@ -12,10 +15,12 @@ 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
|
||||
{
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class ShortcutHelper {
|
||||
// Android documentation says that no more than 5 shortcuts
|
||||
// are supported. However, that may be too many, as not all
|
||||
// launcher will show all 5. Instead, the number is limited
|
||||
@@ -23,6 +28,14 @@ class ShortcutHelper
|
||||
// chance of being shown.
|
||||
private static final int MAX_SHORTCUTS = 3;
|
||||
|
||||
// https://developer.android.com/reference/android/graphics/drawable/AdaptiveIconDrawable.html
|
||||
private static final int ADAPTIVE_BITMAP_SCALE = 1;
|
||||
private static final int ADAPTIVE_BITMAP_SIZE = 108 * ADAPTIVE_BITMAP_SCALE;
|
||||
private static final int ADAPTIVE_BITMAP_VISIBLE_SIZE = 72 * ADAPTIVE_BITMAP_SCALE;
|
||||
private static final int ADAPTIVE_BITMAP_IMAGE_SIZE = ADAPTIVE_BITMAP_VISIBLE_SIZE + 5 * ADAPTIVE_BITMAP_SCALE;
|
||||
private static final int PADDING_COLOR = Color.argb(255, 255, 255, 255);
|
||||
private static final int PADDING_COLOR_OVERLAY = Color.argb(127, 0, 0, 0);
|
||||
|
||||
/**
|
||||
* Add a card to the app shortcuts, and maintain a list of the most
|
||||
* recently used cards. If there is already a shortcut for the card,
|
||||
@@ -30,8 +43,7 @@ class ShortcutHelper
|
||||
* card exceeds the max number of shortcuts, then the least recently
|
||||
* used card shortcut is discarded.
|
||||
*/
|
||||
static void updateShortcuts(Context context, LoyaltyCard card)
|
||||
{
|
||||
static void updateShortcuts(Context context, LoyaltyCard card) {
|
||||
LinkedList<ShortcutInfoCompat> list = new LinkedList<>(ShortcutManagerCompat.getDynamicShortcuts(context));
|
||||
|
||||
DBHelper dbHelper = new DBHelper(context);
|
||||
@@ -44,31 +56,25 @@ class ShortcutHelper
|
||||
|
||||
Integer foundIndex = null;
|
||||
|
||||
for(int index = 0; index < list.size(); index++)
|
||||
{
|
||||
if(list.get(index).getId().equals(shortcutId))
|
||||
{
|
||||
for (int index = 0; index < list.size(); index++) {
|
||||
if (list.get(index).getId().equals(shortcutId)) {
|
||||
// Found the item already
|
||||
foundIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(foundIndex != null)
|
||||
{
|
||||
if (foundIndex != null) {
|
||||
// If the item is already found, then the list needs to be
|
||||
// reordered, so that the selected item now has the lowest
|
||||
// rank, thus letting it survive longer.
|
||||
ShortcutInfoCompat found = list.remove(foundIndex.intValue());
|
||||
list.addFirst(found);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// The item is new to the list. First, we need to trim the list
|
||||
// until it is able to accept a new item, then the item is
|
||||
// inserted.
|
||||
while(list.size() >= MAX_SHORTCUTS)
|
||||
{
|
||||
while (list.size() >= MAX_SHORTCUTS) {
|
||||
list.pollLast();
|
||||
}
|
||||
|
||||
@@ -80,15 +86,14 @@ class ShortcutHelper
|
||||
LinkedList<ShortcutInfoCompat> finalList = new LinkedList<>();
|
||||
|
||||
// The ranks are now updated; the order in the list is the rank.
|
||||
for(int index = 0; index < list.size(); index++)
|
||||
{
|
||||
for (int index = 0; index < list.size(); index++) {
|
||||
ShortcutInfoCompat prevShortcut = list.get(index);
|
||||
|
||||
LoyaltyCard loyaltyCard = dbHelper.getLoyaltyCard(Integer.parseInt(prevShortcut.getId()));
|
||||
|
||||
ShortcutInfoCompat updatedShortcut = createShortcutBuilder(context, loyaltyCard)
|
||||
.setRank(index)
|
||||
.build();
|
||||
.setRank(index)
|
||||
.build();
|
||||
|
||||
finalList.addLast(updatedShortcut);
|
||||
}
|
||||
@@ -100,16 +105,13 @@ class ShortcutHelper
|
||||
* Remove the given card id from the app shortcuts, if such a
|
||||
* shortcut exists.
|
||||
*/
|
||||
static void removeShortcut(Context context, int cardId)
|
||||
{
|
||||
static void removeShortcut(Context context, int cardId) {
|
||||
List<ShortcutInfoCompat> list = ShortcutManagerCompat.getDynamicShortcuts(context);
|
||||
|
||||
String shortcutId = Integer.toString(cardId);
|
||||
|
||||
for(int index = 0; index < list.size(); index++)
|
||||
{
|
||||
if(list.get(index).getId().equals(shortcutId))
|
||||
{
|
||||
for (int index = 0; index < list.size(); index++) {
|
||||
if (list.get(index).getId().equals(shortcutId)) {
|
||||
list.remove(index);
|
||||
break;
|
||||
}
|
||||
@@ -118,6 +120,15 @@ class ShortcutHelper
|
||||
ShortcutManagerCompat.setDynamicShortcuts(context, list);
|
||||
}
|
||||
|
||||
static @NotNull Bitmap createAdaptiveBitmap(@NotNull Bitmap in, int paddingColor){
|
||||
Bitmap ret = Bitmap.createBitmap(ADAPTIVE_BITMAP_SIZE, ADAPTIVE_BITMAP_SIZE, Bitmap.Config.ARGB_8888);
|
||||
Canvas output = new Canvas(ret);
|
||||
output.drawColor(ColorUtils.compositeColors(PADDING_COLOR_OVERLAY, paddingColor));
|
||||
Bitmap resized = Utils.resizeBitmap(in, ADAPTIVE_BITMAP_IMAGE_SIZE);
|
||||
output.drawBitmap(resized, (ADAPTIVE_BITMAP_SIZE - resized.getWidth()) / 2f, (ADAPTIVE_BITMAP_SIZE - resized.getHeight()) / 2f, null);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ShortcutInfoCompat.Builder createShortcutBuilder(Context context, LoyaltyCard loyaltyCard) {
|
||||
Intent intent = new Intent(context, LoyaltyCardViewActivity.class);
|
||||
intent.setAction(Intent.ACTION_MAIN);
|
||||
@@ -129,7 +140,12 @@ class ShortcutHelper
|
||||
bundle.putBoolean("view", true);
|
||||
intent.putExtras(bundle);
|
||||
|
||||
Bitmap iconBitmap = Utils.generateIcon(context, loyaltyCard, true).getLetterTile();
|
||||
Bitmap iconBitmap = Utils.retrieveCardImage(context, loyaltyCard.id, ImageLocationType.icon);
|
||||
if (iconBitmap == null) {
|
||||
iconBitmap = Utils.generateIcon(context, loyaltyCard, true).getLetterTile();
|
||||
}else{
|
||||
iconBitmap = createAdaptiveBitmap(iconBitmap, loyaltyCard.headerColor == null ? PADDING_COLOR : loyaltyCard.headerColor);
|
||||
}
|
||||
|
||||
IconCompat icon = IconCompat.createWithAdaptiveBitmap(iconBitmap);
|
||||
|
||||
|
||||
@@ -5,11 +5,14 @@ import android.text.TextWatcher;
|
||||
|
||||
public class SimpleTextWatcher implements TextWatcher {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) { }
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) { }
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,15 @@ package protect.card_locker;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ImageDecoder;
|
||||
import android.graphics.Matrix;
|
||||
import android.os.Build;
|
||||
import android.os.LocaleList;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
@@ -20,6 +25,7 @@ import com.google.zxing.Result;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -30,10 +36,13 @@ import java.util.Calendar;
|
||||
import java.util.Currency;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
import protect.card_locker.preferences.Settings;
|
||||
|
||||
public class Utils {
|
||||
private static final String TAG = "Catima";
|
||||
@@ -45,12 +54,15 @@ public class Utils {
|
||||
public static final int BARCODE_IMPORT_FROM_IMAGE_FILE = 4;
|
||||
public static final int CARD_IMAGE_FROM_CAMERA_FRONT = 5;
|
||||
public static final int CARD_IMAGE_FROM_CAMERA_BACK = 6;
|
||||
public static final int CARD_IMAGE_FROM_FILE_FRONT = 7;
|
||||
public static final int CARD_IMAGE_FROM_FILE_BACK = 8;
|
||||
public static final int CARD_IMAGE_FROM_CAMERA_ICON = 7;
|
||||
public static final int CARD_IMAGE_FROM_FILE_FRONT = 8;
|
||||
public static final int CARD_IMAGE_FROM_FILE_BACK = 9;
|
||||
public static final int CARD_IMAGE_FROM_FILE_ICON = 10;
|
||||
|
||||
static final double LUMINANCE_MIDPOINT = 0.5;
|
||||
|
||||
static final int BITMAP_SIZE_BIG = 512;
|
||||
static final int BITMAP_SIZE_SMALL = 512;
|
||||
static final int BITMAP_SIZE_BIG = 2048;
|
||||
|
||||
static public LetterBitmap generateIcon(Context context, LoyaltyCard loyaltyCard, boolean forShortcut) {
|
||||
return generateIcon(context, loyaltyCard.store, loyaltyCard.headerColor, forShortcut);
|
||||
@@ -99,7 +111,12 @@ public class Utils {
|
||||
|
||||
Bitmap bitmap;
|
||||
try {
|
||||
bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), intent.getData());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
ImageDecoder.Source image_source = ImageDecoder.createSource(context.getContentResolver(), intent.getData());
|
||||
bitmap = ImageDecoder.decodeBitmap(image_source, (decoder, info, source) -> decoder.setMutableRequired(true));
|
||||
} else {
|
||||
bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), intent.getData());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error getting data from image file");
|
||||
e.printStackTrace();
|
||||
@@ -140,6 +157,21 @@ public class Utils {
|
||||
}
|
||||
|
||||
static public BarcodeValues getBarcodeFromBitmap(Bitmap bitmap) {
|
||||
// This function is vulnerable to OOM, so we try again with a smaller bitmap is we get OOM
|
||||
for (int i = 0; i < 10; i++) {
|
||||
try {
|
||||
return Utils.getBarcodeFromBitmapReal(bitmap);
|
||||
} catch (OutOfMemoryError e) {
|
||||
Log.w(TAG, "Ran OOM in getBarcodeFromBitmap! Trying again with smaller picture! Retry " + i + " of 10.");
|
||||
bitmap = Bitmap.createScaledBitmap(bitmap, (int) Math.round(0.75 * bitmap.getWidth()), (int) Math.round(0.75 * bitmap.getHeight()), false);
|
||||
}
|
||||
}
|
||||
|
||||
// Give up
|
||||
return new BarcodeValues(null, null);
|
||||
}
|
||||
|
||||
static private BarcodeValues getBarcodeFromBitmapReal(Bitmap bitmap) {
|
||||
// In order to decode it, the Bitmap must first be converted into a pixel array...
|
||||
int[] intArray = new int[bitmap.getWidth() * bitmap.getHeight()];
|
||||
bitmap.getPixels(intArray, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
|
||||
@@ -237,13 +269,11 @@ public class Utils {
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
static public Bitmap resizeBitmap(Bitmap bitmap) {
|
||||
static public Bitmap resizeBitmap(Bitmap bitmap, double maxSize) {
|
||||
if (bitmap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
double maxSize = BITMAP_SIZE_BIG;
|
||||
|
||||
double width = bitmap.getWidth();
|
||||
double height = bitmap.getHeight();
|
||||
|
||||
@@ -286,16 +316,20 @@ public class Utils {
|
||||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
|
||||
static public String getCardImageFileName(int loyaltyCardId, boolean front) {
|
||||
static public String getCardImageFileName(int loyaltyCardId, ImageLocationType type) {
|
||||
StringBuilder cardImageFileNameBuilder = new StringBuilder();
|
||||
|
||||
cardImageFileNameBuilder.append("card_");
|
||||
cardImageFileNameBuilder.append(loyaltyCardId);
|
||||
cardImageFileNameBuilder.append("_");
|
||||
if (front) {
|
||||
if (type == ImageLocationType.front) {
|
||||
cardImageFileNameBuilder.append("front");
|
||||
} else {
|
||||
} else if (type == ImageLocationType.back) {
|
||||
cardImageFileNameBuilder.append("back");
|
||||
} else if (type == ImageLocationType.icon) {
|
||||
cardImageFileNameBuilder.append("icon");
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown image type");
|
||||
}
|
||||
cardImageFileNameBuilder.append(".png");
|
||||
|
||||
@@ -313,8 +347,8 @@ public class Utils {
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
|
||||
}
|
||||
|
||||
static public void saveCardImage(Context context, Bitmap bitmap, int loyaltyCardId, boolean front) throws FileNotFoundException {
|
||||
saveCardImage(context, bitmap, getCardImageFileName(loyaltyCardId, front));
|
||||
static public void saveCardImage(Context context, Bitmap bitmap, int loyaltyCardId, ImageLocationType type) throws FileNotFoundException {
|
||||
saveCardImage(context, bitmap, getCardImageFileName(loyaltyCardId, type));
|
||||
}
|
||||
|
||||
static public Bitmap retrieveCardImage(Context context, String fileName) {
|
||||
@@ -328,19 +362,90 @@ public class Utils {
|
||||
return BitmapFactory.decodeStream(in);
|
||||
}
|
||||
|
||||
static public Bitmap retrieveCardImage(Context context, int loyaltyCardId, boolean front) {
|
||||
return retrieveCardImage(context, getCardImageFileName(loyaltyCardId, front));
|
||||
static public Bitmap retrieveCardImage(Context context, int loyaltyCardId, ImageLocationType type) {
|
||||
return retrieveCardImage(context, getCardImageFileName(loyaltyCardId, type));
|
||||
}
|
||||
|
||||
static public Object hashmapGetOrDefault(HashMap hashMap, Object key, Object defaultValue, Class keyType) {
|
||||
Object value = hashMap.get(keyType.cast(key));
|
||||
static public <T, U> U mapGetOrDefault(Map<T, U> map, T key, U defaultValue) {
|
||||
U value = map.get(key);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static public Object hashmapGetOrDefault(HashMap hashMap, String key, Object defaultValue) {
|
||||
return hashmapGetOrDefault(hashMap, key, defaultValue, String.class);
|
||||
static public Locale stringToLocale(String localeString) {
|
||||
String[] localeParts = localeString.split("-");
|
||||
if (localeParts.length == 1) {
|
||||
return new Locale(localeParts[0]);
|
||||
}
|
||||
|
||||
if (localeParts[1].startsWith("r")) {
|
||||
localeParts[1] = localeParts[1].substring(1);
|
||||
}
|
||||
return new Locale(localeParts[0], localeParts[1]);
|
||||
}
|
||||
|
||||
static public Context updateBaseContextLocale(Context context) {
|
||||
Settings settings = new Settings(context);
|
||||
|
||||
Locale chosenLocale = settings.getLocale();
|
||||
|
||||
Resources res = context.getResources();
|
||||
Configuration configuration = res.getConfiguration();
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
configuration.locale = chosenLocale != null ? chosenLocale : Locale.getDefault();
|
||||
res.updateConfiguration(configuration, res.getDisplayMetrics());
|
||||
return context;
|
||||
}
|
||||
|
||||
LocaleList localeList = chosenLocale != null ? new LocaleList(chosenLocale) : LocaleList.getDefault();
|
||||
LocaleList.setDefault(localeList);
|
||||
configuration.setLocales(localeList);
|
||||
return context.createConfigurationContext(configuration);
|
||||
}
|
||||
|
||||
static public long getUnixTime() {
|
||||
return System.currentTimeMillis() / 1000;
|
||||
}
|
||||
|
||||
static public boolean isDarkModeEnabled(Context inputContext) {
|
||||
int nightModeSetting = new Settings(inputContext).getTheme();
|
||||
if (nightModeSetting == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {
|
||||
Configuration config = inputContext.getResources().getConfiguration();
|
||||
int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
return (currentNightMode == Configuration.UI_MODE_NIGHT_YES);
|
||||
} else {
|
||||
return nightModeSetting == AppCompatDelegate.MODE_NIGHT_YES;
|
||||
}
|
||||
}
|
||||
|
||||
public static File createTempFile(Context context, String name) {
|
||||
return new File(context.getCacheDir() + "/" + name);
|
||||
}
|
||||
|
||||
public static String saveTempImage(Context context, Bitmap in, String name, Bitmap.CompressFormat format) {
|
||||
File image = createTempFile(context, name);
|
||||
try (FileOutputStream out = new FileOutputStream(image)) {
|
||||
in.compress(format, 100, out);
|
||||
return image.getAbsolutePath();
|
||||
} catch (IOException e) {
|
||||
Log.d("store temp image", "failed writing temp file for temporary image, name: " + name);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap loadImage(String path) {
|
||||
try {
|
||||
return BitmapFactory.decodeStream(new FileInputStream(path));
|
||||
} catch (IOException e) {
|
||||
Log.d("load image", "failed loading image from " + path);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap loadTempImage(Context context, String name) {
|
||||
return loadImage(context.getCacheDir() + "/" + name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package protect.card_locker.async;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public interface CompatCallable<T> extends Callable<T> {
|
||||
void onPostExecute(Object result);
|
||||
|
||||
void onPreExecute();
|
||||
}
|
||||
175
app/src/main/java/protect/card_locker/async/TaskHandler.java
Normal file
175
app/src/main/java/protect/card_locker/async/TaskHandler.java
Normal file
@@ -0,0 +1,175 @@
|
||||
package protect.card_locker.async;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* AsyncTask has been deprecated so this provides very rudimentary compatibility without
|
||||
* needing to redo too many Parts.
|
||||
* <p>
|
||||
* However this is a much, much more cooperative Behaviour than before so
|
||||
* the callers need to ensure we do NOT rely on forced cancellation and feed less into the
|
||||
* ThreadPools so we don't OOM/Overload the Users device
|
||||
* <p>
|
||||
* This assumes single-threaded callers.
|
||||
*/
|
||||
public class TaskHandler {
|
||||
|
||||
public enum TYPE {
|
||||
BARCODE,
|
||||
IMPORT,
|
||||
EXPORT
|
||||
}
|
||||
|
||||
HashMap<TYPE, ThreadPoolExecutor> executors = generateExecutors();
|
||||
|
||||
final private HashMap<TYPE, LinkedList<Future<?>>> taskList = new HashMap<>();
|
||||
|
||||
private final Handler uiHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
private HashMap<TYPE, ThreadPoolExecutor> generateExecutors() {
|
||||
HashMap<TYPE, ThreadPoolExecutor> initExecutors = new HashMap<>();
|
||||
for (TYPE type : TYPE.values()) {
|
||||
replaceExecutor(initExecutors, type, false, false);
|
||||
}
|
||||
return initExecutors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces (or initializes) an Executor with a clean (new) one
|
||||
*
|
||||
* @param executors Map Reference
|
||||
* @param type Which Queue
|
||||
* @param flushOld attempt shutdown
|
||||
* @param waitOnOld wait for Termination
|
||||
*/
|
||||
private void replaceExecutor(HashMap<TYPE, ThreadPoolExecutor> executors, TYPE type, Boolean flushOld, Boolean waitOnOld) {
|
||||
ThreadPoolExecutor oldExecutor = executors.get(type);
|
||||
if (oldExecutor != null) {
|
||||
if (flushOld) {
|
||||
oldExecutor.shutdownNow();
|
||||
}
|
||||
if (waitOnOld) {
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
executors.put(type, (ThreadPoolExecutor) Executors.newCachedThreadPool());
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a Pseudo-AsyncTask for execution
|
||||
*
|
||||
* @param type Queue
|
||||
* @param callable PseudoAsyncTask
|
||||
*/
|
||||
public void executeTask(TYPE type, CompatCallable<?> callable) {
|
||||
Runnable runner = () -> {
|
||||
try {
|
||||
// Run on the UI Thread
|
||||
uiHandler.post(callable::onPreExecute);
|
||||
|
||||
// Background
|
||||
final Object result = callable.call();
|
||||
|
||||
// Post results on UI Thread so we can show them
|
||||
uiHandler.post(() -> {
|
||||
callable.onPostExecute(result);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
};
|
||||
|
||||
LinkedList<Future<?>> list = taskList.get(type);
|
||||
|
||||
if (list == null) {
|
||||
list = new LinkedList<>();
|
||||
}
|
||||
|
||||
ThreadPoolExecutor executor = executors.get(type);
|
||||
|
||||
if (executor != null) {
|
||||
Future<?> task = executor.submit(runner);
|
||||
// Test Queue Cancellation:
|
||||
// task.cancel(true);
|
||||
list.push(task);
|
||||
taskList.put(type, list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will attempt to cancel a currently running list of Tasks
|
||||
* Useful to ignore scheduled tasks - but not able to hard-stop tasks that are running
|
||||
*
|
||||
* @param type Which Queue to target
|
||||
* @param forceCancel attempt to close the Queue and force-replace it after
|
||||
* @param waitForFinish wait and return after the old executor finished. Times out after 5s
|
||||
* @param waitForCurrentlyRunning wait before cancelling tasks. Useful for tests.
|
||||
*/
|
||||
public void flushTaskList(TYPE type, Boolean forceCancel, Boolean waitForFinish, Boolean waitForCurrentlyRunning) {
|
||||
// Only used for Testing
|
||||
if (waitForCurrentlyRunning) {
|
||||
ThreadPoolExecutor oldExecutor = executors.get(type);
|
||||
|
||||
if (oldExecutor != null) {
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to cancel known Tasks and clean the List
|
||||
LinkedList<Future<?>> tasks = taskList.get(type);
|
||||
if (tasks != null) {
|
||||
for (Future<?> task : tasks) {
|
||||
if (!task.isDone() || !task.isCancelled()) {
|
||||
// Interrupt any Task we can
|
||||
task.cancel(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks = new LinkedList<>();
|
||||
taskList.put(type, tasks);
|
||||
|
||||
if (forceCancel || waitForFinish) {
|
||||
ThreadPoolExecutor oldExecutor = executors.get(type);
|
||||
|
||||
if (oldExecutor != null) {
|
||||
if (forceCancel) {
|
||||
if (waitForFinish) {
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
oldExecutor.shutdownNow();
|
||||
replaceExecutor(executors, type, true, false);
|
||||
} else {
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,18 +12,13 @@ public class CSVHelpers {
|
||||
* if it is not null. Otherwise, a FormatException is thrown.
|
||||
*/
|
||||
static String extractString(String key, CSVRecord record, String defaultValue)
|
||||
throws FormatException
|
||||
{
|
||||
throws FormatException {
|
||||
String toReturn = defaultValue;
|
||||
|
||||
if(record.isMapped(key))
|
||||
{
|
||||
if (record.isMapped(key)) {
|
||||
toReturn = record.get(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(defaultValue == null)
|
||||
{
|
||||
} else {
|
||||
if (defaultValue == null) {
|
||||
throw new FormatException("Field not used but expected: " + key);
|
||||
}
|
||||
}
|
||||
@@ -38,25 +33,19 @@ public class CSVHelpers {
|
||||
* int, a FormatException is thrown.
|
||||
*/
|
||||
static Integer extractInt(String key, CSVRecord record, boolean nullIsOk)
|
||||
throws FormatException
|
||||
{
|
||||
if(record.isMapped(key) == false)
|
||||
{
|
||||
throws FormatException {
|
||||
if (record.isMapped(key) == false) {
|
||||
throw new FormatException("Field not used but expected: " + key);
|
||||
}
|
||||
|
||||
String value = record.get(key);
|
||||
if(value.isEmpty() && nullIsOk)
|
||||
{
|
||||
if (value.isEmpty() && nullIsOk) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
return Integer.parseInt(record.get(key));
|
||||
}
|
||||
catch(NumberFormatException e)
|
||||
{
|
||||
} catch (NumberFormatException e) {
|
||||
throw new FormatException("Failed to parse field: " + key, e);
|
||||
}
|
||||
}
|
||||
@@ -68,25 +57,19 @@ public class CSVHelpers {
|
||||
* int, a FormatException is thrown.
|
||||
*/
|
||||
static Long extractLong(String key, CSVRecord record, boolean nullIsOk)
|
||||
throws FormatException
|
||||
{
|
||||
if(record.isMapped(key) == false)
|
||||
{
|
||||
throws FormatException {
|
||||
if (record.isMapped(key) == false) {
|
||||
throw new FormatException("Field not used but expected: " + key);
|
||||
}
|
||||
|
||||
String value = record.get(key);
|
||||
if(value.isEmpty() && nullIsOk)
|
||||
{
|
||||
if (value.isEmpty() && nullIsOk) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
return Long.parseLong(record.get(key));
|
||||
}
|
||||
catch(NumberFormatException e)
|
||||
{
|
||||
} catch (NumberFormatException e) {
|
||||
throw new FormatException("Failed to parse field: " + key, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.graphics.Bitmap;
|
||||
|
||||
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
|
||||
import net.lingala.zip4j.model.ZipParameters;
|
||||
import net.lingala.zip4j.model.enums.EncryptionMethod;
|
||||
import net.lingala.zip4j.util.InternalZipConstants;
|
||||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
@@ -21,6 +22,7 @@ import java.nio.charset.StandardCharsets;
|
||||
|
||||
import protect.card_locker.DBHelper;
|
||||
import protect.card_locker.Group;
|
||||
import protect.card_locker.ImageLocationType;
|
||||
import protect.card_locker.LoyaltyCard;
|
||||
import protect.card_locker.Utils;
|
||||
|
||||
@@ -28,16 +30,20 @@ import protect.card_locker.Utils;
|
||||
* Class for exporting the database into CSV (Comma Separate Values)
|
||||
* format.
|
||||
*/
|
||||
public class CatimaExporter implements Exporter
|
||||
{
|
||||
public void exportData(Context context, DBHelper db, OutputStream output) throws IOException, InterruptedException
|
||||
{
|
||||
public class CatimaExporter implements Exporter {
|
||||
public void exportData(Context context, DBHelper db, OutputStream output, char[] password) throws IOException, InterruptedException {
|
||||
// Necessary vars
|
||||
int readLen;
|
||||
byte[] readBuffer = new byte[InternalZipConstants.BUFF_SIZE];
|
||||
|
||||
// Create zip output stream
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(output);
|
||||
ZipOutputStream zipOutputStream;
|
||||
|
||||
if (password != null && password.length > 0) {
|
||||
zipOutputStream = new ZipOutputStream(output, password);
|
||||
} else {
|
||||
zipOutputStream = new ZipOutputStream(output);
|
||||
}
|
||||
|
||||
// Generate CSV
|
||||
ByteArrayOutputStream catimaOutputStream = new ByteArrayOutputStream();
|
||||
@@ -45,8 +51,7 @@ public class CatimaExporter implements Exporter
|
||||
writeCSV(db, catimaOutputStreamWriter);
|
||||
|
||||
// Add CSV to zip file
|
||||
ZipParameters csvZipParameters = new ZipParameters();
|
||||
csvZipParameters.setFileNameInZip("catima.csv");
|
||||
ZipParameters csvZipParameters = createZipParameters("catima.csv", password);
|
||||
zipOutputStream.putNextEntry(csvZipParameters);
|
||||
InputStream csvInputStream = new ByteArrayInputStream(catimaOutputStream.toByteArray());
|
||||
while ((readLen = csvInputStream.read(readBuffer)) != -1) {
|
||||
@@ -56,23 +61,16 @@ public class CatimaExporter implements Exporter
|
||||
|
||||
// Loop over all cards again
|
||||
Cursor cardCursor = db.getLoyaltyCardCursor();
|
||||
while(cardCursor.moveToNext())
|
||||
{
|
||||
while (cardCursor.moveToNext()) {
|
||||
// For each card
|
||||
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cardCursor);
|
||||
|
||||
// Prepare looping over both front and back image
|
||||
boolean[] frontValues = new boolean[2];
|
||||
frontValues[0] = true;
|
||||
frontValues[1] = false;
|
||||
|
||||
// For each image
|
||||
for (boolean front : frontValues) {
|
||||
for (ImageLocationType imageLocationType : ImageLocationType.values()) {
|
||||
// If it exists, add to the .zip file
|
||||
Bitmap image = Utils.retrieveCardImage(context, card.id, front);
|
||||
Bitmap image = Utils.retrieveCardImage(context, card.id, imageLocationType);
|
||||
if (image != null) {
|
||||
ZipParameters imageZipParameters = new ZipParameters();
|
||||
imageZipParameters.setFileNameInZip(Utils.getCardImageFileName(card.id, front));
|
||||
ZipParameters imageZipParameters = createZipParameters(Utils.getCardImageFileName(card.id, imageLocationType) ,password);
|
||||
zipOutputStream.putNextEntry(imageZipParameters);
|
||||
InputStream imageInputStream = new ByteArrayInputStream(Utils.bitmapToByteArray(image));
|
||||
while ((readLen = imageInputStream.read(readBuffer)) != -1) {
|
||||
@@ -86,6 +84,16 @@ public class CatimaExporter implements Exporter
|
||||
zipOutputStream.close();
|
||||
}
|
||||
|
||||
private ZipParameters createZipParameters(String fileName, char[] password) {
|
||||
ZipParameters zipParameters = new ZipParameters();
|
||||
zipParameters.setFileNameInZip(fileName);
|
||||
if (password != null && password.length > 0) {
|
||||
zipParameters.setEncryptFiles(true);
|
||||
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
|
||||
}
|
||||
return zipParameters;
|
||||
}
|
||||
|
||||
private void writeCSV(DBHelper db, OutputStreamWriter output) throws IOException, InterruptedException {
|
||||
CSVPrinter printer = new CSVPrinter(output, CSVFormat.RFC4180);
|
||||
|
||||
@@ -99,14 +107,12 @@ public class CatimaExporter implements Exporter
|
||||
|
||||
Cursor groupCursor = db.getGroupCursor();
|
||||
|
||||
while(groupCursor.moveToNext())
|
||||
{
|
||||
while (groupCursor.moveToNext()) {
|
||||
Group group = Group.toGroup(groupCursor);
|
||||
|
||||
printer.printRecord(group._id);
|
||||
|
||||
if(Thread.currentThread().isInterrupted())
|
||||
{
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
}
|
||||
@@ -127,12 +133,12 @@ public class CatimaExporter implements Exporter
|
||||
DBHelper.LoyaltyCardDbIds.BARCODE_ID,
|
||||
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE,
|
||||
DBHelper.LoyaltyCardDbIds.HEADER_COLOR,
|
||||
DBHelper.LoyaltyCardDbIds.STAR_STATUS);
|
||||
DBHelper.LoyaltyCardDbIds.STAR_STATUS,
|
||||
DBHelper.LoyaltyCardDbIds.LAST_USED);
|
||||
|
||||
Cursor cardCursor = db.getLoyaltyCardCursor();
|
||||
|
||||
while(cardCursor.moveToNext())
|
||||
{
|
||||
while (cardCursor.moveToNext()) {
|
||||
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cardCursor);
|
||||
|
||||
printer.printRecord(card.id,
|
||||
@@ -143,12 +149,12 @@ public class CatimaExporter implements Exporter
|
||||
card.balanceType,
|
||||
card.cardId,
|
||||
card.barcodeId,
|
||||
card.barcodeType,
|
||||
card.barcodeType != null ? card.barcodeType.name() : "",
|
||||
card.headerColor,
|
||||
card.starStatus);
|
||||
card.starStatus,
|
||||
card.lastUsed);
|
||||
|
||||
if(Thread.currentThread().isInterrupted())
|
||||
{
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
}
|
||||
@@ -164,16 +170,14 @@ public class CatimaExporter implements Exporter
|
||||
|
||||
Cursor cardCursor2 = db.getLoyaltyCardCursor();
|
||||
|
||||
while(cardCursor2.moveToNext())
|
||||
{
|
||||
while (cardCursor2.moveToNext()) {
|
||||
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cardCursor2);
|
||||
|
||||
for (Group group : db.getLoyaltyCardGroups(card.id)) {
|
||||
printer.printRecord(card.id, group._id);
|
||||
}
|
||||
|
||||
if(Thread.currentThread().isInterrupted())
|
||||
{
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ package protect.card_locker.importexport;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import android.net.Uri;
|
||||
|
||||
import net.lingala.zip4j.io.inputstream.ZipInputStream;
|
||||
import net.lingala.zip4j.model.LocalFileHeader;
|
||||
@@ -26,6 +25,7 @@ import java.util.Currency;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import protect.card_locker.CatimaBarcode;
|
||||
import protect.card_locker.DBHelper;
|
||||
import protect.card_locker.FormatException;
|
||||
import protect.card_locker.Group;
|
||||
@@ -35,36 +35,38 @@ import protect.card_locker.ZipUtils;
|
||||
/**
|
||||
* Class for importing a database from CSV (Comma Separate Values)
|
||||
* formatted data.
|
||||
*
|
||||
* <p>
|
||||
* The database's loyalty cards are expected to appear in the CSV data.
|
||||
* A header is expected for the each table showing the names of the columns.
|
||||
*/
|
||||
public class CatimaImporter implements Importer
|
||||
{
|
||||
public class CatimaImporter implements Importer {
|
||||
public void importData(Context context, DBHelper db, InputStream input, char[] password) throws IOException, FormatException, InterruptedException {
|
||||
InputStream bufferedInputStream = new BufferedInputStream(input);
|
||||
bufferedInputStream.mark(100);
|
||||
|
||||
// First, check if this is a zip file
|
||||
ZipInputStream zipInputStream = new ZipInputStream(bufferedInputStream);
|
||||
LocalFileHeader localFileHeader = zipInputStream.getNextEntry();
|
||||
ZipInputStream zipInputStream = new ZipInputStream(bufferedInputStream, password);
|
||||
|
||||
if (localFileHeader == null) {
|
||||
boolean isZipFile = false;
|
||||
|
||||
LocalFileHeader localFileHeader;
|
||||
while ((localFileHeader = zipInputStream.getNextEntry()) != null) {
|
||||
isZipFile = true;
|
||||
|
||||
String fileName = Uri.parse(localFileHeader.getFileName()).getLastPathSegment();
|
||||
if (fileName.equals("catima.csv")) {
|
||||
importCSV(context, db, new ByteArrayInputStream(ZipUtils.read(zipInputStream).getBytes(StandardCharsets.UTF_8)));
|
||||
} else if (fileName.endsWith(".png")) {
|
||||
Utils.saveCardImage(context, ZipUtils.readImage(zipInputStream), fileName);
|
||||
} else {
|
||||
throw new FormatException("Unexpected file in import: " + fileName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isZipFile) {
|
||||
// This is not a zip file, try importing as bare CSV
|
||||
bufferedInputStream.reset();
|
||||
importCSV(context, db, bufferedInputStream);
|
||||
return;
|
||||
}
|
||||
|
||||
importZipFile(context, db, zipInputStream, localFileHeader);
|
||||
}
|
||||
|
||||
public void importZipFile(Context context, DBHelper db, ZipInputStream input, LocalFileHeader localFileHeader) throws IOException, FormatException, InterruptedException {
|
||||
String fileName = localFileHeader.getFileName();
|
||||
if (fileName.equals("catima.csv")) {
|
||||
importCSV(context, db, new ByteArrayInputStream(ZipUtils.read(input).getBytes(StandardCharsets.UTF_8)));
|
||||
} else {
|
||||
Utils.saveCardImage(context, ZipUtils.readImage(input), fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,41 +99,32 @@ public class CatimaImporter implements Importer
|
||||
bufferedReader.close();
|
||||
}
|
||||
|
||||
public void parseV1(Context context, DBHelper db, BufferedReader input) throws IOException, FormatException, InterruptedException
|
||||
{
|
||||
final CSVParser parser = new CSVParser(input, CSVFormat.RFC4180.withHeader());
|
||||
public void parseV1(Context context, DBHelper db, BufferedReader input) throws IOException, FormatException, InterruptedException {
|
||||
final CSVParser parser = new CSVParser(input, CSVFormat.RFC4180.builder().setHeader().build());
|
||||
|
||||
SQLiteDatabase database = db.getWritableDatabase();
|
||||
database.beginTransaction();
|
||||
|
||||
try
|
||||
{
|
||||
for (CSVRecord record : parser)
|
||||
{
|
||||
try {
|
||||
for (CSVRecord record : parser) {
|
||||
importLoyaltyCard(context, database, db, record);
|
||||
|
||||
if(Thread.currentThread().isInterrupted())
|
||||
{
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
}
|
||||
|
||||
parser.close();
|
||||
database.setTransactionSuccessful();
|
||||
}
|
||||
catch(IllegalArgumentException|IllegalStateException e)
|
||||
{
|
||||
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||
throw new FormatException("Issue parsing CSV data", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
} finally {
|
||||
database.endTransaction();
|
||||
database.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void parseV2(Context context, DBHelper db, BufferedReader input) throws IOException, FormatException, InterruptedException
|
||||
{
|
||||
public void parseV2(Context context, DBHelper db, BufferedReader input) throws IOException, FormatException, InterruptedException {
|
||||
SQLiteDatabase database = db.getWritableDatabase();
|
||||
database.beginTransaction();
|
||||
|
||||
@@ -201,10 +194,9 @@ public class CatimaImporter implements Importer
|
||||
}
|
||||
}
|
||||
|
||||
public void parseV2Groups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
|
||||
{
|
||||
public void parseV2Groups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException {
|
||||
// Parse groups
|
||||
final CSVParser groupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
|
||||
final CSVParser groupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
|
||||
|
||||
List<CSVRecord> records = new ArrayList<>();
|
||||
|
||||
@@ -227,10 +219,9 @@ public class CatimaImporter implements Importer
|
||||
}
|
||||
}
|
||||
|
||||
public void parseV2Cards(Context context, DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
|
||||
{
|
||||
public void parseV2Cards(Context context, DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException {
|
||||
// Parse cards
|
||||
final CSVParser cardParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
|
||||
final CSVParser cardParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
|
||||
|
||||
List<CSVRecord> records = new ArrayList<>();
|
||||
|
||||
@@ -253,10 +244,9 @@ public class CatimaImporter implements Importer
|
||||
}
|
||||
}
|
||||
|
||||
public void parseV2CardGroups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
|
||||
{
|
||||
public void parseV2CardGroups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException {
|
||||
// Parse card group mappings
|
||||
final CSVParser cardGroupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
|
||||
final CSVParser cardGroupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
|
||||
|
||||
List<CSVRecord> records = new ArrayList<>();
|
||||
|
||||
@@ -284,13 +274,11 @@ public class CatimaImporter implements Importer
|
||||
* session.
|
||||
*/
|
||||
private void importLoyaltyCard(Context context, SQLiteDatabase database, DBHelper helper, CSVRecord record)
|
||||
throws IOException, FormatException
|
||||
{
|
||||
throws IOException, FormatException {
|
||||
int id = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ID, record, false);
|
||||
|
||||
String store = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.STORE, record, "");
|
||||
if(store.isEmpty())
|
||||
{
|
||||
if (store.isEmpty()) {
|
||||
throw new FormatException("No store listed, but is required");
|
||||
}
|
||||
|
||||
@@ -298,12 +286,13 @@ public class CatimaImporter implements Importer
|
||||
Date expiry = null;
|
||||
try {
|
||||
expiry = new Date(CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.EXPIRY, record, true));
|
||||
} catch (NullPointerException | FormatException e) { }
|
||||
} catch (NullPointerException | FormatException e) {
|
||||
}
|
||||
|
||||
BigDecimal balance;
|
||||
try {
|
||||
balance = new BigDecimal(CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BALANCE, record, null));
|
||||
} catch (FormatException _e ) {
|
||||
} catch (FormatException _e) {
|
||||
// These fields did not exist in versions 1.8.1 and before
|
||||
// We catch this exception so we can still import old backups
|
||||
balance = new BigDecimal("0");
|
||||
@@ -311,46 +300,50 @@ public class CatimaImporter implements Importer
|
||||
|
||||
Currency balanceType = null;
|
||||
String unparsedBalanceType = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BALANCE_TYPE, record, "");
|
||||
if(!unparsedBalanceType.isEmpty()) {
|
||||
if (!unparsedBalanceType.isEmpty()) {
|
||||
balanceType = Currency.getInstance(unparsedBalanceType);
|
||||
}
|
||||
|
||||
String cardId = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.CARD_ID, record, "");
|
||||
if(cardId.isEmpty())
|
||||
{
|
||||
if (cardId.isEmpty()) {
|
||||
throw new FormatException("No card ID listed, but is required");
|
||||
}
|
||||
|
||||
String barcodeId = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BARCODE_ID, record, "");
|
||||
if(barcodeId.isEmpty())
|
||||
{
|
||||
if (barcodeId.isEmpty()) {
|
||||
barcodeId = null;
|
||||
}
|
||||
|
||||
BarcodeFormat barcodeType = null;
|
||||
CatimaBarcode barcodeType = null;
|
||||
String unparsedBarcodeType = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BARCODE_TYPE, record, "");
|
||||
if(!unparsedBarcodeType.isEmpty())
|
||||
{
|
||||
barcodeType = BarcodeFormat.valueOf(unparsedBarcodeType);
|
||||
if (!unparsedBarcodeType.isEmpty()) {
|
||||
barcodeType = CatimaBarcode.fromName(unparsedBarcodeType);
|
||||
}
|
||||
|
||||
Integer headerColor = null;
|
||||
|
||||
if(record.isMapped(DBHelper.LoyaltyCardDbIds.HEADER_COLOR))
|
||||
{
|
||||
if (record.isMapped(DBHelper.LoyaltyCardDbIds.HEADER_COLOR)) {
|
||||
headerColor = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.HEADER_COLOR, record, true);
|
||||
}
|
||||
|
||||
int starStatus = 0;
|
||||
try {
|
||||
starStatus = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.STAR_STATUS, record, false);
|
||||
} catch (FormatException _e ) {
|
||||
// This field did not exist in versions 0.278 and before
|
||||
} catch (FormatException _e) {
|
||||
// This field did not exist in versions 0.28 and before
|
||||
// We catch this exception so we can still import old backups
|
||||
}
|
||||
if (starStatus != 1) starStatus = 0;
|
||||
|
||||
helper.insertLoyaltyCard(database, id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starStatus);
|
||||
Long lastUsed = 0L;
|
||||
try {
|
||||
lastUsed = CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.LAST_USED, record, false);
|
||||
} catch (FormatException _e) {
|
||||
// This field did not exist in versions 2.5.0 and before
|
||||
// We catch this exception so we can still import old backups
|
||||
}
|
||||
|
||||
helper.insertLoyaltyCard(database, id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starStatus, lastUsed);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,8 +351,7 @@ public class CatimaImporter implements Importer
|
||||
* session.
|
||||
*/
|
||||
private void importGroup(SQLiteDatabase database, DBHelper helper, CSVRecord record)
|
||||
throws IOException, FormatException
|
||||
{
|
||||
throws IOException, FormatException {
|
||||
String id = CSVHelpers.extractString(DBHelper.LoyaltyCardDbGroups.ID, record, null);
|
||||
|
||||
helper.insertGroup(database, id);
|
||||
@@ -370,8 +362,7 @@ public class CatimaImporter implements Importer
|
||||
* session.
|
||||
*/
|
||||
private void importCardGroupMapping(SQLiteDatabase database, DBHelper helper, CSVRecord record)
|
||||
throws IOException, FormatException
|
||||
{
|
||||
throws IOException, FormatException {
|
||||
Integer cardId = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIdsGroups.cardID, record, false);
|
||||
String groupId = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIdsGroups.groupID, record, null);
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package protect.card_locker.importexport;
|
||||
|
||||
public enum DataFormat
|
||||
{
|
||||
public enum DataFormat {
|
||||
Catima,
|
||||
Fidme,
|
||||
Stocard,
|
||||
VoucherVault
|
||||
;
|
||||
VoucherVault;
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ import protect.card_locker.DBHelper;
|
||||
* Interface for a class which can export the contents of the database
|
||||
* in a given format.
|
||||
*/
|
||||
public interface Exporter
|
||||
{
|
||||
public interface Exporter {
|
||||
/**
|
||||
* Export the database to the output stream in a given format.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void exportData(Context context, DBHelper db, OutputStream output) throws IOException, InterruptedException;
|
||||
void exportData(Context context, DBHelper db, OutputStream output, char[] password) throws IOException, InterruptedException;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ package protect.card_locker.importexport;
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import net.lingala.zip4j.io.inputstream.ZipInputStream;
|
||||
import net.lingala.zip4j.model.LocalFileHeader;
|
||||
|
||||
@@ -20,18 +18,18 @@ import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.ParseException;
|
||||
|
||||
import protect.card_locker.CatimaBarcode;
|
||||
import protect.card_locker.DBHelper;
|
||||
import protect.card_locker.FormatException;
|
||||
|
||||
/**
|
||||
* Class for importing a database from CSV (Comma Separate Values)
|
||||
* formatted data.
|
||||
*
|
||||
* <p>
|
||||
* The database's loyalty cards are expected to appear in the CSV data.
|
||||
* A header is expected for the each table showing the names of the columns.
|
||||
*/
|
||||
public class FidmeImporter implements Importer
|
||||
{
|
||||
public class FidmeImporter implements Importer {
|
||||
public void importData(Context context, DBHelper db, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
|
||||
// We actually retrieve a .zip file
|
||||
ZipInputStream zipInputStream = new ZipInputStream(input, password);
|
||||
@@ -57,7 +55,7 @@ public class FidmeImporter implements Importer
|
||||
SQLiteDatabase database = db.getWritableDatabase();
|
||||
database.beginTransaction();
|
||||
|
||||
final CSVParser fidmeParser = new CSVParser(new StringReader(loyaltyCards.toString()), CSVFormat.RFC4180.withDelimiter(';').withHeader());
|
||||
final CSVParser fidmeParser = new CSVParser(new StringReader(loyaltyCards.toString()), CSVFormat.RFC4180.builder().setDelimiter(';').setHeader().build());
|
||||
|
||||
try {
|
||||
for (CSVRecord record : fidmeParser) {
|
||||
@@ -85,8 +83,7 @@ public class FidmeImporter implements Importer
|
||||
* session.
|
||||
*/
|
||||
private void importLoyaltyCard(SQLiteDatabase database, DBHelper helper, CSVRecord record)
|
||||
throws IOException, FormatException
|
||||
{
|
||||
throws IOException, FormatException {
|
||||
// A loyalty card export from Fidme contains the following fields:
|
||||
// Retailer (store name)
|
||||
// Program (program name)
|
||||
@@ -98,8 +95,7 @@ public class FidmeImporter implements Importer
|
||||
// The store is called Retailer
|
||||
String store = CSVHelpers.extractString("Retailer", record, "");
|
||||
|
||||
if (store.isEmpty())
|
||||
{
|
||||
if (store.isEmpty()) {
|
||||
throw new FormatException("No store listed, but is required");
|
||||
}
|
||||
|
||||
@@ -119,21 +115,20 @@ public class FidmeImporter implements Importer
|
||||
|
||||
// The ID is called reference
|
||||
String cardId = CSVHelpers.extractString("Reference", record, "");
|
||||
if(cardId.isEmpty())
|
||||
{
|
||||
if (cardId.isEmpty()) {
|
||||
throw new FormatException("No card ID listed, but is required");
|
||||
}
|
||||
|
||||
// Sadly, Fidme exports don't contain the card type
|
||||
// I guess they have an online DB of all the different companies and what type they use
|
||||
// TODO: Hook this into our own loyalty card DB if we ever get one
|
||||
BarcodeFormat barcodeType = null;
|
||||
CatimaBarcode barcodeType = null;
|
||||
|
||||
// No favourite data in the export either
|
||||
int starStatus = 0;
|
||||
|
||||
// TODO: Front and back image
|
||||
|
||||
helper.insertLoyaltyCard(database, store, note, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, null, starStatus);
|
||||
helper.insertLoyaltyCard(database, store, note, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, null, starStatus, null);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
package protect.card_locker.importexport;
|
||||
|
||||
public enum ImportExportResult
|
||||
{
|
||||
public enum ImportExportResult {
|
||||
Success,
|
||||
GenericFailure,
|
||||
BadPassword
|
||||
;
|
||||
BadPassword;
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@ import protect.card_locker.FormatException;
|
||||
* Interface for a class which can import the contents of a stream
|
||||
* into the database.
|
||||
*/
|
||||
public interface Importer
|
||||
{
|
||||
public interface Importer {
|
||||
/**
|
||||
* Import data from the input stream in a given format into
|
||||
* the database.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws FormatException
|
||||
*/
|
||||
|
||||
@@ -8,26 +8,23 @@ import java.io.OutputStream;
|
||||
|
||||
import protect.card_locker.DBHelper;
|
||||
|
||||
public class MultiFormatExporter
|
||||
{
|
||||
public class MultiFormatExporter {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
/**
|
||||
* Attempts to export data to the output stream in the
|
||||
* given format, if possible.
|
||||
*
|
||||
* <p>
|
||||
* The output stream is closed on success.
|
||||
*
|
||||
* @return ImportExportResult.Success if the database was successfully exported,
|
||||
* another ImportExportResult otherwise. If not Success, partial data may have been
|
||||
* written to the output stream, and it should be discarded.
|
||||
*/
|
||||
public static ImportExportResult exportData(Context context, DBHelper db, OutputStream output, DataFormat format)
|
||||
{
|
||||
public static ImportExportResult exportData(Context context, DBHelper db, OutputStream output, DataFormat format, char[] password) {
|
||||
Exporter exporter = null;
|
||||
|
||||
switch(format)
|
||||
{
|
||||
switch (format) {
|
||||
case Catima:
|
||||
exporter = new CatimaExporter();
|
||||
break;
|
||||
@@ -36,26 +33,18 @@ public class MultiFormatExporter
|
||||
break;
|
||||
}
|
||||
|
||||
if(exporter != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
exporter.exportData(context, db, output);
|
||||
if (exporter != null) {
|
||||
try {
|
||||
exporter.exportData(context, db, output, password);
|
||||
return ImportExportResult.Success;
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to export data", e);
|
||||
}
|
||||
catch(InterruptedException e)
|
||||
{
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Failed to export data", e);
|
||||
}
|
||||
|
||||
return ImportExportResult.GenericFailure;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Log.e(TAG, "Unsupported data format exported: " + format.name());
|
||||
return ImportExportResult.GenericFailure;
|
||||
}
|
||||
|
||||
@@ -14,14 +14,13 @@ import java.text.ParseException;
|
||||
import protect.card_locker.DBHelper;
|
||||
import protect.card_locker.FormatException;
|
||||
|
||||
public class MultiFormatImporter
|
||||
{
|
||||
public class MultiFormatImporter {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
/**
|
||||
* Attempts to import data from the input stream of the
|
||||
* given format into the database.
|
||||
*
|
||||
* <p>
|
||||
* The input stream is not closed, and doing so is the
|
||||
* responsibility of the caller.
|
||||
*
|
||||
@@ -29,12 +28,10 @@ public class MultiFormatImporter
|
||||
* or another result otherwise. If no Success, no data was written to
|
||||
* the database.
|
||||
*/
|
||||
public static ImportExportResult importData(Context context, DBHelper db, InputStream input, DataFormat format, char[] password)
|
||||
{
|
||||
public static ImportExportResult importData(Context context, DBHelper db, InputStream input, DataFormat format, char[] password) {
|
||||
Importer importer = null;
|
||||
|
||||
switch(format)
|
||||
{
|
||||
switch (format) {
|
||||
case Catima:
|
||||
importer = new CatimaImporter();
|
||||
break;
|
||||
@@ -49,25 +46,17 @@ public class MultiFormatImporter
|
||||
break;
|
||||
}
|
||||
|
||||
if (importer != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (importer != null) {
|
||||
try {
|
||||
importer.importData(context, db, input, password);
|
||||
return ImportExportResult.Success;
|
||||
}
|
||||
catch(ZipException e)
|
||||
{
|
||||
} catch (ZipException e) {
|
||||
return ImportExportResult.BadPassword;
|
||||
}
|
||||
catch(IOException | FormatException | InterruptedException | JSONException | ParseException | NullPointerException e)
|
||||
{
|
||||
} catch (IOException | FormatException | InterruptedException | JSONException | ParseException | NullPointerException e) {
|
||||
Log.e(TAG, "Failed to import data", e);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Log.e(TAG, "Unsupported data format imported: " + format.name());
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,10 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.text.ParseException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import protect.card_locker.CatimaBarcode;
|
||||
import protect.card_locker.DBHelper;
|
||||
import protect.card_locker.FormatException;
|
||||
import protect.card_locker.ImageLocationType;
|
||||
import protect.card_locker.R;
|
||||
import protect.card_locker.Utils;
|
||||
import protect.card_locker.ZipUtils;
|
||||
@@ -32,22 +34,19 @@ import protect.card_locker.ZipUtils;
|
||||
/**
|
||||
* Class for importing a database from CSV (Comma Separate Values)
|
||||
* formatted data.
|
||||
*
|
||||
* <p>
|
||||
* The database's loyalty cards are expected to appear in the CSV data.
|
||||
* A header is expected for the each table showing the names of the columns.
|
||||
*/
|
||||
public class StocardImporter implements Importer
|
||||
{
|
||||
public class StocardImporter implements Importer {
|
||||
public void importData(Context context, DBHelper db, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
|
||||
HashMap<String, HashMap<String, Object>> loyaltyCardHashMap = new HashMap<>();
|
||||
HashMap<String, HashMap<String, String>> providers = new HashMap<>();
|
||||
|
||||
final CSVParser parser = new CSVParser(new InputStreamReader(context.getResources().openRawResource(R.raw.stocard_stores), StandardCharsets.UTF_8), CSVFormat.RFC4180.withHeader());
|
||||
final CSVParser parser = new CSVParser(new InputStreamReader(context.getResources().openRawResource(R.raw.stocard_stores), StandardCharsets.UTF_8), CSVFormat.RFC4180.builder().setHeader().build());
|
||||
|
||||
try
|
||||
{
|
||||
for (CSVRecord record : parser)
|
||||
{
|
||||
try {
|
||||
for (CSVRecord record : parser) {
|
||||
HashMap<String, String> recordData = new HashMap<>();
|
||||
recordData.put("name", record.get("name"));
|
||||
recordData.put("barcodeFormat", record.get("barcodeFormat"));
|
||||
@@ -56,7 +55,7 @@ public class StocardImporter implements Importer
|
||||
}
|
||||
|
||||
parser.close();
|
||||
} catch(IllegalArgumentException|IllegalStateException e) {
|
||||
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||
throw new FormatException("Issue parsing CSV data", e);
|
||||
}
|
||||
|
||||
@@ -71,7 +70,7 @@ public class StocardImporter implements Importer
|
||||
String[] nameParts = fileName.split("/");
|
||||
|
||||
if (providersFileName == null) {
|
||||
providersFileName = new String[] {
|
||||
providersFileName = new String[]{
|
||||
nameParts[0],
|
||||
"sync",
|
||||
"data",
|
||||
@@ -79,7 +78,7 @@ public class StocardImporter implements Importer
|
||||
nameParts[0],
|
||||
"analytics-properties.json"
|
||||
};
|
||||
cardBaseName = new String[] {
|
||||
cardBaseName = new String[]{
|
||||
nameParts[0],
|
||||
"sync",
|
||||
"data",
|
||||
@@ -110,19 +109,19 @@ public class StocardImporter implements Importer
|
||||
cardName,
|
||||
"_providerId",
|
||||
jsonObject
|
||||
.getJSONObject("input_provider_reference")
|
||||
.getString("identifier")
|
||||
.substring("/loyalty-card-providers/".length())
|
||||
.getJSONObject("input_provider_reference")
|
||||
.getString("identifier")
|
||||
.substring("/loyalty-card-providers/".length())
|
||||
);
|
||||
|
||||
try {
|
||||
if (jsonObject.has("input_barcode_format")) {
|
||||
loyaltyCardHashMap = appendToLoyaltyCardHashMap(
|
||||
loyaltyCardHashMap,
|
||||
cardName,
|
||||
"barcodeType",
|
||||
jsonObject.getString("input_barcode_format")
|
||||
);
|
||||
} catch (JSONException ignored) {}
|
||||
}
|
||||
}
|
||||
} else if (fileName.endsWith("notes/default.json")) {
|
||||
loyaltyCardHashMap = appendToLoyaltyCardHashMap(
|
||||
@@ -130,7 +129,7 @@ public class StocardImporter implements Importer
|
||||
cardName,
|
||||
"note",
|
||||
ZipUtils.readJSON(zipInputStream)
|
||||
.getString("content")
|
||||
.getString("content")
|
||||
);
|
||||
} else if (fileName.endsWith("/images/front.png")) {
|
||||
loyaltyCardHashMap = appendToLoyaltyCardHashMap(
|
||||
@@ -162,25 +161,25 @@ public class StocardImporter implements Importer
|
||||
HashMap<String, String> providerData = providers.get(providerId);
|
||||
|
||||
String store = providerData != null ? providerData.get("name") : providerId;
|
||||
String note = (String) Utils.hashmapGetOrDefault(loyaltyCardData, "note", "");
|
||||
String note = (String) Utils.mapGetOrDefault(loyaltyCardData, "note", "");
|
||||
String cardId = (String) loyaltyCardData.get("cardId");
|
||||
String barcodeTypeString = (String) Utils.hashmapGetOrDefault(loyaltyCardData, "barcodeType", providerData != null ? providerData.get("barcodeFormat") : null);
|
||||
BarcodeFormat barcodeType = null;
|
||||
String barcodeTypeString = (String) Utils.mapGetOrDefault(loyaltyCardData, "barcodeType", providerData != null ? providerData.get("barcodeFormat") : null);
|
||||
CatimaBarcode barcodeType = null;
|
||||
if (barcodeTypeString != null) {
|
||||
if (barcodeTypeString.equals("RSS_DATABAR_EXPANDED")) {
|
||||
barcodeType = BarcodeFormat.RSS_EXPANDED;
|
||||
barcodeType = CatimaBarcode.fromBarcode(BarcodeFormat.RSS_EXPANDED);
|
||||
} else {
|
||||
barcodeType = BarcodeFormat.valueOf(barcodeTypeString);
|
||||
barcodeType = CatimaBarcode.fromName(barcodeTypeString);
|
||||
}
|
||||
}
|
||||
|
||||
long loyaltyCardInternalId = db.insertLoyaltyCard(database, store, note, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, null, 0);
|
||||
long loyaltyCardInternalId = db.insertLoyaltyCard(database, store, note, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, null, 0, null);
|
||||
|
||||
if (loyaltyCardData.containsKey("frontImage")) {
|
||||
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("frontImage"), (int) loyaltyCardInternalId, true);
|
||||
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("frontImage"), (int) loyaltyCardInternalId, ImageLocationType.front);
|
||||
}
|
||||
if (loyaltyCardData.containsKey("backImage")) {
|
||||
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("backImage"), (int) loyaltyCardInternalId, false);
|
||||
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("backImage"), (int) loyaltyCardInternalId, ImageLocationType.back);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,18 +23,19 @@ import java.util.Currency;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import protect.card_locker.CatimaBarcode;
|
||||
import protect.card_locker.DBHelper;
|
||||
import protect.card_locker.FormatException;
|
||||
import protect.card_locker.Utils;
|
||||
|
||||
/**
|
||||
* Class for importing a database from CSV (Comma Separate Values)
|
||||
* formatted data.
|
||||
*
|
||||
* <p>
|
||||
* The database's loyalty cards are expected to appear in the CSV data.
|
||||
* A header is expected for the each table showing the names of the columns.
|
||||
*/
|
||||
public class VoucherVaultImporter implements Importer
|
||||
{
|
||||
public class VoucherVaultImporter implements Importer {
|
||||
public void importData(Context context, DBHelper db, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
|
||||
|
||||
@@ -74,24 +75,24 @@ public class VoucherVaultImporter implements Importer
|
||||
|
||||
String cardId = jsonCard.getString("code");
|
||||
|
||||
BarcodeFormat barcodeType = null;
|
||||
CatimaBarcode barcodeType = null;
|
||||
|
||||
String codeTypeFromJSON = jsonCard.getString("codeType");
|
||||
switch (codeTypeFromJSON) {
|
||||
case "CODE128":
|
||||
barcodeType = BarcodeFormat.CODE_128;
|
||||
barcodeType = CatimaBarcode.fromBarcode(BarcodeFormat.CODE_128);
|
||||
break;
|
||||
case "CODE39":
|
||||
barcodeType = BarcodeFormat.CODE_39;
|
||||
barcodeType = CatimaBarcode.fromBarcode(BarcodeFormat.CODE_39);
|
||||
break;
|
||||
case "EAN13":
|
||||
barcodeType = BarcodeFormat.EAN_13;
|
||||
barcodeType = CatimaBarcode.fromBarcode(BarcodeFormat.EAN_13);
|
||||
break;
|
||||
case "PDF417":
|
||||
barcodeType = BarcodeFormat.PDF_417;
|
||||
barcodeType = CatimaBarcode.fromBarcode(BarcodeFormat.PDF_417);
|
||||
break;
|
||||
case "QR":
|
||||
barcodeType = BarcodeFormat.QR_CODE;
|
||||
barcodeType = CatimaBarcode.fromBarcode(BarcodeFormat.QR_CODE);
|
||||
break;
|
||||
case "TEXT":
|
||||
break;
|
||||
@@ -128,7 +129,7 @@ public class VoucherVaultImporter implements Importer
|
||||
throw new FormatException("Unknown colour type found: " + colorFromJSON);
|
||||
}
|
||||
|
||||
db.insertLoyaltyCard(store, "", expiry, balance, balanceType, cardId, null, barcodeType, headerColor, 0);
|
||||
db.insertLoyaltyCard(store, "", expiry, balance, balanceType, cardId, null, barcodeType, headerColor, 0, Utils.getUnixTime());
|
||||
}
|
||||
|
||||
database.setTransactionSuccessful();
|
||||
|
||||
@@ -3,111 +3,103 @@ 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 protect.card_locker.R;
|
||||
import protect.card_locker.Utils;
|
||||
|
||||
public class Settings
|
||||
{
|
||||
public class Settings {
|
||||
private Context context;
|
||||
private SharedPreferences settings;
|
||||
|
||||
public Settings(Context context)
|
||||
{
|
||||
public Settings(Context context) {
|
||||
this.context = context;
|
||||
this.settings = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
}
|
||||
|
||||
private String getResString(@StringRes int resId)
|
||||
{
|
||||
private String getResString(@StringRes int resId) {
|
||||
return context.getString(resId);
|
||||
}
|
||||
|
||||
private int getResInt(@IntegerRes int resId)
|
||||
{
|
||||
private int getResInt(@IntegerRes int resId) {
|
||||
return context.getResources().getInteger(resId);
|
||||
}
|
||||
|
||||
private String getString(@StringRes int keyId, String defaultValue)
|
||||
{
|
||||
private String getString(@StringRes int keyId, String defaultValue) {
|
||||
return settings.getString(getResString(keyId), defaultValue);
|
||||
}
|
||||
|
||||
private int getInt(@StringRes int keyId, @IntegerRes int defaultId)
|
||||
{
|
||||
private int getInt(@StringRes int keyId, @IntegerRes int defaultId) {
|
||||
return settings.getInt(getResString(keyId), getResInt(defaultId));
|
||||
}
|
||||
|
||||
private boolean getBoolean(@StringRes int keyId, boolean defaultValue)
|
||||
{
|
||||
private boolean getBoolean(@StringRes int keyId, boolean defaultValue) {
|
||||
return settings.getBoolean(getResString(keyId), defaultValue);
|
||||
}
|
||||
|
||||
public int getTheme()
|
||||
{
|
||||
public Locale getLocale() {
|
||||
String value = getString(R.string.settings_key_locale, "");
|
||||
|
||||
if (value.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Utils.stringToLocale(value);
|
||||
}
|
||||
|
||||
public int getTheme() {
|
||||
String value = getString(R.string.settings_key_theme, getResString(R.string.settings_key_system_theme));
|
||||
|
||||
if(value.equals(getResString(R.string.settings_key_light_theme)))
|
||||
{
|
||||
if (value.equals(getResString(R.string.settings_key_light_theme))) {
|
||||
return AppCompatDelegate.MODE_NIGHT_NO;
|
||||
}
|
||||
else if(value.equals(getResString(R.string.settings_key_dark_theme)))
|
||||
{
|
||||
} else if (value.equals(getResString(R.string.settings_key_dark_theme))) {
|
||||
return AppCompatDelegate.MODE_NIGHT_YES;
|
||||
}
|
||||
|
||||
return AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
|
||||
}
|
||||
|
||||
public double getFontSizeScale()
|
||||
{
|
||||
public double getFontSizeScale() {
|
||||
return getInt(R.string.settings_key_max_font_size_scale, R.integer.settings_max_font_size_scale_pct) / 100.0;
|
||||
}
|
||||
|
||||
public int getSmallFont()
|
||||
{
|
||||
public int getSmallFont() {
|
||||
return 14;
|
||||
}
|
||||
|
||||
public int getMediumFont()
|
||||
{
|
||||
public int getMediumFont() {
|
||||
return 28;
|
||||
}
|
||||
|
||||
public int getLargeFont()
|
||||
{
|
||||
public int getLargeFont() {
|
||||
return 40;
|
||||
}
|
||||
|
||||
public int getFontSizeMin(int fontSize)
|
||||
{
|
||||
public int getFontSizeMin(int fontSize) {
|
||||
return (int) (Math.round(fontSize / 2.0) - 1);
|
||||
}
|
||||
|
||||
public int getFontSizeMax(int fontSize)
|
||||
{
|
||||
public int getFontSizeMax(int fontSize) {
|
||||
return (int) Math.round(fontSize * getFontSizeScale());
|
||||
}
|
||||
|
||||
public boolean useMaxBrightnessDisplayingBarcode()
|
||||
{
|
||||
public boolean useMaxBrightnessDisplayingBarcode() {
|
||||
return getBoolean(R.string.settings_key_display_barcode_max_brightness, true);
|
||||
}
|
||||
|
||||
public boolean getLockBarcodeScreenOrientation()
|
||||
{
|
||||
public boolean getLockBarcodeScreenOrientation() {
|
||||
return getBoolean(R.string.settings_key_lock_barcode_orientation, false);
|
||||
}
|
||||
|
||||
public boolean getKeepScreenOn()
|
||||
{
|
||||
public boolean getKeepScreenOn() {
|
||||
return getBoolean(R.string.settings_key_keep_screen_on, true);
|
||||
}
|
||||
|
||||
public boolean getDisableLockscreenWhileViewingCard()
|
||||
{
|
||||
public boolean getDisableLockscreenWhileViewingCard() {
|
||||
return getBoolean(R.string.settings_key_disable_lockscreen_while_viewing_card, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,54 @@
|
||||
package protect.card_locker.preferences;
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import nl.invissvenska.numberpickerpreference.NumberDialogPreference;
|
||||
import nl.invissvenska.numberpickerpreference.NumberPickerPreferenceDialogFragment;
|
||||
import protect.card_locker.CatimaAppCompatActivity;
|
||||
import protect.card_locker.R;
|
||||
import protect.card_locker.Utils;
|
||||
|
||||
public class SettingsActivity extends AppCompatActivity
|
||||
{
|
||||
public class SettingsActivity extends CatimaAppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(R.string.settings);
|
||||
setContentView(R.layout.settings_activity);
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
// Display the fragment as the main content.
|
||||
SettingsFragment fragment = new SettingsFragment();
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.settings_container, new SettingsFragment())
|
||||
.replace(R.id.settings_container, fragment)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
|
||||
if(id == android.R.id.home)
|
||||
{
|
||||
if (id == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
@@ -49,49 +56,70 @@ public class SettingsActivity extends AppCompatActivity
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragmentCompat
|
||||
{
|
||||
public static class SettingsFragment extends PreferenceFragmentCompat {
|
||||
private static final String DIALOG_FRAGMENT_TAG = "SettingsFragment";
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
|
||||
{
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
// Load the preferences from an XML resource
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
|
||||
// Show pretty names
|
||||
ListPreference localePreference = findPreference(getResources().getString(R.string.settings_key_locale));
|
||||
assert localePreference != null;
|
||||
CharSequence[] entryValues = localePreference.getEntryValues();
|
||||
List<CharSequence> entries = new ArrayList<>();
|
||||
for (CharSequence entry : entryValues) {
|
||||
if (entry.length() == 0) {
|
||||
entries.add(getResources().getString(R.string.settings_system_locale));
|
||||
} else {
|
||||
Locale entryLocale = Utils.stringToLocale(entry.toString());
|
||||
entries.add(entryLocale.getDisplayName(entryLocale));
|
||||
}
|
||||
}
|
||||
|
||||
localePreference.setEntries(entries.toArray(new CharSequence[entryValues.length]));
|
||||
|
||||
Preference themePreference = findPreference(getResources().getString(R.string.settings_key_theme));
|
||||
assert themePreference != null;
|
||||
themePreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
|
||||
{
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object o)
|
||||
{
|
||||
if(o.toString().equals(getResources().getString(R.string.settings_key_light_theme)))
|
||||
{
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
}
|
||||
else if(o.toString().equals(getResources().getString(R.string.settings_key_dark_theme)))
|
||||
{
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
}
|
||||
else
|
||||
{
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||
}
|
||||
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
ActivityCompat.recreate(activity);
|
||||
}
|
||||
return true;
|
||||
themePreference.setOnPreferenceChangeListener((preference, o) -> {
|
||||
if (o.toString().equals(getResources().getString(R.string.settings_key_light_theme))) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
} else if (o.toString().equals(getResources().getString(R.string.settings_key_dark_theme))) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||
}
|
||||
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
ActivityCompat.recreate(activity);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
Preference colorPreference = findPreference(getResources().getString(R.string.setting_key_theme_color));
|
||||
assert colorPreference != null;
|
||||
colorPreference.setOnPreferenceChangeListener((preference, o) -> {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
ActivityCompat.recreate(activity);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
localePreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
// Refresh the activity
|
||||
Intent intent = new Intent(getContext(), SettingsActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
getContext().startActivity(intent);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayPreferenceDialog(Preference preference)
|
||||
{
|
||||
if (preference instanceof NumberDialogPreference)
|
||||
{
|
||||
public void onDisplayPreferenceDialog(Preference preference) {
|
||||
if (preference instanceof NumberDialogPreference) {
|
||||
NumberDialogPreference dialogPreference = (NumberDialogPreference) preference;
|
||||
DialogFragment dialogFragment = NumberPickerPreferenceDialogFragment
|
||||
.newInstance(
|
||||
@@ -103,9 +131,7 @@ public class SettingsActivity extends AppCompatActivity
|
||||
);
|
||||
dialogFragment.setTargetFragment(this, 0);
|
||||
dialogFragment.show(getParentFragmentManager(), DIALOG_FRAGMENT_TAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
super.onDisplayPreferenceDialog(preference);
|
||||
}
|
||||
}
|
||||
|
||||
9
app/src/main/res/drawable/active_dot.xml
Normal file
9
app/src/main/res/drawable/active_dot.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval" android:useLevel="true"
|
||||
android:dither="true">
|
||||
|
||||
<size android:height="12dip" android:width="12dip"/>
|
||||
|
||||
<solid android:color="@android:color/white"/>
|
||||
</shape>
|
||||
@@ -1,7 +0,0 @@
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@color/ic_launcher_background"/>
|
||||
<item android:gravity="center"
|
||||
android:width="256dp"
|
||||
android:height="256dp"
|
||||
android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</layer-list>
|
||||
13
app/src/main/res/drawable/ic_baseline_access_time_24.xml
Normal file
13
app/src/main/res/drawable/ic_baseline_access_time_24.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<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="@android:color/white"
|
||||
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/ic_baseline_payments_24.xml
Normal file
10
app/src/main/res/drawable/ic_baseline_payments_24.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<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="@android:color/white"
|
||||
android:pathData="M19,14L19,6c0,-1.1 -0.9,-2 -2,-2L3,4c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM10,13c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM23,7v11c0,1.1 -0.9,2 -2,2L4,20v-2h17L21,7h2z"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/ic_baseline_sort_24.xml
Normal file
5
app/src/main/res/drawable/ic_baseline_sort_24.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:tint="#FFFFFF" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/inactive_dot.xml
Normal file
9
app/src/main/res/drawable/inactive_dot.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval" android:useLevel="true"
|
||||
android:dither="true">
|
||||
|
||||
<size android:height="8dip" android:width="8dip"/>
|
||||
|
||||
<solid android:color="@android:color/white"/>
|
||||
</shape>
|
||||
@@ -22,21 +22,333 @@
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<LinearLayout
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/aboutText"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:linksClickable="true"
|
||||
android:singleLine="false"
|
||||
android:focusable="true" />
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/version_history"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version_history_main"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:padding="2dp"
|
||||
android:text="@string/version_history"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version_history_sub"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/version_history_main" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/arrow"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/credits"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/credits_main"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:padding="2dp"
|
||||
android:text="@string/credits"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/credits_sub"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/credits_main" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/arrow"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/translate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/translate_main"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:padding="2dp"
|
||||
android:text="@string/help_translate_this_app"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/arrow"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/license"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/license_main"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:padding="2dp"
|
||||
android:text="@string/license"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/license_sub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
android:text="@string/app_license"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/license_main"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/arrow"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/repo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/repo_main"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:padding="2dp"
|
||||
android:text="@string/source_repository"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/repo_sub"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
android:text="@string/on_github"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/repo_main" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/arrow"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/privacy"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/privacy_main"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:padding="2dp"
|
||||
android:text="@string/privacy_policy"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/privacy_sub"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
android:text="@string/and_data_usage"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/privacy_main" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/arrow"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/rate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/rate_main"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:padding="2dp"
|
||||
android:text="@string/rate_this_app"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/rate_sub"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
android:text="@string/on_google_play"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/rate_main" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/arrow"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:padding="8dp"
|
||||
android:id="@+id/report_error"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/report_error_main"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:padding="2dp"
|
||||
android:text="@string/report_error"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/report_error_sub"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@id/report_error_main"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:textSize="16sp"
|
||||
android:text="@string/on_github"
|
||||
android:padding="2dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="@string/arrow"
|
||||
android:textColor="@color/colorSecondaryText"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
65
app/src/main/res/layout/activity_manage_group.xml
Normal file
65
app/src/main/res/layout/activity_manage_group.xml
Normal file
@@ -0,0 +1,65 @@
|
||||
<?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"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context="protect.card_locker.ManageGroupActivity">
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabSave"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
app:srcCompat="@drawable/save_24dp"
|
||||
android:contentDescription="@string/save"
|
||||
android:layout_margin="16dp" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/groups"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:tabMode="scrollable" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/storeNameField"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/storeName">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editTextGroupName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
|
||||
<include
|
||||
android:id="@+id/include"
|
||||
layout="@layout/content_main" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -82,7 +82,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/aztecBarcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/aztecBarcodeText"
|
||||
@@ -103,7 +102,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/code39Barcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/code39BarcodeText"
|
||||
@@ -124,7 +122,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/code128Barcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/code128BarcodeText"
|
||||
@@ -145,7 +142,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/codabarBarcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/codabarBarcodeText"
|
||||
@@ -166,7 +162,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/datamatrixBarcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/datamatrixBarcodeText"
|
||||
@@ -187,7 +182,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/ean8Barcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/ean8BarcodeText"
|
||||
@@ -208,7 +202,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/ean13Barcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/ean13BarcodeText"
|
||||
@@ -229,7 +222,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/itfBarcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/itfBarcodeText"
|
||||
@@ -250,7 +242,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/pdf417Barcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/pdf417BarcodeText"
|
||||
@@ -271,7 +262,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/qrcodeBarcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/qrcodeBarcodeText"
|
||||
@@ -292,7 +282,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/upcaBarcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/upcaBarcodeText"
|
||||
@@ -313,7 +302,6 @@
|
||||
android:layout_height="@dimen/barcode_disp_height"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/upceBarcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
<TextView
|
||||
android:id="@+id/upceBarcodeText"
|
||||
|
||||
@@ -26,12 +26,24 @@
|
||||
android:gravity="center"
|
||||
android:text="@string/noMatchingGiftCards"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
style="@style/AppTheme.TextView.NoData"
|
||||
android:id="@+id/noGroupCardsText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/noGroupCards"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/list"
|
||||
app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager"
|
||||
app:spanCount="@integer/main_view_card_columns"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
android:visibility="gone" />
|
||||
android:background="@color/mainLoyaltyCardBackground"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?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"
|
||||
<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"
|
||||
android:fitsSystemWindows="true">
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabSave"
|
||||
@@ -67,14 +68,16 @@
|
||||
android:paddingTop="@dimen/inputPadding"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
android:layout_marginEnd="@dimen/activity_margin"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:cardCornerRadius="4dp"
|
||||
android:paddingHorizontal="@dimen/inputPadding"
|
||||
app:cardElevation="0dp">
|
||||
app:cardElevation="0dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
android:outlineProvider="none">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
@@ -83,7 +86,7 @@
|
||||
android:contentDescription="@string/thumbnailDescription"
|
||||
android:src="@mipmap/ic_launcher"/>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/storeNameField"
|
||||
@@ -96,7 +99,7 @@
|
||||
android:id="@+id/storeNameEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
android:singleLine="true" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
||||
@@ -120,7 +123,7 @@
|
||||
android:id="@+id/cardIdView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
android:singleLine="true" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
||||
@@ -312,7 +315,6 @@
|
||||
android:padding="10.0dp"
|
||||
android:background="#ffffff"
|
||||
android:id="@+id/barcode"
|
||||
android:contentDescription="@string/barcodeImageDescription"
|
||||
android:layout_weight="1.0"/>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -347,7 +349,7 @@
|
||||
android:paddingTop="@dimen/inputPadding">
|
||||
|
||||
<!-- Front image -->
|
||||
<androidx.cardview.widget.CardView
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
@@ -365,12 +367,11 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:minHeight="50dp"
|
||||
android:background="@color/colorPrimary"
|
||||
android:contentDescription="@string/frontImageDescription"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_camera_white" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Back image -->
|
||||
@@ -383,7 +384,7 @@
|
||||
android:paddingTop="@dimen/inputPadding">
|
||||
|
||||
<!-- Back image -->
|
||||
<androidx.cardview.widget.CardView
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
@@ -401,12 +402,11 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:minHeight="50dp"
|
||||
android:background="@color/colorPrimary"
|
||||
android:contentDescription="@string/backImageDescription"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_camera_white" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</LinearLayout>
|
||||
</TableLayout>
|
||||
</TableLayout>
|
||||
|
||||
@@ -1,118 +1,146 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/row"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="0.5dp"
|
||||
android:background="@drawable/list_row"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/activity_margin">
|
||||
android:layout_margin="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/information_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/activity_margin"
|
||||
android:layout_marginLeft="@dimen/activity_margin"
|
||||
android:layout_toEndOf="@+id/thumbnail_container"
|
||||
android:layout_toRightOf="@+id/thumbnail_container"
|
||||
android:layout_weight="1"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/thumbnail_container"
|
||||
app:layout_constraintEnd_toStartOf="@+id/star"
|
||||
app:layout_constraintStart_toEndOf="@+id/thumbnail_container"
|
||||
app:layout_constraintTop_toTopOf="@+id/thumbnail_container">
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/store"
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:id="@+id/information_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/storeNameTextSize"
|
||||
android:textStyle="bold" />
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/note"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textSize="@dimen/noteTextSize" />
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/balance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textSize="@dimen/noteTextSize" />
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/thumbnail_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="4dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
app:cardBackgroundColor="@android:color/transparent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/expiry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textSize="@dimen/noteTextSize" />
|
||||
<RelativeLayout
|
||||
android:id="@+id/thumbnail_front"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/storeContainer"
|
||||
android:layout_alignBottom="@+id/storeContainer"
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
android:layout_centerVertical="true"
|
||||
android:contentDescription="@string/thumbnailDescription"
|
||||
android:src="@mipmap/ic_launcher" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/thumbnail_back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/selected_thumbnail"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
android:layout_centerInParent="true"
|
||||
android:contentDescription="@string/thumbnailDescription"
|
||||
android:scaleType="centerCrop"
|
||||
app:srcCompat="@drawable/ic_done" />
|
||||
|
||||
</RelativeLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/store"
|
||||
android:paddingStart="16dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="left"
|
||||
android:layout_toRightOf="@+id/thumbnail_container"
|
||||
android:layout_toLeftOf="@+id/star"
|
||||
android:textAppearance="?attr/textAppearanceHeadline6" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/star"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
android:layout_centerVertical="true"
|
||||
android:scaleType="centerCrop"
|
||||
app:srcCompat="@drawable/ic_starred_white"
|
||||
android:contentDescription="@string/starImage"
|
||||
app:tint="?attr/colorControlNormal"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:visibility="gone" />
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/note"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="?attr/textAppearanceBody2"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:visibility="gone" />
|
||||
|
||||
<View android:id="@+id/info_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="?android:attr/dividerVertical"
|
||||
android:visibility="gone" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/balance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingEnd="8dp"
|
||||
android:textAppearance="?attr/textAppearanceBody2"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:drawableLeftCompat="@drawable/ic_baseline_payments_24"
|
||||
android:drawablePadding="4dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:visibility="gone" />
|
||||
<TextView
|
||||
android:id="@+id/expiry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center_vertical"
|
||||
android:textAppearance="?attr/textAppearanceBody2"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:drawableLeftCompat="@drawable/ic_baseline_access_time_24"
|
||||
android:drawablePadding="4dp"
|
||||
android:layout_toEndOf="@+id/balance"
|
||||
android:visibility="gone" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/thumbnail_container"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/thumbnail_front"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
android:contentDescription="@string/thumbnailDescription"
|
||||
android:src="@mipmap/ic_launcher" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/thumbnail_back"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:contentDescription="@string/thumbnailDescription"
|
||||
app:srcCompat="@drawable/ic_done" />
|
||||
|
||||
</RelativeLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/star"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
android:layout_marginLeft="@dimen/activity_margin"
|
||||
app:srcCompat="@drawable/ic_starred_white"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="@dimen/activity_margin"
|
||||
android:contentDescription="@string/starImage"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="#000000" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
@@ -55,25 +55,24 @@
|
||||
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24"
|
||||
android:contentDescription="@string/moveBarcodeToTopOfScreen"
|
||||
app:tint="#ffffff"
|
||||
android:background="@color/colorPrimary"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/barcode"
|
||||
app:layout_constraintBottom_toTopOf="@+id/mainImage"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/barcode"
|
||||
android:layout_width="0dp"
|
||||
android:id="@+id/mainImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginStart="15.0dip"
|
||||
android:layout_marginEnd="15.0dip"
|
||||
android:padding="10dp"
|
||||
android:background="#ffffff"
|
||||
app:layout_constraintBottom_toTopOf="@+id/centerGuideline"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/maximizeButton"
|
||||
android:contentDescription="@string/barcodeImageDescription"/>
|
||||
app:layout_constraintTop_toBottomOf="@+id/maximizeButton"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/minimizeButton"
|
||||
@@ -82,15 +81,31 @@
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="15.0dip"
|
||||
android:layout_marginEnd="15.0dip"
|
||||
android:layout_marginTop="10dp"
|
||||
android:padding="0dp"
|
||||
app:srcCompat="@drawable/ic_baseline_arrow_drop_down_24"
|
||||
android:contentDescription="@string/moveBarcodeToCenterOfScreen"
|
||||
app:tint="#ffffff"
|
||||
android:background="@color/colorPrimary"
|
||||
app:layout_constraintTop_toBottomOf="@+id/barcode"
|
||||
app:layout_constraintTop_toBottomOf="@+id/mainImage"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/dotIndicator"
|
||||
android:visibility="gone"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginStart="15.0dip"
|
||||
android:layout_marginEnd="15.0dip"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/minimizeButton"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/barcodeScaler"
|
||||
android:visibility="gone"
|
||||
@@ -107,12 +122,16 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cardIdView"
|
||||
android:enabled="true"
|
||||
android:textIsSelectable="true"
|
||||
android:focusable="true"
|
||||
android:longClickable="true"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginLeft="10.0dip"
|
||||
android:layout_marginRight="10.0dip"
|
||||
android:paddingBottom="80dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/minimizeButton"
|
||||
app:layout_constraintTop_toBottomOf="@+id/dotIndicator"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -136,8 +155,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/inputBackground"
|
||||
android:fitsSystemWindows="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="0px"
|
||||
android:visibility="gone"
|
||||
app:behavior_hideable="false"
|
||||
app:behavior_peekHeight="80dp"
|
||||
@@ -149,10 +168,10 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:layout_gravity="top|start"
|
||||
android:background="@color/colorPrimary"
|
||||
android:contentDescription="@string/toggleMoreInfo"
|
||||
android:scaleType="fitCenter"
|
||||
app:tint="#ffffff"
|
||||
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24" />
|
||||
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24"
|
||||
app:tint="#ffffff" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/bottomSheetContentWrapper"
|
||||
@@ -164,149 +183,129 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/frontImageView"
|
||||
android:layout_width="match_parent"
|
||||
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"
|
||||
android:layout_weight="1"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/frontImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:contentDescription="@string/frontImageDescription"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/backImageView"
|
||||
android:layout_width="match_parent"
|
||||
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"
|
||||
android:layout_weight="1"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/backImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:contentDescription="@string/backImageDescription"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/noteView"
|
||||
android:autoLink="all"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="all"
|
||||
android:enabled="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:longClickable="true"
|
||||
android:padding="20dp"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="@dimen/singleCardNoteTextSizeMin" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/groupsView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:longClickable="true"
|
||||
android:padding="20dp"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="@dimen/singleCardNoteTextSizeMin" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/balanceView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:longClickable="true"
|
||||
android:padding="20dp"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="@dimen/singleCardNoteTextSizeMin" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/expiryView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:longClickable="true"
|
||||
android:padding="20dp"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="@dimen/singleCardNoteTextSizeMin" />
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/app_bar_layout"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:weightSum="1.0"
|
||||
android:fitsSystemWindows="true">
|
||||
>
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar_landscape"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:background="@android:color/transparent"
|
||||
android:fitsSystemWindows="false"
|
||||
android:paddingTop="0dp"
|
||||
android:theme="@style/CardView.ActionBarTheme"
|
||||
android:visibility="gone"
|
||||
app:contentInsetStart="72.0dip"
|
||||
app:layout_collapseMode="pin" />
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/collapsingToolbarLayout"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:minHeight="56.0dip"
|
||||
android:layout_weight="1.0"
|
||||
app:expandedTitleMarginStart="48dp"
|
||||
app:expandedTitleMarginEnd="64dp"
|
||||
app:contentScrim="?colorPrimary"
|
||||
app:expandedTitleGravity="top">
|
||||
app:expandedTitleGravity="top"
|
||||
app:expandedTitleMarginEnd="64dp"
|
||||
app:expandedTitleMarginStart="48dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/storeName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="40sp"
|
||||
android:textAlignment="center"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="?actionBarSize"
|
||||
android:layout_marginBottom="?actionBarSize"
|
||||
app:layout_collapseMode="parallax"
|
||||
android:fitsSystemWindows="true"/>
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="40sp"
|
||||
app:layout_collapseMode="parallax" />
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@id/toolbar"
|
||||
android:background="@android:color/transparent"
|
||||
android:theme="@style/CardView.ActionBarTheme"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:background="@android:color/transparent"
|
||||
android:theme="@style/CardView.ActionBarTheme"
|
||||
app:contentInsetStart="72.0dip"
|
||||
app:layout_collapseMode="pin" />
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar_landscape"
|
||||
android:visibility="gone"
|
||||
android:background="@android:color/transparent"
|
||||
android:theme="@style/CardView.ActionBarTheme"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
app:contentInsetStart="72.0dip"
|
||||
app:layout_collapseMode="pin"
|
||||
android:paddingTop="6dp" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:fitsSystemWindows="true"
|
||||
android:scaleType="centerCrop"
|
||||
app:srcCompat="@drawable/ic_launcher_foreground"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
@@ -2,8 +2,23 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay"/>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/settings_container"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
21
app/src/main/res/layout/sorting_option.xml
Normal file
21
app/src/main/res/layout/sorting_option.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkBox_reverse"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:paddingLeft="20dp"
|
||||
android:text="@string/reverse"
|
||||
android:textSize="19sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -8,11 +8,16 @@
|
||||
android:icon="@drawable/ic_search_white"
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
app:showAsAction="always|collapseActionView"/>
|
||||
<item
|
||||
android:id="@+id/action_sort"
|
||||
android:title="@string/sort"
|
||||
android:icon="@drawable/ic_baseline_sort_24"
|
||||
app:showAsAction="always"/>
|
||||
<item
|
||||
android:id="@+id/action_manage_groups"
|
||||
android:icon="@drawable/ic_folder_white"
|
||||
android:title="@string/groups"
|
||||
app:showAsAction="always"/>
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/action_import_export"
|
||||
android:icon="@drawable/ic_import_export_white_24dp"
|
||||
@@ -22,10 +27,6 @@
|
||||
android:id="@+id/action_settings"
|
||||
android:title="@string/settings"
|
||||
app:showAsAction="never"/>
|
||||
<item
|
||||
android:id="@+id/action_privacy_policy"
|
||||
android:title="@string/privacy_policy"
|
||||
app:showAsAction="never"/>
|
||||
<item
|
||||
android:id="@+id/action_about"
|
||||
android:title="@string/about"
|
||||
|
||||
82
app/src/main/res/raw/contributors.txt
Normal file
82
app/src/main/res/raw/contributors.txt
Normal file
@@ -0,0 +1,82 @@
|
||||
Sylvia van Os
|
||||
Branden Archer
|
||||
J. Lavoie
|
||||
Allan Nordhøy
|
||||
Heimen Stoffels
|
||||
mondstern
|
||||
solokot
|
||||
Katharine Chui
|
||||
Oğuz Ersen
|
||||
IllusiveMan196
|
||||
Petr Novák
|
||||
Taco
|
||||
Gediminas Murauskas
|
||||
StoyanDimitrov
|
||||
Joel A
|
||||
Nyatsuki
|
||||
Samantaz Fox
|
||||
arno-github
|
||||
Ankit Tiwari
|
||||
Sergio Paredes
|
||||
arshbeerSingh
|
||||
huuhaa
|
||||
Miha Frangež
|
||||
Michael Moroni
|
||||
Olivia (Zoe)
|
||||
laralem
|
||||
betsythefc
|
||||
waffshappen
|
||||
K. Herbert
|
||||
Quentin PAGÈS
|
||||
String E. Fighter
|
||||
Yurical
|
||||
Adolfo Jayme-Barrientos
|
||||
Alessandro Mandelli
|
||||
KovalevArtem
|
||||
Clonewayx
|
||||
D. Domig
|
||||
Diego
|
||||
sr093906
|
||||
Jane Kong
|
||||
Lukas Grassauer
|
||||
Marnick L'Eau
|
||||
Michalis
|
||||
Rosdyana Kusuma
|
||||
schirinowski
|
||||
Thomas Bertels
|
||||
inesre
|
||||
lgasp
|
||||
phlostically
|
||||
Aditya Das
|
||||
Kevin Sicong Jiang
|
||||
Airat
|
||||
BMN
|
||||
Biren
|
||||
Kasina Dheeraj
|
||||
Flav
|
||||
Franciszek Stefan
|
||||
Izzy
|
||||
krkk
|
||||
bittin
|
||||
Maciej Błędkowski
|
||||
Mattia
|
||||
Michael Gangolf
|
||||
pbeckmann
|
||||
Peer Beckmann
|
||||
QuangDNguyen2211
|
||||
Reza
|
||||
Rohan Babbar
|
||||
Ronak Upadhyay
|
||||
Rose Liverman
|
||||
Simone Dotto
|
||||
Still Hsu
|
||||
Subhashish Anand
|
||||
Tymofii Lytvynenko
|
||||
Tjipke van der Heide
|
||||
avikkundu
|
||||
opsik
|
||||
psa-jforestier
|
||||
Robin
|
||||
sergio
|
||||
Marcus
|
||||
techwebpd
|
||||
@@ -24,11 +24,10 @@
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> карти</item>
|
||||
</plurals>
|
||||
<string name="failedOpeningFileManager">Инсталирайте приложение за управление на файлове.</string>
|
||||
<string name="app_license">Свободен софтуер с авторски права, лицензиран под GPLv3+.</string>
|
||||
<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="barcodeImageDescription">Изображение на щрихкода на картата</string>
|
||||
<string name="no">Не</string>
|
||||
<string name="yes">Да</string>
|
||||
<string name="setBackImage">Снимка на задната страна</string>
|
||||
@@ -53,7 +52,7 @@
|
||||
<string name="barcodeId">Стойност на щрихкода</string>
|
||||
<string name="importLoyaltyCardKeychain">Внасяне от Loyalty Card Keychain</string>
|
||||
<string name="importFidmeMessage">Изберете файла <i>fidme-export-request-xxxxxx.zip</i>, предварително изнесен от FidMe и ръчно изберете вида на щрихкодовете.
|
||||
\nИли създайте такъв файл от Data Protection в менюто на профила във FidMe и изберете „Extract my data“.</string>
|
||||
\nСъздайте такъв файл от Data Protection в менюто на профила във FidMe и изберете „Extract my data“.</string>
|
||||
<string name="importFidme">Внасяне от FidMe</string>
|
||||
<string name="exportOptionExplanation">Данните ще бъдат запазени на място по ваш избор.</string>
|
||||
<string name="accept">Приемане</string>
|
||||
@@ -86,10 +85,10 @@
|
||||
<string name="noGroups">Докоснете бутона +, за да добавите списък.</string>
|
||||
<string name="noStoreError">Не е въведено наименование</string>
|
||||
<string name="groups">Списъци</string>
|
||||
<string name="enter_group_name">Въведете име на списък</string>
|
||||
<string name="enter_group_name">Въведете име на списъка</string>
|
||||
<string name="intent_import_card_from_url_share_text">Искам да споделя тази карта с вас</string>
|
||||
<string name="settings_display_barcode_max_brightness">Увеличаване на яркостта при видим щрихкод</string>
|
||||
<string name="settings_lock_barcode_orientation">Спиране на завъртането на щрихкода</string>
|
||||
<string name="settings_lock_barcode_orientation">Без на завъртане на щрихкода</string>
|
||||
<string name="settings_keep_screen_on">Поддържане на екрана включен</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Предотвратяване на заключване на екрана</string>
|
||||
<string name="settings_max_font_size_scale">Максимален размер на шрифта</string>
|
||||
@@ -117,7 +116,7 @@
|
||||
<string name="exportName">Изнасяне</string>
|
||||
<string name="importExport">Внасяне/изнасяне</string>
|
||||
<string name="sendLabel">Изпращане…</string>
|
||||
<string name="scanCardBarcode">Сканиране на щрихкод от карта</string>
|
||||
<string name="scanCardBarcode">Снемане на щрихкод от карта</string>
|
||||
<string name="editCardTitle">Редактиране на карта</string>
|
||||
<string name="share">Споделя</string>
|
||||
<string name="copy_to_clipboard">Копира идентификатора в междинната памет</string>
|
||||
@@ -125,7 +124,7 @@
|
||||
<string name="importSuccessful">Картите са внесени успешно</string>
|
||||
<string name="chooseImportType">От къде ще внесете\?</string>
|
||||
<string name="importCatimaMessage">Изберете файла <i>catima.zip</i>, предварително изнесен от Catima.
|
||||
\nИли създайте такъв файл от меню Внасяне/изнасяне от друго устройство със Catima като изберете Изнасяне.</string>
|
||||
\nСъздайте такъв файл от меню Внасяне/изнасяне от друго устройство с Catima като изберете Изнасяне.</string>
|
||||
<string name="importOptionApplicationTitle">От друго приложение</string>
|
||||
<string name="importOptionFilesystemButton">Избиране от файлова система</string>
|
||||
<string name="importOptionFilesystemExplanation">Изберете определен файл от файловата система.</string>
|
||||
@@ -134,9 +133,9 @@
|
||||
<string name="app_revision_fmt">Компилация: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Издание: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="about_title_fmt">Относно <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Всички права запазени © 2019–<xliff:g>%d</xliff:g> Sylvia van Os.</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Всички права запазени © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="app_copyright_old">На основата на Loyalty Card Keychain
|
||||
\nвсички права запазени © 2016–2020 Branden Archer.</string>
|
||||
\nвсички права запазени © 2016–2020 Branden Archer</string>
|
||||
<string name="about">Относно</string>
|
||||
<string name="importOptionFilesystemTitle">Внасяне от файловата система</string>
|
||||
<string name="importCatima">Внасяне от Catima</string>
|
||||
@@ -157,22 +156,65 @@
|
||||
<string name="importStocard">Внасяне от Stocard</string>
|
||||
<string name="importVoucherVault">Внасяне от Voucher Vault</string>
|
||||
<string name="importVoucherVaultMessage">Изберете файла <i>vouchervault.json</i>, предварително изнесен от Voucher Vault.
|
||||
\nИли създайте такъв файл от меню Изнасяне от Voucher Vault.</string>
|
||||
<string name="importStocardMessage">Изберете вашия <i>***-sync.zip</i> експорт от Stocard, за да го импортирате.
|
||||
\nИли го получете, като изпратите имейл на support@stocardapp.com с искане за експорт на вашите данни.</string>
|
||||
\nСъздайте такъв файл от меню „Export“ във Voucher Vault.</string>
|
||||
<string name="importStocardMessage">Изберете файла <i>***-sync.zip</i>, предварително изнесен от Stocard.
|
||||
\nПолучете го като изпратите писмо на support@stocardapp.com с искане за изнасяне вашите данни.</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">Изберете файла <i>LoyaltyCardKeychain.csv</i>, предварително изнесен от Loyalty Card Keychain.
|
||||
\nИли създайте такъв файл от меню Внасяне/изнасяне от друго устройство със Loyalty Card Keychain като изберете Изнасяне.</string>
|
||||
\nСъздайте такъв файл от меню Внасяне/изнасяне от друго устройство с Loyalty Card Keychain като изберете Изнасяне.</string>
|
||||
<string name="failedParsingImportUriError">Препратката не може да бъде анализирана за внасяне</string>
|
||||
<string name="card_ids_copied">[не превеждай този низ, https://github.com/TheLastProject/Catima/issues/278]</string>
|
||||
<string name="failedGeneratingShareURL">Грешка при създаване на адрес за споделяне. Изпратете доклад за дефект.</string>
|
||||
<string name="deleteTitle">Изтрийте картата</string>
|
||||
<string name="deleteTitle">Премахване на карта</string>
|
||||
<plurals name="deleteCardsTitle">
|
||||
<item quantity="one">Изтриване на <xliff:g>%d</xliff:g> карта</item>
|
||||
<item quantity="other">Изтриване на <xliff:g>%d</xliff:g> карти</item>
|
||||
</plurals>
|
||||
<string name="deleteConfirmation">Потвърдете премахване на карта\?</string>
|
||||
<string name="deleteConfirmation">Потвърдете премахване на картата.</string>
|
||||
<plurals name="deleteCardsConfirmation">
|
||||
<item quantity="one">Изтриване на тази <xliff:g>%d</xliff:g> карта завинаги\?</item>
|
||||
<item quantity="other">Изтриване на тези <xliff:g>%d</xliff:g> карти за постоянно\?</item>
|
||||
<item quantity="one">Желаете ли <xliff:g>%d</xliff:g> карта да бъде премахната\?</item>
|
||||
<item quantity="other">Желаете ли тези <xliff:g>%d</xliff:g> карти да бъдат премахнати\?</item>
|
||||
</plurals>
|
||||
<string name="app_contributors">Осъществено от: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="settings_brown_theme">Кафяво</string>
|
||||
<string name="settings_grey_theme">Сиво</string>
|
||||
<string name="settings_green_theme">Зелено</string>
|
||||
<string name="settings_sky_blue_theme">Небесносиньо</string>
|
||||
<string name="settings_blue_theme">Синьо</string>
|
||||
<string name="settings_violet_theme">Виолетово</string>
|
||||
<string name="settings_magenta_theme">Цикламено</string>
|
||||
<string name="settings_pink_theme">Розово</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_theme_color">Цвят на темата</string>
|
||||
<string name="settings_system_locale">Система</string>
|
||||
<string name="settings_locale">Език</string>
|
||||
<string name="noGroupCards">Групата не съдържа карти</string>
|
||||
<string name="toggleMoreInfo">Превключване на повече информация</string>
|
||||
<string name="barcodeImageDescriptionWithType">Изображение на щрихкод на карта от вида <xliff:g>%s</xliff:g></string>
|
||||
<string name="swipeToSwitchImages">Плъзване или задържане за смяна на изображения</string>
|
||||
<string name="sort_by">Сортиране по</string>
|
||||
<string name="reverse">Наобратно</string>
|
||||
<string name="sort_by_balance">Наличност</string>
|
||||
<string name="sort_by_expiry">Валидност</string>
|
||||
<string name="sort_by_most_recently_used">Последно използване</string>
|
||||
<string name="sort_by_name">Наименование</string>
|
||||
<string name="sort">Сортиране</string>
|
||||
<string name="credits">Заслуги</string>
|
||||
<string name="license">Лиценз</string>
|
||||
<string name="source_repository">Хранилище на изходния код</string>
|
||||
<string name="on_github">в GitHub</string>
|
||||
<string name="rate_this_app">Оценете приложението</string>
|
||||
<string name="report_error">Докладване на грешка</string>
|
||||
<string name="version_history">История на изданията</string>
|
||||
<string name="on_google_play">в Google Play</string>
|
||||
<string name="and_data_usage">и използване на данни</string>
|
||||
<string name="help_translate_this_app">Помогнете за превода на приложението</string>
|
||||
<string name="exportPasswordHint">Въведете парола</string>
|
||||
<string name="exportPassword">Задаване на парола за защита на изнесеното (по избор)</string>
|
||||
<string name="setIcon">Задаване на пиктограма</string>
|
||||
<string name="editGroup">Променяне на списъка: <xliff:g>%s</xliff:g></string>
|
||||
<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_edit">Редактиране на списък</string>
|
||||
</resources>
|
||||
90
app/src/main/res/values-bn-rIN/strings.xml
Normal file
90
app/src/main/res/values-bn-rIN/strings.xml
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="save">সংরক্ষণ</string>
|
||||
<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>
|
||||
<string name="noMatchingGiftCards">কোন ম্যাচিং উপহার কার্ড নেই</string>
|
||||
<string name="noGiftCards">উপহার কার্ড নেই</string>
|
||||
<string name="action_add">কর্ম যোগ</string>
|
||||
<string name="all">সব</string>
|
||||
<string name="noGroupCards">গোষ্ঠী কার্ড নেই</string>
|
||||
<string name="noGroups">গোষ্ঠীগুলি নেই</string>
|
||||
<string name="groups">গোষ্ঠীগুলি</string>
|
||||
<string name="enter_group_name">গোষ্ঠী নাম লিখুন </string>
|
||||
<string name="exportSuccessful">রপ্তানি সফল</string>
|
||||
<string name="importSuccessful">আগম সফল</string>
|
||||
<string name="intent_import_card_from_url_share_text">url শেয়ার টেক্সট থেকে ইন্টেন্ট ইম্পোর্ট কার্ড</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card"> কার্ড দেখা কালিন লকস্ক্রিন নিষ্ক্রিয়</string>
|
||||
<string name="settings_keep_screen_on">সেটিংস পর্দা খোলা রাখুন</string>
|
||||
<string name="settings_lock_barcode_orientation"> তালাবদ্ধ বার কোড অভিযোজন</string>
|
||||
<string name="settings_max_font_size_scale">সর্বোচ্চ হরফ আকার</string>
|
||||
<string name="settings_light_theme">সাদাটে থিম</string>
|
||||
<string name="settings_system_theme">যন্ত্রর থিম</string>
|
||||
<string name="settings_theme">থিম</string>
|
||||
<string name="settings_category_title_ui">বিভাগ শিরোনাম</string>
|
||||
<string name="starImage">তারা ছবি</string>
|
||||
<string name="importCatima">ক্যাতিনা আগম</string>
|
||||
<string name="importLoyaltyCardKeychain">আমদানি লয়্যালটি কার্ড কীচেন</string>
|
||||
<string name="importStocard">স্টো কার্ড আমদানি করুন</string>
|
||||
<string name="importVoucherVault">আমদানি ভাউচার ভল্ট</string>
|
||||
<string name="barcodeId">বারকোড আইডি</string>
|
||||
<string name="sameAsCardId">কার্ড আইডির মতো</string>
|
||||
<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>
|
||||
<string name="photos">ছবি</string>
|
||||
<string name="setFrontImage">সদর ছবি স্থাপন</string>
|
||||
<string name="setBackImage">পিছনের ছবি স্থাপন</string>
|
||||
<string name="removeImage">ছবি অপসারণ</string>
|
||||
<string name="takePhoto">ছবি নেত্তয়া</string>
|
||||
<string name="updateBarcodeQuestionTitle">হালনাগাদ বারকোড প্রশ্ন শিরোনাম</string>
|
||||
<string name="updateBarcodeQuestionText">হালনাগাদ বারকোড প্রশ্ন টেক্সট </string>
|
||||
<string name="yes">হাঁ</string>
|
||||
<string name="no">না</string>
|
||||
<string name="passwordRequired">পাসওয়ার্ড প্রয়োজন</string>
|
||||
<string name="failedGeneratingShareURL">শেয়ার ইউআরএল তৈরি করতে ব্যর্থ হয়েছে</string>
|
||||
<string name="turn_flashlight_on">টর্চলাইট চালু করুন</string>
|
||||
<string name="turn_flashlight_off">টর্চলাইট বন্ধ করুন</string>
|
||||
<string name="settings_locale">লোকেল</string>
|
||||
<string name="settings_system_locale">সিস্টেম লোকেল</string>
|
||||
<string name="settings_theme_color">থিম রঙ</string>
|
||||
<string name="settings_catima_theme">কটিমা থিম</string>
|
||||
<string name="settings_pink_theme">গোলাপী থিম</string>
|
||||
<string name="settings_magenta_theme">ম্যাজেন্টা থিম</string>
|
||||
<string name="settings_violet_theme">ভায়োলেট থিম</string>
|
||||
<string name="settings_blue_theme">নীল থিম</string>
|
||||
<string name="settings_sky_blue_theme">আকাশী নীল থিম</string>
|
||||
<string name="settings_green_theme">সবুজ থিম</string>
|
||||
<string name="settings_brown_theme">বাদামী থিম</string>
|
||||
<string name="sort">সাজান</string>
|
||||
<string name="toggleMoreInfo">আরও তথ্য টগল করুন</string>
|
||||
<string name="swipeToSwitchImages">ছবি পরিবর্তন করতে সোয়াইপ করুন</string>
|
||||
<string name="sort_by_name">নামের দ্বারা সাজান</string>
|
||||
<string name="sort_by_most_recently_used">সর্বাধিক সম্প্রতি ব্যবহৃত দ্বারা সাজান</string>
|
||||
<string name="sort_by_expiry">মেয়াদ শেষ করে সাজান</string>
|
||||
<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="unlockScreen">পর্দা আনলক করুন</string>
|
||||
<string name="confirm">নিশ্চিত করুন</string>
|
||||
<string name="delete">মুছে ফেলুন</string>
|
||||
<string name="edit">সম্পাদনা</string>
|
||||
</resources>
|
||||
90
app/src/main/res/values-bs/strings.xml
Normal file
90
app/src/main/res/values-bs/strings.xml
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="save">Snimi</string>
|
||||
<string name="cancel">Odustani</string>
|
||||
<string name="unstar">Ukloni sve omiljene</string>
|
||||
<string name="star">Omiljene</string>
|
||||
<string name="barcodeNoBarcode">Ova kartica nema barkode</string>
|
||||
<string name="barcodeType">Barcode tip</string>
|
||||
<string name="note">Bilježnica</string>
|
||||
<string name="storeName">Ime</string>
|
||||
<string name="noMatchingGiftCards">Nisam našao ništa. Pokušaj promijeniti pretragu.</string>
|
||||
<string name="noGiftCards">Kliknite + Plus dugme da dodate kartu ili uvozite nešto iz menija prvo.</string>
|
||||
<string name="action_add">Dodaj</string>
|
||||
<string name="all">Sve</string>
|
||||
<string name="noGroupCards">Ova grupa ne sadrži nikakve karte</string>
|
||||
<string name="noGroups">Kliknite + Plus dugme da dodate grupe za kategorizaciju prvo.</string>
|
||||
<string name="groups">Grupe</string>
|
||||
<string name="enter_group_name">Unesite ime grupe</string>
|
||||
<string name="exportSuccessful">Podaci o kartama izvožen</string>
|
||||
<string name="importSuccessful">Uvezeni podaci o kartama</string>
|
||||
<string name="intent_import_card_from_url_share_text">Želim podijeliti čestitku s tobom</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Spriječi zaključavanje ekrana</string>
|
||||
<string name="settings_keep_screen_on">Zadrži ekran</string>
|
||||
<string name="settings_lock_barcode_orientation">Zaključaj barcode orjentacija</string>
|
||||
<string name="settings_max_font_size_scale">Max. veliäťina fonta</string>
|
||||
<string name="settings_light_theme">Svjetlo</string>
|
||||
<string name="settings_system_theme">Sistem</string>
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="settings_category_title_ui">Korisničko okruženje</string>
|
||||
<string name="starImage">Omiljena zvijezda</string>
|
||||
<string name="importCatima">Uvezi iz Catima</string>
|
||||
<string name="importLoyaltyCardKeychain">Uvezi iz Loyalty Card Keychain</string>
|
||||
<string name="importStocard">Uvezi iz Stokarda</string>
|
||||
<string name="importVoucherVault">Uvezi iz trezora vaučer</string>
|
||||
<string name="barcodeId">Barcode vrijednost</string>
|
||||
<string name="sameAsCardId">Isto kao i kartica</string>
|
||||
<string name="setBarcodeId">Postavi vrijednost za bar kod</string>
|
||||
<string name="unsupportedBarcodeType">Ovaj bar kod još nije prikazan. Ona može biti podržana u kasnijoj verziji app.</string>
|
||||
<string name="wrongValueForBarcodeType">Izabrana vrijednost nije izvršna</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">IDs kartica kopiran u clipboard</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Želim podijeliti karte s tobom</string>
|
||||
<string name="frontImageDescription">Slika kartice</string>
|
||||
<string name="backImageDescription">Slika pozadine kartice</string>
|
||||
<string name="photos">Slike</string>
|
||||
<string name="setFrontImage">Postavi naslovnu sliku</string>
|
||||
<string name="setBackImage">Vrati sliku</string>
|
||||
<string name="removeImage">Ukloni sliku</string>
|
||||
<string name="takePhoto">Slikaj</string>
|
||||
<string name="updateBarcodeQuestionTitle">Ažurirati bar kod vrijednost\?</string>
|
||||
<string name="updateBarcodeQuestionText">Promijenio si auto. Da li želite ažurirati bar kod koristiti istu vrijednost\?</string>
|
||||
<string name="yes">Da</string>
|
||||
<string name="no">Ne.</string>
|
||||
<string name="passwordRequired">Upišite šifru</string>
|
||||
<string name="failedGeneratingShareURL">Ne mogu generisati oštriji URL. Molim vas, prijavite ovo.</string>
|
||||
<string name="turn_flashlight_on">Upali lampu</string>
|
||||
<string name="turn_flashlight_off">Ugasi lampu</string>
|
||||
<string name="settings_locale">Jezik</string>
|
||||
<string name="settings_system_locale">Sistem</string>
|
||||
<string name="settings_theme_color">Boja teme</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_pink_theme">Ružičasto</string>
|
||||
<string name="settings_magenta_theme">Ljubičasto</string>
|
||||
<string name="settings_violet_theme">Ljubičasto</string>
|
||||
<string name="settings_blue_theme">Plavo</string>
|
||||
<string name="settings_sky_blue_theme">Nebo plavo</string>
|
||||
<string name="settings_green_theme">Zeleno</string>
|
||||
<string name="settings_brown_theme">Braun</string>
|
||||
<string name="sort">Poništi sortiranje</string>
|
||||
<string name="toggleMoreInfo">Uključi savjete</string>
|
||||
<string name="swipeToSwitchImages">Swipe ili long press za prebacivanje slika</string>
|
||||
<string name="sort_by_name">Ime</string>
|
||||
<string name="sort_by_most_recently_used">Nedavno Korišten</string>
|
||||
<string name="sort_by_expiry">Sajam</string>
|
||||
<string name="reverse">Rikverc</string>
|
||||
<string name="sort_by">Sortiraj</string>
|
||||
<string name="noCardExistsError">Nisam mogao pronaći karticu</string>
|
||||
<string name="noStoreError">Nije uneseno ime</string>
|
||||
<string name="card_ids_copied">Kopiran ID kartice(s)</string>
|
||||
<string name="noCardsMessage">Dodaj prvo kartu</string>
|
||||
<string name="addCardTitle">Dodaj Kartu</string>
|
||||
<string name="editCardTitle">Izmijeni Karticu</string>
|
||||
<string name="sendLabel">Pošalji…</string>
|
||||
<string name="share">Podijeli</string>
|
||||
<string name="copy_to_clipboard">Kopiraj ID u clipboard</string>
|
||||
<string name="deleteConfirmation">Izbriši trajno ovu karticu\?</string>
|
||||
<string name="unlockScreen">Odblokalna Rotacija</string>
|
||||
<string name="confirm">Potvrdi</string>
|
||||
<string name="delete">Obriši</string>
|
||||
<string name="edit">Izmijeni</string>
|
||||
</resources>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="action_add">Přidat</string>
|
||||
<string name="noGiftCards">Klepnutím na tlačítko + plus přidáte kartu nebo ji nejprve importujete z nabídky⋮.</string>
|
||||
<string name="storeName">Název</string>
|
||||
@@ -16,13 +16,12 @@
|
||||
<string name="editCardTitle">Editovat věrnostní kartu</string>
|
||||
<string name="addCardTitle">Přidat věrnostní kartu</string>
|
||||
<string name="scanCardBarcode">Skenování Čárový Kód Karty</string>
|
||||
<string name="barcodeImageDescription">Obrázek čárového kódu karty</string>
|
||||
<string name="noStoreError">Zadáno žádné jméno</string>
|
||||
<string name="noCardIdError">Žádné ID karty zadáno</string>
|
||||
<string name="importExport">Import/Export</string>
|
||||
<string name="exportName">Export</string>
|
||||
<string name="importExportHelp">Zálohování karet vám umožní přesunout je do jiného zařízení.</string>
|
||||
<string name="importSuccessfulTitle">Dovážit</string>
|
||||
<string name="importSuccessfulTitle">Importováno</string>
|
||||
<string name="importFailedTitle">Import selhal</string>
|
||||
<string name="importFailed">Nelze importovat karty</string>
|
||||
<string name="exportSuccessfulTitle">Exportovat</string>
|
||||
@@ -38,7 +37,7 @@
|
||||
<string name="importOptionApplicationExplanation">K otevření souboru použijte libovolnou aplikaci nebo svého oblíbeného správce souborů.</string>
|
||||
<string name="importOptionApplicationButton">Použijte jinou aplikaci</string>
|
||||
<string name="about">O aplikaci</string>
|
||||
<string name="app_license">Copylefted libre software, licencovaný GPLv3+.</string>
|
||||
<string name="app_license">Copyleftovaný svobodný software s licencí GPLv3+</string>
|
||||
<string name="about_title_fmt">O aplikaci <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Verze: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Informace o revizi: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
@@ -53,10 +52,10 @@
|
||||
<string name="expiryDate">Platnost</string>
|
||||
<string name="editBarcode">Upravit čárový kód</string>
|
||||
<string name="barcode">Kód</string>
|
||||
<string name="app_resources">Zdroje třetích stran Libre: <xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="app_libraries">Libre knihovny třetích stran: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="app_resources">Svobodné zdroje třetích stran: <xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="app_libraries">Svobodné knihovny třetích stran: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="app_copyright_old">Na základě Loyalty Card Keychain
|
||||
\ncopyright © 2016–2020 Branden Archer.</string>
|
||||
\ncopyright © 2016–2020 Branden Archer</string>
|
||||
<string name="exportOptionExplanation">Data budou zapsána na místo podle vašeho výběru.</string>
|
||||
<string name="failedParsingImportUriError">Nelze analyzovat import URI</string>
|
||||
<string name="noCardExistsError">Nelze najít kartu</string>
|
||||
@@ -72,4 +71,155 @@
|
||||
<string name="barcodeType">Typ čárového kódu</string>
|
||||
<string name="noMatchingGiftCards">Nic jsem nenašel. Zkuste změnit vyhledávání.</string>
|
||||
<string name="action_search">Vyhledávání</string>
|
||||
<string name="thumbnailDescription">Miniatura karty</string>
|
||||
<string name="card_ids_copied">Zkopírované ID karty(karet)</string>
|
||||
<plurals name="deleteCardsConfirmation">
|
||||
<item quantity="one">Opravdu chcete kartu <xliff:g>%d</xliff:g> trvale odstranit\?</item>
|
||||
<item quantity="few">Opravdu chcete karty <xliff:g>%d</xliff:g> trvale odstranit\?</item>
|
||||
<item quantity="other">Opravdu chcete karty <xliff:g>%d</xliff:g> trvale odstranit\?</item>
|
||||
</plurals>
|
||||
<plurals name="deleteCardsTitle">
|
||||
<item quantity="one">Odstranit kartu <xliff:g>%d</xliff:g></item>
|
||||
<item quantity="few">Odstranit karty <xliff:g>%d</xliff:g></item>
|
||||
<item quantity="other">Odstranit karty <xliff:g>%d</xliff:g></item>
|
||||
</plurals>
|
||||
<string name="importSuccessful">Data karty importována</string>
|
||||
<string name="intent_import_card_from_url_share_text">Chci s Vámi sdílet kartu</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Bránit uzamykání obrazovky</string>
|
||||
<string name="settings_keep_screen_on">Udržovat obrazovku zapnutou</string>
|
||||
<string name="settings_lock_barcode_orientation">Zamknout orientaci čárového kódu</string>
|
||||
<string name="settings_max_font_size_scale">Maximální velikost písma</string>
|
||||
<string name="settings_dark_theme">Tmavý</string>
|
||||
<string name="settings_light_theme">Světlý</string>
|
||||
<string name="settings_system_theme">Systém</string>
|
||||
<string name="settings_theme">Vzhled</string>
|
||||
<string name="settings_category_title_ui">Uživatelské rozhraní</string>
|
||||
<string name="settings">Nastavení</string>
|
||||
<string name="card">Karta</string>
|
||||
<string name="balancePoints"><xliff:g>%s</xliff:g> bodů</string>
|
||||
<string name="balanceSentence">Zůstatek: <xliff:g>%s</xliff:g></string>
|
||||
<string name="expiryStateSentenceExpired">Platnost vypršela: <xliff:g>%s</xliff:g></string>
|
||||
<string name="expiryStateSentence">Platí do: <xliff:g>%s</xliff:g></string>
|
||||
<string name="moveDown">Přesunout dolů</string>
|
||||
<string name="moveUp">Přesunout nahoru</string>
|
||||
<string name="enterBarcodeInstructions">Zadejte ID karty a níže vyberte typ čárového kódu nebo \"Tato karta nemá čárový kód\".</string>
|
||||
<string name="settings_brown_theme">Hnědá</string>
|
||||
<string name="settings_grey_theme">Šedá</string>
|
||||
<string name="settings_green_theme">Zelená</string>
|
||||
<string name="settings_sky_blue_theme">Azurová</string>
|
||||
<string name="settings_blue_theme">Modrá</string>
|
||||
<string name="settings_violet_theme">Fialová</string>
|
||||
<string name="settings_magenta_theme">Purpurová</string>
|
||||
<string name="settings_pink_theme">Růžová</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_theme_color">Barva motivu</string>
|
||||
<string name="settings_system_locale">Systém</string>
|
||||
<string name="settings_locale">Jazyk</string>
|
||||
<string name="turn_flashlight_off">Vypnout světlo</string>
|
||||
<string name="turn_flashlight_on">Zapnout světlo</string>
|
||||
<string name="failedGeneratingShareURL">Nepodařilo se vygenerovat sdílenou adresu URL. Nahlaste to prosím.</string>
|
||||
<string name="passwordRequired">Zadejte prosím heslo</string>
|
||||
<string name="no">Ne</string>
|
||||
<string name="yes">Ano</string>
|
||||
<string name="updateBarcodeQuestionText">Změnili jste ID karty. Chcete také aktualizovat čárový kód, aby používal stejnou hodnotu\?</string>
|
||||
<string name="updateBarcodeQuestionTitle">Aktualizovat hodnotu čárového kódu\?</string>
|
||||
<string name="takePhoto">Pořídit fotku</string>
|
||||
<string name="removeImage">Odstranit obrázek</string>
|
||||
<string name="setBackImage">Nastavit obrázek zadní strany</string>
|
||||
<string name="setFrontImage">Nastavit obrázek přední strany</string>
|
||||
<string name="photos">Fotky</string>
|
||||
<string name="backImageDescription">Obrázek zadní strany karty</string>
|
||||
<string name="frontImageDescription">Obrázek přední strany karty</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Chci s Vámi sdílet kartu</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">ID karty zkopírováno do schránky</string>
|
||||
<string name="wrongValueForBarcodeType">Hodnota není platná pro vybraný typ čárového kódu</string>
|
||||
<string name="unsupportedBarcodeType">Tento typ čárového kódu zatím nelze zobrazit. Možná bude podporován v pozdější verzi aplikace.</string>
|
||||
<string name="barcodeId">Hodnota čárového kódu</string>
|
||||
<string name="setBarcodeId">Nastavení hodnoty čárového kódu</string>
|
||||
<string name="sameAsCardId">Stejné jako ID karty</string>
|
||||
<string name="importVoucherVaultMessage">Vyberte svůj <i>vouchervault.json</i> export z Voucher Vault, který chcete importovat.
|
||||
\nVytvořte jej tak, že nejprve stisknete tlačítko Exportovat v aplikaci Voucher Vault.</string>
|
||||
<string name="importVoucherVault">Import z Voucher Vault</string>
|
||||
<string name="importStocardMessage">Vyberte svůj <i>***-sync.zip</i> export z aplikace Stocard, který chcete importovat.
|
||||
\nZískejte ji zasláním e-mailu na adresu support@stocardapp.com s žádostí o export vašich dat.</string>
|
||||
<string name="importStocard">Import ze Stocard</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">Vyberte export <i>LoyaltyCardKeychain.csv</i> z klíčenky věrnostních karet, který chcete importovat.
|
||||
\nVytvořte jej z nabídky Import/Export v Loyalty Card Keychain tak, že tam nejprve stisknete tlačítko Exportovat.</string>
|
||||
<string name="importLoyaltyCardKeychain">Import z Loyalty Card Keychain</string>
|
||||
<string name="importFidmeMessage">Vyberte svůj <i>fidme-export-request-xxxxxx.zip</i> export z FidMe k importu a poté vyberte typy čárových kódů ručně.
|
||||
\nVytvořte jej ze svého profilu FidMe tak, že nejprve zvolíte možnost Ochrana dat a poté stisknete tlačítko Extract moje data.</string>
|
||||
<string name="importFidme">Import z FidMe</string>
|
||||
<string name="importCatimaMessage">Vyberte export <i>catima.zip</i> z programu Catima, který chcete importovat.
|
||||
\nVytvořte jej z nabídky Import/Export jiné aplikace Catima tak, že v ní nejprve stisknete tlačítko Exportovat.</string>
|
||||
<string name="importCatima">Import z Catima</string>
|
||||
<string name="accept">Přijmout</string>
|
||||
<string name="privacy_policy_popup_text">Oznámení o zásadách ochrany osobních údajů (vyžadováno některými obchody s aplikacemi):
|
||||
\n
|
||||
\nNejsou shromažďovány žádné údaje, což může potvrdit každý, protože naše aplikace je svobodný software.</string>
|
||||
<string name="privacy_policy">Zásady soukromí</string>
|
||||
<string name="app_loyalty_card_keychain">Loyalty Card Keychain</string>
|
||||
<string name="chooseImportType">Importovat data z\?</string>
|
||||
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> se nezdá být platným zůstatkem.</string>
|
||||
<string name="points">Body</string>
|
||||
<string name="currency">Měna</string>
|
||||
<string name="balance">Zůstatek</string>
|
||||
<string name="errorReadingImage">Obrázek se nepodařilo přečíst</string>
|
||||
<string name="noBarcodeFound">Čarový kód nenalezen</string>
|
||||
<string name="groupsList">Skupiny: <xliff:g>%s</xliff:g></string>
|
||||
<string name="addFromImage">Výběr obrázku z galerie</string>
|
||||
<string name="addManually">Ruční zadání ID karty</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Ukončit bez uložení\?</string>
|
||||
<string name="leaveWithoutSaveTitle">Ukončit</string>
|
||||
<string name="failedOpeningFileManager">Nejprve si nainstalujte správce souborů.</string>
|
||||
<string name="deleteConfirmationGroup">Smazat skupinu\?</string>
|
||||
<string name="all">Všechny</string>
|
||||
<plurals name="groupCardCount">
|
||||
<item quantity="one"><xliff:g>%d</xliff:g> karta</item>
|
||||
<item quantity="few"><xliff:g>%d</xliff:g> karty</item>
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> karet</item>
|
||||
</plurals>
|
||||
<string name="noGroups">Kliknutím na tlačítko + plus nejprve přidejte skupiny pro kategorizaci.</string>
|
||||
<string name="groups">Skupiny</string>
|
||||
<string name="enter_group_name">Zadejte název skupiny</string>
|
||||
<string name="exportSuccessful">Data karty exportována</string>
|
||||
<string name="settings_display_barcode_max_brightness">Rozjasněné zobrazení čárového kódu</string>
|
||||
<string name="starImage">Oblíbená hvězda</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<plurals name="selectedCardCount">
|
||||
<item quantity="one">Vybrána <xliff:g>%d</xliff:g> karta</item>
|
||||
<item quantity="few">Vybrány <xliff:g>%d</xliff:g> karty</item>
|
||||
<item quantity="other">Vybráno <xliff:g>%d</xliff:g> karet</item>
|
||||
</plurals>
|
||||
<string name="app_contributors">Přispěli: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="noGroupCards">Tato skupina neobsahuje žádné karty</string>
|
||||
<string name="sort_by">Seřadit podle</string>
|
||||
<string name="reverse">Obrátit</string>
|
||||
<string name="sort_by_balance">Zůstatek</string>
|
||||
<string name="sort_by_expiry">Vypršení</string>
|
||||
<string name="sort_by_most_recently_used">Naposledy použité</string>
|
||||
<string name="sort_by_name">Název</string>
|
||||
<string name="swipeToSwitchImages">Přejetím nebo dlouhým stisknutím přepínáte obrázky</string>
|
||||
<string name="toggleMoreInfo">Přepnout zobrazení dalších informací</string>
|
||||
<string name="sort">Seřadit</string>
|
||||
<string name="barcodeImageDescriptionWithType">Obrázek čárového kódu karty typu <xliff:g>%s</xliff:g></string>
|
||||
<string name="version_history">Historie verzí</string>
|
||||
<string name="rate_this_app">Ohodnoťte tuto aplikaci</string>
|
||||
<string name="and_data_usage">a využití dat</string>
|
||||
<string name="credits">Kredity</string>
|
||||
<string name="on_github">na GitHubu</string>
|
||||
<string name="source_repository">Úložiště zdrojů</string>
|
||||
<string name="license">Licence</string>
|
||||
<string name="help_translate_this_app">Pomozte s překladem této aplikace</string>
|
||||
<string name="report_error">Nahlásit chybu</string>
|
||||
<string name="on_google_play">na Google Play</string>
|
||||
<string name="exportPassword">Nastavení hesla pro ochranu exportu (volitelné)</string>
|
||||
<string name="exportPasswordHint">Zadejte heslo</string>
|
||||
<string name="selectColor">Vyberte barvu</string>
|
||||
<string name="setIcon">Nastavit ikonu</string>
|
||||
<string name="group_edit">Upravit skupinu</string>
|
||||
<string name="group_name_already_in_use">Již použitý název skupiny</string>
|
||||
<string name="group_name_is_empty">Název skupiny nemůže být prázdný</string>
|
||||
<string name="group_updated">Skupina aktualizována</string>
|
||||
<string name="editGroup">Úprava skupiny: <xliff:g>%s</xliff:g></string>
|
||||
<string name="noGiftCardsGroup">Zatím nemáte žádné věrnostní karty. Jakmile nějaké přidáte, můžete je přiřadit do skupiny zde.</string>
|
||||
</resources>
|
||||
7
app/src/main/res/values-cy/strings.xml
Normal file
7
app/src/main/res/values-cy/strings.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="noGiftCards">Cliciwch y + plws botwm i ychwanegu cerdyn, neu mewnforio rhai o\'r ⋮ ddewislen cyntaf.</string>
|
||||
<string name="action_add">Ychwanegu</string>
|
||||
<string name="action_search">Chwilio</string>
|
||||
<string name="noMatchingGiftCards">Nid oedd hyd i unrhyw beth. Ceisiwch newid eich chwiliad.</string>
|
||||
</resources>
|
||||
@@ -36,4 +36,61 @@
|
||||
</plurals>
|
||||
<string name="action_add">Tilføj</string>
|
||||
<string name="action_search">Søg</string>
|
||||
<string name="importExport">Import/eksport</string>
|
||||
<string name="exportName">Eksport</string>
|
||||
<string name="importExportHelp">Hvis du sikkerhedskopierer dine kort, kan du flytte dem til en anden enhed.</string>
|
||||
<string name="importSuccessfulTitle">Importeret</string>
|
||||
<string name="importFailedTitle">Import mislykkedes</string>
|
||||
<string name="importFailed">Kunne ikke importere kort</string>
|
||||
<string name="exportSuccessfulTitle">Eksporteret</string>
|
||||
<string name="exportFailedTitle">Eksport mislykkedes</string>
|
||||
<string name="exportFailed">Kunne ikke eksportere kort</string>
|
||||
<string name="importing">Importere…</string>
|
||||
<string name="exporting">Eksportere…</string>
|
||||
<string name="settings_dark_theme">Mørk</string>
|
||||
<string name="settings_light_theme">Lys</string>
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="settings_category_title_ui">Brugergrænseflade</string>
|
||||
<string name="settings">Indstillinger</string>
|
||||
<string name="starImage">Favorit stjerne</string>
|
||||
<string name="thumbnailDescription">Miniaturebillede til kort</string>
|
||||
<string name="copy_to_clipboard_toast">Kort-ID kopieret til udklipsholderen</string>
|
||||
<string name="enterBarcodeInstructions">Indtast kortets ID, og vælg enten kortets stregkodetype nedenfor, eller \"Dette kort har ingen stregkode\".</string>
|
||||
<string name="selectBarcodeTitle">Vælg stregkode</string>
|
||||
<string name="app_copyright_old">Baseret på Loyalty Card Keychain
|
||||
\ncopyright © 2016-2020 Branden Archer.</string>
|
||||
<string name="about">Om</string>
|
||||
<string name="importOptionApplicationButton">Brug en anden app</string>
|
||||
<string name="importOptionApplicationExplanation">Brug en hvilken som helst app eller din foretrukne filhåndtering til at åbne en fil.</string>
|
||||
<string name="importOptionApplicationTitle">Brug en anden app</string>
|
||||
<string name="noCardsMessage">Tilføj først et kort</string>
|
||||
<string name="cardShortcut">Kort genvej</string>
|
||||
<string name="importOptionFilesystemButton">Fra filsystemet</string>
|
||||
<string name="importOptionFilesystemExplanation">Vælg en bestemt fil fra filsystemet.</string>
|
||||
<string name="importOptionFilesystemTitle">Import fra filsystem</string>
|
||||
<string name="exportOptionExplanation">Dataene skrives til en placering efter eget valg.</string>
|
||||
<string name="noExternalStoragePermissionError">Giv først tilladelse til ekstern lagring til at importere eller eksportere kort</string>
|
||||
<string name="failedParsingImportUriError">Kunne ikke analysere import-URI\'en</string>
|
||||
<string name="noCardExistsError">Kunne ikke finde kort</string>
|
||||
<string name="noCardIdError">Der er ikke angivet noget kort-ID</string>
|
||||
<string name="noStoreError">Intet navn angivet</string>
|
||||
<string name="deleteConfirmationGroup">Slet gruppe\?</string>
|
||||
<string name="all">Alle</string>
|
||||
<string name="noGroupCards">Denne gruppe indeholder ikke nogen kort</string>
|
||||
<string name="noGroups">Klik på + plus-knappen for først at tilføje grupper til kategorisering.</string>
|
||||
<string name="groups">Grupper</string>
|
||||
<string name="enter_group_name">Indtast gruppenavn</string>
|
||||
<string name="exportSuccessful">Eksporterede kortdata</string>
|
||||
<string name="importSuccessful">Kortdata importeret</string>
|
||||
<string name="intent_import_card_from_url_share_text">Jeg vil dele et kort med jer</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Forebyg låseskærm</string>
|
||||
<string name="settings_keep_screen_on">LHold skærm tændt</string>
|
||||
<string name="settings_lock_barcode_orientation">Lås stregkode-orientering</string>
|
||||
<string name="moveUp">Bevæg dig opad</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Forlade uden at gemme\?</string>
|
||||
<string name="settings_display_barcode_max_brightness">Lysere stregkodevisning</string>
|
||||
<string name="failedOpeningFileManager">Installer først en filhåndteringsprogram.</string>
|
||||
<string name="moveDown">Bevæger sig nedad</string>
|
||||
<string name="leaveWithoutSaveTitle">Afslut</string>
|
||||
<string name="addManually">Indtast kort-ID manuelt</string>
|
||||
</resources>
|
||||
@@ -2,8 +2,8 @@
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="action_search">Suchen</string>
|
||||
<string name="action_add">Hinzufügen</string>
|
||||
<string name="noGiftCards">Klicken Sie auf das Pluszeichen +, um eine Karte hinzuzufügen, oder importieren Sie zunächst einige aus dem ⋮ Menü.</string>
|
||||
<string name="noMatchingGiftCards">Nichts gefunden. Versuchen Sie, Ihre Suche zu ändern.</string>
|
||||
<string name="noGiftCards">Füge eine Karte mit + hinzu oder importiere welche über das ⋮ Menü.</string>
|
||||
<string name="noMatchingGiftCards">Nichts gefunden. Versuche, deine Suche zu ändern.</string>
|
||||
<string name="storeName">Name</string>
|
||||
<string name="note">Notiz</string>
|
||||
<string name="cardId">Kartennummer</string>
|
||||
@@ -12,25 +12,24 @@
|
||||
<string name="edit">Bearbeiten</string>
|
||||
<string name="delete">Löschen</string>
|
||||
<string name="confirm">Bestätigen</string>
|
||||
<string name="lockScreen">Rotation blockieren</string>
|
||||
<string name="unlockScreen">Rotation zulassen</string>
|
||||
<string name="lockScreen">Rotation sperren</string>
|
||||
<string name="unlockScreen">Rotation erlauben</string>
|
||||
<string name="star">Zu den Favoriten hinzufügen</string>
|
||||
<string name="unstar">Aus der Favoritenliste entfernen</string>
|
||||
<string name="unstar">Aus den Favoriten entfernen</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="copy_to_clipboard">Nummer in die Zwischenablage kopieren</string>
|
||||
<string name="copy_to_clipboard">Kartennummer in die Zwischenablage kopieren</string>
|
||||
<string name="sendLabel">Senden …</string>
|
||||
<string name="editCardTitle">Kundenkarte bearbeiten</string>
|
||||
<string name="addCardTitle">Neue Kundenkarte</string>
|
||||
<string name="scanCardBarcode">Strichcode scannen</string>
|
||||
<string name="editCardTitle">Karte bearbeiten</string>
|
||||
<string name="addCardTitle">Neue Karte</string>
|
||||
<string name="scanCardBarcode">Barcode scannen</string>
|
||||
<string name="cardShortcut">Shortcut zu einer Karte</string>
|
||||
<string name="noCardsMessage">Fügen Sie zuerst eine Karte hinzu</string>
|
||||
<string name="barcodeImageDescription">Bild des Strichcodes</string>
|
||||
<string name="noCardsMessage">Füge zuerst eine Karte hinzu</string>
|
||||
<string name="noStoreError">Kein Name eingegeben</string>
|
||||
<string name="noCardIdError">Keine Kartennummer angegeben</string>
|
||||
<string name="noCardExistsError">Karte konnte nicht gefunden werden</string>
|
||||
<string name="importExport">Import/Export</string>
|
||||
<string name="exportName">Exportieren</string>
|
||||
<string name="importExportHelp">Durch das Sichern Ihrer Karten können Sie sie auf ein anderes Gerät verschieben.</string>
|
||||
<string name="exportName">Export</string>
|
||||
<string name="importExportHelp">Durch das Sichern deiner Karten kannst du sie auf ein anderes Gerät übertragen.</string>
|
||||
<string name="importSuccessfulTitle">Importiert</string>
|
||||
<string name="importFailedTitle">Import fehlgeschlagen</string>
|
||||
<string name="importFailed">Karten konnten nicht importiert werden</string>
|
||||
@@ -39,51 +38,52 @@
|
||||
<string name="exportFailed">Karten konnten nicht exportiert werden</string>
|
||||
<string name="importing">Importiere…</string>
|
||||
<string name="exporting">Exportiere…</string>
|
||||
<string name="noExternalStoragePermissionError">Erteilen Sie zuerst die Erlaubnis zur externen Speicherung, um Karten zu importieren oder zu exportieren</string>
|
||||
<string name="importOptionFilesystemTitle">Importiere aus Dateisystem</string>
|
||||
<string name="importOptionFilesystemExplanation">Wähle eine Datei aus dem Speicher aus.</string>
|
||||
<string name="importOptionFilesystemButton">Aus Dateisystem</string>
|
||||
<string name="importOptionApplicationTitle">Andere Anwendung verwenden</string>
|
||||
<string name="importOptionApplicationExplanation">Verwenden Sie eine beliebige Anwendung oder Ihren bevorzugten Dateiverwaltungsprogramm, um eine Datei zu öffnen.</string>
|
||||
<string name="importOptionApplicationButton">Andere Anwendung verwenden</string>
|
||||
<string name="noExternalStoragePermissionError">Erlaube Speicherzugriff um Karten zu importieren oder exportieren</string>
|
||||
<string name="importOptionFilesystemTitle">Importiere aus dem Dateisystem</string>
|
||||
<string name="importOptionFilesystemExplanation">Wähle eine Datei vom Dateisystem aus.</string>
|
||||
<string name="importOptionFilesystemButton">Wähle vom Dateisystem</string>
|
||||
<string name="importOptionApplicationTitle">Andere Anwendungen</string>
|
||||
<string name="importOptionApplicationExplanation">Beliebige Anwendung oder deinen bevorzugten Dateimanager zur Dateiauswahl verwenden.</string>
|
||||
<string name="importOptionApplicationButton">Aus anderer Anwendung</string>
|
||||
<string name="about">Über</string>
|
||||
<string name="app_license">Freie Software, lizensiert unter der GPLv3+.</string>
|
||||
<string name="app_license">Freie Software, lizensiert unter der GPLv3+</string>
|
||||
<string name="about_title_fmt">Über <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Version: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Informationen zu dieser Version: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="selectBarcodeTitle">Strichcode auswählen</string>
|
||||
<string name="copy_to_clipboard_toast">Nummer in die Zwischenablage kopiert</string>
|
||||
<string name="app_revision_fmt">Revisionsinfo: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="selectBarcodeTitle">Barcode auswählen</string>
|
||||
<string name="copy_to_clipboard_toast">Kartennummer in die Zwischenablage kopiert</string>
|
||||
<string name="thumbnailDescription">Vorschaubild für die Karte</string>
|
||||
<string name="settings">Einstellungen</string>
|
||||
<string name="settings_category_title_ui">Benutzeroberfläche</string>
|
||||
<string name="settings_display_barcode_max_brightness">Helligkeit bei Strichcode Ansicht erhöhen</string>
|
||||
<string name="settings_lock_barcode_orientation">Strichcodeausrichtung sperren</string>
|
||||
<string name="settings_display_barcode_max_brightness">Barcodeansicht aufhellen</string>
|
||||
<string name="settings_lock_barcode_orientation">Barcoderotation sperren</string>
|
||||
<string name="exportSuccessful">Kartendaten exportiert</string>
|
||||
<string name="importSuccessful">Kartendaten importiert</string>
|
||||
<string name="intent_import_card_from_url_share_text">Ich will eine Karte mit Ihnen teilen</string>
|
||||
<string name="intent_import_card_from_url_share_text">Ich würde gerne diese Karte mit dir teilen</string>
|
||||
<string name="settings_dark_theme">Dunkel</string>
|
||||
<string name="settings_light_theme">Hell</string>
|
||||
<string name="settings_system_theme">System</string>
|
||||
<string name="settings_theme">Design</string>
|
||||
<string name="enterBarcodeInstructions">Geben Sie die Karten-ID ein und wählen Sie unten entweder den Strichcodetyp oder „Diese Karte hat keinen Strichcode“.</string>
|
||||
<string name="settings_theme">Farbschema</string>
|
||||
<string name="enterBarcodeInstructions">Gib die Kartennummer ein und wähle entweder den Barcode-Typ unten oder wähle \"Diese Karte hat keinen Barcode\" aus.</string>
|
||||
<string name="app_copyright_old">Basierend auf Loyalty Card Keychain
|
||||
\nCopyright © 2016-2020 Branden Archer.</string>
|
||||
<string name="exportOptionExplanation">Die Daten werden an einen Ort Ihrer Wahl geschrieben.</string>
|
||||
<string name="failedParsingImportUriError">Der Import-URI konnte nicht analysiert werden</string>
|
||||
\nCopyright © 2016-2020 Branden Archer</string>
|
||||
<string name="exportOptionExplanation">Die Daten werden an einen Ort deiner Wahl geschrieben.</string>
|
||||
<string name="failedParsingImportUriError">Die Import-URI konnte nicht verarbeitet werden</string>
|
||||
<string name="share">Teilen</string>
|
||||
<string name="barcodeNoBarcode">Diese Karte hat keinen Strichcode</string>
|
||||
<string name="barcodeType">Strichcode-Typ</string>
|
||||
<string name="barcodeNoBarcode">Diese Karte hat keinen Barcode</string>
|
||||
<string name="barcodeType">Barcodetyp</string>
|
||||
<string name="starImage">Favoritenstern</string>
|
||||
<string name="deleteConfirmationGroup">Gruppe löschen\?</string>
|
||||
<string name="deleteConfirmationGroup">Gruppe löschen?</string>
|
||||
<string name="all">Alle</string>
|
||||
<string name="noGroups">Klicken Sie auf das Pluszeichen +, um zunächst Gruppen zur Kategorisierung hinzuzufügen.</string>
|
||||
<string name="noGroups">Klicke auf das Pluszeichen + um eine Gruppe hinzuzufügen.</string>
|
||||
<string name="noGroupCards">Diese Gruppe hat noch keine Karten</string>
|
||||
<string name="groups">Gruppen</string>
|
||||
<string name="enter_group_name">Geben Sie den Gruppennamen ein</string>
|
||||
<string name="enter_group_name">Gib einen Gruppennamen ein</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Beenden ohne zu speichern\?</string>
|
||||
<string name="leaveWithoutSaveTitle">Beenden</string>
|
||||
<string name="failedOpeningFileManager">Installieren Sie zunächst ein Dateiverwaltungsprogramm.</string>
|
||||
<string name="noBarcode">Kein Strichcode</string>
|
||||
<string name="addManually">Die Karten-ID manuell eingeben</string>
|
||||
<string name="failedOpeningFileManager">Installiere zuerst einen Dateimanager.</string>
|
||||
<string name="noBarcode">Kein Barcode</string>
|
||||
<string name="addManually">Kartennummer manuell eingeben</string>
|
||||
<string name="moveDown">Nach unten verschieben</string>
|
||||
<string name="moveUp">Nach oben verschieben</string>
|
||||
<plurals name="groupCardCount">
|
||||
@@ -91,18 +91,18 @@
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> Karten</item>
|
||||
</plurals>
|
||||
<string name="groupsList">Gruppen: <xliff:g>%s</xliff:g></string>
|
||||
<string name="app_loyalty_card_keychain">Bonuskartenschlüsselring</string>
|
||||
<string name="chooseImportType">Daten importieren aus\?</string>
|
||||
<string name="app_loyalty_card_keychain">Loyalty Card Keychain</string>
|
||||
<string name="chooseImportType">Daten importieren aus?</string>
|
||||
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> scheint kein gültiges Guthaben zu sein.</string>
|
||||
<string name="points">Punkte</string>
|
||||
<string name="currency">Währung</string>
|
||||
<string name="balance">Guthaben</string>
|
||||
<string name="moveBarcodeToCenterOfScreen">Strichcode auf dem Bildschirm zentrieren</string>
|
||||
<string name="moveBarcodeToTopOfScreen">Strichcode auf dem Bildschirm nach oben schieben</string>
|
||||
<string name="moveBarcodeToCenterOfScreen">Barcode auf dem Bildschirm zentrieren</string>
|
||||
<string name="moveBarcodeToTopOfScreen">Barcode auf dem Bildschirm oben fixieren</string>
|
||||
<string name="chooseExpiryDate">Ablaufdatum wählen</string>
|
||||
<string name="never">Nie</string>
|
||||
<string name="expiryDate">Ablaufdatum</string>
|
||||
<string name="editBarcode">Strichcode bearbeiten</string>
|
||||
<string name="editBarcode">Barcode ändern</string>
|
||||
<string name="barcode">Strichcode</string>
|
||||
<string name="card">Karte</string>
|
||||
<string name="balancePoints"><xliff:g>%s</xliff:g> Punkte</string>
|
||||
@@ -110,63 +110,63 @@
|
||||
<string name="expiryStateSentenceExpired">Abgelaufen: <xliff:g>%s</xliff:g></string>
|
||||
<string name="expiryStateSentence">Läuft ab: <xliff:g>%s</xliff:g></string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Sperrbildschirm verhindern</string>
|
||||
<string name="settings_keep_screen_on">Bildschirm eingeschaltet halten</string>
|
||||
<string name="settings_keep_screen_on">Bildschirm aktiv halten</string>
|
||||
<string name="privacy_policy_popup_text">Hinweis zum Datenschutz (oft gefordert):
|
||||
\n
|
||||
\nKEINE DATEN WERDEN GESAMMELT, was jeder bestätigen kann, da unsere Anwendung eine freie Software ist.</string>
|
||||
<string name="accept">Annehmen</string>
|
||||
<string name="privacy_policy">Datenschutzrichtlinie</string>
|
||||
<string name="importVoucherVaultMessage">Wählen Sie Ihren <i>vouchervault.json</i>-Export aus Voucher Vault zum Importieren aus.
|
||||
\nOder erstellen Sie ihn, indem Sie zuerst auf Export in Voucher Vault drücken.</string>
|
||||
\nErstellen Sie ihn, indem Sie zuerst auf Export in Voucher Vault drücken.</string>
|
||||
<string name="importVoucherVault">Aus Voucher Vault importieren</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">Wählen Sie Ihren <i>LoyaltyCardKeychain.csv</i>-Export aus Loyalty Card Keychain zum Importieren aus.
|
||||
\nOder erstellen Sie ihn über das Menü Import/Export in Loyalty Card Keychain, indem Sie dort zuerst auf Export drücken.</string>
|
||||
\nErstellen Sie ihn über das Menü Import/Export in Loyalty Card Keychain, indem Sie dort zuerst auf Export drücken.</string>
|
||||
<string name="importLoyaltyCardKeychain">Aus Loyalty Card Keychain importieren</string>
|
||||
<string name="importFidmeMessage">Wählen Sie Ihren <i>fidme-export-request-xxxxxx.zip</i>-Export aus FidMe zum Importieren aus und wählen Sie anschließend die Strichcodetypen manuell aus.
|
||||
\nOder erstellen Sie ihn aus Ihrem FidMe-Profil, indem Sie Datenschutz wählen und dann zuerst auf Meine Daten extrahieren drücken.</string>
|
||||
<string name="importFidme">Aus FidMe importieren</string>
|
||||
<string name="importCatimaMessage">Wählen Sie Ihren <i>catima.zip</i>-Export aus Catima zum Importieren aus.
|
||||
\nOder erstellen Sie ihn aus dem Import/Export-Menü einer anderen Catima-Anwendung, indem Sie dort zuerst Export drücken.</string>
|
||||
\nErstellen Sie ihn aus dem Import/Export-Menü einer anderen Catima-Anwendung, indem Sie dort zuerst Export drücken.</string>
|
||||
<string name="importCatima">Aus Catima importieren</string>
|
||||
<string name="setBarcodeId">Strichcodewert setzen</string>
|
||||
<string name="sameAsCardId">Gleich wie Karten-ID</string>
|
||||
<string name="barcodeId">Strichcodewert</string>
|
||||
<string name="errorReadingImage">Das Bild konnte nicht gelesen werden</string>
|
||||
<string name="noBarcodeFound">Kein Strichcode gefunden</string>
|
||||
<string name="addFromImage">Bild aus der Galerie auswählen</string>
|
||||
<string name="settings_max_font_size_scale">Max. Schriftgröße</string>
|
||||
<string name="unsupportedBarcodeType">Dieser Strichcodetyp kann noch nicht angezeigt werden. Er wird möglicherweise in einer späteren Version der Anwendung unterstützt.</string>
|
||||
<string name="wrongValueForBarcodeType">Der Wert ist für den gewählten Strichcodetyp nicht gültig</string>
|
||||
<string name="setBarcodeId">Manuell eingeben</string>
|
||||
<string name="sameAsCardId">Entspricht Kartennummer</string>
|
||||
<string name="barcodeId">Barcodewert</string>
|
||||
<string name="errorReadingImage">Bildverarbeitung fehlgeschlagen</string>
|
||||
<string name="noBarcodeFound">Kein Barcode erkannt</string>
|
||||
<string name="addFromImage">Bild aus der Galerie wählen</string>
|
||||
<string name="settings_max_font_size_scale">Maximale Schriftgröße</string>
|
||||
<string name="unsupportedBarcodeType">Dieser Barcodetyp kann noch nicht angezeigt werden. Wir hoffen das Format in einer zukünftigen Version zu unterstützen.</string>
|
||||
<string name="wrongValueForBarcodeType">Der Wert ist für den gewählten Barcodetyp leider nicht gültig</string>
|
||||
<string name="app_resources">Freie Ressourcen von Drittanbietern: <xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="app_libraries">Freie Bibliotheken von Drittanbietern: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019–<xliff:g>%d</xliff:g> Sylvia van Os.</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Ich möchte Karten mit dir teilen</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Ich möchte diese Karten mit dir teilen</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">Kartennummern in die Zwischenablage kopiert</string>
|
||||
<string name="card_ids_copied">Kartennummer(n) kopiert</string>
|
||||
<string name="no">Nein</string>
|
||||
<string name="yes">Ja</string>
|
||||
<string name="updateBarcodeQuestionText">Sie haben die Karten-ID geändert. Möchten Sie auch den Strichcode aktualisieren, um denselben Wert zu verwenden\?</string>
|
||||
<string name="updateBarcodeQuestionTitle">Strichcodewert aktualisieren\?</string>
|
||||
<string name="updateBarcodeQuestionText">Kartennummer geändert. Möchtest du auch den Barcode auf den gleichen Wert ändern?</string>
|
||||
<string name="updateBarcodeQuestionTitle">Barcodewert aktualisieren?</string>
|
||||
<string name="takePhoto">Foto aufnehmen</string>
|
||||
<string name="removeImage">Bild entfernen</string>
|
||||
<string name="setBackImage">Rückseitenbild einstellen</string>
|
||||
<string name="setFrontImage">Vorderseitenbild einstellen</string>
|
||||
<string name="setBackImage">Kartenrückseite</string>
|
||||
<string name="setFrontImage">Kartenvorderseite</string>
|
||||
<string name="photos">Fotos</string>
|
||||
<string name="frontImageDescription">Bild der Kartenvorderseite</string>
|
||||
<string name="backImageDescription">Bild der Kartenrückseite</string>
|
||||
<string name="passwordRequired">Bitte geben Sie das Passwort ein</string>
|
||||
<string name="passwordRequired">Bitte gib das Passwort ein</string>
|
||||
<string name="importStocardMessage">Wählen Sie Ihren <i>***-sync.zip</i>-Export aus Stocard zum Importieren aus.
|
||||
\nOder Sie erhalten ihn, indem Sie eine E-Mail an support@stocardapp.com senden und um einen Export Ihrer Daten bitten.</string>
|
||||
\nSie erhalten ihn, indem Sie eine E-Mail an support@stocardapp.com senden und um einen Export Ihrer Daten bitten.</string>
|
||||
<string name="importStocard">Von Stocard importieren</string>
|
||||
<string name="turn_flashlight_off">Taschenlampe ausschalten</string>
|
||||
<string name="turn_flashlight_on">Taschenlampe einschalten</string>
|
||||
<string name="failedGeneratingShareURL">Keine teilbare URL konnte generiert werden. Bitte melden Sie dies.</string>
|
||||
<string name="turn_flashlight_off">Licht ausschalten</string>
|
||||
<string name="turn_flashlight_on">Licht einschalten</string>
|
||||
<string name="failedGeneratingShareURL">URL konnte nicht erstellt werden. Bitte melde das an uns.</string>
|
||||
<plurals name="selectedCardCount">
|
||||
<item quantity="one"><xliff:g>%d</xliff:g> Karte ausgewählt</item>
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> Karten ausgewählt</item>
|
||||
</plurals>
|
||||
<string name="deleteTitle">Karte entfernen</string>
|
||||
<string name="deleteConfirmation">Diese Karte löschen\?</string>
|
||||
<string name="deleteTitle">Karte löschen</string>
|
||||
<string name="deleteConfirmation">Diese Karte wirklich löschen?</string>
|
||||
<plurals name="deleteCardsConfirmation">
|
||||
<item quantity="one">Diese <xliff:g>%d</xliff:g> Karte endgültig löschen\?</item>
|
||||
<item quantity="other">Diese <xliff:g>%d</xliff:g> Karten endgültig löschen\?</item>
|
||||
@@ -175,4 +175,47 @@
|
||||
<item quantity="one"><xliff:g>%d</xliff:g> Karte löschen</item>
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> Karten löschen</item>
|
||||
</plurals>
|
||||
<string name="settings_system_locale">System</string>
|
||||
<string name="settings_locale">Sprache</string>
|
||||
<string name="settings_brown_theme">Braun</string>
|
||||
<string name="settings_grey_theme">Grau</string>
|
||||
<string name="settings_green_theme">Grün</string>
|
||||
<string name="settings_sky_blue_theme">Himmelblau</string>
|
||||
<string name="settings_blue_theme">Blau</string>
|
||||
<string name="settings_violet_theme">Violett</string>
|
||||
<string name="settings_magenta_theme">Magenta</string>
|
||||
<string name="settings_pink_theme">Rosa</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_theme_color">Designfarbe</string>
|
||||
<string name="app_contributors">Ermöglicht durch: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="toggleMoreInfo">Umschalten, um weitere Informationen anzuzeigen</string>
|
||||
<string name="barcodeImageDescriptionWithType">Bild des Kartenstrichcodes des Typs <xliff:g>%s</xliff:g></string>
|
||||
<string name="swipeToSwitchImages">Wischen oder langes Drücken zum Wechseln der Bilder</string>
|
||||
<string name="sort_by">Sortieren nach</string>
|
||||
<string name="sort_by_balance">Kontostand</string>
|
||||
<string name="sort_by_expiry">Ablaufdatum</string>
|
||||
<string name="sort_by_most_recently_used">Zuletzt verwendet</string>
|
||||
<string name="sort_by_name">Name</string>
|
||||
<string name="sort">Sortieren</string>
|
||||
<string name="reverse">Umgekehrt</string>
|
||||
<string name="version_history">Versionshistorie</string>
|
||||
<string name="credits">Dank an</string>
|
||||
<string name="help_translate_this_app">Hilfe bei der Übersetzung</string>
|
||||
<string name="and_data_usage">und Datennutzung</string>
|
||||
<string name="rate_this_app">Bewerte die Anwendung</string>
|
||||
<string name="on_google_play">auf Google Play</string>
|
||||
<string name="license">Lizenz</string>
|
||||
<string name="source_repository">Quellcode</string>
|
||||
<string name="on_github">auf GitHub</string>
|
||||
<string name="report_error">Fehler melden</string>
|
||||
<string name="exportPassword">Legen Sie ein Passwort fest, um Ihren Export zu schützen (optional)</string>
|
||||
<string name="exportPasswordHint">Passwort eingeben</string>
|
||||
<string name="group_name_already_in_use">Der Gruppenname wird bereits verwendet</string>
|
||||
<string name="group_name_is_empty">Gruppenname darf nicht leer sein</string>
|
||||
<string name="group_updated">Gruppe aktualisiert</string>
|
||||
<string name="editGroup">Gruppe wird bearbeitet: <xliff:g>%s</xliff:g></string>
|
||||
<string name="group_edit">Gruppe bearbeiten</string>
|
||||
<string name="noGiftCardsGroup">Sie haben noch keine Kundenkarten. Sobald Sie welche hinzugefügt haben, können Sie sie hier der Gruppe zuordnen.</string>
|
||||
<string name="setIcon">Symbol einstellen</string>
|
||||
<string name="selectColor">Farbe auswählen</string>
|
||||
</resources>
|
||||
@@ -20,7 +20,6 @@
|
||||
<string name="scanCardBarcode">Σαρώστε τον κωδικό της κάρτας</string>
|
||||
<string name="cardShortcut">Συντόμευση Κάρτας</string>
|
||||
<string name="noCardsMessage">Δεν υπάρχουν κάρτες. προσθέστε μία πρώτα</string>
|
||||
<string name="barcodeImageDescription">Εικόνα του barcode της κάρτας</string>
|
||||
<string name="noStoreError">Δεν δώσατε κατάστημα</string>
|
||||
<string name="noCardIdError">Δεν δώσατε κωδικό κάρτας</string>
|
||||
<string name="noCardExistsError">Δεν ήταν δυνατό να εντοπιστεί κάρτα</string>
|
||||
|
||||
@@ -52,4 +52,40 @@
|
||||
<string name="action_search">Serĉi</string>
|
||||
<string name="deleteConfirmation">Ĉu forigi ĉi tiun karton\?</string>
|
||||
<string name="deleteTitle">Forigi karton</string>
|
||||
<string name="settings_lock_barcode_orientation">Seruro barcode orientiĝo</string>
|
||||
<string name="settings_display_barcode_max_brightness">Heligi barcode vido</string>
|
||||
<string name="settings_max_font_size_scale">Max. tiparo grandeco</string>
|
||||
<string name="starImage">Preferata stelo</string>
|
||||
<string name="thumbnailDescription">Bildeto por karto</string>
|
||||
<string name="app_copyright_old">Bazita sur Lojaleco Karto Keychain
|
||||
\nkopirajto © 2016-2020 Branden Archer.</string>
|
||||
<string name="importOptionApplicationButton">Uzi alian app</string>
|
||||
<string name="importOptionApplicationExplanation">Uzi ajna app aŭ via preferata dosiera # mana\? ero por malfermi dosieron.</string>
|
||||
<string name="importOptionApplicationTitle">Uzi alian app</string>
|
||||
<string name="importOptionFilesystemExplanation">Elektu specifa dosiero de la dosiersistemo.</string>
|
||||
<string name="exportOptionExplanation">La datumoj estos skribita al loko de via elekto.</string>
|
||||
<string name="noExternalStoragePermissionError">Grant ekstera stokado permeso de importado aŭ eksportado kartoj unua</string>
|
||||
<string name="exportFailed">Ne povis eksporti kartoj</string>
|
||||
<string name="importFailed">Ne povis importi kartoj</string>
|
||||
<string name="importExportHelp">Subtenanta supre vian kartoj permesas vin movi ilin al alia aparato.</string>
|
||||
<string name="failedParsingImportUriError">Ne eblis analizi la importado URI</string>
|
||||
<string name="noCardExistsError">Ne eblis trovi karto</string>
|
||||
<string name="noCardIdError">Neniu karto ID eniris</string>
|
||||
<string name="noStoreError">Neniu eniris nomo</string>
|
||||
<string name="noCardsMessage">Aldoni karto unua</string>
|
||||
<string name="cardShortcut">Karto Mallongirejo</string>
|
||||
<string name="scanCardBarcode">Scintigrafio Barcode Card</string>
|
||||
<string name="share">Interŝanĝado</string>
|
||||
<string name="unlockScreen">Malbloki Rotacio</string>
|
||||
<string name="lockScreen">Bloko Rotacio</string>
|
||||
<string name="star">Aldoni al miaj plej ŝatataj</string>
|
||||
<string name="copy_to_clipboard_toast">Card ID kopiita al la tondujo</string>
|
||||
<string name="settings_keep_screen_on">Teni sur ekrano</string>
|
||||
<string name="importSuccessful">Karto datumo importitaj</string>
|
||||
<string name="enter_group_name">Eniri nomo de la grupo</string>
|
||||
<string name="noGroups">Klaki la + plus butonon por aldoni grupoj por categorization unua.</string>
|
||||
<string name="all">Ĉiuj</string>
|
||||
<string name="intent_import_card_from_url_share_text">Mi deziras dividi karto kun vi</string>
|
||||
<string name="exportSuccessful">Karto datumo eksportita</string>
|
||||
<string name="noGroupCards">Ĉi tiu grupo ne enhavas ajnan kartoj</string>
|
||||
</resources>
|
||||
@@ -20,7 +20,6 @@
|
||||
<string name="scanCardBarcode">Escanear código de barras de la tarjeta</string>
|
||||
<string name="cardShortcut">Atajo de tarjeta</string>
|
||||
<string name="noCardsMessage">Añada una tarjeta primero</string>
|
||||
<string name="barcodeImageDescription">Imagen del código de barras de la tarjeta</string>
|
||||
<string name="noStoreError">No se proporcionó ningún nombre</string>
|
||||
<string name="noCardIdError">Id. de tarjeta no especificado</string>
|
||||
<string name="noCardExistsError">No se ha podido encontrar la tarjeta</string>
|
||||
@@ -113,7 +112,7 @@
|
||||
\nO créalo primero desde tu perfil de FidMe eligiendo Protección de datos y pulsa Extraer mis datos.</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">Seleccione su <i>LoyaltyCardKeychain.csv</i> exportado desde Loyalty Card Keychain para importarlo.
|
||||
\nO créalo primero desde el menú Importar/Exportar en Loyalty Card Keychain pulsando Exportar desde allí.</string>
|
||||
<string name="importStocardMessage">Seleccione su <i>*-sync.zip</i> exportado de Stocard para importarla, y selecciona los tipos de códigos de barras manualmente después.
|
||||
<string name="importStocardMessage">Seleccione su exportación <i>*-sync.zip</i> de Stocard para importarla.
|
||||
\nO consígalo enviando un correo electrónico a support@stocardapp.com solicitando una exportación de sus datos.</string>
|
||||
<string name="importVoucherVaultMessage">Seleccione su <i>vouchervault.json</i> exportado desde Voucher Vault para importarlo.
|
||||
\nO créalo pulsando primero Exportar en Voucher Vault.</string>
|
||||
@@ -175,4 +174,18 @@
|
||||
<item quantity="one">Borrar <xliff:g>%d</xliff:g> tarjeta</item>
|
||||
<item quantity="other">Borrar <xliff:g>%d</xliff:g> tarjetas</item>
|
||||
</plurals>
|
||||
<string name="app_contributors">Hecho posible por: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="settings_brown_theme">Marrón</string>
|
||||
<string name="settings_grey_theme">Gris</string>
|
||||
<string name="settings_green_theme">Verde</string>
|
||||
<string name="settings_sky_blue_theme">Azul cielo</string>
|
||||
<string name="settings_blue_theme">Azul</string>
|
||||
<string name="settings_violet_theme">Violeta</string>
|
||||
<string name="settings_magenta_theme">Magenta</string>
|
||||
<string name="settings_pink_theme">Rosa</string>
|
||||
<string name="settings_theme_color">Color del tema</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_system_locale">Sistema</string>
|
||||
<string name="settings_locale">Lengua</string>
|
||||
<string name="noGroupCards">Este grupo no contiene ninguna tarjeta</string>
|
||||
</resources>
|
||||
@@ -117,7 +117,6 @@
|
||||
<string name="noCardExistsError">Korttia ei löytynyt</string>
|
||||
<string name="noCardIdError">Kortin ID-tunnusta ei annettu</string>
|
||||
<string name="noStoreError">Nimeä ei annettu</string>
|
||||
<string name="barcodeImageDescription">Kuva kortin viivakoodista</string>
|
||||
<string name="card_ids_copied">Kopioidut korttitunnukset</string>
|
||||
<string name="noCardsMessage">Lisää ensin kortti</string>
|
||||
<string name="cardShortcut">Kortin pikakuvake</string>
|
||||
@@ -175,4 +174,18 @@
|
||||
<string name="failedGeneratingShareURL">Ei pystynyt luomaan jaettavaa URL-osoitetta. Ilmoita tästä.</string>
|
||||
<string name="turn_flashlight_on">Sytytä taskulamppu</string>
|
||||
<string name="turn_flashlight_off">Sammuta salamavalo</string>
|
||||
<string name="app_contributors">Mahdollistanut: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="settings_brown_theme">Ruskea</string>
|
||||
<string name="settings_grey_theme">Harmaa</string>
|
||||
<string name="settings_green_theme">Vihreä</string>
|
||||
<string name="settings_sky_blue_theme">Taivaan sininen</string>
|
||||
<string name="settings_blue_theme">Siniset</string>
|
||||
<string name="settings_violet_theme">Violetti</string>
|
||||
<string name="settings_magenta_theme">Magenta</string>
|
||||
<string name="settings_pink_theme">Pinkki</string>
|
||||
<string name="settings_theme_color">Teeman väri</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_system_locale">Järjestelmä</string>
|
||||
<string name="settings_locale">Kieli</string>
|
||||
<string name="noGroupCards">Tämä ryhmä ei sisällä kortteja</string>
|
||||
</resources>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?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">
|
||||
<string name="action_add">Ajouter</string>
|
||||
<string name="noGiftCards">Cliquez sur le bouton + plus pour ajouter une carte, ou importez-en d’abord depuis le menu ⋮</string>
|
||||
<string name="noGiftCards">Cliquez sur le bouton + plus pour ajouter une carte, ou importez les depuis le menu ⋮</string>
|
||||
<string name="storeName">Nom</string>
|
||||
<string name="note">Notes</string>
|
||||
<string name="cardId">Numéro</string>
|
||||
@@ -20,7 +20,6 @@
|
||||
<string name="scanCardBarcode">Scanner le code-barres</string>
|
||||
<string name="cardShortcut">Raccourci de carte</string>
|
||||
<string name="noCardsMessage">Ajoutez d\'abord une carte</string>
|
||||
<string name="barcodeImageDescription">Image du code-barres</string>
|
||||
<string name="noStoreError">Aucun nom saisi</string>
|
||||
<string name="noCardIdError">Aucun numéro de carte saisi</string>
|
||||
<string name="noCardExistsError">Aucune carte trouvée</string>
|
||||
@@ -43,7 +42,7 @@
|
||||
<string name="importOptionApplicationExplanation">Utilisez le gestionnaire de fichiers de votre choix pour importer un fichier.</string>
|
||||
<string name="importOptionApplicationButton">Utiliser une autre application</string>
|
||||
<string name="about">À propos</string>
|
||||
<string name="app_license">Logiciel libre à copyleft, sous licence GPLv3+.</string>
|
||||
<string name="app_license">Logiciel libre à copyleft, sous licence GPLv3+</string>
|
||||
<string name="about_title_fmt">À propos de <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Version : <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Notes de version : <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
@@ -63,7 +62,7 @@
|
||||
<string name="settings_theme">Thème</string>
|
||||
<string name="enterBarcodeInstructions">Entrez l’identifiant de la carte et choisissez le type de code-barres ci-dessous, ou « Cette carte n’a pas de code-barres ».</string>
|
||||
<string name="app_copyright_old">Basé sur Loyalty Card Keychain
|
||||
\ncopyright © 2016-2020 Branden Archer.</string>
|
||||
\ncopyright © 2016-2020 Branden Archer</string>
|
||||
<string name="exportOptionExplanation">Les données seront exportées vers l\'emplacement de votre choix.</string>
|
||||
<string name="failedParsingImportUriError">Impossible d\'analyser l\'URI d\'importation</string>
|
||||
<string name="share">Partager</string>
|
||||
@@ -117,16 +116,16 @@
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Empêcher le verrouillage de l’écran</string>
|
||||
<string name="settings_keep_screen_on">Garder l’écran allumé</string>
|
||||
<string name="importVoucherVaultMessage">Sélectionnez votre exportation <i>vouchervault.json</i> de Voucher Vault à importer.
|
||||
\nOu créez-la en appuyant d’abord sur Exporter dans Voucher Vault.</string>
|
||||
\nCréez-la en appuyant d’abord sur Exporter dans Voucher Vault.</string>
|
||||
<string name="importVoucherVault">Importer depuis Voucher Vault</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">Sélectionnez votre exportation <i>LoyaltyCardKeychain.csv</i> à partir de Loyalty Card Keychain pour l’importer.
|
||||
\nOu créez-la à partir du menu Importer/Exporter du Loyalty Card Keychain en appuyant d’abord sur Exporter.</string>
|
||||
\nCréez-la à partir du menu Importer/Exporter du Loyalty Card Keychain en appuyant d’abord sur Exporter.</string>
|
||||
<string name="importLoyaltyCardKeychain">Importer depuis Loyalty Card Keychain</string>
|
||||
<string name="importFidmeMessage">Sélectionnez votre exportation <i>fidme-export-request-xxxxxx.zip</i> de FidMe pour l’importer, puis sélectionnez manuellement les types de codes-barres.
|
||||
\nOu créez-la à partir de votre profil FidMe en choisissant Protection des données, puis en cliquant sur Extraire mes données d’abord.</string>
|
||||
\nCréez-la à partir de votre profil FidMe en choisissant Protection des données, puis en cliquant sur Extraire mes données d’abord.</string>
|
||||
<string name="importFidme">Importer depuis FidMe</string>
|
||||
<string name="importCatimaMessage">Sélectionnez votre exportation <i>catima.zip</i> depuis Catima à importer.
|
||||
\nOu créez-la à partir du menu Importer/Exporter d’une autre application Catima en appuyant d’abord sur Exporter.</string>
|
||||
\nCréez-la à partir du menu Importer/Exporter d’une autre application Catima en appuyant d’abord sur Exporter.</string>
|
||||
<string name="importCatima">Importer depuis Catima</string>
|
||||
<string name="addFromImage">Sélectionner dans la galerie</string>
|
||||
<string name="errorReadingImage">Impossible de lire l\'image</string>
|
||||
@@ -139,7 +138,7 @@
|
||||
<string name="wrongValueForBarcodeType">La valeur n\'est pas valide pour le type de code-barres sélectionné</string>
|
||||
<string name="app_resources">Ressources tierces libres : <xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="app_libraries">Bibliothèques tierces libres : <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019–<xliff:g>%d</xliff:g> Sylvia van Os.</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Je veux partager des cartes avec vous</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">Identifiants des cartes copiés dans le presse-papiers</string>
|
||||
<string name="card_ids_copied">Num. de la carte copié(s)</string>
|
||||
@@ -156,7 +155,7 @@
|
||||
<string name="frontImageDescription">Image recto de la carte</string>
|
||||
<string name="passwordRequired">Veuillez entrer le mot de passe</string>
|
||||
<string name="importStocardMessage">Sélectionnez votre exportation <i>***-sync.zip</i> de Stocard pour l’importer.
|
||||
\nVous pouvez aussi l’obtenir en envoyant un courriel à support@stocardapp.com pour demander une exportation de vos données.</string>
|
||||
\nVous pouvez l’obtenir en envoyant un courriel à support@stocardapp.com pour demander une exportation de vos données.</string>
|
||||
<string name="importStocard">Importer depuis Stocard</string>
|
||||
<string name="turn_flashlight_off">Éteindre la lampe de poche</string>
|
||||
<string name="turn_flashlight_on">Allumer la lampe de poche</string>
|
||||
@@ -175,4 +174,48 @@
|
||||
<item quantity="one">Supprimer <xliff:g>%d</xliff:g> carte</item>
|
||||
<item quantity="other">Supprimer <xliff:g>%d</xliff:g> cartes</item>
|
||||
</plurals>
|
||||
<string name="settings_system_locale">Système</string>
|
||||
<string name="settings_locale">Langue</string>
|
||||
<string name="settings_brown_theme">Marron</string>
|
||||
<string name="settings_grey_theme">Gris</string>
|
||||
<string name="settings_green_theme">Vert</string>
|
||||
<string name="settings_sky_blue_theme">Bleu ciel</string>
|
||||
<string name="settings_blue_theme">Bleu</string>
|
||||
<string name="settings_violet_theme">Violet</string>
|
||||
<string name="settings_magenta_theme">Magenta</string>
|
||||
<string name="settings_pink_theme">Rose</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_theme_color">Couleur du thème</string>
|
||||
<string name="app_contributors">Rendu possible par : <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="noGroupCards">Ce groupe ne contient pas de cartes</string>
|
||||
<string name="toggleMoreInfo">Activer/désactiver l\'affichage de plus d\'infos</string>
|
||||
<string name="barcodeImageDescriptionWithType">Image du code-barres de la carte de type <xliff:g>%s</xliff:g></string>
|
||||
<string name="swipeToSwitchImages">Balayez ou appuyez longuement pour changer d\'image</string>
|
||||
<string name="sort">Trier</string>
|
||||
<string name="sort_by">Trier par</string>
|
||||
<string name="reverse">Inversé</string>
|
||||
<string name="sort_by_expiry">Date d\'expiration</string>
|
||||
<string name="sort_by_most_recently_used">Les plus récemment utilisées</string>
|
||||
<string name="sort_by_name">Nom</string>
|
||||
<string name="sort_by_balance">Solde</string>
|
||||
<string name="report_error">Signaler une erreur</string>
|
||||
<string name="on_google_play">sur Google Play</string>
|
||||
<string name="rate_this_app">Notez cette appli</string>
|
||||
<string name="and_data_usage">utilisation des données</string>
|
||||
<string name="on_github">sur GitHub</string>
|
||||
<string name="source_repository">Dépôt source</string>
|
||||
<string name="license">Licence</string>
|
||||
<string name="help_translate_this_app">Aidez à traduire cette appli</string>
|
||||
<string name="credits">Contributeurs</string>
|
||||
<string name="version_history">Historique des versions</string>
|
||||
<string name="exportPassword">Définissez un mot de passe pour protéger vos exportations (facultatif)</string>
|
||||
<string name="exportPasswordHint">Entrez le mot de passe</string>
|
||||
<string name="editGroup">Modification du groupe : <xliff:g> %s </xliff:g></string>
|
||||
<string name="noGiftCardsGroup">Vous n\'avez pas encore de cartes de fidélité. Une fois que vous en aurez ajouté, vous pourrez les affecter au groupe ici.</string>
|
||||
<string name="group_edit">Modifier le groupe</string>
|
||||
<string name="group_name_already_in_use">Nom de groupe déjà utilisé</string>
|
||||
<string name="group_updated">Groupe mis à jour</string>
|
||||
<string name="group_name_is_empty">Le nom du groupe ne peut pas être vide</string>
|
||||
<string name="setIcon">Définir l\'icône</string>
|
||||
<string name="selectColor">Sélectionnez la couleur</string>
|
||||
</resources>
|
||||
86
app/src/main/res/values-hr/strings.xml
Normal file
86
app/src/main/res/values-hr/strings.xml
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="unstar">Ukloni iz favorita</string>
|
||||
<string name="action_search">Pretraživanje</string>
|
||||
<string name="save">Spremi</string>
|
||||
<string name="edit">Uredi</string>
|
||||
<string name="delete">Ukloni</string>
|
||||
<string name="confirm">Potvrdi</string>
|
||||
<string name="lockScreen">Rotacija bloka</string>
|
||||
<string name="unlockScreen">Otključaj Rotaciju</string>
|
||||
<string name="deleteTitle">Ukloni kartu</string>
|
||||
<string name="deleteConfirmation">Izbrisati ovu karticu zauvijek\?</string>
|
||||
<string name="copy_to_clipboard">Kopiraj ID u međuspremnik</string>
|
||||
<string name="share">Podijeli</string>
|
||||
<string name="sendLabel">Pošalji…</string>
|
||||
<string name="editCardTitle">Uredi karticu</string>
|
||||
<string name="addCardTitle">Dodaj Kartu</string>
|
||||
<string name="scanCardBarcode">Skeniranje crtičnog koda kartice</string>
|
||||
<string name="cardShortcut">Oznaka karte</string>
|
||||
<string name="noCardsMessage">Najprije dodajte karticu</string>
|
||||
<string name="card_ids_copied">Kopirani ID kartice</string>
|
||||
<string name="noBarcode">Nema crtičnog koda</string>
|
||||
<string name="star">Dodaj u favorite</string>
|
||||
<string name="action_add">Dodaj</string>
|
||||
<string name="storeName">Ime</string>
|
||||
<string name="note">Napomena</string>
|
||||
<string name="noMatchingGiftCards">Ništa nisam našao. Pokušajte promijeniti pretraživanje.</string>
|
||||
<string name="cardId">ID kartice</string>
|
||||
<string name="barcodeType">Vrsta crtičnog koda</string>
|
||||
<string name="barcodeNoBarcode">Na ovoj kartici nema crtičnog koda</string>
|
||||
<string name="cancel">Poništi</string>
|
||||
<string name="noGiftCards">Pritisnite gumb + plus da biste dodali karticu ili ga najprije uvezite iz izbornika ⋮.</string>
|
||||
<string name="noStoreError">Ime nije uneseno</string>
|
||||
<string name="noCardExistsError">Nije moguće pronaći karticu</string>
|
||||
<string name="failedParsingImportUriError">Nije moguće analizirati uvoz URI</string>
|
||||
<string name="importExport">Uvoz / Izvoz</string>
|
||||
<string name="exportName">Izvoz</string>
|
||||
<string name="importExportHelp">Sigurnosno kopiranje kartica omogućuje vam da ih premjestite na drugi uređaj.</string>
|
||||
<string name="importSuccessfulTitle">Uvezeno</string>
|
||||
<string name="importFailedTitle">Nije moguće uvesti</string>
|
||||
<string name="importFailed">Nije moguće uvesti karte</string>
|
||||
<string name="exportSuccessfulTitle">Izvezeno</string>
|
||||
<string name="about">Oh</string>
|
||||
<string name="importOptionApplicationButton">Koristite drugu aplikaciju</string>
|
||||
<string name="barcode">Barkod</string>
|
||||
<string name="exportOptionExplanation">Podaci će biti zabilježeni na odabranom mjestu.</string>
|
||||
<string name="exportFailedTitle">Izvoz nije uspio</string>
|
||||
<string name="exporting">Opskrba…</string>
|
||||
<string name="noExternalStoragePermissionError">Najprije odobrite dopuštenje za vanjsku pohranu za uvoz ili izvoz kartica</string>
|
||||
<string name="importOptionFilesystemExplanation">Odaberite određenu datoteku iz datotečnog sustava.</string>
|
||||
<string name="importOptionApplicationTitle">Koristite drugu aplikaciju</string>
|
||||
<string name="settings">Postavke</string>
|
||||
<string name="settings_dark_theme">Tamno</string>
|
||||
<string name="exportFailed">Nije moguće izvesti karte</string>
|
||||
<string name="importing">Uvoz…</string>
|
||||
<string name="importOptionFilesystemTitle">Uvoz iz datotečnog sustava</string>
|
||||
<string name="importOptionFilesystemButton">Iz datotečnog sustava</string>
|
||||
<string name="importOptionApplicationExplanation">Koristite bilo koju aplikaciju ili omiljeni upravitelj datoteka za otvaranje datoteke.</string>
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="settings_system_theme">Sustav</string>
|
||||
<string name="settings_light_theme">Svjetlo</string>
|
||||
<string name="settings_max_font_size_scale">Maksimalna veličina fonta</string>
|
||||
<string name="settings_display_barcode_max_brightness">Osvijetlite izgled crtičnog koda</string>
|
||||
<string name="moveDown">Pomicanje prema dolje</string>
|
||||
<string name="addManually">Ručno unesite ID kartice</string>
|
||||
<string name="thumbnailDescription">Sličica za karticu</string>
|
||||
<string name="starImage">Omiljena zvijezda</string>
|
||||
<string name="settings_category_title_ui">Korisničko sučelje</string>
|
||||
<string name="settings_lock_barcode_orientation">Zaključavanje orijentacije crtičnog koda</string>
|
||||
<string name="exportSuccessful">Izvezeni podaci o karti</string>
|
||||
<string name="settings_keep_screen_on">Držite zaslon uključen</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Spriječiti zaključavanje zaslona</string>
|
||||
<string name="intent_import_card_from_url_share_text">Želim podijeliti razglednicu s vama</string>
|
||||
<string name="importSuccessful">Uvezeni podaci o karti</string>
|
||||
<string name="enter_group_name">Unesite naziv grupe</string>
|
||||
<string name="groups">Grupe</string>
|
||||
<string name="noGroups">Pritisnite gumb + plus da biste najprije dodali grupe za klasifikaciju.</string>
|
||||
<string name="noGroupCards">Ova grupa ne sadrži nikakve kartice</string>
|
||||
<string name="addFromImage">Odaberite sliku iz galerije</string>
|
||||
<string name="deleteConfirmationGroup">Izbriši grupu\?</string>
|
||||
<string name="failedOpeningFileManager">Najprije instalirajte upravitelj datoteka.</string>
|
||||
<string name="moveUp">Pomicanje gore</string>
|
||||
<string name="leaveWithoutSaveTitle">Izlaz</string>
|
||||
<string name="card">Karta</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Otići bez očuvanja\?</string>
|
||||
</resources>
|
||||
210
app/src/main/res/values-in-rID/strings.xml
Normal file
210
app/src/main/res/values-in-rID/strings.xml
Normal file
@@ -0,0 +1,210 @@
|
||||
<?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">
|
||||
<string name="app_revision_url">https://github.com/TheLastProject/Catima/releases</string>
|
||||
<string name="storeName">Nama</string>
|
||||
<string name="note">Keterangan</string>
|
||||
<string name="delete">Hapus</string>
|
||||
<string name="edit">Ubah</string>
|
||||
<string name="save">Simpan</string>
|
||||
<string name="deleteTitle">Hapus kartu</string>
|
||||
<string name="cardId">Kartu ID</string>
|
||||
<string name="barcodeType">Tipe barcode</string>
|
||||
<string name="star">Tambahkan ke favorit</string>
|
||||
<string name="unstar">Hapus dari favorit</string>
|
||||
<string name="action_add">Tambah</string>
|
||||
<string name="action_search">Cari</string>
|
||||
<string name="sort_by_name">Nama</string>
|
||||
<string name="sort_by_balance">Saldo</string>
|
||||
<string name="sort_by">Sortir dengan</string>
|
||||
<string name="sort">Sortir</string>
|
||||
<string name="credits">Kredit</string>
|
||||
<string name="license">Lisensi</string>
|
||||
<string name="settings">Pengaturan</string>
|
||||
<string name="settings_system_theme">Sistem</string>
|
||||
<string name="selectBarcodeTitle">Pilih Barcode</string>
|
||||
<string name="deleteConfirmation">Hapus kartu ini secara permanen?</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="share">Bagikan</string>
|
||||
<string name="editCardTitle">Ubah Kartu</string>
|
||||
<string name="addCardTitle">Tambah Kartu</string>
|
||||
<string name="scanCardBarcode">Pindai Kartu Barcode</string>
|
||||
<string name="barcodeNoBarcode">Kartu ini tidak memiliki barcode</string>
|
||||
<string name="cancel">Batalkan</string>
|
||||
<string name="importExport">Import/Ekspor</string>
|
||||
<string name="settings_category_title_ui">Tampilan Pengguna</string>
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="all">Semua</string>
|
||||
<string name="leaveWithoutSaveTitle">Keluar</string>
|
||||
<string name="card">Kartu</string>
|
||||
<string name="barcode">Barcode</string>
|
||||
<string name="chooseExpiryDate">Pilih masa berlaku</string>
|
||||
<string name="noBarcodeFound">Barcode tidak ditemukan</string>
|
||||
<string name="errorReadingImage">TIdak dapat membaca gambar</string>
|
||||
<string name="balance">Saldo</string>
|
||||
<string name="currency">Mata uang</string>
|
||||
<string name="chooseImportType">Impor data dari?</string>
|
||||
<string name="accept">Terima</string>
|
||||
<string name="importCatima">Impor dari Catima</string>
|
||||
<string name="importFidme">Impor dari FidMe</string>
|
||||
<string name="barcodeId">Nilai barcode</string>
|
||||
<string name="sameAsCardId">Sama denga kartu ID</string>
|
||||
<string name="setBarcodeId">Tentukan nilai barcode</string>
|
||||
<string name="photos">Foto</string>
|
||||
<string name="setFrontImage">Atur gambar bagian depan</string>
|
||||
<string name="report_error">Lapor Kesalahan</string>
|
||||
<string name="rate_this_app">Beri nilai pada aplikasi ini</string>
|
||||
<string name="sort_by_expiry">Masa berlaku</string>
|
||||
<string name="sort_by_most_recently_used">Paling banyak digunakan</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_pink_theme">Merah Muda</string>
|
||||
<string name="settings_blue_theme">Biru</string>
|
||||
<string name="settings_green_theme">Hijau</string>
|
||||
<string name="settings_sky_blue_theme">Biru Langit</string>
|
||||
<string name="settings_grey_theme">Abu-abu</string>
|
||||
<string name="settings_brown_theme">Cokelat</string>
|
||||
<string name="settings_violet_theme">Ungu</string>
|
||||
<string name="settings_magenta_theme">Magenta</string>
|
||||
<string name="settings_theme_color">Warna tema</string>
|
||||
<string name="settings_system_locale">Sistem</string>
|
||||
<string name="settings_locale">Bahasa</string>
|
||||
<string name="turn_flashlight_on">Hidupkan lampu flash</string>
|
||||
<string name="turn_flashlight_off">Matikan lampu flash</string>
|
||||
<string name="exportPasswordHint">Masukan kata sandi</string>
|
||||
<string name="yes">Ya</string>
|
||||
<string name="no">Tidak</string>
|
||||
<string name="takePhoto">Ambil foto</string>
|
||||
<string name="removeImage">Hapus gambar</string>
|
||||
<string name="setBackImage">Atur gambar bagian belakang</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Saya ingin berbagi kartu dengan anda</string>
|
||||
<string name="noGiftCards">Klik tanda + tombol tambah untuk menambahkan kartu, atau mengimpor beberapa kartu melalui menu ⋮ terlebih dahulu.</string>
|
||||
<string name="noMatchingGiftCards">Tidak menemukan apapun. Coba untuk mengubah pencarian anda.</string>
|
||||
<string name="noBarcode">Bukan barcode</string>
|
||||
<string name="confirm">Konfirmasi</string>
|
||||
<string name="copy_to_clipboard">Salin ID</string>
|
||||
<string name="sendLabel">Kirim…</string>
|
||||
<string name="noCardsMessage">Tambah kartu terlebih dahulu</string>
|
||||
<string name="noStoreError">Nama masih kosong</string>
|
||||
<string name="noCardIdError">Kartu ID masih kosong</string>
|
||||
<string name="noCardExistsError">Tidak dapat menemukan kartu</string>
|
||||
<string name="failedParsingImportUriError">Tidak dapat menguraikan alamat impor situs web</string>
|
||||
<string name="exportName">Ekspor</string>
|
||||
<string name="importSuccessfulTitle">Sudah diimpor</string>
|
||||
<string name="importFailedTitle">Impor gagal</string>
|
||||
<string name="importFailed">Tidak dapat mengimpor kartu</string>
|
||||
<string name="exportSuccessfulTitle">Sudah diekspor</string>
|
||||
<string name="exportFailedTitle">Ekspor gagal</string>
|
||||
<string name="exportFailed">Tidak dapat mengekspor kartu</string>
|
||||
<string name="importing">Mengimpor…</string>
|
||||
<string name="exporting">Mengekspor…</string>
|
||||
<string name="noExternalStoragePermissionError">Berikan izin penyimpanan eksternal untuk mengimpor atau mengekspor kartu terlebih dahulu</string>
|
||||
<string name="exportOptionExplanation">Data akan ditulis ke lokasi pilihan Anda.</string>
|
||||
<string name="importOptionFilesystemTitle">Impor dari sistem</string>
|
||||
<string name="importOptionFilesystemExplanation">Pilih file dari sistem.</string>
|
||||
<string name="importOptionFilesystemButton">Dari sistem</string>
|
||||
<string name="importOptionApplicationTitle">Gunakan aplikasi lain</string>
|
||||
<string name="importOptionApplicationExplanation">Gunakan aplikasi lain atau pengelola file favorit anda untuk membuka file.</string>
|
||||
<string name="importOptionApplicationButton">Gunakan aplikasi lain</string>
|
||||
<string name="about">Tentang</string>
|
||||
<string name="app_copyright_fmt">Hak Cipta © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="app_copyright_old">Berdasarkan Loyalty Card Keychain
|
||||
\nhak cipta © 2016–2020 Branden Archer</string>
|
||||
<string name="app_license">Perangkat lunak bebas copyleft, berlisensi GPLv3+</string>
|
||||
<string name="about_title_fmt">Tentang <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Versi: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Info Revisi: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="app_libraries">Pustaka pihak ketiga gratis: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="app_resources">Sumber daya pihak ketiga gratis: <xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="enterBarcodeInstructions">Masukkan ID kartu, dan pilih jenis barcodenya di bawah atau \"Kartu ini tidak memiliki barcode\".</string>
|
||||
<string name="copy_to_clipboard_toast">ID kartu telah disalin</string>
|
||||
<string name="thumbnailDescription">Gambar tampilan untuk kartu</string>
|
||||
<string name="starImage">Favorit</string>
|
||||
<string name="settings_light_theme">Terang</string>
|
||||
<string name="settings_dark_theme">Gelap</string>
|
||||
<string name="settings_max_font_size_scale">Ukuran maksimal huruf</string>
|
||||
<string name="settings_display_barcode_max_brightness">Terangkan tampilan barcode</string>
|
||||
<string name="settings_lock_barcode_orientation">Kunci orientasi barcode</string>
|
||||
<string name="settings_keep_screen_on">Biarkan layar menyala</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Mencegah layar menyala</string>
|
||||
<string name="intent_import_card_from_url_share_text">Saya ingin berbagi kartu dengan anda</string>
|
||||
<string name="importSuccessful">Data kartu terimpor</string>
|
||||
<string name="exportSuccessful">Data kartu terekspor</string>
|
||||
<string name="enter_group_name">Masukan nama grup</string>
|
||||
<string name="groups">Grup</string>
|
||||
<string name="noGroups">Klik pada tombol tambah + untuk menambahkan grup atau kategori terlebih dahulu.</string>
|
||||
<string name="noGroupCards">Grup ini tidak memilik kartu</string>
|
||||
<string name="deleteConfirmationGroup">Hapus grup?</string>
|
||||
<string name="failedOpeningFileManager">Instal aplikasi pengelola file terlebih dahulu.</string>
|
||||
<string name="moveUp">Pindah ke atas</string>
|
||||
<string name="moveDown">Pindah ke bawah</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Keluar tanpa menyimpan?</string>
|
||||
<string name="addManually">Masukan ID kartu</string>
|
||||
<string name="addFromImage">Pilih gambar dari galeri</string>
|
||||
<string name="groupsList">Grup: <xliff:g>%s</xliff:g></string>
|
||||
<string name="expiryStateSentence">Masa ber: <xliff:g>%s</xliff:g></string>
|
||||
<string name="expiryStateSentenceExpired">Kadaluwarsa: <xliff:g>%s</xliff:g></string>
|
||||
<string name="balanceSentence">Saldo: <xliff:g>%s</xliff:g></string>
|
||||
<string name="balancePoints"><xliff:g>%s</xliff:g> poin</string>
|
||||
<string name="editBarcode">Ubah barcode</string>
|
||||
<string name="expiryDate">Tanggal masa berlaku</string>
|
||||
<string name="never">Tidak pernah</string>
|
||||
<string name="moveBarcodeToTopOfScreen">Pindah barcode ke bagian paling depan</string>
|
||||
<string name="moveBarcodeToCenterOfScreen">Pusatkan barcode pada layar</string>
|
||||
<string name="points">Poin</string>
|
||||
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> sepertinya bukan saldo yang valid.</string>
|
||||
<string name="app_loyalty_card_keychain">Loyalty Card Keychain</string>
|
||||
<string name="privacy_policy">Kebijakan Privasi</string>
|
||||
<string name="privacy_policy_popup_text">Pemberitahuan kebijakan privasi (diperlukan oleh beberapa toko aplikasi):
|
||||
\n
|
||||
\nTIDAK ADA DATA YANG DIKUMPULKAN SAMA SEKALI, yang dapat dikonfirmasi oleh siapa pun karena aplikasi kami adalah libre software.</string>
|
||||
<string name="importCatimaMessage">Pilih ekspor <i>catima.zip</i> Anda dari Catima untuk diimpor.
|
||||
\nBuat dari menu Impor/Ekspor aplikasi Catima lain dengan menekan Ekspor di sana terlebih dahulu.</string>
|
||||
<string name="importFidmeMessage">Pilih ekspor <i>fidme-export-request-xxxxxx.zip</i> Anda dari FidMe untuk diimpor, dan pilih jenis barcode secara manual setelahnya.
|
||||
\nBuat dari profil FidMe Anda dengan memilih Perlindungan Data lalu tekan Ekstrak data saya terlebih dahulu.</string>
|
||||
<string name="importLoyaltyCardKeychain">Impor dari Loyalty Card Keychain</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">Pilih ekspor <i>LoyaltyCardKeychain.csv</i> Anda dari Loyalty Card Keychain untuk diimpor.
|
||||
\nBuat dari menu Import/Export di Loyalty Card Keychain dengan menekan Export terlebih dahulu.</string>
|
||||
<string name="importStocard">Impor dari Stocard</string>
|
||||
<string name="importStocardMessage">Pilih ekspor <i>***-sync.zip</i> Anda dari Stocard untuk diimpor.
|
||||
\nDapatkan dengan mengirim email ke support@stocardapp.com untuk meminta ekspor data Anda.</string>
|
||||
<string name="importVoucherVault">Impor dari Voucher Vault</string>
|
||||
<string name="importVoucherVaultMessage">Pilih ekspor <i>vouchervault.json</i> Anda dari Vault Voucher untuk diimpor.
|
||||
\nBuat dengan menekan Ekspor di Vault Voucher terlebih dahulu.</string>
|
||||
<string name="unsupportedBarcodeType">Jenis barcode ini belum dapat ditampilkan. Ini mungkin didukung di versi aplikasi yang lebih baru.</string>
|
||||
<string name="wrongValueForBarcodeType">Nilai tidak berlaku untuk jenis barcode yang dipilih</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">ID kartu telah disalin</string>
|
||||
<string name="frontImageDescription">Gambar depan kartu</string>
|
||||
<string name="backImageDescription">Gambar belakang kartu</string>
|
||||
<string name="updateBarcodeQuestionTitle">Perbarui barcode?</string>
|
||||
<string name="updateBarcodeQuestionText">Anda mengubah ID kartu. Apakah Anda juga ingin memperbarui barcode untuk menggunakan nilai yang sama?</string>
|
||||
<string name="passwordRequired">Silahkan masukan kata sandi</string>
|
||||
<string name="exportPassword">Tetapkan kata sandi untuk melindungi ekspor anda (opsional)</string>
|
||||
<string name="failedGeneratingShareURL">Tidak dapat membuat alamat berbagi. Mohon laporkan ini.</string>
|
||||
<string name="app_contributors">Pengembangan dibantu oleh: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="toggleMoreInfo">Tampilkan info selengkapnya</string>
|
||||
<string name="swipeToSwitchImages">Geser atau tekan yang lama untuk mengganti gambar</string>
|
||||
<string name="reverse">Ubah urutan</string>
|
||||
<string name="version_history">Riwayat Versi</string>
|
||||
<string name="help_translate_this_app">Bantu terjemahkan aplikasi ini</string>
|
||||
<string name="source_repository">Sumber Repositori</string>
|
||||
<string name="on_github">di GitHub</string>
|
||||
<string name="and_data_usage">dan penggunaan data</string>
|
||||
<string name="on_google_play">di Google Play</string>
|
||||
<string name="lockScreen">Blokir rotasi</string>
|
||||
<string name="unlockScreen">Buka blokir rotasi</string>
|
||||
<string name="cardShortcut">Pintasan kartu</string>
|
||||
<string name="card_ids_copied">ID kartu yang tersalin</string>
|
||||
<string name="barcodeImageDescriptionWithType">Gambar dari jenis barcode <xliff:g>%s</xliff:g></string>
|
||||
<string name="importExportHelp">Mencadangkan kartu memungkinkan anda memindahkannya ke perangkat lain.</string>
|
||||
<plurals name="selectedCardCount">
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> kartu dipilih</item>
|
||||
</plurals>
|
||||
<plurals name="groupCardCount">
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> kartu</item>
|
||||
</plurals>
|
||||
<plurals name="deleteCardsConfirmation">
|
||||
<item quantity="other">Hapus kartu <xliff:g>%d</xliff:g> ini secara permanen\?</item>
|
||||
</plurals>
|
||||
<plurals name="deleteCardsTitle">
|
||||
<item quantity="other">Hapus <xliff:g>%d</xliff:g> kartu</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
87
app/src/main/res/values-is/strings.xml
Normal file
87
app/src/main/res/values-is/strings.xml
Normal file
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="action_add">Bæta</string>
|
||||
<string name="noBarcode">Nei strikamerkið</string>
|
||||
<string name="action_search">Leita að</string>
|
||||
<string name="delete">Eyða</string>
|
||||
<string name="unlockScreen">Opna Snúningur</string>
|
||||
<string name="noGiftCards">Smelltu á + plús takka til að bæta kort, eða að flytja inn sumir frá ⋮ matseðill fyrst.</string>
|
||||
<string name="note">Athugið</string>
|
||||
<string name="barcodeType">Strikamerkið tegund</string>
|
||||
<string name="cancel">Hætta</string>
|
||||
<string name="noMatchingGiftCards">Vissi ekki að finna neitt. Reyna að breyta leita.</string>
|
||||
<string name="storeName">Nafnið</string>
|
||||
<string name="barcodeNoBarcode">Þetta kort hefur ekki strikamerkið</string>
|
||||
<string name="star">Bæta við eftirlæti</string>
|
||||
<string name="unstar">Fjarlægja frá eftirlæti</string>
|
||||
<string name="save">Sparaðu</string>
|
||||
<string name="edit">Breyta</string>
|
||||
<string name="confirm">Staðfesta</string>
|
||||
<string name="lockScreen">Blokk Snúningur</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="sendLabel">Sendu…</string>
|
||||
<string name="deleteConfirmation">Eyða þetta kort til frambúðar\?</string>
|
||||
<string name="share">Deila</string>
|
||||
<string name="editCardTitle">Breyta Kort</string>
|
||||
<string name="addCardTitle">Bæta Kort</string>
|
||||
<string name="scanCardBarcode">Skanna Kort Strikamerkið</string>
|
||||
<string name="noCardsMessage">Bæta kort fyrstu</string>
|
||||
<string name="exportFailedTitle">Flytja mistókst</string>
|
||||
<string name="exportSuccessfulTitle">Flutt</string>
|
||||
<string name="noStoreError">Ekkert nafn slegið</string>
|
||||
<string name="noCardExistsError">Gæti ekki fundið kort</string>
|
||||
<string name="failedParsingImportUriError">Get ekki lesið inn URI</string>
|
||||
<string name="exportName">Flytja</string>
|
||||
<string name="importExportHelp">Stuðningur upp spil gerir þér kleift að færa þá til annar tæki.</string>
|
||||
<string name="importSuccessfulTitle">Flutt</string>
|
||||
<string name="importFailedTitle">Innflutningur mistókst</string>
|
||||
<string name="noExternalStoragePermissionError">Grant ytri geymslu leyfi til að flytja eða flytja spil fyrstu</string>
|
||||
<string name="exportOptionExplanation">Gögnum verður skrifað á stað af eigin vali.</string>
|
||||
<string name="importOptionFilesystemTitle">Innflutningur frá möppuna</string>
|
||||
<string name="importOptionFilesystemExplanation">Velja ákveðna skrá frá möppuna.</string>
|
||||
<string name="starImage">Uppáhalds stjörnu</string>
|
||||
<string name="never">Aldrei</string>
|
||||
<string name="currency">Mynt</string>
|
||||
<string name="moveBarcodeToTopOfScreen">Færa strikamerkið að efst á skjánum</string>
|
||||
<string name="moveBarcodeToCenterOfScreen">Miðju strikamerkið á skjánum</string>
|
||||
<string name="errorReadingImage">Gat ekki lesið ímynd</string>
|
||||
<string name="importOptionApplicationButton">Notaðu annan app</string>
|
||||
<string name="about">Um</string>
|
||||
<string name="settings">Stillingar</string>
|
||||
<string name="settings_max_font_size_scale">Max. letrið</string>
|
||||
<string name="settings_lock_barcode_orientation">Læsa strikamerkið stefnumörkun</string>
|
||||
<string name="settings_keep_screen_on">Halda á skjánum</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Að koma í veg fyrir að læsa skjánum</string>
|
||||
<string name="editBarcode">Breyta strikamerkið</string>
|
||||
<string name="settings_light_theme">Ljós</string>
|
||||
<string name="importOptionFilesystemButton">Frá möppuna</string>
|
||||
<string name="chooseImportType">Flytja gögn úr\?</string>
|
||||
<string name="balance">Jafnvægi</string>
|
||||
<string name="points">Stig</string>
|
||||
<string name="importOptionApplicationTitle">Notaðu annan app</string>
|
||||
<string name="importOptionApplicationExplanation">Nota allir app eða uppáhalds skráasafn að opna skrá.</string>
|
||||
<string name="selectBarcodeTitle">Veldu Strikamerkið</string>
|
||||
<string name="thumbnailDescription">Þumalinn fyrir kort</string>
|
||||
<string name="settings_theme">Þema</string>
|
||||
<string name="app_license">Copylefted frítt hugbúnaður, leyfi GPLv3+</string>
|
||||
<string name="noBarcodeFound">Nei strikamerkið var komist</string>
|
||||
<string name="settings_category_title_ui">Notandi tengi</string>
|
||||
<string name="settings_system_theme">Kerfi</string>
|
||||
<string name="settings_dark_theme">Dökk</string>
|
||||
<string name="settings_display_barcode_max_brightness">Bjartari strikamerkið skoða</string>
|
||||
<string name="enter_group_name">Inn nafn hópur</string>
|
||||
<string name="intent_import_card_from_url_share_text">Ég vil deila kort með þér</string>
|
||||
<string name="importSuccessful">Kortið gögn flutt</string>
|
||||
<string name="groups">Tekur</string>
|
||||
<string name="exportSuccessful">Kortagögn flutt út</string>
|
||||
<string name="failedOpeningFileManager">Setja skráasafn fyrst.</string>
|
||||
<string name="moveUp">Fara upp</string>
|
||||
<string name="leaveWithoutSaveTitle">Brottför</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Fara án þess að bjarga\?</string>
|
||||
<string name="addFromImage">Veldu mynd frá gallerí</string>
|
||||
<string name="card">Kort</string>
|
||||
<string name="barcode">Strikamerkið</string>
|
||||
<string name="expiryDate">Fyrningu</string>
|
||||
<string name="moveDown">Fara neðar</string>
|
||||
<string name="chooseExpiryDate">Velja rennur</string>
|
||||
</resources>
|
||||
@@ -24,7 +24,6 @@
|
||||
<string name="scanCardBarcode">Scansiona il codice carta</string>
|
||||
<string name="cardShortcut">Scorciatoia per la carta</string>
|
||||
<string name="noCardsMessage">Aggiungi prima una carta</string>
|
||||
<string name="barcodeImageDescription">Immagine del codice della carta</string>
|
||||
<string name="noStoreError">Nessun nome inserito</string>
|
||||
<string name="noCardIdError">Nessun codice carta inserito</string>
|
||||
<string name="noCardExistsError">Impossibile trovare la carta</string>
|
||||
@@ -48,7 +47,7 @@
|
||||
<string name="importOptionApplicationExplanation">Usa qualsiasi app o il tuo gestore di file preferito per aprire un file.</string>
|
||||
<string name="importOptionApplicationButton">Usa un’altra app</string>
|
||||
<string name="about">Informazioni</string>
|
||||
<string name="app_license">Software libero con copyleft, licenza GPLv3+.</string>
|
||||
<string name="app_license">Software libero con copyleft, licenza GPLv3+</string>
|
||||
<string name="about_title_fmt">Informazioni su <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Versione: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Informazioni sulla revisione: <xliff:g id="app_revision_url"> %s </xliff:g></string>
|
||||
@@ -68,7 +67,7 @@
|
||||
<string name="exportSuccessful">Dati della carta importati</string>
|
||||
<string name="importSuccessful">Dati della carta importati</string>
|
||||
<string name="app_copyright_old">Basato su Loyalty Card Keychain
|
||||
\ncopyright © 2016–2020 Branden Archer.</string>
|
||||
\ncopyright © 2016–2020 Branden Archer</string>
|
||||
<string name="exportOptionExplanation">I dati verranno scritti in una posizione a tua scelta.</string>
|
||||
<string name="barcodeType">Tipo di codice a barre</string>
|
||||
<string name="unstar">Rimuovi dai preferiti</string>
|
||||
@@ -117,16 +116,16 @@
|
||||
\nNESSUN DATO VIENE RACCOLTO, cosa che chiunque può confermare dato che la nostra applicazione è un software libero.</string>
|
||||
<string name="privacy_policy">Informativa sulla riservatezza</string>
|
||||
<string name="importVoucherVaultMessage">Seleziona la tua esportazione <i>vouchervault.json</i> da Voucher Vault da importare.
|
||||
\nOppure crealo premendo prima Esporta in Voucher Vault.</string>
|
||||
\nCrealo premendo prima Esporta in Voucher Vault.</string>
|
||||
<string name="importVoucherVault">Importa da Voucher Vault</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">Seleziona la tua esportazione <i>LoyaltyCardKeychain.csv</i> da Loyalty Card Keychain per importarla.
|
||||
\nOppure createlo dal menù Importazione/Esportazione in Loyalty Card Keychain premendo prima su Esporta.</string>
|
||||
\nCreatelo dal menù Importazione/Esportazione in Loyalty Card Keychain premendo prima su Esporta.</string>
|
||||
<string name="importLoyaltyCardKeychain">Importa da Loyalty Card Keychain</string>
|
||||
<string name="importFidmeMessage">Seleziona la tua esportazione <i>fidme-export-request-xxxxxx.zip</i> da FidMe per importare, e seleziona i tipi di codice a barre manualmente dopo.
|
||||
\nOppure crearlo dal tuo profilo FidMe scegliendo Protezione Dati e poi premendo Estrai i miei dati prima.</string>
|
||||
\nCrearlo dal tuo profilo FidMe scegliendo Protezione Dati e poi premendo Estrai i miei dati prima.</string>
|
||||
<string name="importFidme">Importa da FidMe</string>
|
||||
<string name="importCatimaMessage">Seleziona la tua esportazione <i>catima.zip</i> da Catima per importarla.
|
||||
\nOppure crealo dal menù Importazione/Esportazione di un\'altra applicazione Catima premendo prima Esporta.</string>
|
||||
\nCrealo dal menù Importazione/Esportazione di un\'altra applicazione Catima premendo prima Esporta.</string>
|
||||
<string name="importCatima">Importa da Catima</string>
|
||||
<string name="setBarcodeId">Imposta il valore del codice a barre</string>
|
||||
<string name="sameAsCardId">Uguale all\'ID della carta</string>
|
||||
@@ -139,7 +138,7 @@
|
||||
<string name="wrongValueForBarcodeType">Il valore non è valido per il tipo di codice a barre selezionato</string>
|
||||
<string name="app_resources">Risorse libre di terze parti: <xliff:g id="app_resources_list"> %s </xliff:g></string>
|
||||
<string name="app_libraries">Librerie libre di terze parti: <xliff:g id="app_libraries_list"> %s </xliff:g></string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019–<xliff:g>%d</xliff:g> Sylvia van Os.</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Voglio condividere alcune carte con te</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">Numeri delle carte copiati negli appunti</string>
|
||||
<string name="card_ids_copied">Numero/i della carta copiato/i</string>
|
||||
@@ -156,7 +155,7 @@
|
||||
<string name="frontImageDescription">Immagine frontale della carta</string>
|
||||
<string name="passwordRequired">Si prega di inserire la password</string>
|
||||
<string name="importStocardMessage">Seleziona la tua esportazione <i>***-sync.zip</i> da Stocard per importare.
|
||||
\nOppure ottenerlo inviando un\'e-mail a support@stocardapp.com chiedendo un\'esportazione dei tuoi dati.</string>
|
||||
\nOttienilo inviando un\'e-mail a support@stocardapp.com chiedendo un\'esportazione dei tuoi dati.</string>
|
||||
<string name="importStocard">Importa da Stocard</string>
|
||||
<string name="turn_flashlight_off">Spegni la torcia</string>
|
||||
<string name="turn_flashlight_on">Accendi la torcia</string>
|
||||
@@ -175,4 +174,48 @@
|
||||
<item quantity="one">Elimina <xliff:g>%d</xliff:g> carta</item>
|
||||
<item quantity="other">Elimina <xliff:g>%d</xliff:g> carte</item>
|
||||
</plurals>
|
||||
<string name="settings_system_locale">Sistema</string>
|
||||
<string name="settings_locale">Lingua</string>
|
||||
<string name="settings_brown_theme">Marrone</string>
|
||||
<string name="settings_grey_theme">Grigio</string>
|
||||
<string name="settings_green_theme">Verde</string>
|
||||
<string name="settings_sky_blue_theme">Azzurro</string>
|
||||
<string name="settings_blue_theme">Blu</string>
|
||||
<string name="settings_violet_theme">Viola</string>
|
||||
<string name="settings_magenta_theme">Magenta</string>
|
||||
<string name="settings_pink_theme">Rosa</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_theme_color">Colore del tema</string>
|
||||
<string name="app_contributors">Reso possibile da: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="noGroupCards">Questo gruppo non contiene carte</string>
|
||||
<string name="toggleMoreInfo">Attiva/disattiva la visualizzazione di altre informazioni</string>
|
||||
<string name="barcodeImageDescriptionWithType">Immagine del codice a barre della carta del tipo <xliff:g>%s</xliff:g></string>
|
||||
<string name="swipeToSwitchImages">Scorri o premi a lungo per cambiare immagine</string>
|
||||
<string name="sort_by">Ordina per</string>
|
||||
<string name="reverse">Inverti</string>
|
||||
<string name="sort_by_balance">Saldo</string>
|
||||
<string name="sort_by_expiry">Scadenza</string>
|
||||
<string name="sort_by_most_recently_used">Usate più di recente</string>
|
||||
<string name="sort_by_name">Nome</string>
|
||||
<string name="sort">Ordina</string>
|
||||
<string name="license">Licenza</string>
|
||||
<string name="source_repository">Repository fonti</string>
|
||||
<string name="on_github">su GitHub</string>
|
||||
<string name="exportPasswordHint">Inserisci la password</string>
|
||||
<string name="on_google_play">su Google Play</string>
|
||||
<string name="exportPassword">Imposta una password per proteggere la tua esportazione (opzionale)</string>
|
||||
<string name="version_history">Cronologia delle versioni</string>
|
||||
<string name="credits">Crediti</string>
|
||||
<string name="help_translate_this_app">Aiuta a tradurre questa app</string>
|
||||
<string name="and_data_usage">e utilizzo dei dati</string>
|
||||
<string name="rate_this_app">Valuta questa applicazione</string>
|
||||
<string name="report_error">Segnala un errore</string>
|
||||
<string name="editGroup">Gruppo di modifica: <xliff:g>%s</xliff:g></string>
|
||||
<string name="group_name_is_empty">Il nome del gruppo non può essere vuoto</string>
|
||||
<string name="noGiftCardsGroup">Non hai ancora nessuna carta fedeltà. Una volta che ne hai aggiunte, puoi assegnarle al gruppo qui.</string>
|
||||
<string name="group_edit">Modifica il gruppo</string>
|
||||
<string name="group_name_already_in_use">Nome del gruppo già in uso</string>
|
||||
<string name="group_updated">Gruppo aggiornato</string>
|
||||
<string name="selectColor">Seleziona il colore</string>
|
||||
<string name="setIcon">Imposta l\'icona</string>
|
||||
</resources>
|
||||
@@ -76,10 +76,10 @@
|
||||
<string name="app_revision_fmt">Revision Info: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Version: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="about_title_fmt">About <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="app_license">Copylefted libre software, licensed GPLv3+.</string>
|
||||
<string name="app_license">Copylefted libre software, licensed GPLv3+</string>
|
||||
<string name="app_copyright_old">Based on Loyalty Card Keychain
|
||||
\ncopyright © 2016–2020 Branden Archer.</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019–<xliff:g>%d</xliff:g> Sylvia van Os.</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="app_resources">Libre third-party resources: <xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="about">Catimaについて</string>
|
||||
<string name="importOptionApplicationButton">外部のアプリを使う</string>
|
||||
@@ -95,7 +95,7 @@
|
||||
<string name="exportFailed">カードをエクスポートできませんでした</string>
|
||||
<string name="exportFailedTitle">エクスポートに失敗しました</string>
|
||||
<string name="exportSuccessfulTitle">エクスポートしました</string>
|
||||
<string name="sameAsCardId">カードの表記と同一</string>
|
||||
<string name="sameAsCardId">カード番号に合わせる</string>
|
||||
<string name="barcodeId">バーコード番号</string>
|
||||
<string name="importVoucherVaultMessage">Voucher Vaultでエクスポートした <i>vouchervault.json</i>ファイルを選択してください。
|
||||
\nファイルがない場合、Voucher Vaultでファイルをエクスポートしてください。</string>
|
||||
@@ -110,7 +110,6 @@
|
||||
<string name="noCardExistsError">カードが見つかりません</string>
|
||||
<string name="noCardIdError">カード番号が入力されていません</string>
|
||||
<string name="noStoreError">名前が入力されていません</string>
|
||||
<string name="barcodeImageDescription">バーコードの画像</string>
|
||||
<string name="noCardsMessage">カードを追加</string>
|
||||
<string name="cardShortcut">カードのショートカット</string>
|
||||
<string name="scanCardBarcode">カードのバーコードをスキャン</string>
|
||||
@@ -126,7 +125,7 @@
|
||||
<string name="delete">削除</string>
|
||||
<string name="edit">編集</string>
|
||||
<string name="save">保存</string>
|
||||
<string name="cancel">取り消し</string>
|
||||
<string name="cancel">取消</string>
|
||||
<string name="unstar">お気に入りから削除</string>
|
||||
<string name="star">お気に入りに追加</string>
|
||||
<string name="noBarcode">バーコードなし</string>
|
||||
@@ -141,10 +140,10 @@
|
||||
<string name="action_search">検索</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">カードを共有しましょう</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">カード番号をクリップボードにコピーしました</string>
|
||||
<string name="card_ids_copied">コピーしたカード</string>
|
||||
<string name="card_ids_copied">カード番号をコピーしました</string>
|
||||
<string name="turn_flashlight_off">ライトをオフにする</string>
|
||||
<string name="turn_flashlight_on">ライトをオンにする</string>
|
||||
<string name="failedGeneratingShareURL">共有URLの生成に失敗しました。バグを報告してください。</string>
|
||||
<string name="failedGeneratingShareURL">共有URLの生成を生成できませんでした。バグを報告してください。</string>
|
||||
<string name="passwordRequired">パスワードを入力してください</string>
|
||||
<string name="no">いいえ</string>
|
||||
<string name="yes">はい</string>
|
||||
@@ -153,11 +152,11 @@
|
||||
<string name="takePhoto">写真を撮影する</string>
|
||||
<string name="removeImage">画像を削除</string>
|
||||
<string name="setBackImage">裏面の画像を設定</string>
|
||||
<string name="setFrontImage">表面の画像を設定</string>
|
||||
<string name="setFrontImage">オモテ面の画像を設定</string>
|
||||
<string name="photos">フォト</string>
|
||||
<string name="backImageDescription">裏面</string>
|
||||
<string name="frontImageDescription">表面</string>
|
||||
<string name="importStocardMessage">Stocardでエクスポートした<i>***-sync.zip</i>ファイルを選択し、手動でバーコード形式を選択してください。
|
||||
<string name="backImageDescription">カードの裏面</string>
|
||||
<string name="frontImageDescription">カードのオモテ面</string>
|
||||
<string name="importStocardMessage">Stocardでエクスポートした<i>***-sync.zip</i>ファイルを選択してください。
|
||||
\nファイルがない場合、e-mailing support@stocardapp.comにデータのエクスポートを要求してください。</string>
|
||||
<string name="importStocard">Stocardからインポート</string>
|
||||
<plurals name="selectedCardCount">
|
||||
@@ -165,4 +164,46 @@
|
||||
</plurals>
|
||||
<string name="deleteConfirmation">このカードを削除しますか?</string>
|
||||
<string name="deleteTitle">カードの削除</string>
|
||||
<plurals name="deleteCardsConfirmation">
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> 枚のカードを削除しますか?</item>
|
||||
</plurals>
|
||||
<plurals name="deleteCardsTitle">
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> 枚のカードの削除</item>
|
||||
</plurals>
|
||||
<string name="barcodeImageDescriptionWithType">バーコード形式の画像 <xliff:g>%s</xliff:g></string>
|
||||
<string name="toggleMoreInfo">詳細を表示する</string>
|
||||
<string name="app_contributors">Made possible by: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="settings_brown_theme">Brown</string>
|
||||
<string name="settings_grey_theme">Gray</string>
|
||||
<string name="settings_green_theme">Green</string>
|
||||
<string name="settings_sky_blue_theme">Sky Blue</string>
|
||||
<string name="settings_blue_theme">Blue</string>
|
||||
<string name="settings_violet_theme">Violet</string>
|
||||
<string name="settings_magenta_theme">Magenta</string>
|
||||
<string name="settings_pink_theme">Pink</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_theme_color">テーマカラー</string>
|
||||
<string name="settings_system_locale">システムに従う</string>
|
||||
<string name="settings_locale">言語</string>
|
||||
<string name="noGroupCards">このグループにはカードがありません</string>
|
||||
<string name="swipeToSwitchImages">画像を切り替えるには長押し、またはスワイプ</string>
|
||||
<string name="sort_by">並び替え</string>
|
||||
<string name="sort_by_balance">残高</string>
|
||||
<string name="sort_by_expiry">期限</string>
|
||||
<string name="sort_by_most_recently_used">最近使用したカード</string>
|
||||
<string name="sort_by_name">名前</string>
|
||||
<string name="sort">並び替え</string>
|
||||
<string name="rate_this_app">このアプリを評価する</string>
|
||||
<string name="on_github">GitHub</string>
|
||||
<string name="source_repository">ソースリポジトリ</string>
|
||||
<string name="exportPassword">パスワードを設定してエクスポートしたファイルを保護する(任意)</string>
|
||||
<string name="exportPasswordHint">パスワードを入力してください</string>
|
||||
<string name="version_history">更新履歴</string>
|
||||
<string name="credits">貢献者</string>
|
||||
<string name="help_translate_this_app">このアプリの翻訳を手伝う</string>
|
||||
<string name="license">ライセンス</string>
|
||||
<string name="on_google_play">Google Play</string>
|
||||
<string name="report_error">エラーを報告する</string>
|
||||
<string name="reverse">逆順</string>
|
||||
<string name="and_data_usage">and data usage</string>
|
||||
</resources>
|
||||
@@ -63,7 +63,6 @@
|
||||
<string name="importFailedTitle">가져오기 실패</string>
|
||||
<string name="importSuccessfulTitle">가져오기 완료</string>
|
||||
<string name="noCardIdError">카드 ID를 입력하지 않음</string>
|
||||
<string name="barcodeImageDescription">카드 바코드 이미지</string>
|
||||
<string name="storeName">매장</string>
|
||||
<string name="thumbnailDescription">카드 섬네일</string>
|
||||
<string name="importOptionApplicationButton">외부 앱 사용</string>
|
||||
|
||||
89
app/src/main/res/values-lb/strings.xml
Normal file
89
app/src/main/res/values-lb/strings.xml
Normal file
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="deleteTitle">Kaart läschen</string>
|
||||
<string name="action_search">Sichen</string>
|
||||
<string name="action_add">Derbäisetzen</string>
|
||||
<string name="noBarcode">Kee barcode</string>
|
||||
<string name="star">An meng Favoriten bäisetzen</string>
|
||||
<string name="unstar">Aus Favoriten ewechhuelen</string>
|
||||
<string name="cancel">Stornieren</string>
|
||||
<string name="save">Späicheren</string>
|
||||
<string name="edit">Änneren</string>
|
||||
<string name="delete">Läschen</string>
|
||||
<string name="confirm">Bestätegen</string>
|
||||
<string name="lockScreen">Blockrotation</string>
|
||||
<string name="unlockScreen">Déblockéieren Rotatioun</string>
|
||||
<string name="deleteConfirmation">Dës Kaart dauerhaft läschen\?</string>
|
||||
<string name="ok">Okay</string>
|
||||
<string name="share">Aktie</string>
|
||||
<string name="sendLabel">Schécken…</string>
|
||||
<string name="editCardTitle">Kaart änneren</string>
|
||||
<string name="addCardTitle">Kaart derbäisetzen</string>
|
||||
<string name="cardShortcut">Kaart Bréck</string>
|
||||
<string name="exportSuccessfulTitle">Exportéieren</string>
|
||||
<string name="exportFailedTitle">Export fehlgeschlagen</string>
|
||||
<string name="exportFailed">Kaarten konnten net exportéiert ginn</string>
|
||||
<string name="importing">Importéieren…</string>
|
||||
<string name="importOptionFilesystemTitle">Import aus dem Dateisystem</string>
|
||||
<string name="importOptionFilesystemExplanation">Wielt eng bestëmmte Datei aus dem Dateisystem.</string>
|
||||
<string name="importOptionFilesystemButton">Aus dem Dateisystem</string>
|
||||
<string name="importOptionApplicationTitle">Benotzt eng aner app</string>
|
||||
<string name="importOptionApplicationButton">Benotzt eng aner app</string>
|
||||
<string name="app_license">Ënner Copyleft stehende fräi software, lizenséiert GPLv3+</string>
|
||||
<string name="groups">Gruppen</string>
|
||||
<string name="importCatima">Import aus Catima</string>
|
||||
<string name="importFidme">Import aus FidMe</string>
|
||||
<string name="importVoucherVault">Import aus Voucher Vault</string>
|
||||
<string name="barcodeId">Barcode-Wäert</string>
|
||||
<string name="sameAsCardId">Déiselwecht wéi kaart ID</string>
|
||||
<string name="frontImageDescription">Vorderes Bild vun der Kaart</string>
|
||||
<string name="backImageDescription">D \' hënnescht Bild vun der Kaart</string>
|
||||
<string name="photos">Fotoen</string>
|
||||
<string name="setFrontImage">Vorderes Bild einstellen</string>
|
||||
<string name="setBackImage">Bild zerécksetzen</string>
|
||||
<string name="removeImage">Bild ewechhuelen</string>
|
||||
<string name="takePhoto">Mach eng Foto</string>
|
||||
<string name="no">Neen</string>
|
||||
<string name="exportPassword">Leeë Si e Passwuert fir de Schutz vun Hirem Exports fest (optional)</string>
|
||||
<string name="exportPasswordHint">Passwuert aginn</string>
|
||||
<string name="noMatchingGiftCards">Ech hunn näischt fonnt. Probéieren Iech, Är Sich ze änneren.</string>
|
||||
<string name="note">Beuechten</string>
|
||||
<string name="barcodeNoBarcode">Dës Kaart huet kee Barcode</string>
|
||||
<string name="importExportHelp">Wann Dir Är Kaarten sécheren, kënnen Si se op een anert Instrument réckelen.</string>
|
||||
<string name="about">Iwwer</string>
|
||||
<string name="selectBarcodeTitle">Wielt Barcode</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Ech wëll e puer Kaarten mat Iech deelen</string>
|
||||
<string name="updateBarcodeQuestionTitle">Aktualiséiert barcode-Wäert\?</string>
|
||||
<string name="intent_import_card_from_url_share_text">Ech wëll eng Kaart mat dir deelen</string>
|
||||
<string name="importSuccessfulTitle">Anere sproochen</string>
|
||||
<string name="unsupportedBarcodeType">Dee barcode-Typ kann net ugewise ginn. Et kann zu enger spéiderer Versioun vun der App ënnerstëtzt ginn.</string>
|
||||
<string name="yes">Jo</string>
|
||||
<string name="importFailedTitle">Import fehlgeschlagen</string>
|
||||
<string name="importFailed">Kaarten konnten net anere sproochen ginn</string>
|
||||
<string name="exporting">Ausführende…</string>
|
||||
<string name="exportOptionExplanation">D \' Donnéeë ginn op eng Plaz vun Hirer Wal geschriwwen.</string>
|
||||
<string name="importOptionApplicationExplanation">Benotzen Se eng beliebige App oder Hire bevorzugten Dateimanager, fir eng Datei ze opmaachen.</string>
|
||||
<string name="accept">Averstane</string>
|
||||
<string name="settings_display_barcode_max_brightness">Erhellen barcode-Usiicht</string>
|
||||
<string name="enterBarcodeInstructions">Gitt d \' Kaarten-ID en an wielen Se entweder den Barcode-Typ ënnen oder \"Dës Kaart huet kee Barcode\".</string>
|
||||
<string name="importStocard">Importéieren vun Stocard</string>
|
||||
<string name="importLoyaltyCardKeychain">Import vun Loyalty Card Keychain</string>
|
||||
<string name="setBarcodeId">Leeë Si barcode-Wäert</string>
|
||||
<string name="wrongValueForBarcodeType">De Wäert ass fir de ausgewielt Barcode-Typ net gëllt</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">Kaarten-IDs an d \' Tëschentablag inspiréiere</string>
|
||||
<string name="updateBarcodeQuestionText">Si hunn d \' Kaarten-ID geännert. Wëllt Dir och de Barcode aktualiséieren, fir deselwechte Wäert ze benotzen\?</string>
|
||||
<string name="settings_dark_theme">Donkel</string>
|
||||
<string name="settings_lock_barcode_orientation">Barcode-Ausriichtung spären</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Bildschierm spären verhënneren</string>
|
||||
<string name="settings_light_theme">Liicht</string>
|
||||
<string name="settings_max_font_size_scale">Max. Schrëftgréisst</string>
|
||||
<string name="settings_keep_screen_on">Hale Si op Bildschierm</string>
|
||||
<string name="importSuccessful">Kartendaten anere sproochen</string>
|
||||
<string name="exportSuccessful">Exportierte Kartendaten</string>
|
||||
<string name="enter_group_name">Gruppenname aginn</string>
|
||||
<string name="noGroupCards">Dës Grupp ass keng Kaarten</string>
|
||||
<plurals name="groupCardCount">
|
||||
<item quantity="one"><xliff:g>%d</xliff:g> Kaart</item>
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> Netzwerkkarten</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="editCardTitle">Redaguoti lojalumo kortelę</string>
|
||||
<string name="addCardTitle">Pridėti lojalumo kortelę</string>
|
||||
<string name="scanCardBarcode">Skenuoti kortelės brūkšninį kodą</string>
|
||||
<string name="barcodeImageDescription">Kortelės brūkšninio kodo vaizdas</string>
|
||||
<string name="noStoreError">Neįvestas pavadinimas</string>
|
||||
<string name="noCardIdError">Neįvestas kortelės ID</string>
|
||||
<string name="importExport">Importuoti/Exportuoti</string>
|
||||
@@ -26,7 +25,7 @@
|
||||
<string name="exporting">Eksportuoja…</string>
|
||||
<string name="noExternalStoragePermissionError">Pirmiausia suteikite išorinės saugyklos leidimą, kad galėtumėte importuoti arba eksportuoti korteles</string>
|
||||
<string name="about">Apie</string>
|
||||
<string name="app_license">Copylefted libre programinė įranga, licencijuota GPLv3+.</string>
|
||||
<string name="app_license">Copylefted laisvoji programinė įranga, licencijuota GPLv3+</string>
|
||||
<string name="about_title_fmt">Apie <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Versija: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Revizijos info: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
@@ -46,10 +45,10 @@
|
||||
<string name="action_search">Ieškoti</string>
|
||||
<string name="cardShortcut">Kortelės sparčioji nuoroda</string>
|
||||
<string name="importVoucherVaultMessage">Pasirinkite savo <i>vouchervault.json</i> eksportą iš Voucher Vault, kurį norite importuoti.
|
||||
\nArba sukurkite jį pirmiausia paspausdami Eksportuoti Voucher Vault.</string>
|
||||
\nSukurkite jį pirmiausia paspausdami Eksportuoti Voucher Vault.</string>
|
||||
<string name="importVoucherVault">Importuoti iš Voucher Vault</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">Pasirinkite savo <i> LoyaltyCardKeychain.csv</i> eksportą iš Loyalty Card Keychain, kurį norite importuoti.
|
||||
\nArba sukurkite jį iš Loyalty Card Keychain meniu Importas/Eksportas, pirmiausia paspausdami Eksportuoti.</string>
|
||||
\nSukurkite jį iš Loyalty Card Keychain meniu Importavimas/Eksportavimas, pirmiausia paspausdami Eksportuoti.</string>
|
||||
<string name="importLoyaltyCardKeychain">Importuoti iš Loyalty Card Keychain</string>
|
||||
<string name="app_loyalty_card_keychain">Loyalty Card Keychain</string>
|
||||
<string name="parsingBalanceFailed">Panašu, kad <xliff:g> %s </xliff:g> reikšmė nėra tinkama.</string>
|
||||
@@ -80,18 +79,18 @@
|
||||
<string name="sameAsCardId">Tokia pat kaip kortelės ID</string>
|
||||
<string name="barcodeId">Brūkšninio kodo reikšmė</string>
|
||||
<string name="importStocardMessage">Pasirinkite <i>***-sync.zip</i> eksportą iš Stocard, kad galėtumėte importuoti.
|
||||
\nArba gaukite susisiekę el. paštu support@stocardapp.com, prašydami eksportuoti jūsų duomenis.</string>
|
||||
\nGaukite susisiekę el. paštu support@stocardapp.com, prašydami eksportuoti jūsų duomenis.</string>
|
||||
<string name="importStocard">Importuoti iš Stocard</string>
|
||||
<string name="importFidmeMessage">Pasirinkite <i>fidme-export-request-xxxxxx.zip</i> eksportą iš FidMe, kurį norite importuoti, ir po to brūkšninių kodų tipus pasirinkite rankiniu būdu.
|
||||
\nArba sukurkite jį iš savo FidMe profilio, pasirinkę Duomenų apsauga ir pirmiausia paspaudę Išgauti mano duomenis.</string>
|
||||
\nSukurkite jį iš savo FidMe profilio, pasirinkę Duomenų apsauga ir pirmiausia paspaudę Išgauti mano duomenis.</string>
|
||||
<string name="importFidme">Importuoti iš FidMe</string>
|
||||
<string name="importCatimaMessage">Norėdami importuoti, pasirinkite savo <i> catima.zip </i> eksportą iš Catima.
|
||||
\nArba sukurkite ją iš kitos Catima programos importavimo / eksportavimo meniu, pirmiausia paspausdami Eksportuoti ten.</string>
|
||||
<string name="importCatimaMessage">Norėdami importuoti, pasirinkite savo <i> catima.zip </i> eksportavimą iš Catima.
|
||||
\nSukurkite ją iš kitos Catima programos importavimo / eksportavimo meniu, pirmiausia ten paspausdami Eksportuoti.</string>
|
||||
<string name="importCatima">Importuoti iš Catima</string>
|
||||
<string name="accept">Priimti</string>
|
||||
<string name="privacy_policy_popup_text">Privatumo politikos pranešimas (kurio reikalaujama kai kuriose programėlių parduotuvėse):
|
||||
\n
|
||||
\nJOKIE DUOMENYS NĖRA RENKAMI, o tai gali patvirtinti bet kas, nes mūsų programėlė yra libre programinė įranga.</string>
|
||||
\nJOKIE DUOMENYS NĖRA RENKAMI, o tai gali patvirtinti bet kas, nes mūsų programėlė yra laisvoji programinė įranga.</string>
|
||||
<string name="privacy_policy">Privatumo politika</string>
|
||||
<string name="chooseImportType">Importuoti duomenis iš\?</string>
|
||||
<string name="points">Taškai</string>
|
||||
@@ -143,11 +142,11 @@
|
||||
<string name="starImage">Mėgstamiausia žvaigždė</string>
|
||||
<string name="thumbnailDescription">Kortelės miniatiūra</string>
|
||||
<string name="enterBarcodeInstructions">Įveskite kortelės ID ir toliau pasirinkite jos brūkšninio kodo tipą arba \"Ši kortelė neturi brūkšninio kodo\".</string>
|
||||
<string name="app_resources">Libre trečiųjų šalių ištekliai: <xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="app_libraries">Libre trečiųjų šalių bibliotekos: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="app_resources">Laisvosios trečiųjų šalių ištekliai: <xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="app_libraries">Laisvosios trečiųjų šalių bibliotekos: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="app_copyright_old">Paremta Loyalty Card Keychain
|
||||
\nautorinės teisės © 2016–2020 Branden Archer.</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Autorinės teisės © 2019–<xliff:g>%d</xliff:g> Sylvia van Os.</string>
|
||||
\nautorinės teisės © 2016–2020 Branden Archer</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Autorinės teisės © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="importOptionApplicationButton">Naudoti kitą programą</string>
|
||||
<string name="importOptionApplicationExplanation">Norėdami atidaryti failą, naudokite bet kurią programą arba mėgstamą failų tvarkyklę.</string>
|
||||
<string name="importOptionApplicationTitle">Naudoti kitą programą</string>
|
||||
@@ -179,4 +178,48 @@
|
||||
<item quantity="few">Ištrinti <xliff:g>%d</xliff:g> korteles</item>
|
||||
<item quantity="other">Ištrinti <xliff:g>%d</xliff:g> kortelių</item>
|
||||
</plurals>
|
||||
<string name="settings_system_locale">Sistemos</string>
|
||||
<string name="settings_locale">Kalba</string>
|
||||
<string name="settings_brown_theme">Ruda</string>
|
||||
<string name="settings_grey_theme">Pilka</string>
|
||||
<string name="settings_green_theme">Žalia</string>
|
||||
<string name="settings_sky_blue_theme">Dangaus mėlynumo</string>
|
||||
<string name="settings_blue_theme">Mėlyna</string>
|
||||
<string name="settings_violet_theme">Violetinė</string>
|
||||
<string name="settings_magenta_theme">Rausvai raudona</string>
|
||||
<string name="settings_pink_theme">Rožinė</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_theme_color">Temos spalva</string>
|
||||
<string name="app_contributors">Tapo įmanoma su pagalba: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="noGroupCards">Šioje grupėje nėra jokių kortelių</string>
|
||||
<string name="toggleMoreInfo">Perjungti išsamios informacijos rodymą</string>
|
||||
<string name="barcodeImageDescriptionWithType"><xliff:g>%s</xliff:g> tipo kortelės brūkšninio kodo vaizdas</string>
|
||||
<string name="swipeToSwitchImages">Perbraukite arba ilgai palaikykite paspaudę, kad perjungtumėte vaizdus</string>
|
||||
<string name="sort_by">Rikiuoti pagal</string>
|
||||
<string name="reverse">Atvirkštinis</string>
|
||||
<string name="sort_by_balance">Balansas</string>
|
||||
<string name="sort_by_expiry">Galiojimo pabaiga</string>
|
||||
<string name="sort_by_most_recently_used">Vėliausiai naudota</string>
|
||||
<string name="sort_by_name">Pavadinimas</string>
|
||||
<string name="sort">Rikiuoti</string>
|
||||
<string name="credits">Padėkos</string>
|
||||
<string name="source_repository">Šaltinio repozitorija</string>
|
||||
<string name="and_data_usage">ir duomenų naudojimas</string>
|
||||
<string name="rate_this_app">Įvertinkite šią programėlę</string>
|
||||
<string name="version_history">Versijų istorija</string>
|
||||
<string name="license">Licencija</string>
|
||||
<string name="on_github">GitHub</string>
|
||||
<string name="on_google_play">Google Play</string>
|
||||
<string name="help_translate_this_app">Padėkite išversti šią programėlę</string>
|
||||
<string name="report_error">Pranešti apie klaidą</string>
|
||||
<string name="exportPasswordHint">Įveskite slaptažodį</string>
|
||||
<string name="exportPassword">Nustatykite slaptažodį, kad apsaugotumėte eksportavimą (neprivaloma)</string>
|
||||
<string name="group_name_already_in_use">Toks grupės pavadinimas jau naudojamas</string>
|
||||
<string name="group_name_is_empty">Grupės pavadinimas negali būti tuščias</string>
|
||||
<string name="editGroup">Redaguojama grupė: <xliff:g>%s</xliff:g></string>
|
||||
<string name="group_updated">Grupė atnaujinta</string>
|
||||
<string name="group_edit">Redaguoti grupę</string>
|
||||
<string name="noGiftCardsGroup">Dar neturite jokių lojalumo kortelių. Kai kelias pridėsite, galėsite jas priskirti grupei čia.</string>
|
||||
<string name="setIcon">Nustatyti piktogramą</string>
|
||||
<string name="selectColor">Pasirinkti spalvą</string>
|
||||
</resources>
|
||||
96
app/src/main/res/values-lv/strings.xml
Normal file
96
app/src/main/res/values-lv/strings.xml
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="action_search">Meklēšana</string>
|
||||
<string name="action_add">Pievienot</string>
|
||||
<string name="noGiftCards">Noklikšķiniet uz pogas + plus, lai pievienotu karti, vai vispirms importējiet dažus no ⋮ izvēlnes.</string>
|
||||
<string name="noMatchingGiftCards">Neko neatradu. Mēģiniet mainīt meklēšanu.</string>
|
||||
<string name="storeName">Nosaukums</string>
|
||||
<string name="note">Piezīme</string>
|
||||
<string name="barcodeType">Svītrkoda Tips</string>
|
||||
<string name="barcodeNoBarcode">Šai kartei nav svītrkoda</string>
|
||||
<string name="noBarcode">Nav svītrkoda</string>
|
||||
<string name="star">Pievienot izlasei</string>
|
||||
<string name="unstar">Noņemt no izlases</string>
|
||||
<string name="cancel">Atcelt</string>
|
||||
<string name="save">Saglabāt</string>
|
||||
<string name="edit">Rediģēt</string>
|
||||
<string name="delete">Dzēst</string>
|
||||
<string name="moveBarcodeToTopOfScreen">Pārvietojiet svītrkodu uz ekrāna augšdaļu</string>
|
||||
<string name="moveBarcodeToCenterOfScreen">Centrējiet svītrkodu uz ekrāna</string>
|
||||
<string name="errorReadingImage">Nevarēja nolasīt attēlu</string>
|
||||
<string name="balance">Bilance</string>
|
||||
<string name="noBarcodeFound">Svītrkods netika atrasts</string>
|
||||
<string name="currency">Valūta</string>
|
||||
<string name="points">Punkts</string>
|
||||
<string name="chooseImportType">Importēt datus no\?</string>
|
||||
<string name="sendLabel">Nosūtīt…</string>
|
||||
<string name="editCardTitle">Rediģēt Karti</string>
|
||||
<string name="share">Daļa</string>
|
||||
<string name="confirm">Apstiprināt</string>
|
||||
<string name="lockScreen">Bloķēt Rotāciju</string>
|
||||
<string name="unlockScreen">Atbloķēt Rotāciju</string>
|
||||
<string name="deleteTitle">Dzēst karti</string>
|
||||
<string name="deleteConfirmation">Dzēst šo karti pastāvīgi\?</string>
|
||||
<string name="ok">LABI</string>
|
||||
<string name="addCardTitle">Pievienot Karti</string>
|
||||
<string name="scanCardBarcode">Skenēšanas Kartes Svītrkods</string>
|
||||
<string name="cardShortcut">Kartes Saīsne</string>
|
||||
<string name="noCardsMessage">Vispirms pievienojiet karti</string>
|
||||
<string name="noStoreError">Vārds nav ievadīts</string>
|
||||
<string name="noCardExistsError">Nevarēja atrast karti</string>
|
||||
<string name="failedParsingImportUriError">Nevarēja parsēt importa URI</string>
|
||||
<string name="importExport">Imports/Eksports</string>
|
||||
<string name="exportName">Eksports</string>
|
||||
<string name="importExportHelp">Jūsu Karšu dublēšana ļauj pārvietot tās uz citu ierīci.</string>
|
||||
<string name="importSuccessfulTitle">Importēts</string>
|
||||
<string name="importFailedTitle">Neizdevās importēt</string>
|
||||
<string name="importFailed">Nevarēja importēt kartes</string>
|
||||
<string name="exportSuccessfulTitle">Eksports</string>
|
||||
<string name="exportFailedTitle">Eksports neizdevās</string>
|
||||
<string name="exportFailed">Nevarēja eksportēt kartes</string>
|
||||
<string name="importing">Imports…</string>
|
||||
<string name="exporting">Eksports…</string>
|
||||
<string name="noExternalStoragePermissionError">Piešķiriet ārējai atmiņai atļauju vispirms importēt vai eksportēt kartes</string>
|
||||
<string name="exportOptionExplanation">Dati tiks rakstīts uz vietu, pēc jūsu izvēles.</string>
|
||||
<string name="importOptionFilesystemTitle">Importēt no failu sistēmas</string>
|
||||
<string name="importOptionFilesystemExplanation">Izvēlieties konkrētu failu no failu sistēmas.</string>
|
||||
<string name="importOptionFilesystemButton">No failu sistēmas</string>
|
||||
<string name="importOptionApplicationTitle">Izmantojiet citu lietotni</string>
|
||||
<string name="importOptionApplicationExplanation">Izmantojiet jebkuru lietotni vai savu iecienītāko failu pārvaldnieku, lai atvērtu failu.</string>
|
||||
<string name="importOptionApplicationButton">Izmantojiet citu lietotni</string>
|
||||
<string name="about">Par</string>
|
||||
<string name="app_license">Copylefted libre programmatūra, licencēta GPLv3+</string>
|
||||
<string name="selectBarcodeTitle">Izvēlieties Svītrkodu</string>
|
||||
<string name="copy_to_clipboard_toast">Kartes ID kopēts starpliktuvē</string>
|
||||
<string name="thumbnailDescription">Sīktēls kartei</string>
|
||||
<string name="starImage">Mīļākā zvaigzne</string>
|
||||
<string name="settings">Iestatījums</string>
|
||||
<string name="settings_category_title_ui">Interfeiss</string>
|
||||
<string name="settings_theme">Tēma</string>
|
||||
<string name="settings_system_theme">Sistēma</string>
|
||||
<string name="settings_light_theme">Gaisma</string>
|
||||
<string name="settings_dark_theme">Tumšs</string>
|
||||
<string name="settings_max_font_size_scale">Max. fonts</string>
|
||||
<string name="settings_display_barcode_max_brightness">Izgaismojiet svītrkoda skatu</string>
|
||||
<string name="settings_lock_barcode_orientation">Lock svītrkoda orientācija</string>
|
||||
<string name="settings_keep_screen_on">Saglabāt ekrānu</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Novērst bloķēšanas ekrānu</string>
|
||||
<string name="intent_import_card_from_url_share_text">Es vēlos dalīties ar jums karti</string>
|
||||
<string name="importSuccessful">Importētie kartes dati</string>
|
||||
<string name="exportSuccessful">Kartes dati eksportēti</string>
|
||||
<string name="noGroups">Noklikšķiniet uz pogas + plus, lai vispirms pievienotu grupas kategorizēšanai.</string>
|
||||
<string name="noGroupCards">Šajā grupā nav nevienas kartes</string>
|
||||
<string name="all">Visi</string>
|
||||
<string name="deleteConfirmationGroup">Dzēst grupu\?</string>
|
||||
<string name="failedOpeningFileManager">Vispirms instalējiet failu pārvaldnieku.</string>
|
||||
<string name="moveUp">Pārvietot uz augšu</string>
|
||||
<string name="moveDown">Pārvietot uz leju</string>
|
||||
<string name="leaveWithoutSaveTitle">Izeja</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Atstāt bez taupīšanas\?</string>
|
||||
<string name="addFromImage">Izvēlieties attēlu no galerijas</string>
|
||||
<string name="card">Karte</string>
|
||||
<string name="barcode">Svītrkods</string>
|
||||
<string name="expiryDate">Derīguma termiņš</string>
|
||||
<string name="never">Nekad</string>
|
||||
<string name="chooseExpiryDate">Izvēlieties derīguma termiņu</string>
|
||||
</resources>
|
||||
@@ -11,7 +11,7 @@
|
||||
<string name="edit">Rediger</string>
|
||||
<string name="delete">Slett</string>
|
||||
<string name="confirm">Bekreft</string>
|
||||
<string name="lockScreen">Ingen rotering</string>
|
||||
<string name="lockScreen">Skru av rotering</string>
|
||||
<string name="unlockScreen">Skru på rotering</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="copy_to_clipboard">Kopier ID til utklippstavle</string>
|
||||
@@ -21,11 +21,10 @@
|
||||
<string name="scanCardBarcode">Skann kortets strekkode</string>
|
||||
<string name="cardShortcut">Kort-snarvei</string>
|
||||
<string name="noCardsMessage">Legg til et kort først</string>
|
||||
<string name="barcodeImageDescription">Bilde av kortets strekkode</string>
|
||||
<string name="noStoreError">Navn ikke angitt</string>
|
||||
<string name="noCardIdError">Ingen kort-ID innskrevet</string>
|
||||
<string name="noCardExistsError">Kunne ikke finne kort</string>
|
||||
<string name="importExport">Import/eksport</string>
|
||||
<string name="importExport">Importer/eksporter</string>
|
||||
<string name="exportName">Eksporter</string>
|
||||
<string name="importExportHelp">Sikkerhetskopiering av kort lar deg flytte dem til en annen enhet.</string>
|
||||
<string name="importSuccessfulTitle">Importert</string>
|
||||
@@ -41,11 +40,11 @@
|
||||
<string name="importOptionFilesystemTitle">Importer fra filsystem</string>
|
||||
<string name="importOptionFilesystemExplanation">Velg spesifikk fil fra filsystemet.</string>
|
||||
<string name="importOptionFilesystemButton">Fra filsystem</string>
|
||||
<string name="importOptionApplicationTitle">Bruk et annet program</string>
|
||||
<string name="importOptionApplicationExplanation">Bruk hvilket som helst program, eller din favoritt-filutforsker for å åpne en fil.</string>
|
||||
<string name="importOptionApplicationButton">Bruk et annet program</string>
|
||||
<string name="importOptionApplicationTitle">Bruk en annen app</string>
|
||||
<string name="importOptionApplicationExplanation">Bruk en hvilken som helst app, eller din favoritt-filutforsker for å åpne en fil.</string>
|
||||
<string name="importOptionApplicationButton">Bruk en annen app</string>
|
||||
<string name="about">Om</string>
|
||||
<string name="app_license">Gemenhetslig fri programvare, lisensiert GPLv3+.</string>
|
||||
<string name="app_license">Gemenhetslig fri programvare, lisensiert GPLv3+</string>
|
||||
<string name="about_title_fmt">Om <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Versjon: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Utgivelsesinfo: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
@@ -65,7 +64,7 @@
|
||||
<string name="settings_system_theme">System</string>
|
||||
<string name="settings_theme">Drakt</string>
|
||||
<string name="app_copyright_old">Basert på Kundekortknippe
|
||||
\nopphavsrett 2016–2020 Branden Archer.</string>
|
||||
\nopphavsrett 2016–2020 Branden Archer</string>
|
||||
<string name="failedParsingImportUriError">Kunne ikke tolke importerings-URI</string>
|
||||
<string name="share">Del</string>
|
||||
<string name="barcodeNoBarcode">Dette kortet har ingen strekkode</string>
|
||||
@@ -75,13 +74,13 @@
|
||||
<string name="unstar">Fjern fra favoritter</string>
|
||||
<string name="star">Legg til i favoritter</string>
|
||||
<string name="noGroups">Klikk på «+»- (pluss)-tegnet for å legge til grupper for kategorisering først.</string>
|
||||
<string name="deleteConfirmationGroup">Slett gruppe\?</string>
|
||||
<string name="deleteConfirmationGroup">Slett gruppe?</string>
|
||||
<string name="all">Alle</string>
|
||||
<string name="groups">Grupper</string>
|
||||
<string name="enter_group_name">Skriv inn gruppenavn</string>
|
||||
<string name="noBarcode">Ingen strekkode</string>
|
||||
<string name="failedOpeningFileManager">Installer en filbehandler først.</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Forlat uten å lagre\?</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Forlat uten å lagre?</string>
|
||||
<string name="leaveWithoutSaveTitle">Avslutt</string>
|
||||
<string name="addManually">Skriv inn kort-ID manuelt</string>
|
||||
<string name="moveDown">Flytt nedover</string>
|
||||
@@ -107,46 +106,44 @@
|
||||
<string name="balance">Saldo</string>
|
||||
<string name="balancePoints"><xliff:g>%s</xliff:g> poeng</string>
|
||||
<string name="balanceSentence">Saldo: <xliff:g>%s</xliff:g></string>
|
||||
<string name="chooseImportType">Importer data fra\?</string>
|
||||
<string name="chooseImportType">Importer data fra?</string>
|
||||
<string name="app_loyalty_card_keychain">Kundekortknippe</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Forhindre skjermlås</string>
|
||||
<string name="settings_keep_screen_on">Behold skjerm påslått</string>
|
||||
<string name="privacy_policy_popup_text">Personvernspraksis-notis (påkrevd av noen programbutikker):
|
||||
\n
|
||||
\nINGEN DATA SAMLES INN, noe alle kan bekreftes siden programmet vårt er fri programvare.</string>
|
||||
\nINGEN DATA SAMLES INN I DET HELE TATT, noe alle kan bekreftes siden programmet vårt er fri programvare.</string>
|
||||
<string name="accept">Godta</string>
|
||||
<string name="privacy_policy">Personvernspraksis</string>
|
||||
<string name="importFidme">Importer fra FidMe</string>
|
||||
<string name="importCatima">Importer fra Catima</string>
|
||||
<string name="errorReadingImage">Klarte ikke å lese bildet</string>
|
||||
<string name="errorReadingImage">Kunne ikke lese bildet</string>
|
||||
<string name="noBarcodeFound">Fant ingen strekkode</string>
|
||||
<string name="addFromImage">Velg bilde fra galleri</string>
|
||||
<string name="unsupportedBarcodeType">Denne strekkodetypen kan ikke vises for øyeblikket. Støtte kan bli lagt til i en senere versjon av programmet.</string>
|
||||
<string name="setBarcodeId">Sett strekkodeverdi</string>
|
||||
<string name="sameAsCardId">Samme som kort-ID</string>
|
||||
<string name="barcodeId">Strekkodeverdi</string>
|
||||
<string name="importVoucherVaultMessage">Finn en fil som antagelig heter <i>voucher.vault.json</i> å importere.
|
||||
\nEller opprett den ved å trykke «Eksport» i Voucher Vault først.</string>
|
||||
<string name="importVoucherVaultMessage">Velg din <i>vouchervault.json</i>-eksport fra Voucher Vault å importere.
|
||||
\nOpprett den ved å trykke «Eksport» i Voucher Vault først.</string>
|
||||
<string name="importVoucherVault">Importer fra Voucher Vault</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">Finn en fil som antagelig heter <i>LoyaltyCardKeychain.csv</i> å importere.
|
||||
\nEller opprett den i Import/eksport-menyen i Kundekortknippe ved å trykke «Eksporter» der først.</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">Velg din <i>LoyaltyCardKeychain.csv</i>-eksport fra Kundekortknippe å importere.
|
||||
\nOpprett den i «Import/Eksport»-menyen i Kundekortknippe ved å trykke «Eksporter» der først.</string>
|
||||
<string name="importLoyaltyCardKeychain">Importer fra Kundekortknippe</string>
|
||||
<string name="importFidmeMessage">Finn en fil som antagelig heter <i>fidme.export-request-xxxxx.zip</i> å importere, for så å velge strekkodetypene manuelt etterpå-
|
||||
\nEller opprett den i din FidMe-profil ved å velge «Databeskyttelse», for så å trykke «Pakk ut dataen min» først.</string>
|
||||
<string name="importCatimaMessage">Finn en fil som antagelig heter <i>Catima.csv</i> å importere.
|
||||
\nEller opprett den i Import/eksport-menyen i et annet Catima-program ved å trykke «Eksporter» der først.</string>
|
||||
<string name="settings_max_font_size_scale">Maksimal skriftstørrelse</string>
|
||||
<string name="importFidmeMessage">Velg din <i>fidme.export-request-xxxxx.zip</i>-eksport fra FidMe å importere, for så å velge strekkodetypene manuelt etterpå-
|
||||
\nOpprett den i din FidMe-profil ved å velge «Databeskyttelse», for så å trykke «Pakk ut dataen min» først.</string>
|
||||
<string name="settings_max_font_size_scale">Maks. skriftstørrelse</string>
|
||||
<string name="wrongValueForBarcodeType">Verdien er ikke gyldig for valgt strekkodetype</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Jeg ønsker å dele noen kort med deg</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">Kopierte kort-ID-er til utklippstavle</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Jeg vil dele noen kort med deg</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">Kort-ID-er kopiert til utklippstavle</string>
|
||||
<string name="app_resources">Frie tredjepartsressurser: <xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="app_libraries">Frie tredjepartsbibliotek: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="card_ids_copied">Kopierte kort-ID(er)</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Opphavsrett © 2019–<xliff:g>%d</xliff:g> Sylvia van Os.</string>
|
||||
<string name="updateBarcodeQuestionText">Du har endret kortets ID. Ønsker du å også oppdatere strekkoden til samme verdi\?</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Opphavsrett © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="updateBarcodeQuestionText">Du har endret kortets ID. Ønsker du å også oppdatere strekkoden til samme verdi?</string>
|
||||
<string name="no">Nei</string>
|
||||
<string name="yes">Ja</string>
|
||||
<string name="updateBarcodeQuestionTitle">Oppdater strekkodeverdi\?</string>
|
||||
<string name="updateBarcodeQuestionTitle">Oppdater strekkodeverdi?</string>
|
||||
<string name="takePhoto">Ta et bilde</string>
|
||||
<string name="removeImage">Fjern bilde</string>
|
||||
<string name="setBackImage">Sett bakside</string>
|
||||
@@ -155,24 +152,68 @@
|
||||
<string name="backImageDescription">Kortets bakside</string>
|
||||
<string name="frontImageDescription">Kortets forside</string>
|
||||
<string name="importStocardMessage">Velg din <i>***-sync.zip</i>-eksport fra Stocard å importere.
|
||||
\nEller få den ved å sende e-post til support@stocardapp.com der du etterspør eksport av dataen din.</string>
|
||||
\nSkaff den ved å sende e-post til support@stocardapp.com der du etterspør eksport av dataen din.</string>
|
||||
<string name="passwordRequired">Skriv inn passordet</string>
|
||||
<string name="importStocard">Importer fra Stocard</string>
|
||||
<string name="failedGeneratingShareURL">Klarte ikke å lage delbar nettadresse. Rapporter denne feilen.</string>
|
||||
<plurals name="selectedCardCount">
|
||||
<item quantity="one"><xliff:g>%d</xliff:g> kort valgt</item>
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> kort valgt</item>
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> korten valgt</item>
|
||||
</plurals>
|
||||
<string name="deleteConfirmation">Slett dette kortet\?</string>
|
||||
<string name="deleteConfirmation">Slett dette kortet for godt?</string>
|
||||
<plurals name="deleteCardsConfirmation">
|
||||
<item quantity="one">Slett dette kortet for godt\?</item>
|
||||
<item quantity="other">Slett disse <xliff:g xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">%d</xliff:g> kortene for godt\?</item>
|
||||
<item quantity="one">Slett dette <xliff:g>%d</xliff:g> kortet for godt\?</item>
|
||||
<item quantity="other">Slett disse <xliff:g>%d</xliff:g> kortene for godt\?</item>
|
||||
</plurals>
|
||||
<string name="turn_flashlight_on">Skru på lommelykten</string>
|
||||
<string name="turn_flashlight_off">Skru av lommelykten</string>
|
||||
<string name="deleteTitle">Fjern kundekort</string>
|
||||
<string name="deleteTitle">Slett kort</string>
|
||||
<plurals name="deleteCardsTitle">
|
||||
<item quantity="one">Slett <xliff:g xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">%d</xliff:g> kort</item>
|
||||
<item quantity="other">Slett <xliff:g xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">%d</xliff:g> kort</item>
|
||||
<item quantity="one">Slett <xliff:g xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">%s</xliff:g> kort</item>
|
||||
<item quantity="other">Slett <xliff:g xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">%s</xliff:g> kort</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
<string name="settings_system_locale">System</string>
|
||||
<string name="settings_locale">Språk</string>
|
||||
<string name="settings_violet_theme">Fiolett</string>
|
||||
<string name="settings_magenta_theme">Magentarød</string>
|
||||
<string name="app_contributors">Muliggjort av: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="settings_brown_theme">Brun</string>
|
||||
<string name="settings_grey_theme">Grå</string>
|
||||
<string name="settings_green_theme">Grønn</string>
|
||||
<string name="settings_sky_blue_theme">Himmelblå</string>
|
||||
<string name="settings_blue_theme">Blå</string>
|
||||
<string name="settings_pink_theme">Rosa</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_theme_color">Draktfarge</string>
|
||||
<string name="noGroupCards">Denne gruppen inneholder ikke noen kort</string>
|
||||
<string name="toggleMoreInfo">Veksle visning av mer info</string>
|
||||
<string name="barcodeImageDescriptionWithType">Bilde av kortstrekkode av typen <xliff:g>%s</xliff:g></string>
|
||||
<string name="swipeToSwitchImages">Dra eller hold lenge for å bygge bilder</string>
|
||||
<string name="sort_by">Sorter etter</string>
|
||||
<string name="reverse">Vend</string>
|
||||
<string name="sort_by_balance">Saldo</string>
|
||||
<string name="sort_by_expiry">Utløp</string>
|
||||
<string name="sort_by_most_recently_used">Nyligst brukt</string>
|
||||
<string name="sort_by_name">Navn</string>
|
||||
<string name="sort">Sorter</string>
|
||||
<string name="help_translate_this_app">Bistå oversettelsen av programmet</string>
|
||||
<string name="license">Lisens</string>
|
||||
<string name="version_history">Versjonshistorikk</string>
|
||||
<string name="importCatimaMessage">Velg din <i>catima.zip</i>-eksport fra Catima å importere.
|
||||
\nOpprett den fra «Importer/Eksporter»-menyen i en annen Catima-app ved å trykke på «Eksporter» der først</string>
|
||||
<string name="source_repository">Kildekode</string>
|
||||
<string name="on_github">på GitHub</string>
|
||||
<string name="and_data_usage">og bruk av data</string>
|
||||
<string name="rate_this_app">Vurder dette programmet</string>
|
||||
<string name="on_google_play">på Google Play</string>
|
||||
<string name="report_error">Rapporter feil</string>
|
||||
<string name="credits">Bidragsytere</string>
|
||||
<string name="exportPassword">Sett et passord for å beskytte eksporten din (valgfritt)</string>
|
||||
<string name="exportPasswordHint">Skriv inn passord</string>
|
||||
<string name="group_edit">Rediger gruppe</string>
|
||||
<string name="group_name_already_in_use">Gruppenavn allerede i bruk</string>
|
||||
<string name="group_updated">Gruppe oppdatert</string>
|
||||
<string name="group_name_is_empty">Gruppenavn kan ikke være tomt</string>
|
||||
<string name="editGroup">Redigerer gruppe: <xliff:g>%s</xliff:g></string>
|
||||
<string name="noGiftCardsGroup">Du har ingen lojalitetskort enda. Når du først har det kan du legge dem til i en gruppe her.</string>
|
||||
</resources>
|
||||
@@ -19,4 +19,6 @@
|
||||
<color name="inputDividerBorder">#666666</color>
|
||||
|
||||
<color name="iconColor">#ffffff</color>
|
||||
|
||||
<color name="mainLoyaltyCardBackground">#000000</color>
|
||||
</resources>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user