Compare commits

...

1212 Commits

Author SHA1 Message Date
Sylvia van Os
0ddb88b45c Add Maestro screenshot generation 2023-09-28 20:30:53 +02:00
Sylvia van Os
b326778219 Merge pull request #1527 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-09-28 17:51:25 +02:00
Mateus Souza
81e16d95ac Translated using Weblate (Portuguese)
Currently translated at 100.0% (129 of 129 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2023-09-28 06:44:59 +02:00
Mateus Souza
ef18bbdf7c Translated using Weblate (Portuguese)
Currently translated at 100.0% (302 of 302 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2023-09-28 06:44:58 +02:00
109247019824
6562a0177b Translated using Weblate (Bulgarian)
Currently translated at 100.0% (302 of 302 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-09-28 06:44:58 +02:00
Eric
275a427355 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (302 of 302 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-09-28 06:44:57 +02:00
Skrripy
ce6a79f03d Translated using Weblate (Ukrainian)
Currently translated at 100.0% (302 of 302 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2023-09-28 06:44:57 +02:00
solokot
dc792c8425 Translated using Weblate (Russian)
Currently translated at 100.0% (302 of 302 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-09-28 06:44:57 +02:00
J. Lavoie
680d2173d1 Translated using Weblate (French)
Currently translated at 100.0% (302 of 302 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-09-28 06:44:57 +02:00
gallegonovato
e95a20b971 Translated using Weblate (Spanish)
Currently translated at 100.0% (302 of 302 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2023-09-28 06:44:57 +02:00
kb01guy
56de06abac Translated using Weblate (German)
Currently translated at 98.6% (298 of 302 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-09-28 06:44:57 +02:00
Sylvia van Os
488c542cd5 Merge remote-tracking branch 'weblate/main' 2023-09-26 20:05:45 +02:00
Sylvia van Os
0e0693bdad Fix changelog to fastlane action 2023-09-26 19:57:12 +02:00
TheScientistPT
86267a2e38 Translated using Weblate (Portuguese)
Currently translated at 98.3% (294 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2023-09-26 19:55:16 +02:00
Sylvia van Os
e2171856ff Update CHANGELOG 2023-09-26 19:32:39 +02:00
Sylvia van Os
3c3a37a9e8 Merge pull request #1524 from CatimaLoyalty/betterDefaultCardColours
Better default card colours
2023-09-26 19:30:59 +02:00
Sylvia van Os
573da1e4ff New add card workflow (#1512) 2023-09-26 19:30:35 +02:00
Sylvia van Os
1f70446bce Fix typo
Co-authored-by: FC (Fay) Stegerman <flx@obfusk.net>
2023-09-25 22:22:40 +02:00
TheScientistPT
ff4ef15dfc Translated using Weblate (Portuguese)
Currently translated at 98.3% (294 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2023-09-25 22:01:46 +02:00
Sylvia van Os
926f3adb18 Remove default card colour which uses wrong foreground colour 2023-09-24 15:44:26 +02:00
Sylvia van Os
4b2d981cc6 Add test to ensure colours have white foreground 2023-09-24 15:44:22 +02:00
Sylvia van Os
93d5c5e03e Link feature graphic to homepage 2023-09-24 15:13:11 +02:00
Sylvia van Os
475f071575 Merge pull request #1522 from CatimaLoyalty/create-pull-request/patch-1695546611
Update feature graphic
2023-09-24 11:18:57 +02:00
TheLastProject
f77fa88ced Update feature graphic 2023-09-24 09:10:11 +00:00
Sand Smith
7fe5c18cb8 Translated using Weblate (Chinese (Traditional))
Currently translated at 94.9% (284 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hant/
2023-09-24 11:03:13 +02:00
109247019824
7e16798b33 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-09-24 11:03:13 +02:00
Jiri Grönroos
3edfb68bd7 Translated using Weblate (Finnish)
Currently translated at 99.3% (297 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fi/
2023-09-24 11:03:13 +02:00
Eric
4f307af6bd Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-09-24 11:03:13 +02:00
Skrripy
08848af908 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (129 of 129 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2023-09-24 11:03:13 +02:00
Skrripy
f4e9b85ae3 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2023-09-24 11:03:12 +02:00
HudobniVolk
73ccb0ce65 Translated using Weblate (Slovenian)
Currently translated at 91.6% (274 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sl/
2023-09-24 11:02:27 +02:00
Sylvia van Os
15c5ee7f2c Merge pull request #1521 from CatimaLoyalty/create-pull-request/patch-1695528761
Update contributors
2023-09-24 09:42:31 +02:00
Sand Smith
f08be0d13f Translated using Weblate (Chinese (Traditional))
Currently translated at 94.9% (284 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hant/
2023-09-24 06:03:21 +00:00
109247019824
aa115e36fd Translated using Weblate (Bulgarian)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-09-24 06:03:20 +00:00
Jiri Grönroos
cfa45013f4 Translated using Weblate (Finnish)
Currently translated at 99.3% (297 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fi/
2023-09-24 06:03:19 +00:00
Eric
cca01ae5a3 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-09-24 06:03:18 +00:00
Skrripy
44af31f6d4 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (129 of 129 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2023-09-24 06:03:17 +00:00
Skrripy
8fb076421a Translated using Weblate (Ukrainian)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2023-09-24 06:03:05 +00:00
HudobniVolk
89f8ca1387 Translated using Weblate (Slovenian)
Currently translated at 91.6% (274 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sl/
2023-09-24 06:03:04 +00:00
TheLastProject
fddb462618 Update contributors 2023-09-24 04:12:40 +00:00
Sylvia van Os
97343515a3 Consistency: may not/cannot -> must not 2023-09-23 18:11:42 +02:00
Sylvia van Os
dcbd2aa390 Merge pull request #1514 from CatimaLoyalty/improveValidation
Improve validation
2023-09-22 22:32:21 +02:00
Sylvia van Os
12e7aaa615 Trim spaces in store name 2023-09-22 22:02:15 +02:00
Sylvia van Os
50f93b87f5 Cleanups 2023-09-22 21:18:52 +02:00
Sylvia van Os
b4cefbc15e Merge pull request #1517 from CatimaLoyalty/returnToLastViewAfterEdit
Return to last view after edit
2023-09-22 21:04:17 +02:00
Sylvia van Os
4ce17c3742 Merge pull request #1520 from obfusk/rm-unused-setgroupnameerror
ManageGroupsActivity: rm unused setGroupNameError()
2023-09-22 20:55:57 +02:00
FC Stegerman
5035b83ae1 ManageGroupsActivity: rm unused setGroupNameError() 2023-09-22 20:13:32 +02:00
Sylvia van Os
dc327a3e24 Merge pull request #1519 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-09-21 19:03:08 +02:00
solokot
4ddceb83d5 Translated using Weblate (Russian)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-09-21 15:44:20 +02:00
Heimen Stoffels
31048218af Translated using Weblate (Dutch)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-09-21 15:44:20 +02:00
Slávek Banko
6e3a9ca380 Translated using Weblate (Czech)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2023-09-21 15:44:20 +02:00
lassr8
09134f4c5f Translated using Weblate (Spanish)
Currently translated at 28.6% (37 of 129 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/es/
2023-09-21 05:03:56 +02:00
Sylvia van Os
89c9271726 Improve permission string 2023-09-20 18:11:08 +02:00
Sylvia van Os
473f8e6b72 Fix barcode not showing when returning and changing from none to some barcode 2023-09-19 20:45:34 +02:00
Sylvia van Os
8310f09641 Hide keyboard when switching back to view view 2023-09-19 19:40:13 +02:00
Sylvia van Os
31b9123a8f Don't close view activity when entering edit activity 2023-09-19 19:39:33 +02:00
Sylvia van Os
cc4aed6773 Update Fastlane 2023-09-18 19:30:20 +02:00
Sylvia van Os
a868aac579 Merge pull request #1515 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-09-18 19:24:37 +02:00
Áron Dubovszky
da48eec787 Translated using Weblate (Hungarian)
Currently translated at 98.6% (295 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hu/
2023-09-18 19:00:19 +02:00
Sylvia van Os
4aa56a55fe Balance validation fixes
Remove old string which may sometimes display "does not seem like a
valid balance." and default to 0 as balance if field is emptied.
2023-09-17 17:59:42 +02:00
Sylvia van Os
c3daa1cc86 Remove no longer used strings 2023-09-17 17:37:24 +02:00
Sylvia van Os
00d08d741c Don't regenerate barcode if value is empty 2023-09-17 17:37:24 +02:00
Sylvia van Os
2f33be6b3c Improve validation
If a field is empty when it shouldn't be, show it at the correct UI
element and focus
2023-09-17 17:37:21 +02:00
Sylvia van Os
d54a3127a6 Improve create group dialog
Don't show error from the start, disable OK button unless state is okay
2023-09-17 16:39:57 +02:00
Sylvia van Os
40ecf46b40 Merge branch 'main' of github.com:CatimaLoyalty/Android 2023-09-17 12:21:09 +02:00
Sylvia van Os
dd9b6a8fed Update fastlane 2023-09-17 12:21:02 +02:00
Sylvia van Os
194e1d5c26 Merge pull request #1513 from CatimaLoyalty/create-pull-request/patch-1694923968
Update contributors
2023-09-17 10:10:28 +02:00
TheLastProject
9360f2a1e0 Update contributors 2023-09-17 04:12:47 +00:00
Sylvia van Os
2030b6b08d Release Catima 2.26.0 2023-09-14 20:10:38 +02:00
Sylvia van Os
0b2ad13df9 Merge pull request #1508 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-09-14 19:52:19 +02:00
Kristoffer Grundström
dbc60c39b1 Translated using Weblate (Swedish)
Currently translated at 98.3% (294 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sv/
2023-09-14 19:45:37 +02:00
Alexandra Moroz
7db52fe1db Translated using Weblate (Romanian)
Currently translated at 45.8% (137 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ro/
2023-09-14 19:45:37 +02:00
J. Lavoie
f8bcfd6bdf Translated using Weblate (Italian)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-09-14 19:45:37 +02:00
J. Lavoie
16f79b4e23 Translated using Weblate (French)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-09-14 19:45:37 +02:00
J. Lavoie
b1273a1c8a Translated using Weblate (German)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-09-14 19:45:37 +02:00
Sylvia van Os
d127d7fce5 Merge pull request #1507 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-09-13 18:05:24 +02:00
sarami
0aaa4120c7 Translated using Weblate (Korean)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ko/
2023-09-13 10:52:44 +02:00
Lionel HANNEQUIN
9a11669e6d Translated using Weblate (French)
Currently translated at 99.6% (298 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-09-13 10:52:44 +02:00
FC Stegerman
3e7859b265 Translated using Weblate (German)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-09-13 10:52:44 +02:00
Sylvia van Os
34a3f79f9c Update compat 2023-09-11 20:21:59 +02:00
Sylvia van Os
8b8737fa23 Update actions 2023-09-11 19:48:39 +02:00
Sylvia van Os
cf1a53f1b4 Limit permissions for CI jobs where possible 2023-09-10 20:52:56 +02:00
Sylvia van Os
fea4c63840 Allow triggering workflows manually 2023-09-10 12:03:27 +02:00
Sylvia van Os
d0881151fe Update contributors-to-file to v3 2023-09-10 11:58:51 +02:00
Sylvia van Os
e692d27973 Merge pull request #1499 from obfusk/locale-res
app locale improvements
2023-09-10 11:37:50 +02:00
Sylvia van Os
c16a5bc6f6 Merge pull request #1504 from CatimaLoyalty/create-pull-request/patch-1694329960
Update contributors
2023-09-10 09:16:13 +02:00
TheLastProject
df765410d8 Update contributors 2023-09-10 07:12:39 +00:00
Sylvia van Os
0b5e10040d Merge pull request #1503 from CatimaLoyalty/create-pull-request/patch-1694245801
Update feature graphic
2023-09-09 11:13:11 +02:00
TheLastProject
9ff6d78345 Update feature graphic 2023-09-09 07:50:00 +00:00
Sylvia van Os
7a35cba4de Merge pull request #1502 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-09-09 09:48:46 +02:00
Mykola Skira
cbfe761cb8 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (129 of 129 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2023-09-09 02:54:22 +02:00
Ziad OUALHADJ
e0256d07a5 Translated using Weblate (French)
Currently translated at 99.2% (128 of 129 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2023-09-09 02:54:22 +02:00
Mykola Skira
39caf35ae5 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2023-09-09 02:54:22 +02:00
FC Stegerman
704a420e5e disable ast & lb again 2023-09-07 23:39:39 +02:00
Sylvia van Os
f2605ca7f2 Fix Weblate oops 2023-09-07 20:00:24 +02:00
Sylvia van Os
c75657c58a Merge pull request #1500 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-09-06 18:47:53 +02:00
Govind S Nair
63ec0cf098 Translated using Weblate (Hindi)
Currently translated at 56.8% (170 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hi/
2023-09-06 16:30:19 +02:00
Sex Garo
589b532e9f Translated using Weblate (Arabic)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-09-06 16:30:18 +02:00
EngageIndo
4c9e057394 Translated using Weblate (Indonesian)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/id/
2023-09-06 16:30:18 +02:00
Sabrina
f7f4156a78 Translated using Weblate (Korean)
Currently translated at 97.6% (292 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ko/
2023-09-06 16:30:17 +02:00
Sylvia van Os
f9f235af5c Translated using Weblate (German)
Currently translated at 99.3% (297 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-09-06 16:30:11 +02:00
essys
f6c74a7da5 Translated using Weblate (German)
Currently translated at 99.3% (297 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-09-06 16:30:11 +02:00
FC Stegerman
1367e29bd4 disable languages < 29% translated 2023-09-05 02:56:38 +02:00
FC Stegerman
f025d72a11 add comment about locales to settings.xml 2023-09-05 02:49:13 +02:00
FC Stegerman
30f2eb1fb9 CI: add update-locales workflow 2023-09-05 02:46:45 +02:00
FC Stegerman
e8c2e6ecd0 add all langs & rm empty ones 2023-09-05 02:42:30 +02:00
FC Stegerman
025be0e5e3 add & use .scripts/locales.py for localeConfig 2023-09-05 02:17:20 +02:00
FC Stegerman
b9f380a2b8 s/zh-TW/zh-rTW/ 2023-09-05 02:16:55 +02:00
pesta007
b2632a03b7 Translated using Weblate (Arabic)
Currently translated at 91.9% (275 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-09-04 06:57:46 +02:00
Jean-Luc Tibaux
ad4275ae45 Translated using Weblate (German)
Currently translated at 98.6% (295 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-09-04 06:57:46 +02:00
Sylvia van Os
2376517858 Merge pull request #1495 from CatimaLoyalty/create-pull-request/patch-1693725203
Update contributors
2023-09-03 10:22:47 +02:00
TheLastProject
a666885b22 Update contributors 2023-09-03 07:13:23 +00:00
FC (Fay) Stegerman
62d4b3ab0d feature graphic: only run on title.txt changes & clean png (#1494) 2023-09-03 02:07:35 +02:00
Sylvia van Os
e20ac7738b Merge pull request #1492 from CatimaLoyalty/create-pull-request/patch-1693693712
Update feature graphic
2023-09-03 01:30:10 +02:00
TheLastProject
cef64004d1 Update feature graphic 2023-09-02 22:28:32 +00:00
Sylvia van Os
35d2408a0e Merge pull request #1491 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-09-03 00:27:08 +02:00
michaelpratana
1055ba1ca0 Translated using Weblate (Indonesian)
Currently translated at 98.6% (295 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/id/
2023-09-02 23:57:25 +02:00
solokot
2bbdb873cc Translated using Weblate (Russian)
Currently translated at 100.0% (129 of 129 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-09-02 23:57:25 +02:00
Ziad OUALHADJ
b22d76ac02 Translated using Weblate (French)
Currently translated at 97.6% (126 of 129 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2023-09-02 23:57:25 +02:00
Daniel Sych
6975688b9f Translated using Weblate (Polish)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2023-09-02 23:57:25 +02:00
Heimen Stoffels
310800f28a Translated using Weblate (Dutch)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-09-02 23:57:25 +02:00
Ziad OUALHADJ
525fdf064c Translated using Weblate (Italian)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-09-02 23:57:25 +02:00
gallegonovato
5f74f1fbb5 Translated using Weblate (Spanish)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2023-09-02 23:57:25 +02:00
Sylvia van Os
5caae534fc Don't run the changelog job unnecessarily 2023-09-01 19:47:58 +02:00
Sylvia van Os
9ebd312c08 Merge pull request #1488 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-09-01 19:46:53 +02:00
Sylvia van Os
9e77b671e0 Merge pull request #1490 from CatimaLoyalty/fix/ci_updates
CI cleanups
2023-09-01 19:42:40 +02:00
Sylvia van Os
7a361c9afe CI cleanups 2023-09-01 19:41:03 +02:00
Sylvia van Os
6ef86ef29b Merge pull request #1489 from CatimaLoyalty/feature/generatedFeatureGraphic
Feature/generated feature graphic
2023-09-01 19:26:22 +02:00
Sylvia van Os
b9bf8e166a Programmatically generate feature graphic
Also use Noto as font for languages not supported by Lexend Deca and
move the text slightly futher down for better looks in CJK languages
2023-09-01 19:25:51 +02:00
Eric
3d55c2c82c Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (129 of 129 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-09-01 13:40:44 +02:00
Eric
ef56aea88d Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-09-01 13:40:39 +02:00
J. Lavoie
40a3fa7b5b Translated using Weblate (French)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-09-01 13:40:38 +02:00
Younes Bouhouche
184d2aeebd Translated using Weblate (Arabic)
Currently translated at 91.3% (273 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-08-31 20:11:37 +02:00
Oğuz Ersen
8f6603dc79 Translated using Weblate (Turkish)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2023-08-31 20:11:37 +02:00
109247019824
68b53467d0 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-08-31 20:11:37 +02:00
Slávek Banko
9c401c7e85 Translated using Weblate (Czech)
Currently translated at 100.0% (129 of 129 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-08-31 20:11:37 +02:00
solokot
3b0440b9fa Translated using Weblate (Russian)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-08-31 20:11:37 +02:00
Heimen Stoffels
cd148d2bb0 Translated using Weblate (Dutch)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-08-31 20:11:37 +02:00
Allan Nordhøy
487cffac30 Translated using Weblate (Norwegian Bokmål)
Currently translated at 99.3% (297 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2023-08-31 20:11:37 +02:00
Slávek Banko
0ab557e29c Translated using Weblate (Czech)
Currently translated at 100.0% (299 of 299 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2023-08-31 20:11:37 +02:00
Ziad OUALHADJ
05125f86cd New feature graphic 2023-08-31 19:52:19 +02:00
Sylvia van Os
b35ccd7d58 Merge pull request #1487 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-08-31 19:34:53 +02:00
Younes Bouhouche
eab6538f1c Translated using Weblate (Arabic)
Currently translated at 92.6% (276 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-08-31 09:53:07 +02:00
Sylvia van Os
53753690aa Merge pull request #1486 from CatimaLoyalty/create-pull-request/patch-1693340314
Update Fastlane changelogs
2023-08-29 22:21:01 +02:00
TheLastProject
c42a02e532 Update Fastlane changelogs 2023-08-29 20:18:34 +00:00
Sylvia van Os
2d75ebe395 Update CHANGELOG 2023-08-29 22:18:14 +02:00
FC (Fay) Stegerman
8ba860f6c3 embed history/privacy policy/license in app (#1346) 2023-08-29 21:57:49 +02:00
Sylvia van Os
68a638e93e Merge pull request #1485 from CatimaLoyalty/create-pull-request/patch-1693328819
Update Fastlane changelogs
2023-08-29 19:08:04 +02:00
TheLastProject
306e413d94 Update Fastlane changelogs 2023-08-29 17:06:59 +00:00
Sylvia van Os
c57aefa5a3 Update CHANGELOG 2023-08-29 19:06:43 +02:00
Quang Trung
5668fb1152 Android 13 per app language support (#1447) 2023-08-29 19:06:07 +02:00
Sylvia van Os
d62de3d641 Merge pull request #1484 from obfusk/copyright
About: explicitly mention contributors' copyright
2023-08-28 20:20:44 +02:00
FC Stegerman
727eb13a6f remove app_copyright_fmt when identical to untranslated original 2023-08-28 20:12:36 +02:00
FC Stegerman
4ebbe758e3 About: explicitly mention contributors' copyright 2023-08-28 19:28:39 +02:00
Sylvia van Os
c6071263e0 Merge pull request #1483 from CatimaLoyalty/create-pull-request/patch-1693170785
Update Fastlane changelogs
2023-08-27 23:13:24 +02:00
TheLastProject
ecb861c9a1 Update Fastlane changelogs 2023-08-27 21:13:05 +00:00
Sylvia van Os
4cf16d92d4 Merge pull request #1482 from obfusk/patch-6
fix typo in CHANGELOG.md
2023-08-27 23:12:47 +02:00
FC (Fay) Stegerman
8fde18c46a fix typo in CHANGELOG.md 2023-08-27 20:58:23 +00:00
Sylvia van Os
f63eca0747 Merge pull request #1481 from CatimaLoyalty/create-pull-request/patch-1693169829
Update Fastlane changelogs
2023-08-27 22:57:20 +02:00
TheLastProject
5053d63a33 Update Fastlane changelogs 2023-08-27 20:57:09 +00:00
Sylvia van Os
4d08613b3c Update CHANGELOG 2023-08-27 22:56:52 +02:00
Sylvia van Os
715df432a9 Move archive mode into a display option (#1477) 2023-08-27 22:55:45 +02:00
Sylvia van Os
92802fd467 Merge pull request #1480 from CatimaLoyalty/create-pull-request/patch-1693120402
Update contributors
2023-08-27 22:27:52 +02:00
TheLastProject
f0a6593c1a Update contributors 2023-08-27 07:13:21 +00:00
Sylvia van Os
86c4e46293 Merge pull request #1474 from CatimaLoyalty/dependabot/gradle/com.github.spotbugs-5.1.3
Bump com.github.spotbugs from 5.1.2 to 5.1.3
2023-08-25 20:09:08 +02:00
Sylvia van Os
2d4fa0fd85 Release Catima 2.25.3 2023-08-25 18:23:57 +02:00
Sylvia van Os
42863418a4 Merge pull request #1475 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-08-23 17:53:21 +02:00
Aya Ichrak
ac4ccf2635 Translated using Weblate (Arabic)
Currently translated at 92.9% (277 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-08-23 16:53:52 +02:00
Sylvia van Os
89762864ff Translated using Weblate (Arabic)
Currently translated at 92.6% (276 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-08-23 11:52:22 +02:00
ChaoticNeutralCzech
22b8f4b387 Translated using Weblate (Czech)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2023-08-23 11:52:22 +02:00
Osama ALSHBIBI
aebb0e84dc Translated using Weblate (Arabic)
Currently translated at 92.6% (276 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-08-23 11:52:21 +02:00
IllusiveMan196
b75862532c Translated using Weblate (Ukrainian)
Currently translated at 100.0% (128 of 128 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2023-08-23 11:52:21 +02:00
Sylvia van Os
f30fa04d56 Add chat badge 2023-08-22 20:02:29 +02:00
Sylvia van Os
053b51f086 Merge pull request #1476 from CatimaLoyalty/create-pull-request/patch-1692514045
Update contributors
2023-08-20 08:50:28 +02:00
TheLastProject
f8960d9a1e Update contributors 2023-08-20 06:47:25 +00:00
dependabot[bot]
eb84900fab Bump com.github.spotbugs from 5.1.2 to 5.1.3
Bumps com.github.spotbugs from 5.1.2 to 5.1.3.

---
updated-dependencies:
- dependency-name: com.github.spotbugs
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-16 02:54:47 +00:00
Sylvia van Os
8949166ed1 Merge pull request #1473 from CatimaLoyalty/create-pull-request/patch-1691910455
Update contributors
2023-08-13 11:19:16 +02:00
TheLastProject
23c437580a Update contributors 2023-08-13 07:07:35 +00:00
Sylvia van Os
3e46e84b5d Merge pull request #1472 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-08-11 08:22:05 +02:00
solokot
3146e25a46 Translated using Weblate (Russian)
Currently translated at 100.0% (128 of 128 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-08-11 07:51:46 +02:00
Sylvia van Os
dc7b1b032b Merge pull request #1471 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-08-10 09:07:11 +02:00
Eric
18716fb333 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (128 of 128 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-08-10 00:52:13 +02:00
Slávek Banko
5879b8716b Translated using Weblate (Czech)
Currently translated at 100.0% (128 of 128 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-08-10 00:52:13 +02:00
Sylvia van Os
970e4b4a31 Merge pull request #1470 from CatimaLoyalty/dependabot/gradle/com.github.spotbugs-5.1.2
Bump com.github.spotbugs from 5.1.1 to 5.1.2
2023-08-09 08:12:10 +02:00
dependabot[bot]
b25e07d37a Bump com.github.spotbugs from 5.1.1 to 5.1.2
Bumps com.github.spotbugs from 5.1.1 to 5.1.2.

---
updated-dependencies:
- dependency-name: com.github.spotbugs
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-09 02:17:50 +00:00
Sylvia van Os
c1041a09f5 Merge pull request #1469 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-08-08 18:07:33 +02:00
Clxff H3r4ld0
a4a70f44e0 Translated using Weblate (Indonesian)
Currently translated at 95.3% (122 of 128 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/id/
2023-08-08 17:52:18 +02:00
しいたけ
2e52e7b231 Translated using Weblate (Japanese)
Currently translated at 78.1% (233 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ja/
2023-08-08 17:52:18 +02:00
skauVictor
a7b1864c6b Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2023-08-08 17:52:18 +02:00
Sylvia van Os
ee3af751fe Merge pull request #1468 from CatimaLoyalty/create-pull-request/patch-1691305961
Update contributors
2023-08-06 09:35:54 +02:00
TheLastProject
34698c7bdd Update contributors 2023-08-06 07:12:41 +00:00
Sylvia van Os
a45875ef25 Merge pull request #1465 from CatimaLoyalty/create-pull-request/patch-1691229717
Update Fastlane changelogs
2023-08-05 12:02:09 +02:00
TheLastProject
c4df103c02 Update Fastlane changelogs 2023-08-05 10:01:57 +00:00
Sylvia van Os
44211accc9 Update CHANGELOG 2023-08-05 12:01:41 +02:00
Sylvia van Os
7be1ee99ca Merge pull request #1463 from obfusk/fix-colorpicker
LoyaltyCardEditActivity: fix color picker dialog crash & bug
2023-08-05 12:00:49 +02:00
FC Stegerman
b83dbb3a87 StocardImporter: refactor (#1443)
* StocardImporter: refactor

* StocardImporter: trim CSV fields

* LoyaltyCard: add .toString()

* StocardRecord: add .toString()

* StocardImporter: handle usages better

* StocardImporter: use label

* ImportExportTest: add importStocard2 + stocard2.zip

* StocardImporter: iterate over card map in key order

* StocardImporter: cleanup, handle label better, use providers file

* make spotbugs happy

* StocardImporter: can't use providersFileName, list known files, log unknown

* StocardImporter: fix regex, log properly, s/Provider/Store/

* StocardImporter: test /usages/ timestamp, nicer if/else flow

* StocardImporter: fix label usage

* StocardImporter: remove label prefix, improve error
2023-08-05 11:52:59 +02:00
FC Stegerman
7e3a5a9831 LoyaltyCardEditActivity: fix wrong balance parse after locale changes (#1454) 2023-08-05 11:29:59 +02:00
Sylvia van Os
1b2f939c5a Merge pull request #1462 from CatimaLoyalty/dependabot/gradle/com.github.spotbugs-5.1.1
Bump com.github.spotbugs from 5.1.0 to 5.1.1
2023-08-04 23:50:07 +02:00
FC Stegerman
29919851f5 LoyaltyCardEditActivity: fix color picker dialog crash & bug 2023-08-04 04:15:45 +02:00
dependabot[bot]
b255cd63de Bump com.github.spotbugs from 5.1.0 to 5.1.1
Bumps com.github.spotbugs from 5.1.0 to 5.1.1.

---
updated-dependencies:
- dependency-name: com.github.spotbugs
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-04 02:13:47 +00:00
Sylvia van Os
5d022ee1d1 Merge pull request #1460 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-08-02 18:23:57 +02:00
Montazer Al-Taiee
ecd8fe6d43 Translated using Weblate (Arabic)
Currently translated at 92.6% (276 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-08-02 15:07:57 +02:00
Eric
340046905d Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (128 of 128 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-08-02 15:07:57 +02:00
Slávek Banko
aba6dc9070 Translated using Weblate (Czech)
Currently translated at 100.0% (128 of 128 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-08-02 15:07:57 +02:00
Sylvia van Os
7e75f86aba Merge pull request #1459 from CatimaLoyalty/dependabot/gradle/com.github.spotbugs-5.1.0
Bump com.github.spotbugs from 5.0.14 to 5.1.0
2023-08-01 08:23:55 +02:00
Sylvia van Os
8c021141b0 Merge pull request #1458 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-08-01 08:23:19 +02:00
dependabot[bot]
1739ac827a Bump com.github.spotbugs from 5.0.14 to 5.1.0
Bumps com.github.spotbugs from 5.0.14 to 5.1.0.

---
updated-dependencies:
- dependency-name: com.github.spotbugs
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 02:59:27 +00:00
Reza Almanda
2c8bbd3f44 Translated using Weblate (Indonesian)
Currently translated at 95.2% (121 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/id/
2023-08-01 03:16:37 +02:00
Slávek Banko
2afad63f31 Translated using Weblate (Czech)
Currently translated at 100.0% (127 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-08-01 03:16:37 +02:00
Sylvia van Os
e4d2196892 Merge pull request #1457 from CatimaLoyalty/create-pull-request/patch-1690827013
Update Fastlane changelogs
2023-07-31 20:10:25 +02:00
TheLastProject
b26aced825 Update Fastlane changelogs 2023-07-31 18:10:12 +00:00
Sylvia van Os
a9625fc1cf Update CHANGELOG 2023-07-31 20:09:54 +02:00
Sylvia van Os
d86fb9475f Merge pull request #1452 from obfusk/fix-date-rotate
LoyaltyCardEditActivity: fix state loss on rotation for dates
2023-07-31 20:08:40 +02:00
Sylvia van Os
b6ea845236 Merge pull request #1456 from CatimaLoyalty/dependabot/gradle/com.google.zxing-core-3.5.2
Bump com.google.zxing:core from 3.5.1 to 3.5.2
2023-07-31 19:22:18 +02:00
dependabot[bot]
1e88e0c1cc Bump com.google.zxing:core from 3.5.1 to 3.5.2
Bumps [com.google.zxing:core](https://github.com/zxing/zxing) from 3.5.1 to 3.5.2.
- [Release notes](https://github.com/zxing/zxing/releases)
- [Changelog](https://github.com/zxing/zxing/blob/master/CHANGES)
- [Commits](https://github.com/zxing/zxing/compare/zxing-3.5.1...zxing-3.5.2)

---
updated-dependencies:
- dependency-name: com.google.zxing:core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-31 02:58:42 +00:00
Sylvia van Os
72b8781eec Merge pull request #1455 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-30 13:22:12 +02:00
Reza Almanda
dd8c63b088 Translated using Weblate (Indonesian)
Currently translated at 95.2% (121 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/id/
2023-07-30 13:08:02 +02:00
Eric
ec9affd8c3 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (127 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-07-30 13:08:02 +02:00
Sylvia van Os
605e9711fa Translated using Weblate (Polish)
Currently translated at 36.2% (46 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pl/
2023-07-30 13:08:02 +02:00
FC Stegerman
6dfbb169df LoyaltyCardEditActivity: fix noDataLossOnResumeOrRotate test 2023-07-29 21:30:08 +02:00
FC Stegerman
f671c6b0d1 LoyaltyCardEditActivity: fix state loss on rotation for dates 2023-07-29 21:14:51 +02:00
Sylvia van Os
b98ee46566 Merge pull request #1451 from obfusk/fix-divider
only show divider with name/note + extra field
2023-07-29 16:52:20 +02:00
FC Stegerman
3353cf288f only show divider with name/note + extra field 2023-07-29 15:49:09 +02:00
Sylvia van Os
a408f8d727 Release Catima 2.25.2 2023-07-27 19:14:44 +02:00
Sylvia van Os
2d7bb02d1a Update fastlane 2023-07-27 19:07:10 +02:00
Sylvia van Os
38c8e38ed6 Merge pull request #1446 from CatimaLoyalty/create-pull-request/patch-1690299279
Update Fastlane changelogs
2023-07-25 17:35:15 +02:00
TheLastProject
28b95b8f75 Update Fastlane changelogs 2023-07-25 15:34:39 +00:00
Sylvia van Os
c1ebbdb997 Update CHANGELOG.md 2023-07-25 17:34:22 +02:00
Sylvia van Os
fadba7a11c Merge pull request #1445 from obfusk/stocard-csv
add python script & update stocard csv
2023-07-24 20:54:41 +02:00
FC Stegerman
fd61434565 move stocard readme & script 2023-07-24 20:35:25 +02:00
Sylvia van Os
398dff4b3c Merge pull request #1444 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-24 19:35:57 +02:00
FC Stegerman
5c95b750b2 rename to dump_stocard_stores.py 2023-07-24 18:24:42 +02:00
FC Stegerman
9851c0a2fa update stocard_stores.csv 2023-07-24 18:22:03 +02:00
FC Stegerman
c121f846c5 add stocard_stores.py script 2023-07-24 18:17:57 +02:00
ChengCheng
c20ba027cf Added translation using Weblate (Chinese (Literary)) 2023-07-24 11:42:49 +02:00
Kamborio
e5dd26b8ee Translated using Weblate (Spanish)
Currently translated at 29.1% (37 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/es/
2023-07-24 11:41:46 +02:00
Danylo Lystopadov
3b449464ac Translated using Weblate (Ukrainian)
Currently translated at 100.0% (127 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2023-07-24 11:41:46 +02:00
Danylo Lystopadov
3f4d4e38cd Translated using Weblate (Ukrainian)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2023-07-24 11:41:46 +02:00
Sylvia van Os
30ccd03686 Merge pull request #1442 from obfusk/usages-len
StocardImporter: check usages is not empty just in case
2023-07-23 21:57:48 +02:00
FC Stegerman
5493947c28 StocardImporter: check usages is not empty just in case 2023-07-23 20:56:24 +02:00
Sylvia van Os
4172903b42 Merge pull request #1441 from CatimaLoyalty/stocard_20230721
Update Stocard importer
2023-07-23 16:48:53 +02:00
Sylvia van Os
00b1368176 Fix image import 2023-07-23 16:29:55 +02:00
Sylvia van Os
09fee5628f Read usage-statistics/content.json file for lastUsed data 2023-07-23 14:28:14 +02:00
Sylvia van Os
7a7a2f8361 Read input_provider_name in field if available 2023-07-23 14:25:56 +02:00
Sylvia van Os
a9ced56023 Include newer Stocard export 2023-07-23 14:01:59 +02:00
Sylvia van Os
a4af171598 Small credits dialog tweak 2023-07-23 13:06:16 +02:00
Sylvia van Os
164c82a779 Merge pull request #1440 from CatimaLoyalty/create-pull-request/patch-1690096427
Update contributors
2023-07-23 10:01:30 +02:00
TheLastProject
608c3ab863 Update contributors 2023-07-23 07:13:47 +00:00
Sylvia van Os
379a71c7ad Merge pull request #1439 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-22 17:21:15 +02:00
Jiri Grönroos
ee6a6dffcf Translated using Weblate (Finnish)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fi/
2023-07-22 17:08:30 +02:00
solokot
1d6a393914 Translated using Weblate (Russian)
Currently translated at 100.0% (127 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-07-22 17:08:30 +02:00
Tim Trek
5c4a905ac0 Translated using Weblate (German)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-07-22 17:08:30 +02:00
Sylvia van Os
91ce71ea68 Merge pull request #1438 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-22 10:42:18 +02:00
Eric
f07ac3e026 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (127 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-07-22 03:11:31 +02:00
Slávek Banko
649f2c47b4 Translated using Weblate (Czech)
Currently translated at 100.0% (127 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-07-22 03:11:31 +02:00
Milan Šalka
62dcc373ed Translated using Weblate (Slovak)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sk/
2023-07-22 03:11:31 +02:00
Wiktor
e9b04adec6 Translated using Weblate (Polish)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2023-07-22 03:11:31 +02:00
Sylvia van Os
636be16bdd Merge pull request #1436 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-20 17:26:50 +02:00
Sylvia van Os
5ad28f37b8 Merge pull request #1437 from CatimaLoyalty/feature/elevatedMainScreen
Small main screen layout tweaks
2023-07-20 17:26:17 +02:00
Sylvia van Os
5ff6059e86 Small main screen layout tweaks 2023-07-20 16:59:39 +02:00
Balázs Meskó
b9df712394 Translated using Weblate (Hungarian)
Currently translated at 33.0% (42 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/hu/
2023-07-20 13:07:59 +02:00
Eric
790fd7e48f Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (127 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-07-20 13:07:59 +02:00
Slávek Banko
bb43266a01 Translated using Weblate (Czech)
Currently translated at 100.0% (127 of 127 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-07-20 13:07:58 +02:00
Sylvia van Os
450cfce84a Merge pull request #1434 from obfusk/refactor-importer-part-2
refactor importer part 2
2023-07-19 21:17:22 +02:00
Sylvia van Os
6cef56b38b Merge pull request #1435 from CatimaLoyalty/create-pull-request/patch-1689792805
Update Fastlane changelogs
2023-07-19 20:53:53 +02:00
TheLastProject
fbb7cf7e9c Update Fastlane changelogs 2023-07-19 18:53:24 +00:00
Sylvia van Os
9ab2a6a5b2 Update CHANGELOG 2023-07-19 20:53:06 +02:00
Quang Trung
682fc8303c Fix crash on configuration changes in DatePickerFragment (#1431) 2023-07-19 20:52:25 +02:00
FC Stegerman
aa1274566b refactor FidmeImporter 2023-07-19 01:25:00 +02:00
FC Stegerman
d8cd581cb0 refactor StocardImporter 2023-07-19 01:10:39 +02:00
FC Stegerman
2cd00f9103 refactor VoucherVaultImporter 2023-07-19 00:24:09 +02:00
Sylvia van Os
ae07f94b25 Merge pull request #1433 from obfusk/test-bitmaps
use JPGs instead of LetterBitmap b/c of partial robolectric Canvas support
2023-07-18 23:53:15 +02:00
FC Stegerman
22d671263a JPGs instead of LetterBitmap (robolectric missing Canvas support) 2023-07-18 23:27:44 +02:00
Sylvia van Os
227f30361f Try to fix autoclose for real 2023-07-17 21:15:14 +02:00
Sylvia van Os
b964652b83 Merge pull request #1429 from CatimaLoyalty/create-pull-request/patch-1689620901
Update Fastlane changelogs
2023-07-17 21:09:32 +02:00
TheLastProject
f926ffa1d0 Update Fastlane changelogs 2023-07-17 19:08:21 +00:00
Sylvia van Os
d03b8b5635 Merge branch 'main' of github.com:CatimaLoyalty/Android 2023-07-17 21:08:02 +02:00
Sylvia van Os
4e5fea7a52 Update CHANGELOG 2023-07-17 21:07:54 +02:00
Sylvia van Os
95cb6c0a08 Merge pull request #1422 from obfusk/refactor-importer-part-1
refactor importer part 1
2023-07-17 21:06:00 +02:00
FC Stegerman
d350d0b2c7 CatimaImporter: add comment about card group import
Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2023-07-17 20:42:36 +02:00
FC Stegerman
ac0f6f6f3e Utils.getRenamedCardImageFileName(): add javadoc
Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2023-07-17 20:35:02 +02:00
FC Stegerman
ab030ba002 LocaltyCard.isDuplicate(): reformat & add comments
Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2023-07-17 20:23:52 +02:00
Sylvia van Os
93103c8c6d Merge branch 'main' of github.com:CatimaLoyalty/Android 2023-07-17 18:36:28 +02:00
Sylvia van Os
576ec1e6de Release Catima 2.25.1 2023-07-17 18:35:50 +02:00
Sylvia van Os
b602ce5d78 Merge pull request #1426 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-17 18:29:08 +02:00
Cabrito
0ecd38ed1c Translated using Weblate (Portuguese)
Currently translated at 100.0% (126 of 126 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2023-07-17 18:03:59 +02:00
Cabrito
d48e02463c Translated using Weblate (Portuguese)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2023-07-17 18:03:59 +02:00
Sylvia van Os
b9d9c8d2e3 Use chevron-style up/down icons in groups layout 2023-07-16 21:34:03 +02:00
FC Stegerman
3ae665b70f DBHelper: add note to DEFAULT_ZOOM_LEVEL 2023-07-16 20:16:01 +02:00
FC Stegerman
9cf9959b6b add importExistingCardsAfterModification test 2023-07-16 19:53:41 +02:00
FC Stegerman
d11e2c166b Utils.copyToTempFile(): use try for resource management 2023-07-16 18:29:38 +02:00
FC Stegerman
f783be7a4f importer: handle inputFile errors better 2023-07-16 18:16:41 +02:00
FC Stegerman
9ee96b88e8 CatimaImporter: add .close() 2023-07-16 18:04:26 +02:00
FC Stegerman
ba896fc1db DBHelper: don't use DEFAULT_ZOOM_LEVEL in migration 2023-07-16 18:02:52 +02:00
Sylvia van Os
47f1ea80b6 Merge pull request #1424 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-16 15:14:48 +02:00
Projjal Moitra
b5efa28e85 Translated using Weblate (Bengali (India))
Currently translated at 96.3% (287 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn_IN/
2023-07-16 15:05:41 +02:00
solokot
d456a8920d Translated using Weblate (Russian)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-07-16 15:05:41 +02:00
Sylvia van Os
4ef0c96b29 Merge pull request #1423 from CatimaLoyalty/create-pull-request/patch-1689492043
Update contributors
2023-07-16 10:03:08 +02:00
TheLastProject
343c77f9e3 Update contributors 2023-07-16 07:20:43 +00:00
FC Stegerman
1425d4af58 CatimaImporter: add saveAndDeduplicate() & refactor 2023-07-16 05:08:44 +02:00
FC Stegerman
48510494eb Utils: split off CARD_IMAGE_FILENAME_REGEX 2023-07-16 05:05:44 +02:00
FC Stegerman
d5d53b241a Utils: add getRenamedCardImageFileName() 2023-07-16 04:44:24 +02:00
FC Stegerman
901c2d8154 LoyaltyCard: fix isDuplicate() 2023-07-16 04:43:27 +02:00
FC Stegerman
84d7e15b5c LoyaltyCard: add isDuplicate(); Utils: add equals() 2023-07-16 03:29:31 +02:00
FC Stegerman
b8fa4d7060 DBHelper: add DEFAULT_ZOOM_LEVEL 2023-07-16 03:12:29 +02:00
FC Stegerman
da9e3bb6b2 CatimaImporter: read ZIP twice, get checksums 2023-07-16 02:23:54 +02:00
FC Stegerman
3a5973a04d Utils: add checksum() 2023-07-16 02:13:34 +02:00
Sylvia van Os
673e64924b Add security policy 2023-07-16 01:25:53 +02:00
FC Stegerman
5f99f2b17e Utils: add imageFiles() 2023-07-16 00:57:00 +02:00
FC Stegerman
bf05103955 import: copy ZIP, use File instead of InputStream 2023-07-16 00:45:18 +02:00
Sylvia van Os
5ea6155c39 Merge pull request #1421 from obfusk/patch-5
revert s/Frie/Gratis/ in nb-rNO translation
2023-07-14 20:07:25 +02:00
FC Stegerman
abb1cd29f0 revert s/Frie/Gratis/ in nb-rNO translation 2023-07-14 17:31:56 +00:00
Sylvia van Os
52363cdff4 Merge pull request #1420 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-14 17:52:25 +02:00
Bottan Hermawan
ac4f4e3a9a Translated using Weblate (Indonesian)
Currently translated at 95.2% (120 of 126 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/id/
2023-07-14 16:53:20 +02:00
Bottan Hermawan
555387e20d Translated using Weblate (Indonesian)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/id/
2023-07-14 16:53:20 +02:00
Sylvia van Os
70ae8ff167 Merge pull request #1419 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-13 19:03:47 +02:00
Balázs Meskó
86512532f1 Translated using Weblate (Hungarian)
Currently translated at 30.9% (39 of 126 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/hu/
2023-07-13 14:45:59 +02:00
Eric
ebf6318aa2 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (126 of 126 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-07-13 14:45:59 +02:00
Slávek Banko
fd482a4cba Translated using Weblate (Czech)
Currently translated at 100.0% (126 of 126 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-07-13 14:45:59 +02:00
Erik Spjelkavik
54d91dc8a1 Translated using Weblate (Norwegian Bokmål)
Currently translated at 99.3% (296 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2023-07-13 14:45:59 +02:00
J. Lavoie
9fa7fe388f Translated using Weblate (French)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-07-13 14:45:59 +02:00
Kamborio
1415d8da3e Translated using Weblate (Spanish)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2023-07-13 14:45:59 +02:00
J. Lavoie
0ad5de18e1 Translated using Weblate (German)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-07-13 14:45:59 +02:00
Sylvia van Os
9659a2a2cd Merge pull request #1418 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-12 17:12:10 +02:00
Giovanni Donisi
1dd894bd27 Translated using Weblate (Italian)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-07-12 16:52:59 +02:00
Sylvia van Os
0d9151294e Merge pull request #1416 from CatimaLoyalty/create-pull-request/patch-1689096450
Update Fastlane changelogs
2023-07-11 19:31:39 +02:00
Sylvia van Os
09dda99afc Merge pull request #1415 from obfusk/fix-shortcuts
ShortcutHelper: trim after skipping missing cards
2023-07-11 19:31:18 +02:00
TheLastProject
a4fb91b9aa Update Fastlane changelogs 2023-07-11 17:27:30 +00:00
Sylvia van Os
036b821b28 Update CHANGELOG 2023-07-11 19:27:12 +02:00
Sylvia van Os
479a35657f Merge pull request #1414 from obfusk/fix-shortcuts
ShortcutHelper: skip outdated cards that no longer exist
2023-07-11 19:19:14 +02:00
FC Stegerman
eca9d1c74c ShortcutHelper: trim after skipping missing cards 2023-07-11 19:18:41 +02:00
FC Stegerman
95055f1ce6 ShortcutHelper: skip outdated cards that no longer exist 2023-07-11 18:14:34 +02:00
Sylvia van Os
f4a5ae74d6 Release Catima 2.25.0 2023-07-09 18:31:06 +02:00
Sylvia van Os
16952186c7 Merge pull request #1411 from joserebelo/permissions-conflict-fix
Fix content provider permissions conflict
2023-07-09 15:55:02 +02:00
José Rebelo
7d12279b0d Fix content provider permissions conflict 2023-07-09 14:03:34 +01:00
Sylvia van Os
15a49344a3 Merge pull request #1409 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-09 13:35:10 +02:00
Eric
ff15ce0615 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (125 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-07-09 13:13:46 +02:00
Slávek Banko
57144c4cd1 Translated using Weblate (Czech)
Currently translated at 100.0% (125 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-07-09 13:13:46 +02:00
Allan Nordhøy
50387f55d4 Translated using Weblate (Norwegian Bokmål)
Currently translated at 98.9% (295 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2023-07-09 13:13:46 +02:00
Sylvia van Os
0fa07d3d0b Merge pull request #1408 from CatimaLoyalty/create-pull-request/patch-1688886665
Update contributors
2023-07-09 09:34:07 +02:00
TheLastProject
05516f88fc Update contributors 2023-07-09 07:11:04 +00:00
Sylvia van Os
841a5e3ddb Merge pull request #1407 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-08 18:22:17 +02:00
Kis Dominik
2889b45c51 Translated using Weblate (Hungarian)
Currently translated at 31.2% (39 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/hu/
2023-07-08 17:53:57 +02:00
Kis Dominik
9ebb53b224 Translated using Weblate (Hungarian)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hu/
2023-07-08 17:53:56 +02:00
109247019824
14b8b3bd7a Translated using Weblate (Bulgarian)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-07-08 17:53:56 +02:00
Sylvia van Os
3e4c3e9852 Merge pull request #1406 from CatimaLoyalty/create-pull-request/patch-1688747814
Update Fastlane changelogs
2023-07-07 18:41:25 +02:00
TheLastProject
fa417cdfe5 Update Fastlane changelogs 2023-07-07 16:36:53 +00:00
Sylvia van Os
a9863d1921 Update CHANGELOG 2023-07-07 18:36:36 +02:00
Sylvia van Os
f2b7a63a02 Merge pull request #1404 from joserebelo/import-trailing-slash
Fix parse of import URI with trailing slash
2023-07-07 18:35:25 +02:00
Sylvia van Os
8e0a40ee3f Merge pull request #1405 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-07 17:35:54 +02:00
enescan201
21064803eb Translated using Weblate (Turkish)
Currently translated at 61.6% (77 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/tr/
2023-07-07 12:53:18 +02:00
enescan201
031b751a9d Translated using Weblate (Turkish)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2023-07-07 12:53:18 +02:00
109247019824
bb9b640aa5 Translated using Weblate (Bulgarian)
Currently translated at 96.6% (288 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-07-07 12:53:18 +02:00
Eric
1681d077b6 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (125 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-07-07 12:53:18 +02:00
yangyangdaji
3500444e0c Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-07-07 12:53:18 +02:00
Slávek Banko
e05ebbe607 Translated using Weblate (Czech)
Currently translated at 100.0% (125 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-07-07 12:53:18 +02:00
solokot
b3bb20c795 Translated using Weblate (Russian)
Currently translated at 100.0% (125 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-07-07 12:53:18 +02:00
solokot
b0315f279a Translated using Weblate (Russian)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-07-07 12:53:18 +02:00
Heimen Stoffels
9e788cb604 Translated using Weblate (Dutch)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-07-07 12:53:17 +02:00
Slávek Banko
090f3dc80b Translated using Weblate (Czech)
Currently translated at 100.0% (298 of 298 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2023-07-07 12:53:17 +02:00
Sylvia van Os
e4f2f8f46b Remove unused imports 2023-07-05 21:57:20 +02:00
Eric
e5ecd59569 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (125 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-07-05 17:18:24 +02:00
tjw123hh
441ae9587e Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (292 of 292 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-07-05 17:18:23 +02:00
Slávek Banko
0c1e16592d Translated using Weblate (Czech)
Currently translated at 100.0% (125 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-07-05 17:18:00 +02:00
solokot
02659f840e Translated using Weblate (Russian)
Currently translated at 100.0% (292 of 292 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-07-05 17:17:59 +02:00
Heimen Stoffels
eca5ec10d3 Translated using Weblate (Dutch)
Currently translated at 100.0% (292 of 292 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-07-05 17:17:43 +02:00
J. Lavoie
dbc8df018d Translated using Weblate (Italian)
Currently translated at 100.0% (292 of 292 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-07-05 17:17:25 +02:00
J. Lavoie
874b887da1 Translated using Weblate (French)
Currently translated at 100.0% (292 of 292 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-07-05 17:17:08 +02:00
J. Lavoie
5367324219 Translated using Weblate (German)
Currently translated at 100.0% (292 of 292 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-07-05 17:16:41 +02:00
Slávek Banko
6df58e0574 Translated using Weblate (Czech)
Currently translated at 100.0% (292 of 292 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2023-07-05 17:16:18 +02:00
José Rebelo
c8b6328cc6 Fix parse of import URI with trailing slash 2023-07-05 13:05:47 +01:00
Sylvia van Os
90616214f0 Merge pull request #1403 from CatimaLoyalty/create-pull-request/patch-1688507089
Update Fastlane changelogs
2023-07-04 23:44:59 +02:00
TheLastProject
e3bce7eb50 Update Fastlane changelogs 2023-07-04 21:44:49 +00:00
Sylvia van Os
b2d1660cf8 Update CHANGELOG 2023-07-04 23:44:33 +02:00
Sylvia van Os
3de24bb6f0 Merge pull request #1402 from CatimaLoyalty/feature/improveSettingsScreen
Reorganize settings screen
2023-07-04 23:43:33 +02:00
Sylvia van Os
b4e403d214 Reorganize settings screen 2023-07-04 23:30:46 +02:00
Sylvia van Os
b66351ab58 Fix needs info autoclose 2023-07-04 21:01:36 +02:00
Sylvia van Os
c9d775f426 Merge pull request #1401 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-04 20:53:24 +02:00
notlin4
6d4af3d86b Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hant/
2023-07-04 08:52:51 +02:00
Sylvia van Os
37803bd906 Merge pull request #1400 from CatimaLoyalty/create-pull-request/patch-1688410909
Update Fastlane changelogs
2023-07-03 21:08:22 +02:00
TheLastProject
f3fcea7ab1 Update Fastlane changelogs 2023-07-03 19:01:49 +00:00
Sylvia van Os
9a67ea039c Update CHANGELOG 2023-07-03 21:01:33 +02:00
José Rebelo
bf94d208bd Introduce read-only ContentProvider for cards (#1121) 2023-07-03 20:59:39 +02:00
Sylvia van Os
28c0b488e6 Merge pull request #1399 from CatimaLoyalty/create-pull-request/patch-1688280270
Update contributors
2023-07-02 13:02:55 +02:00
TheLastProject
dc926bbfe7 Update contributors 2023-07-02 06:44:30 +00:00
Sylvia van Os
00d5fa4c2d Merge pull request #1398 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-07-02 00:06:18 +02:00
Giacomo Alessandroni
9aca91fb86 Translated using Weblate (Italian)
Currently translated at 77.6% (97 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/it/
2023-07-01 23:53:28 +02:00
Sylvia van Os
bdab8624b5 Merge pull request #1390 from obfusk/timeout
CI: on retry, stop gradle daemon and timeout
2023-07-01 15:05:03 +02:00
Sylvia van Os
9bdfe64c79 Merge pull request #1397 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-30 11:54:05 +02:00
Tomislav Kraljević
f5f7e40219 Translated using Weblate (Croatian)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hr/
2023-06-30 10:53:48 +02:00
Sylvia van Os
2f51e7db68 Merge pull request #1396 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-28 13:07:22 +02:00
Eric
2cb9846f42 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (125 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-06-28 12:52:55 +02:00
Sylvia van Os
1dbe46b97e Merge pull request #1395 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-26 23:17:40 +02:00
Projjal Moitra
7e5611b062 Translated using Weblate (Bengali (India))
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn_IN/
2023-06-26 20:53:09 +02:00
Sylvia van Os
d3a7acd9ab Merge pull request #1393 from CatimaLoyalty/create-pull-request/patch-1687677398
Update contributors
2023-06-25 09:38:20 +02:00
TheLastProject
c023a9787d Update contributors 2023-06-25 07:16:38 +00:00
Sylvia van Os
6de0ed6956 Merge pull request #1391 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-24 18:57:03 +02:00
ayuyydev
aa5f0a7bf8 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hant/
2023-06-24 15:53:29 +02:00
Slávek Banko
6dd5bd957c Translated using Weblate (Czech)
Currently translated at 100.0% (125 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-06-24 15:53:28 +02:00
Michael Moroni
c69df5edfd Translated using Weblate (Italian)
Currently translated at 62.4% (78 of 125 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/it/
2023-06-24 15:53:28 +02:00
FC Stegerman
758d034c31 CI: on retry, stop gradle daemon and timeout 2023-06-24 00:29:51 +02:00
Sylvia van Os
7bcf82a619 Merge pull request #1386 from obfusk/data-matrix-not-square
CatimaBarcode: DATA_MATRIX is not always square
2023-06-23 23:16:02 +02:00
FC Stegerman
fd755185b9 BarcodeImageWriterTask: treat DATA_MATRIX as 1D for max width 2023-06-23 22:23:12 +02:00
FC Stegerman
0ac57be5f1 CatimaBarcode: DATA_MATRIX is not always square 2023-06-23 22:21:42 +02:00
Sylvia van Os
bb929a48ea Merge pull request #1388 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-23 17:48:12 +02:00
Hosam Elzubair
218850be33 Translated using Weblate (Arabic)
Currently translated at 3.2% (4 of 124 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ar/
2023-06-23 14:58:05 +02:00
notlin4
ec07cceced Translated using Weblate (Chinese (Traditional))
Currently translated at 95.4% (274 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hant/
2023-06-23 14:58:05 +02:00
yangyangdaji
71ac1c5dad Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (124 of 124 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-06-23 14:58:05 +02:00
yangyangdaji
b16ecfbb2c Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-06-23 14:58:05 +02:00
남현정
c64bfbabc0 Translated using Weblate (Korean)
Currently translated at 97.5% (121 of 124 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ko/
2023-06-23 14:58:05 +02:00
남현정
fc8073f717 Translated using Weblate (Korean)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ko/
2023-06-23 14:58:05 +02:00
Sylvia van Os
7f56617a3c Merge pull request #1385 from CatimaLoyalty/create-pull-request/patch-1687468237
Update Fastlane changelogs
2023-06-22 23:10:53 +02:00
TheLastProject
f5dc2930b5 Update Fastlane changelogs 2023-06-22 21:10:37 +00:00
Sylvia van Os
4bdc0fef70 Update CHANGELOG 2023-06-22 23:10:21 +02:00
Sylvia van Os
2f3c96b97c Merge pull request #1359 from obfusk/barcode-rendering
Improve barcode rendering (square codes & padding)
2023-06-22 23:09:23 +02:00
FC Stegerman
6ff11e22e1 Improve barcode rendering (square codes & padding) 2023-06-22 21:41:33 +02:00
Sylvia van Os
0b188f2ba7 Merge pull request #1371 from obfusk/currency-symbols
LoyaltyCardEditActivity: work around Currency.getSymbol() bug
2023-06-22 19:58:17 +02:00
Sylvia van Os
827d5ba3f9 Merge pull request #1384 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-22 07:06:53 +02:00
IllusiveMan196
05fea6e208 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (124 of 124 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2023-06-22 02:53:45 +02:00
Sylvia van Os
6064d29cb0 Merge pull request #1383 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-20 20:54:46 +02:00
Oğuz Ersen
0a92daa77a Translated using Weblate (Turkish)
Currently translated at 99.6% (286 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2023-06-20 19:49:45 +02:00
Slávek Banko
bb065aead4 Translated using Weblate (Czech)
Currently translated at 100.0% (124 of 124 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-06-20 19:49:45 +02:00
Michael Moroni
56467c2680 Translated using Weblate (Italian)
Currently translated at 59.6% (74 of 124 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/it/
2023-06-20 19:49:45 +02:00
solokot
1941db1e52 Translated using Weblate (Russian)
Currently translated at 100.0% (124 of 124 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-06-20 19:49:45 +02:00
Allan Nordhøy
c595981996 Translated using Weblate (Norwegian Bokmål)
Currently translated at 98.9% (284 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2023-06-20 19:49:45 +02:00
Michael Moroni
0145a820de Translated using Weblate (Italian)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-06-20 19:49:45 +02:00
Sylvia van Os
224ab7f2e7 Release Catima v2.24.2 2023-06-18 18:15:55 +02:00
Sylvia van Os
1b47a62c70 Merge pull request #1380 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-18 16:48:15 +02:00
Sylvia van Os
f241bad3e4 Fix broken translation 2023-06-18 16:42:40 +02:00
Viktor Broov
c8657870af Translated using Weblate (Esperanto)
Currently translated at 37.6% (108 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/eo/
2023-06-18 16:38:07 +02:00
Sylvia van Os
0ed7a0a6e1 Merge pull request #1378 from CatimaLoyalty/create-pull-request/patch-1687070038
Update contributors
2023-06-18 10:25:47 +02:00
TheLastProject
325330c542 Update contributors 2023-06-18 06:33:57 +00:00
Sylvia van Os
2506f60348 Merge pull request #1377 from CatimaLoyalty/create-pull-request/patch-1686995327
Update Fastlane changelogs
2023-06-17 11:51:42 +02:00
TheLastProject
5bf6f52425 Update Fastlane changelogs 2023-06-17 09:48:47 +00:00
Sylvia van Os
fb1728e5de Update CHANGELOG 2023-06-17 11:48:32 +02:00
Sylvia van Os
d321f733c1 Merge pull request #1376 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-16 21:00:30 +02:00
SC
8ff46f8754 Translated using Weblate (Portuguese)
Currently translated at 95.9% (118 of 123 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2023-06-16 20:51:09 +02:00
SC
a061978c93 Translated using Weblate (Portuguese)
Currently translated at 97.9% (281 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2023-06-16 20:51:09 +02:00
solokot
f3bfc9b278 Translated using Weblate (Russian)
Currently translated at 100.0% (123 of 123 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-06-16 20:51:09 +02:00
gallegonovato
43ebe5e029 Translated using Weblate (Spanish)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2023-06-16 20:51:09 +02:00
Sylvia van Os
2357f4d430 Merge pull request #1375 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-15 23:35:41 +02:00
Pierre NIKOLOV
7869feb3a1 Translated using Weblate (French)
Currently translated at 98.3% (121 of 123 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2023-06-14 05:54:10 +02:00
Sylvia van Os
53ce856c33 Merge pull request #1372 from obfusk/rtl-buttons
LoyaltyCardViewActivity: RTL fixes for buttons
2023-06-13 23:53:04 +02:00
Sylvia van Os
aa321a71ad Merge pull request #1370 from obfusk/sort-rtl
sorting_option.xml: RTL fix
2023-06-13 19:35:16 +02:00
Sylvia van Os
f721237fbc Merge pull request #1373 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-13 19:29:43 +02:00
FC Stegerman
194a7ae365 improve button bar RTL handling using linear layouts 2023-06-12 15:26:21 +02:00
Slávek Banko
1aa1d8bcc1 Translated using Weblate (Czech)
Currently translated at 100.0% (123 of 123 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-06-12 10:54:13 +02:00
FC Stegerman
a8355f609b LoyaltyCardViewActivity: RTL fixes for buttons 2023-06-11 23:09:47 +02:00
FC Stegerman
7c766d0832 LoyaltyCardEditActivity: work around Currency.getSymbol() bug 2023-06-11 17:30:19 +02:00
FC Stegerman
3abe99470e sorting_option.xml: RTL fix 2023-06-11 15:34:42 +02:00
Sylvia van Os
6937342226 Release Catima 2.24.1 2023-06-11 10:57:10 +02:00
Sylvia van Os
e229aa9565 Merge pull request #1368 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-11 10:52:29 +02:00
Sabri Ünal
5fd629bdbc Translated using Weblate (Turkish)
Currently translated at 98.2% (282 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2023-06-11 10:44:09 +02:00
109247019824
4c261e1e04 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-06-11 10:44:09 +02:00
Tymofii Lytvynenko
c8be038b81 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2023-06-11 10:44:08 +02:00
Kacper Małecki
268b4cf827 Translated using Weblate (Polish)
Currently translated at 98.9% (284 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2023-06-11 10:44:08 +02:00
Daniele Tricoli
ada8fd9bd4 Translated using Weblate (Italian)
Currently translated at 98.6% (283 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-06-11 10:44:07 +02:00
Sylvia van Os
285c3d6a38 Merge pull request #1367 from CatimaLoyalty/create-pull-request/patch-1686465528
Update contributors
2023-06-11 09:32:15 +02:00
TheLastProject
07efe99630 Update contributors 2023-06-11 06:38:48 +00:00
Sylvia van Os
a7d3a1c30d Merge pull request #1365 from CatimaLoyalty/create-pull-request/patch-1686414904
Update Fastlane changelogs
2023-06-10 18:38:26 +02:00
Sylvia van Os
fcc995397f Merge pull request #1364 from obfusk/about-rtl
about_activity: make _sub layout consistent (fixes RTL)
2023-06-10 18:38:11 +02:00
TheLastProject
cef0d037f7 Update Fastlane changelogs 2023-06-10 16:35:03 +00:00
Sylvia van Os
6e390717da Make header colour code more consistent (#1363)
- Ensure a header colour is picked for the main screen
- Simplify all different header colour code pickers into a single code
  path
2023-06-10 18:34:49 +02:00
FC Stegerman
f785586c71 about_activity: make _sub layout consistent (fixes RTL) 2023-06-10 16:44:05 +02:00
Sylvia van Os
e66c5e36fb Release Catima 2.24.0 2023-06-10 10:44:42 +02:00
Sylvia van Os
fd0ca37a6a Merge branch 'main' of github.com:CatimaLoyalty/Android 2023-06-08 20:26:39 +02:00
Sylvia van Os
e926a397a7 Add missing dates to CHANGELOG 2023-06-08 20:26:31 +02:00
Sylvia van Os
4f9a6b307f Merge pull request #1358 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-08 19:59:39 +02:00
Clxff H3r4ld0
df60f6adc2 Translated using Weblate (Indonesian)
Currently translated at 93.4% (114 of 122 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/id/
2023-06-08 16:49:14 +02:00
Clxff H3r4ld0
d6287a3cf1 Translated using Weblate (Indonesian)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/id/
2023-06-08 16:49:14 +02:00
Sylvia van Os
7f81d727f0 Merge pull request #1357 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-07 18:37:15 +02:00
Sylvia van Os
03239f0cab Fix dark mode rendering glitch (#1355) 2023-06-07 18:35:30 +02:00
Sylvia van Os
4b6497cba2 Merge pull request #1356 from obfusk/gha-ubuntu-openjdk
CI: use OpenJDK 17 from Ubuntu
2023-06-07 18:31:29 +02:00
109247019824
99008291fb Translated using Weblate (Bulgarian)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-06-07 15:49:23 +02:00
solokot
079049722c Translated using Weblate (Russian)
Currently translated at 100.0% (122 of 122 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-06-07 15:49:23 +02:00
FineFindus
73200e1ac3 Translated using Weblate (German)
Currently translated at 100.0% (122 of 122 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/de/
2023-06-07 15:49:23 +02:00
frablock
39b816ddb1 Translated using Weblate (French)
Currently translated at 99.1% (121 of 122 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2023-06-07 15:49:23 +02:00
Hubert Maciejewicz
be43c1633d Translated using Weblate (Polish)
Currently translated at 98.6% (283 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2023-06-07 15:49:23 +02:00
J. Lavoie
f6c9613731 Translated using Weblate (French)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-06-07 15:49:23 +02:00
FineFindus
99de8cffd8 Translated using Weblate (German)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-06-07 15:49:23 +02:00
FC Stegerman
a867265c66 CI: use OpenJDK 17 from Ubuntu 2023-06-07 13:19:40 +02:00
Sylvia van Os
f43df37c80 Merge pull request #1353 from obfusk/patch-4
CI: add 5m timeout (before retry) to unit test that gets stuck
2023-06-06 23:31:39 +02:00
FC Stegerman
cb70b1229f CI: add 5m timeout (before retry) to unit test that gets stuck 2023-06-05 18:58:58 +00:00
Ziad OUALHADJ
b0b54a1065 Fixed the sorting option to match the other filters 2023-06-05 20:22:07 +02:00
Sylvia van Os
4ccfa7fb84 Merge pull request #1352 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-05 19:35:12 +02:00
Sylvia van Os
9932b10652 Fix broken translation 2023-06-05 19:15:18 +02:00
Mai Tnt
60fe6a13ff Translated using Weblate (Croatian)
Currently translated at 97.9% (281 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hr/
2023-06-05 12:22:44 +02:00
Slávek Banko
0bf30f08a1 Translated using Weblate (Czech)
Currently translated at 100.0% (122 of 122 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-06-05 12:22:43 +02:00
solokot
112fca041b Translated using Weblate (Russian)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-06-05 12:22:38 +02:00
Heimen Stoffels
59af5cb07b Translated using Weblate (Dutch)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-06-05 12:22:38 +02:00
Slávek Banko
9182837ae8 Translated using Weblate (Czech)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2023-06-05 12:22:37 +02:00
Mr. Adil
3f3d85c8b6 Translated using Weblate (Bengali)
Currently translated at 31.7% (89 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn/
2023-06-05 09:53:14 +02:00
Jason Li
29c068df47 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (121 of 121 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-06-05 09:53:13 +02:00
Jason Li
03a480f3b9 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-06-05 09:53:13 +02:00
Slávek Banko
0feb0fcd16 Translated using Weblate (Czech)
Currently translated at 100.0% (121 of 121 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-06-05 09:53:13 +02:00
J. Lavoie
7f1a221fec Translated using Weblate (Italian)
Currently translated at 99.6% (279 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-06-05 09:53:13 +02:00
J. Lavoie
7b52338669 Translated using Weblate (French)
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-06-05 09:53:13 +02:00
J. Lavoie
0a2925eafa Translated using Weblate (German)
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-06-05 09:53:13 +02:00
Sylvia van Os
92f37376a6 Merge pull request #1351 from obfusk/patch-3
README: explicitly say "OpenJDK 17", not just "Java 17"
2023-06-04 22:00:20 +02:00
FC Stegerman
08fbc30a29 README: explicitly say "OpenJDK 17", not just "Java 17" 2023-06-04 19:07:43 +00:00
Sylvia van Os
91dbcf339f Catima uses Java 17 to build 2023-06-04 20:59:26 +02:00
Sylvia van Os
24fe6886c9 Lower fullscreen bottom padding to reduce the chance of overlapping UI elements
Partially fixes https://github.com/CatimaLoyalty/Android/issues/1332
2023-06-04 19:20:00 +02:00
Sylvia van Os
270546d022 Update screenshots 2023-06-04 19:00:59 +02:00
Sylvia van Os
fe278324f3 Merge pull request #1349 from CatimaLoyalty/create-pull-request/patch-1685896355
Update Fastlane changelogs
2023-06-04 18:34:52 +02:00
TheLastProject
c7c18a0a14 Update Fastlane changelogs 2023-06-04 16:32:35 +00:00
Sylvia van Os
d6fcb71722 Merge pull request #1347 from CatimaLoyalty/feature/detailSettings
Support selecting exactly which details to view in main view
2023-06-04 18:32:20 +02:00
Sylvia van Os
32ce1e02aa Smaller store name font on main screen 2023-06-04 18:14:23 +02:00
Sylvia van Os
8a8faac201 Merge pull request #1345 from obfusk/dialog-top-padding
add top content padding to dialogs
2023-06-04 16:11:31 +02:00
Sylvia van Os
2793f38d19 Move store name below card image 2023-06-04 14:55:26 +02:00
Sylvia van Os
654e3f7843 Improve text readability on icon 2023-06-04 11:20:17 +02:00
Sylvia van Os
2a6fe92b1b Support selecting exactly which details to view in main view 2023-06-04 11:06:35 +02:00
Sylvia van Os
b3cd102332 Merge pull request #1348 from CatimaLoyalty/create-pull-request/patch-1685860707
Update contributors
2023-06-04 11:03:31 +02:00
TheLastProject
e12bfa81dc Update contributors 2023-06-04 06:38:26 +00:00
FC Stegerman
e859e7849d add top content padding to dialogs 2023-06-03 23:14:49 +02:00
Sylvia van Os
7a4c9ce84f Release Catima 2.23.3 2023-06-03 17:12:27 +02:00
Sylvia van Os
6419ca7d11 Merge pull request #1341 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-03 15:59:03 +02:00
Clxff H3r4ld0
d1b23c712a Translated using Weblate (Indonesian)
Currently translated at 94.1% (113 of 120 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/id/
2023-06-03 15:44:42 +02:00
Sabri Ünal
ef5b525401 Translated using Weblate (Turkish)
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2023-06-03 15:44:42 +02:00
frablock
a8d5cb9ef8 Translated using Weblate (French)
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-06-03 15:44:42 +02:00
Sylvia van Os
42090310d4 Merge pull request #1340 from CatimaLoyalty/create-pull-request/patch-1685795604
Update Fastlane changelogs
2023-06-03 14:34:32 +02:00
TheLastProject
9d8da2a451 Update Fastlane changelogs 2023-06-03 12:33:24 +00:00
Sylvia van Os
fb488af2b7 Fix barcode being invisible on square screens
See https://github.com/CatimaLoyalty/Android/issues/1339
2023-06-03 14:33:04 +02:00
Sylvia van Os
71052c9f69 Merge pull request #1338 from CatimaLoyalty/create-pull-request/patch-1685789977
Update Fastlane changelogs
2023-06-03 13:00:10 +02:00
TheLastProject
2a285f6d21 Update Fastlane changelogs 2023-06-03 10:59:37 +00:00
Sylvia van Os
e668ae7d9d Update CHANGELOG 2023-06-03 12:59:20 +02:00
Sylvia van Os
4a197c542a Merge pull request #1329 from obfusk/patch-2
make checkBox_reverse font size match sort type radio buttons
2023-06-03 12:58:44 +02:00
Sylvia van Os
720c6b6510 Merge pull request #1337 from obfusk/view-card-id
LoyaltyCardViewActivity: use "Card ID" as title for dialog
2023-06-02 20:24:14 +02:00
FC Stegerman
d932ebb9f2 LoyaltyCardViewActivity: use "Card ID" as title for dialog 2023-06-02 20:17:04 +02:00
Poorva Patidar
77b6d8724b Made barcode value text Selectable (#1331) 2023-06-02 19:57:51 +02:00
Swayam Khare
5ff002da51 Added margin to EditText in AlertDialog (#1328) 2023-06-02 19:47:23 +02:00
Sylvia van Os
16b3fbdf9c Merge pull request #1334 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-06-02 08:32:18 +02:00
109247019824
4f11eceb3b Translated using Weblate (Bulgarian)
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-06-02 06:47:46 +02:00
Eryk Michalak
c11d777bcc Translated using Weblate (Polish)
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2023-06-02 06:47:46 +02:00
Sylvia van Os
49cda90ac6 Merge pull request #1330 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-31 21:13:11 +02:00
Balázs Meskó
63e4f4fd0d Translated using Weblate (Hungarian)
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hu/
2023-05-31 20:49:42 +02:00
109247019824
c44845582c Translated using Weblate (Bulgarian)
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-05-31 20:49:42 +02:00
solokot
b0771d3b01 Translated using Weblate (Russian)
Currently translated at 100.0% (120 of 120 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-05-31 20:49:42 +02:00
FC Stegerman
285a7a9aa7 make checkBox_reverse font size match sort type radio buttons 2023-05-31 15:40:04 +00:00
Sylvia van Os
818c5e1643 Merge branch 'main' of github.com:TheLastProject/loyalty-card-locker 2023-05-30 18:54:50 +02:00
Sylvia van Os
7ffaf65635 Use regular title in info dialog 2023-05-30 18:54:42 +02:00
Sylvia van Os
bf50dcbaf3 Merge pull request #1321 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-30 18:25:02 +02:00
Balanda Nazarii
3e83035cf6 Translated using Weblate (Ukrainian)
Currently translated at 98.3% (118 of 120 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2023-05-30 13:24:00 +02:00
Sylvia van Os
e921aab322 Release Catima 2.23.2 2023-05-30 12:59:21 +02:00
Sylvia van Os
1ea125d7f9 Merge pull request #1317 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-30 12:48:13 +02:00
Sylvia van Os
c828ec516c Merge pull request #1319 from CatimaLoyalty/create-pull-request/patch-1685442708
Update Fastlane changelogs
2023-05-30 12:32:31 +02:00
TheLastProject
5704ce1381 Update Fastlane changelogs 2023-05-30 10:31:47 +00:00
Sylvia van Os
ca33184e81 Merge branch 'main' of github.com:TheLastProject/loyalty-card-locker 2023-05-30 12:31:31 +02:00
Sylvia van Os
82db76f3a9 Fix long barcode values causing barcode to scale down to nothing 2023-05-30 12:31:21 +02:00
Sylvia van Os
ab6955cf9b Fix set icon menu sometimes re-opening after returning from image cropper 2023-05-30 12:29:55 +02:00
Enol P
a1c81c3223 Translated using Weblate (Asturian)
Currently translated at 0.8% (1 of 120 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ast/
2023-05-30 12:06:46 +02:00
Enol P
43e7114f16 Translated using Weblate (Asturian)
Currently translated at 30.3% (85 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ast/
2023-05-30 12:06:46 +02:00
Slávek Banko
d1b84097f6 Translated using Weblate (Czech)
Currently translated at 100.0% (120 of 120 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-05-30 12:06:45 +02:00
solokot
2c9b3896c9 Translated using Weblate (Russian)
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-05-30 12:06:40 +02:00
Heimen Stoffels
3dbee69847 Translated using Weblate (Dutch)
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-05-30 12:06:39 +02:00
Slávek Banko
4f9414ab4f Translated using Weblate (Czech)
Currently translated at 100.0% (280 of 280 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2023-05-30 12:06:39 +02:00
Enol P
5a4043bf90 Added translation using Weblate (Asturian) 2023-05-30 02:00:59 +02:00
Balanda Nazarii
f742639925 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2023-05-30 00:10:19 +02:00
Eryk Michalak
e50cca781e Translated using Weblate (Polish)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2023-05-30 00:10:19 +02:00
Sylvia van Os
1abff7c900 Merge pull request #1316 from CatimaLoyalty/create-pull-request/patch-1685381842
Update Fastlane changelogs
2023-05-29 19:40:10 +02:00
TheLastProject
8f24fcee96 Update Fastlane changelogs 2023-05-29 17:37:22 +00:00
Sylvia van Os
f3e1bfc503 Improve button styling in Groups screen 2023-05-29 19:37:03 +02:00
Sylvia van Os
65e3b87df4 Merge branch 'main' of github.com:TheLastProject/loyalty-card-locker 2023-05-29 18:20:08 +02:00
Sylvia van Os
2dbe9ebb8a Fix text and icon alignment on home screen 2023-05-29 18:06:49 +02:00
Sylvia van Os
ccfbe1f679 Merge pull request #1315 from CatimaLoyalty/create-pull-request/patch-1685369384
Update Fastlane changelogs
2023-05-29 16:27:57 +02:00
TheLastProject
3a4467db83 Update Fastlane changelogs 2023-05-29 14:09:44 +00:00
Sylvia van Os
419d28163e Long-press card icon in view activity to change it 2023-05-29 16:09:27 +02:00
Sylvia van Os
89483c4c4e Merge branch 'main' of github.com:TheLastProject/loyalty-card-locker 2023-05-28 21:18:24 +02:00
Sylvia van Os
4e921eb5d7 Update fastlane 2023-05-28 21:18:16 +02:00
Sylvia van Os
0cf266c6f1 Merge pull request #1314 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-28 14:24:58 +02:00
Slávek Banko
20f9f971a1 Translated using Weblate (Czech)
Currently translated at 100.0% (119 of 119 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-05-28 12:49:56 +02:00
Heimen Stoffels
0150ca81cf Translated using Weblate (Dutch)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-05-28 12:49:56 +02:00
Sylvia van Os
4fd6092f8d Merge pull request #1313 from CatimaLoyalty/create-pull-request/patch-1685258004
Update contributors
2023-05-28 10:33:47 +02:00
TheLastProject
a488003e4a Update contributors 2023-05-28 07:13:23 +00:00
Sylvia van Os
9e0e8bab75 Release Catima 2.23.1 2023-05-27 17:53:03 +02:00
Sylvia van Os
0eca05d656 Merge pull request #1310 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-27 12:45:32 +02:00
Sylvia van Os
1c5d102a59 Fix lint 2023-05-27 12:39:20 +02:00
Eudes-alencar
400d0f4e22 Translated using Weblate (Portuguese)
Currently translated at 100.0% (118 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2023-05-27 12:31:19 +02:00
Clxff H3r4ld0
4c0593d333 Translated using Weblate (Indonesian)
Currently translated at 94.0% (111 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/id/
2023-05-27 12:31:19 +02:00
Eudes-alencar
87d82b1b6d Translated using Weblate (Portuguese)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2023-05-27 12:31:19 +02:00
WaldiS
8ea4a3309d Translated using Weblate (Polish)
Currently translated at 99.6% (287 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2023-05-27 12:31:19 +02:00
Sylvia van Os
18088b30bd Delete unused resources 2023-05-25 22:43:58 +02:00
Sylvia van Os
875309bc5e Merge pull request #1309 from CatimaLoyalty/create-pull-request/patch-1685044413
Update Fastlane changelogs
2023-05-25 22:04:46 +02:00
TheLastProject
95520a7051 Update Fastlane changelogs 2023-05-25 19:53:32 +00:00
Sylvia van Os
ab9391db38 Update libraries
It seems Material 1.9.0 slightly changes some paddings, so created new
screenshots
2023-05-25 21:52:38 +02:00
Sylvia van Os
e43e4b37ae Merge branch 'main' of github.com:TheLastProject/loyalty-card-locker 2023-05-25 21:28:47 +02:00
Sylvia van Os
f2d856b661 Actually properly remove font scale setting 2023-05-25 21:20:32 +02:00
Sylvia van Os
8c6c5fb767 Merge pull request #1308 from obfusk/patch-1
fix typo in RELEASE_STEPS.md
2023-05-25 21:10:41 +02:00
FC Stegerman
bb4ec8f8be fix typo in RELEASE_STEPS.md 2023-05-25 18:55:53 +00:00
Sylvia van Os
e5fd277198 Release Catima 2.23.0 2023-05-25 19:01:37 +02:00
Sylvia van Os
93b089c646 Merge pull request #1306 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-25 18:12:36 +02:00
Clxff Heraldo
5e37a9b89f Translated using Weblate (Indonesian)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/id/
2023-05-25 18:05:27 +02:00
Slávek Banko
27cc7b9008 Translated using Weblate (Czech)
Currently translated at 100.0% (118 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-05-25 18:05:27 +02:00
Slávek Banko
0749bbd432 Translated using Weblate (Czech)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2023-05-25 18:05:27 +02:00
Sylvia van Os
9b1e0537c9 Merge pull request #1305 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-24 18:00:00 +02:00
Balázs Meskó
3b2b45f08f Translated using Weblate (Hungarian)
Currently translated at 25.4% (30 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/hu/
2023-05-24 13:50:37 +02:00
Milo Ivir
60a5e60ae0 Translated using Weblate (Croatian)
Currently translated at 2.5% (3 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/hr/
2023-05-24 13:50:37 +02:00
Milo Ivir
77513d5528 Translated using Weblate (Croatian)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hr/
2023-05-24 13:50:37 +02:00
丛林意志
15fa483490 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (118 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-05-24 13:50:37 +02:00
SilverFS
40ba47d60c Translated using Weblate (Dutch)
Currently translated at 11.8% (14 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/nl/
2023-05-24 13:50:37 +02:00
solokot
986327d141 Translated using Weblate (Russian)
Currently translated at 100.0% (118 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-05-24 13:50:37 +02:00
Jean Mareilles
36f0dde3b2 Translated using Weblate (French)
Currently translated at 99.1% (117 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2023-05-24 13:50:37 +02:00
Giovanni Donisi
f0a695a616 Translated using Weblate (Italian)
Currently translated at 99.6% (287 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-05-24 13:50:37 +02:00
Jean Mareilles
810b0f3c14 Translated using Weblate (French)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-05-24 13:50:37 +02:00
Mateo Gomez
fcf08a8900 Translated using Weblate (Spanish)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2023-05-24 13:50:37 +02:00
Sylvia van Os
939bf6a788 Merge pull request #1304 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-22 20:15:09 +02:00
Minecraft boom
935f899d0f Translated using Weblate (Arabic)
Currently translated at 97.2% (280 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-05-22 06:54:30 +02:00
Balázs Meskó
6c8d79ef36 Translated using Weblate (Hungarian)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hu/
2023-05-22 06:54:30 +02:00
Oğuz Ersen
178707b482 Translated using Weblate (Turkish)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2023-05-22 06:54:30 +02:00
109247019824
0f2c9cb63d Translated using Weblate (Bulgarian)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-05-22 06:54:30 +02:00
丛林意志
0869a00f0c Translated using Weblate (Chinese (Simplified))
Currently translated at 99.1% (117 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hans/
2023-05-22 06:54:30 +02:00
丛林意志
b63b8c4ea7 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-05-22 06:54:30 +02:00
solokot
76d77a2af4 Translated using Weblate (Russian)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-05-22 06:54:30 +02:00
Heimen Stoffels
dade0b7a54 Translated using Weblate (Dutch)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-05-22 06:54:30 +02:00
Artūras Kalenda
68801d6958 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (288 of 288 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2023-05-22 06:54:30 +02:00
Sylvia van Os
5c3ec85043 Merge pull request #1303 from CatimaLoyalty/create-pull-request/patch-1684674032
Update Fastlane changelogs
2023-05-21 15:02:20 +02:00
TheLastProject
6332e396cb Update Fastlane changelogs 2023-05-21 13:00:31 +00:00
Sylvia van Os
7f022feb6a Fix crash when using "Take a photo" with disabled camera app 2023-05-21 15:00:11 +02:00
Sylvia van Os
1fa8487474 Bump AGP 2023-05-21 14:48:20 +02:00
Sylvia van Os
0e040a73eb Merge branch 'main' of github.com:TheLastProject/loyalty-card-locker 2023-05-21 14:34:51 +02:00
Sylvia van Os
65acb885af Fix crash on disabled camera app 2023-05-21 14:34:39 +02:00
Sylvia van Os
ee28957cbd Merge pull request #1302 from CatimaLoyalty/create-pull-request/patch-1684649320
Update contributors
2023-05-21 09:23:27 +02:00
TheLastProject
0e9f4d9f2b Update contributors 2023-05-21 06:08:39 +00:00
Sylvia van Os
58974cf738 Merge pull request #1301 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-20 13:32:23 +02:00
Balázs Meskó
c56c931a70 Translated using Weblate (Hungarian)
Currently translated at 15.2% (18 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/hu/
2023-05-20 11:53:50 +02:00
Quentin PAGÈS
c83e8b6682 Translated using Weblate (Occitan)
Currently translated at 34.8% (100 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/oc/
2023-05-20 11:53:50 +02:00
109247019824
449ab86b5a Translated using Weblate (Bulgarian)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-05-20 11:53:50 +02:00
solokot
8f18bbe0ac Translated using Weblate (Russian)
Currently translated at 100.0% (118 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-05-20 11:53:50 +02:00
Altons
992e61b88a Translated using Weblate (French)
Currently translated at 97.4% (115 of 118 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2023-05-20 11:53:50 +02:00
solokot
47b92fb38c Translated using Weblate (Russian)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-05-20 11:53:50 +02:00
Heimen Stoffels
b9963bb967 Translated using Weblate (Dutch)
Currently translated at 100.0% (287 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-05-20 11:53:50 +02:00
Carlo Cuoghi
d642d57b85 Translated using Weblate (Italian)
Currently translated at 98.2% (282 of 287 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-05-20 11:53:50 +02:00
Sylvia van Os
9e0e8f6d7f Redo all screenshots with exact same Material colour 2023-05-18 22:54:38 +02:00
Sylvia van Os
e486755e6a Merge pull request #1273 from CatimaLoyalty/feature/donationLink
Add donation link on non-Google installs
2023-05-18 21:44:48 +02:00
Sylvia van Os
1bb803ef0a Add donation link on non-Google installs
Inspired by https://git.zx2c4.com/wireguard-android/commit/?id=dc1860c74dd67e18a66fe9e243eeffa689bef043
2023-05-18 19:33:06 +02:00
Sylvia van Os
f729f9758b Merge pull request #1299 from CatimaLoyalty/dependabot/gradle/org.robolectric-robolectric-4.10.3
Bump org.robolectric:robolectric from 4.10.2 to 4.10.3
2023-05-18 19:03:47 +02:00
Sylvia van Os
abe3bc7d87 Merge pull request #1300 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-18 19:03:27 +02:00
Balázs Meskó
454bb6a1aa Translated using Weblate (Hungarian)
Currently translated at 7.6% (9 of 117 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/hu/
2023-05-18 18:52:16 +02:00
Balázs Meskó
2d4d4e2309 Translated using Weblate (Hungarian)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hu/
2023-05-18 18:52:16 +02:00
IllusiveMan196
e7c4010e8d Translated using Weblate (Ukrainian)
Currently translated at 100.0% (117 of 117 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2023-05-18 18:52:16 +02:00
dependabot[bot]
cc363e0c04 Bump org.robolectric:robolectric from 4.10.2 to 4.10.3
Bumps [org.robolectric:robolectric](https://github.com/robolectric/robolectric) from 4.10.2 to 4.10.3.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.10.2...robolectric-4.10.3)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-18 02:58:51 +00:00
Sylvia van Os
deacc4a69b Merge pull request #1298 from CatimaLoyalty/create-pull-request/patch-1684361188
Update Fastlane changelogs
2023-05-18 00:26:17 +02:00
TheLastProject
ac6e6e0985 Update Fastlane changelogs 2023-05-17 22:06:27 +00:00
Sylvia van Os
fd37a2708f Update CHANGELOG 2023-05-18 00:06:13 +02:00
Sylvia van Os
85ea314dc9 Merge pull request #1294 from pokegh0st/fix/preferences
Update Settings screen to use Material You design
2023-05-18 00:05:22 +02:00
Sylvia van Os
7fd5fe6ee0 Merge pull request #1290 from CatimaLoyalty/dependabot/gradle/org.robolectric-robolectric-4.10.2
Bump org.robolectric:robolectric from 4.10.1 to 4.10.2
2023-05-17 21:17:10 +02:00
Sylvia van Os
2c35ad3044 Merge pull request #1297 from CatimaLoyalty/create-pull-request/patch-1684350973
Update Fastlane changelogs
2023-05-17 21:16:47 +02:00
TheLastProject
210e305bae Update Fastlane changelogs 2023-05-17 19:16:13 +00:00
Sylvia van Os
b48de921fc Redesign of home screen and view UI (#1296)
* Redesign of home screen and view UI

* Update screenshots and CHANGELOG

* Make spotbugs happy

* Fix double store name announcement
2023-05-17 21:15:56 +02:00
Sylvia van Os
ebc2bfcbbb Merge pull request #1295 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-16 20:01:45 +02:00
Subhradeep Bera
b1ec67928f Translated using Weblate (Bengali (India))
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn_IN/
2023-05-16 19:51:02 +02:00
pokegh0st
2beafe954b fix: Change dialog windows to Material 3 2023-05-16 18:52:07 +03:00
pokegh0st
25b6c4d8cc fix: Change switches to Material 3 2023-05-15 19:49:00 +03:00
Sylvia van Os
a3f1b9c0b9 Merge pull request #1293 from CatimaLoyalty/create-pull-request/patch-1684044523
Update contributors
2023-05-14 09:45:50 +02:00
TheLastProject
14d5545c88 Update contributors 2023-05-14 06:08:42 +00:00
Sylvia van Os
0977b9d20a Merge pull request #1292 from CatimaLoyalty/create-pull-request/patch-1683439738
Update contributors
2023-05-07 10:38:07 +02:00
Sylvia van Os
bad0990dfb Merge pull request #1291 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-05-07 10:37:50 +02:00
TheLastProject
98c34abd66 Update contributors 2023-05-07 06:08:58 +00:00
Clxff Heraldo
b4d1463453 Translated using Weblate (Indonesian)
Currently translated at 94.0% (110 of 117 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/id/
2023-05-07 06:54:09 +02:00
dependabot[bot]
659b86e31a Bump org.robolectric:robolectric from 4.10.1 to 4.10.2
Bumps [org.robolectric:robolectric](https://github.com/robolectric/robolectric) from 4.10.1 to 4.10.2.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.10.1...robolectric-4.10.2)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-05 02:58:25 +00:00
Sylvia van Os
d63e269172 Merge pull request #1286 from CatimaLoyalty/dependabot/gradle/org.robolectric-robolectric-4.10.1
Bump org.robolectric:robolectric from 4.10 to 4.10.1
2023-05-03 18:17:01 +02:00
dependabot[bot]
77aa768c5c Bump org.robolectric:robolectric from 4.10 to 4.10.1
Bumps [org.robolectric:robolectric](https://github.com/robolectric/robolectric) from 4.10 to 4.10.1.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.10...robolectric-4.10.1)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-03 02:58:28 +00:00
Sylvia van Os
8c74d4c2d0 Merge pull request #1283 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-04-30 13:44:34 +02:00
Sylvia van Os
a6280108ec Delete invalid translation 2023-04-30 13:37:44 +02:00
Sylvia van Os
829630219f Merge pull request #1284 from CatimaLoyalty/create-pull-request/patch-1682832840
Update contributors
2023-04-30 11:11:14 +02:00
TheLastProject
22a736d7fd Update contributors 2023-04-30 05:34:00 +00:00
Gael Caraballo
4418492e7c Translated using Weblate (Catalan)
Currently translated at 19.3% (54 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ca/
2023-04-30 06:52:58 +02:00
Cap Amr Karam
c21e12bbf0 Translated using Weblate (Arabic)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-04-30 06:52:58 +02:00
liva
9af05be128 Translated using Weblate (Latvian)
Currently translated at 98.2% (274 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lv/
2023-04-30 06:52:58 +02:00
Sylvia van Os
e036443233 Merge pull request #1280 from CatimaLoyalty/create-pull-request/patch-1682233171
Update contributors
2023-04-23 11:01:43 +02:00
TheLastProject
7e605f284d Update contributors 2023-04-23 06:59:30 +00:00
Sylvia van Os
e712b8e18d Update fastlane 2023-04-19 17:44:53 +02:00
Sylvia van Os
2ff137ee04 Merge pull request #1278 from CatimaLoyalty/simplify_tests
Move all import unit test strings to their own files
2023-04-18 18:42:15 +02:00
Sylvia van Os
3b45802a7f Move all import unit test strings to their own files
They should've been files from the start, because you import files, not
text string.
2023-04-17 20:48:27 +02:00
Sylvia van Os
0de4847f6a Merge pull request #1276 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-04-16 22:02:19 +02:00
Projjal Moitra
47e2566043 Translated using Weblate (Bengali (India))
Currently translated at 78.4% (219 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn_IN/
2023-04-16 20:49:48 +02:00
Sylvia van Os
18c17796b9 Merge pull request #1275 from CatimaLoyalty/fix/unitTestsTarget
Ensure unit tests use targetSdk instead of API 23 (Android 6)
2023-04-16 16:11:34 +02:00
Sylvia van Os
4b2b999653 Ensure unit tests use targetSdk instead of API 23 (Android 6) 2023-04-16 15:20:30 +02:00
Sylvia van Os
3b51121c9e Merge pull request #1274 from CatimaLoyalty/create-pull-request/patch-1681625007
Update contributors
2023-04-16 09:45:59 +02:00
TheLastProject
2fc9581643 Update contributors 2023-04-16 06:03:27 +00:00
Sylvia van Os
68f3f37e23 Merge pull request #1272 from CatimaLoyalty/fix/ci
Fix CI build
2023-04-14 21:10:04 +02:00
Sylvia van Os
38658d0aa7 Fix CI build 2023-04-14 21:02:53 +02:00
Sylvia van Os
339750e97c Update AGP to 8.0.0 2023-04-14 20:56:29 +02:00
Sylvia van Os
510995a5c5 Release Catima 2.22.1 2023-04-14 18:38:48 +02:00
Sylvia van Os
a039d5de9e Merge pull request #1270 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-04-14 18:10:52 +02:00
Projjal Moitra
df11bd8f69 Translated using Weblate (Bengali (India))
Currently translated at 73.8% (206 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn_IN/
2023-04-14 17:48:15 +02:00
Sylvia van Os
17c80573bd Merge pull request #1269 from CatimaLoyalty/dependabot/gradle/org.robolectric-robolectric-4.10
Bump org.robolectric:robolectric from 4.9.2 to 4.10
2023-04-12 17:36:52 +02:00
dependabot[bot]
bc71c02e87 Bump org.robolectric:robolectric from 4.9.2 to 4.10
Bumps [org.robolectric:robolectric](https://github.com/robolectric/robolectric) from 4.9.2 to 4.10.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.9.2...robolectric-4.10)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-12 02:59:34 +00:00
Sylvia van Os
d892fe40ba Merge pull request #1268 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-04-11 18:08:38 +02:00
SC
06839f6ddb Translated using Weblate (Portuguese)
Currently translated at 100.0% (117 of 117 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2023-04-11 16:54:22 +02:00
Projjal Moitra
ee57703ffc Translated using Weblate (Bengali (India))
Currently translated at 72.0% (201 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn_IN/
2023-04-11 16:54:22 +02:00
solokot
e780f5fb87 Translated using Weblate (Russian)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-04-11 16:54:22 +02:00
Sylvia van Os
6b9a0a0696 Merge pull request #1266 from CatimaLoyalty/deps/update_spotbugs
Update spotbugs
2023-04-10 22:38:01 +02:00
Sylvia van Os
6653a940ed Make spotbugs happy 2023-04-10 21:36:35 +02:00
Sylvia van Os
47821752f0 Merge pull request #1267 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-04-10 13:19:47 +02:00
Sylvia van Os
bf05bd7e56 Fix lint 2023-04-10 13:12:10 +02:00
Projjal Moitra
2dd622b9c4 Translated using Weblate (Bengali (India))
Currently translated at 68.1% (190 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn_IN/
2023-04-10 09:53:13 +02:00
Sylvia van Os
643527a7fb Translated using Weblate (Bengali (India))
Currently translated at 68.1% (190 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn_IN/
2023-04-10 09:53:13 +02:00
Slávek Banko
0aae4c9c64 Translated using Weblate (Czech)
Currently translated at 100.0% (117 of 117 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-04-10 09:53:13 +02:00
solokot
14c5b756f7 Translated using Weblate (Russian)
Currently translated at 100.0% (117 of 117 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-04-10 09:53:13 +02:00
Sylvia van Os
ded3c63ec5 Translated using Weblate (Bengali)
Currently translated at 31.1% (87 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn/
2023-04-10 09:53:13 +02:00
يوسف لطفي
e3a22e425b Translated using Weblate (Arabic)
Currently translated at 98.5% (275 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-04-10 09:53:13 +02:00
Projjal Moitra
275d387f3c Translated using Weblate (Bengali (India))
Currently translated at 62.7% (175 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn_IN/
2023-04-10 09:53:13 +02:00
Mobashir Raihan
fbbad75c15 Translated using Weblate (Bengali)
Currently translated at 31.5% (88 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn/
2023-04-10 09:53:13 +02:00
Sylvia van Os
a55e9da067 Merge pull request #1265 from CatimaLoyalty/create-pull-request/patch-1681019014
Update contributors
2023-04-09 08:52:12 +02:00
TheLastProject
a5116395c8 Update contributors 2023-04-09 05:43:33 +00:00
dependabot[bot]
5cf41ed664 Bump com.github.spotbugs from 4.7.5 to 5.0.14
Bumps com.github.spotbugs from 4.7.5 to 5.0.14.

---
updated-dependencies:
- dependency-name: com.github.spotbugs
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-05 16:44:16 +00:00
Sylvia van Os
bbde3ec3b8 Merge pull request #1260 from CatimaLoyalty/create-pull-request/patch-1680713019
Update Fastlane changelogs
2023-04-05 18:43:53 +02:00
TheLastProject
db56d56e3b Update Fastlane changelogs 2023-04-05 16:43:39 +00:00
Sylvia van Os
f4c0628366 Merge pull request #1259 from CatimaLoyalty/library_updates
Update all libraries
2023-04-05 18:43:20 +02:00
Sylvia van Os
1e6641a884 Disable MissingQuantity due to Weblate bug
See https://github.com/WeblateOrg/weblate/issues/7520
2023-04-04 22:57:54 +02:00
Sylvia van Os
b9bd3f5967 Update all libraries 2023-04-04 22:22:51 +02:00
Sylvia van Os
28eaac0c67 Merge pull request #1257 from CatimaLoyalty/create-pull-request/patch-1680414497
Update contributors
2023-04-02 09:59:58 +02:00
TheLastProject
5690ca03e7 Update contributors 2023-04-02 05:48:17 +00:00
Sylvia van Os
71f7b21112 Merge pull request #1256 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-31 19:54:27 +02:00
Slávek Banko
f9ece83f2b Translated using Weblate (Czech)
Currently translated at 100.0% (116 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-03-30 17:42:01 +02:00
Sylvia van Os
3bab0f43eb Merge pull request #1255 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-26 14:53:46 +02:00
SC
941fa929dd Translated using Weblate (Portuguese)
Currently translated at 100.0% (116 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2023-03-26 14:42:11 +02:00
Szia Tomi
46846d2448 Translated using Weblate (Hungarian)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hu/
2023-03-26 14:42:11 +02:00
Sylvia van Os
7b7c1b88b9 Merge pull request #1254 from CatimaLoyalty/create-pull-request/patch-1679813344
Update contributors
2023-03-26 12:33:46 +02:00
TheLastProject
0926bb71e1 Update contributors 2023-03-26 06:49:04 +00:00
Sylvia van Os
cfc4ce7c3c Merge pull request #1251 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-20 12:50:12 +01:00
109247019824
1f217dd846 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-03-20 01:05:23 +01:00
Michael Moroni
6c74b95e90 Translated using Weblate (Italian)
Currently translated at 62.0% (72 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/it/
2023-03-20 01:05:23 +01:00
Denis Shilin
9fca77d561 Translated using Weblate (Russian)
Currently translated at 100.0% (116 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-03-20 01:05:23 +01:00
Altons
1f0873aab4 Translated using Weblate (French)
Currently translated at 98.2% (114 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2023-03-20 01:05:23 +01:00
Sylvia van Os
ca3a09740a Merge pull request #1250 from CatimaLoyalty/create-pull-request/patch-1679204700
Update contributors
2023-03-19 11:04:38 +01:00
TheLastProject
c104de839e Update contributors 2023-03-19 05:45:00 +00:00
Sylvia van Os
0f4380c1e2 Merge pull request #1249 from CatimaLoyalty/fix/stocard_export_name
Fix Stocard export filenames
2023-03-18 17:59:46 +01:00
Sylvia van Os
64e3b047d9 Fix Stocard export filenames
Stocard renamed their exports to no longer contain sync, only your user
id.
2023-03-18 17:48:53 +01:00
Sylvia van Os
729639e0e6 Release Catima 2.22.0 2023-03-18 17:01:58 +01:00
Sylvia van Os
3e79147673 Merge pull request #1247 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-18 15:39:46 +01:00
Tom Sawyer
59a656c422 Translated using Weblate (Swedish)
Currently translated at 2.5% (3 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/sv/
2023-03-18 15:34:29 +01:00
Altons
bdf8994fed Translated using Weblate (French)
Currently translated at 97.4% (113 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2023-03-18 15:34:29 +01:00
Sylvia van Os
3aa595083b Show new Valid from feature in screenshots 2023-03-17 23:33:41 +01:00
Sylvia van Os
37f1183208 Merge pull request #1246 from CatimaLoyalty/create-pull-request/patch-1679091521
Update Fastlane changelogs
2023-03-17 23:19:21 +01:00
TheLastProject
839496aa04 Update Fastlane changelogs 2023-03-17 22:18:40 +00:00
Sylvia van Os
4a7a6b109c Merge pull request #1245 from CatimaLoyalty/fix/stocard_import
Fix Stocard import
2023-03-17 23:18:22 +01:00
Sylvia van Os
2b2d5ca7cf Fix Stocard import 2023-03-17 23:09:00 +01:00
Sylvia van Os
463af746fa Merge pull request #1244 from CatimaLoyalty/create-pull-request/patch-1678989883
Update Fastlane changelogs
2023-03-16 19:05:30 +01:00
TheLastProject
d75b79fce4 Update Fastlane changelogs 2023-03-16 18:04:43 +00:00
Sylvia van Os
2ec29da6b1 Merge pull request #1243 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-16 19:04:26 +01:00
ahmed-awad26
e80bebe887 Translated using Weblate (Arabic)
Currently translated at 98.2% (274 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2023-03-16 13:38:03 +01:00
Denis Shilin
1555b3b24b Translated using Weblate (Russian)
Currently translated at 94.8% (110 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-03-16 13:38:03 +01:00
Allan Nordhøy
12f42f86a5 Translated using Weblate (English)
Currently translated at 100.0% (116 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/en/
2023-03-16 13:38:03 +01:00
Sylvia van Os
a74e17db10 Merge pull request #1241 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-13 21:39:53 +01:00
Denis Shilin
96335d3ee8 Translated using Weblate (Russian)
Currently translated at 93.9% (109 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-03-13 15:42:46 +01:00
Patrik
fb3d945f51 Translated using Weblate (Slovak)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sk/
2023-03-13 15:42:46 +01:00
Sylvia van Os
843ffbb87e Merge pull request #1240 from CatimaLoyalty/create-pull-request/patch-1678623157
Update Fastlane changelogs
2023-03-12 13:13:35 +01:00
TheLastProject
99e19321f0 Update Fastlane changelogs 2023-03-12 12:12:36 +00:00
Sylvia van Os
4e5a90eb93 Fix typo in old CHANGELOG 2023-03-12 13:12:21 +01:00
Sylvia van Os
9745ea671e Merge pull request #1238 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-12 13:10:38 +01:00
Denis Shilin
94a63d6e0c Translated using Weblate (Russian)
Currently translated at 81.0% (94 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-03-12 13:00:09 +01:00
Sylvia van Os
725ca3b9ca Merge pull request #1236 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-12 12:57:35 +01:00
Denis Shilin
46a2164143 Translated using Weblate (Russian)
Currently translated at 76.7% (89 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-03-12 12:40:30 +01:00
Sylvia van Os
5304be6f54 Translated using Weblate (English)
Currently translated at 100.0% (116 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/en/
2023-03-12 12:40:30 +01:00
Sylvia van Os
8321e796f5 Merge pull request #1235 from CatimaLoyalty/create-pull-request/patch-1678600178
Update contributors
2023-03-12 12:37:46 +01:00
TheLastProject
c1f82e90be Update contributors 2023-03-12 05:49:38 +00:00
Sylvia van Os
758f265638 Merge pull request #1234 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-09 17:57:17 +01:00
Nosnahc
590020bb6f Translated using Weblate (French)
Currently translated at 98.2% (114 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2023-03-09 10:42:20 +01:00
Sylvia van Os
f18c2a2d0c Merge pull request #1231 from CatimaLoyalty/create-pull-request/patch-1677996975
Update contributors
2023-03-05 12:55:58 +01:00
TheLastProject
3a17ee83e0 Update contributors 2023-03-05 06:16:15 +00:00
Sylvia van Os
f36d4aebb6 Merge pull request #1230 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-04 14:23:47 +01:00
Tian Jiale
71cb1cace4 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-03-04 13:39:54 +01:00
lucafont2
1e4e035281 Translated using Weblate (Italian)
Currently translated at 62.0% (72 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/it/
2023-03-04 13:39:54 +01:00
Sylvia van Os
7da4eb6587 Merge pull request #1229 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-03 13:57:26 +01:00
Tian Jiale
d454864fa7 Translated using Weblate (Chinese (Simplified))
Currently translated at 98.2% (274 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-03-03 13:36:36 +01:00
Sylvia van Os
f5e6d7be71 Merge pull request #1227 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-03-02 22:21:29 +01:00
Sylvia van Os
967a17242d Fix lint 2023-03-02 14:02:22 +01:00
Luna Jernberg
6c5dd7a713 Translated using Weblate (Swedish)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sv/
2023-03-02 09:37:09 +01:00
Alexander
139b144cb3 Translated using Weblate (Icelandic)
Currently translated at 42.2% (118 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/is/
2023-03-01 03:39:16 +01:00
Sylvia van Os
5deacf7ecc Merge pull request #1224 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-02-28 21:32:38 +01:00
Jesse Davids
6e49aea713 Translated using Weblate (Dutch)
Currently translated at 11.2% (13 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/nl/
2023-02-26 06:40:23 +01:00
Jesse Davids
68257ce3ad Translated using Weblate (Dutch)
Currently translated at 6.0% (7 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/nl/
2023-02-25 04:40:19 +01:00
Sirius Chan
149a1caeff Translated using Weblate (Chinese (Traditional))
Currently translated at 7.7% (9 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/zh_Hant/
2023-02-25 04:40:19 +01:00
Sirius Chan
07e5788cb2 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hant/
2023-02-25 04:40:19 +01:00
Sylvia van Os
c072e2e70d Merge pull request #1225 from CatimaLoyalty/dependabot/gradle/net.lingala.zip4j-zip4j-2.11.5
Bump net.lingala.zip4j:zip4j from 2.11.4 to 2.11.5
2023-02-23 15:13:43 +01:00
dependabot[bot]
0701b9b3de Bump net.lingala.zip4j:zip4j from 2.11.4 to 2.11.5
Bumps [net.lingala.zip4j:zip4j](https://github.com/srikanth-lingala/zip4j) from 2.11.4 to 2.11.5.
- [Release notes](https://github.com/srikanth-lingala/zip4j/releases)
- [Commits](https://github.com/srikanth-lingala/zip4j/compare/v2.11.4...v2.11.5)

---
updated-dependencies:
- dependency-name: net.lingala.zip4j:zip4j
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-23 02:16:17 +00:00
Sylvia van Os
f84242d97c Merge pull request #1223 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-02-15 21:10:51 +01:00
IllusiveMan196
79f35ed715 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (116 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2023-02-15 20:40:26 +01:00
Sylvia van Os
eff4f3f8df Merge pull request #1221 from CatimaLoyalty/create-pull-request/patch-1676182226
Update contributors
2023-02-12 09:32:03 +01:00
TheLastProject
ee405f670d Update contributors 2023-02-12 06:10:25 +00:00
Sylvia van Os
7dcb9b336d Merge pull request #1219 from CatimaLoyalty/dependabot/gradle/net.lingala.zip4j-zip4j-2.11.4
Bump net.lingala.zip4j:zip4j from 2.11.3 to 2.11.4
2023-02-11 18:35:03 +01:00
Sylvia van Os
923e6dc062 Merge pull request #1220 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-02-11 18:13:10 +01:00
Allan Nordhøy
2ea04e8715 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2023-02-11 06:57:05 +01:00
SC
f264941ae4 Translated using Weblate (Portuguese)
Currently translated at 100.0% (116 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2023-02-11 06:57:05 +01:00
SC
e6ef5c9bb2 Translated using Weblate (Portuguese)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2023-02-11 06:57:05 +01:00
HudobniVolk
024cc2d50e Translated using Weblate (Slovenian)
Currently translated at 27.5% (32 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/sl/
2023-02-11 06:57:05 +01:00
Brage Nesteby Reitan
48b62f6aea Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2023-02-11 06:57:05 +01:00
dependabot[bot]
ff07fe71cc Bump net.lingala.zip4j:zip4j from 2.11.3 to 2.11.4
Bumps [net.lingala.zip4j:zip4j](https://github.com/srikanth-lingala/zip4j) from 2.11.3 to 2.11.4.
- [Release notes](https://github.com/srikanth-lingala/zip4j/releases)
- [Commits](https://github.com/srikanth-lingala/zip4j/compare/v2.11.3...v2.11.4)

---
updated-dependencies:
- dependency-name: net.lingala.zip4j:zip4j
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-10 02:58:35 +00:00
Sylvia van Os
402cf57c29 Add Catalan to supported languages 2023-02-09 23:27:56 +01:00
Sylvia van Os
e19ac0d0c2 Merge pull request #1218 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-02-09 20:16:40 +01:00
Francesc Bassas i Bullich
fc5d4a6435 Translated using Weblate (Catalan)
Currently translated at 18.9% (53 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ca/
2023-02-09 19:40:22 +01:00
gittyboy-cell
50754a3430 Translated using Weblate (Indonesian)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/id/
2023-02-09 19:40:22 +01:00
HudobniVolk
0375f6dbe5 Translated using Weblate (Slovenian)
Currently translated at 26.7% (31 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/sl/
2023-02-09 19:40:22 +01:00
HudobniVolk
deb808ffb6 Translated using Weblate (Slovenian)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sl/
2023-02-09 19:40:22 +01:00
Sylvia van Os
166c1e7bc6 Merge pull request #1216 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-02-07 22:44:27 +01:00
Hamustra Scans
bfa19d0166 Translated using Weblate (Korean)
Currently translated at 37.9% (106 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ko/
2023-02-07 22:22:31 +01:00
sal0max
f92805ec64 Translated using Weblate (German)
Currently translated at 100.0% (116 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/de/
2023-02-07 22:22:31 +01:00
sal0max
73e6e9f34a Translated using Weblate (German)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-02-07 22:22:31 +01:00
Francesc Bassas i Bullich
6a76681412 Added translation using Weblate (Catalan) 2023-02-07 22:22:31 +01:00
Sylvia van Os
f05a5dde1e Merge pull request #1213 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-02-06 19:41:51 +01:00
gnu-ewm
4a93ba3478 Translated using Weblate (Polish)
Currently translated at 39.6% (46 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pl/
2023-02-06 17:39:42 +01:00
Michael Moroni
af43138ae9 Translated using Weblate (Italian)
Currently translated at 58.6% (68 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/it/
2023-02-06 17:39:42 +01:00
Günter Neiß
dcd6e4b9a9 Translated using Weblate (German)
Currently translated at 100.0% (116 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/de/
2023-02-06 17:39:42 +01:00
Dan
0ce2395605 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2023-02-06 17:39:42 +01:00
solokot
89dbc9e9aa Translated using Weblate (Russian)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-02-06 17:39:42 +01:00
gnu-ewm
788a8f0efe Translated using Weblate (Polish)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2023-02-06 17:39:42 +01:00
J. Lavoie
d0c9ae2a4a Translated using Weblate (Italian)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-02-06 17:39:42 +01:00
J. Lavoie
c000a8129c Translated using Weblate (French)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-02-06 17:39:42 +01:00
J. Lavoie
bfb4fdb61c Translated using Weblate (German)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-02-06 17:39:42 +01:00
Sylvia van Os
1929401d3e Merge pull request #1210 from CatimaLoyalty/create-pull-request/patch-1675576485
Update contributors
2023-02-05 12:06:41 +01:00
TheLastProject
eef13a1a91 Update contributors 2023-02-05 05:54:45 +00:00
Sylvia van Os
64f340d798 Merge pull request #1208 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-02-05 01:01:09 +01:00
Oğuz Ersen
f12422fc07 Translated using Weblate (Turkish)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2023-02-04 22:08:08 +01:00
109247019824
d78315ef12 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-02-04 22:08:08 +01:00
Jorma Karvonen
af8c3eeb54 Translated using Weblate (Finnish)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fi/
2023-02-04 22:08:08 +01:00
Slávek Banko
16e4205028 Translated using Weblate (Czech)
Currently translated at 100.0% (116 of 116 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-02-04 22:08:08 +01:00
Heimen Stoffels
399aa767d2 Translated using Weblate (Dutch)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-02-04 22:08:08 +01:00
Allan Nordhøy
96c735cf80 Translated using Weblate (Norwegian Bokmål)
Currently translated at 96.7% (270 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2023-02-04 22:08:07 +01:00
gallegonovato
50a8395ec6 Translated using Weblate (Spanish)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2023-02-04 22:08:07 +01:00
Slávek Banko
c720ca1085 Translated using Weblate (Czech)
Currently translated at 100.0% (279 of 279 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2023-02-04 22:08:07 +01:00
Sylvia van Os
d82088f66a Merge pull request #1207 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-02-04 15:51:09 +01:00
Jiri Grönroos
1fce3e17f6 Translated using Weblate (Finnish)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fi/
2023-02-04 15:35:30 +01:00
Evgeniy Khramov
569db96f81 Translated using Weblate (Russian)
Currently translated at 35.6% (41 of 115 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2023-02-04 15:35:30 +01:00
Salem Malus
b7cb1dffc1 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2023-02-04 15:35:30 +01:00
Sylvia van Os
e17fc66d35 Update dependencies (#1205)
* Update appcompat to 1.6.0

* Update constraintlayout to 2.1.4

* Update exifinterface to 1.3.5

* Update test:core to 1.5.0
2023-02-03 22:56:23 +01:00
Sylvia van Os
8dac7ae9d1 Merge pull request #1203 from CatimaLoyalty/create-pull-request/patch-1675277210
Update Fastlane changelogs
2023-02-01 19:48:43 +01:00
TheLastProject
28a0417fa8 Update Fastlane changelogs 2023-02-01 18:46:49 +00:00
Sylvia van Os
58d4bd7f47 Update CHANGELOG 2023-02-01 19:46:31 +01:00
Sylvia van Os
1779aef162 Merge pull request #1083 from vanogrid/feature/validFromField
Add Valid From field
2023-02-01 19:29:38 +01:00
Sylvia van Os
557ec68428 Fix info button being hidden when only validFrom is set 2023-02-01 19:22:22 +01:00
Sylvia van Os
96a7c8ee36 String consistency improvement 2023-02-01 19:22:22 +01:00
Alexander Ivanov
3a9b92231e Set min/max date in the DatePickerDialog when 'valid from' or 'expiry' dates are set
Signed-off-by: Alexander Ivanov <vanogrid@gmail.com>
2023-02-01 19:22:22 +01:00
Alexander Ivanov
f1753ea943 Add Valid From field
Signed-off-by: Alexander Ivanov <vanogrid@gmail.com>
2023-02-01 19:22:20 +01:00
Sylvia van Os
36ab78ec6e Merge pull request #1202 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-30 17:55:11 +01:00
Cliff Heraldo
8a3a782558 Translated using Weblate (Indonesian)
Currently translated at 20.0% (23 of 115 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/id/
2023-01-30 16:41:04 +01:00
Cliff Heraldo
2c5606bf0a Translated using Weblate (Indonesian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/id/
2023-01-30 16:41:04 +01:00
gnu-ewm
5eb36aad5b Translated using Weblate (Polish)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2023-01-30 16:41:04 +01:00
Sylvia van Os
b028d32e2c Merge pull request #1200 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-29 13:30:29 +01:00
Sylvia van Os
dfefdda9f9 Translated using Weblate (Romanian)
Currently translated at 1.7% (2 of 115 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ro/
2023-01-29 13:09:25 +01:00
Sylvia van Os
bc1cc68f27 Update Fastlane 2023-01-29 13:05:11 +01:00
Sylvia van Os
386a5f75b0 Merge pull request #1198 from CatimaLoyalty/create-pull-request/patch-1674969594
Update contributors
2023-01-29 12:04:10 +01:00
Sylvia van Os
d30a9fd1e5 Merge pull request #1197 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-29 12:02:46 +01:00
TheLastProject
0c8e5576b8 Update contributors 2023-01-29 05:19:54 +00:00
Cliff Heraldo
93e40c08aa Translated using Weblate (Indonesian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/id/
2023-01-29 02:19:44 +01:00
HudobniVolk
24eb1e9627 Translated using Weblate (Slovenian)
Currently translated at 25.2% (29 of 115 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/sl/
2023-01-29 00:54:59 +01:00
Dan
19e6b8bea9 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (115 of 115 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2023-01-29 00:54:59 +01:00
HudobniVolk
87f844943e Translated using Weblate (Slovenian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sl/
2023-01-29 00:54:59 +01:00
J. Lavoie
718738ff78 Translated using Weblate (French)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2023-01-29 00:54:59 +01:00
J. Lavoie
d7bb019068 Translated using Weblate (German)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2023-01-29 00:54:59 +01:00
Sylvia van Os
f925404ab7 Revert "Fix filename"
This reverts commit 38495546e0.
2023-01-27 21:50:34 +01:00
Sylvia van Os
38495546e0 Fix filename 2023-01-27 19:19:26 +01:00
Sylvia van Os
36e7ea5b20 Release Catima 2.21.2 2023-01-27 18:36:24 +01:00
Sylvia van Os
85d53ae3c7 Merge pull request #1194 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-27 18:07:26 +01:00
Sylvia van Os
e9b6b5682e Translated using Weblate (Dutch)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-01-27 18:01:46 +01:00
SC
0abc583d10 Translated using Weblate (Portuguese)
Currently translated at 100.0% (115 of 115 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2023-01-27 17:56:35 +01:00
SC
8c91d30b4c Translated using Weblate (Portuguese)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2023-01-27 17:56:31 +01:00
Oğuz Ersen
76e8715ab2 Translated using Weblate (Turkish)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2023-01-27 17:56:31 +01:00
Quentin PAGÈS
f5f2edca75 Translated using Weblate (Occitan)
Currently translated at 0.8% (1 of 115 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/oc/
2023-01-27 17:56:31 +01:00
109247019824
e648e22ecc Translated using Weblate (Bulgarian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2023-01-27 17:56:31 +01:00
HudobniVolk
02b020e9e5 Translated using Weblate (Slovenian)
Currently translated at 21.7% (25 of 115 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/sl/
2023-01-27 17:56:31 +01:00
Slávek Banko
e7dc3cd511 Translated using Weblate (Czech)
Currently translated at 100.0% (115 of 115 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2023-01-27 17:56:30 +01:00
Michael Moroni
eb3ac53e46 Translated using Weblate (Italian)
Currently translated at 56.5% (65 of 115 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/it/
2023-01-27 17:56:26 +01:00
Dan
dd683b4a8c Translated using Weblate (Ukrainian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2023-01-27 17:56:24 +01:00
solokot
e90ba5d2db Translated using Weblate (Russian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2023-01-27 17:56:24 +01:00
Heimen Stoffels
07cff7eac4 Translated using Weblate (Dutch)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2023-01-27 17:56:24 +01:00
Michael Moroni
3eea18fc82 Translated using Weblate (Italian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-01-27 17:56:23 +01:00
gallegonovato
5d3ceb6d49 Translated using Weblate (Spanish)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2023-01-27 17:56:23 +01:00
Slávek Banko
3dc7a25d88 Translated using Weblate (Czech)
Currently translated at 100.0% (275 of 275 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2023-01-27 17:56:23 +01:00
Sylvia van Os
95e02d1646 Merge pull request #1191 from CatimaLoyalty/dependabot/gradle/net.lingala.zip4j-zip4j-2.11.3
Bump zip4j from 2.11.2 to 2.11.3
2023-01-26 19:15:58 +01:00
Sylvia van Os
81ecf8ba92 Merge pull request #1193 from CatimaLoyalty/security/gradle_wrapper_verification
Add Gradle wrapper verification
2023-01-26 19:10:13 +01:00
Sylvia van Os
bf0e1a2e77 Add Gradle wrapper verification 2023-01-26 19:02:04 +01:00
Sylvia van Os
4d1c9244fd Merge pull request #1192 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-26 18:48:57 +01:00
HudobniVolk
1f1e523100 Translated using Weblate (Slovenian)
Currently translated at 20.1% (23 of 114 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/sl/
2023-01-26 17:55:06 +01:00
HudobniVolk
cb32cf9e52 Translated using Weblate (Slovenian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sl/
2023-01-26 17:55:06 +01:00
dependabot[bot]
af812d8cda Bump zip4j from 2.11.2 to 2.11.3
Bumps [zip4j](https://github.com/srikanth-lingala/zip4j) from 2.11.2 to 2.11.3.
- [Release notes](https://github.com/srikanth-lingala/zip4j/releases)
- [Commits](https://github.com/srikanth-lingala/zip4j/compare/v2.11.2...v2.11.3)

---
updated-dependencies:
- dependency-name: net.lingala.zip4j:zip4j
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-26 02:03:45 +00:00
Sylvia van Os
c8a7addc52 Merge pull request #1190 from CatimaLoyalty/create-pull-request/patch-1674683901
Update Fastlane changelogs
2023-01-25 22:58:43 +01:00
TheLastProject
3e64d7c5ad Update Fastlane changelogs 2023-01-25 21:58:21 +00:00
Sylvia van Os
277462a939 Update CHANGELOG 2023-01-25 22:58:03 +01:00
Sylvia van Os
24623d5c58 Merge pull request #1189 from CatimaLoyalty/sdk/33
Update targetSdk to 33
2023-01-25 22:57:34 +01:00
Sylvia van Os
4b25b7ad39 Update targetSdk to 33 2023-01-25 19:59:08 +01:00
Sylvia van Os
4016d5499b Merge pull request #1188 from CatimaLoyalty/sdk/32
Update targetSdk to 32
2023-01-25 19:40:53 +01:00
Sylvia van Os
d8b96a8c5f Update targetSdk to 32 2023-01-25 19:36:09 +01:00
Sylvia van Os
614753303f Fix crash when permissionRequestResult gets cancelled 2023-01-25 18:30:47 +01:00
Sylvia van Os
50a344b97f Merge branch 'main' of github.com:TheLastProject/loyalty-card-locker 2023-01-25 18:23:54 +01:00
Sylvia van Os
2cd6da6ffc Fix crash on invalid import URI 2023-01-25 18:13:58 +01:00
Sylvia van Os
c03fba133f Merge pull request #1187 from CatimaLoyalty/create-pull-request/patch-1674662809
Update Fastlane changelogs
2023-01-25 17:32:55 +01:00
TheLastProject
f3cba588f6 Update Fastlane changelogs 2023-01-25 16:06:48 +00:00
Sylvia van Os
ad364ad0ac Merge branch 'main' of github.com:TheLastProject/loyalty-card-locker 2023-01-25 17:06:19 +01:00
Sylvia van Os
f4cff85d93 Document permission change 2023-01-25 17:06:08 +01:00
Sylvia van Os
cbc86ff131 Merge pull request #1185 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-24 23:31:38 +01:00
Sylvia van Os
5f733474a9 Merge pull request #1186 from CatimaLoyalty/fix/permissionRefactor
Refactor permission code
2023-01-24 23:28:38 +01:00
Sylvia van Os
89a13cecf5 Create extra result function to work around onPermissionResult not existing on Android 5 2023-01-24 23:14:57 +01:00
Sylvia van Os
fd2400eaf5 Refactor permission code
- Remove write permission (was never needed)
- Only use read permission for Android 5 and 6
- Simplify logic by mocking a valid permission result if permission
  already granted
2023-01-24 20:44:17 +01:00
Sylvia van Os
9598f2f4ff Translated using Weblate (Slovenian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sl/
2023-01-24 07:53:22 +01:00
IllusiveMan196
acca53787c Translated using Weblate (Ukrainian)
Currently translated at 100.0% (114 of 114 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2023-01-23 02:12:44 +01:00
HudobniVolk
060e360344 Translated using Weblate (Slovenian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sl/
2023-01-23 02:12:44 +01:00
Sylvia van Os
9ef014e05c Fix main rename breaking github scripts 2023-01-22 13:12:25 +01:00
Sylvia van Os
4cb27d3bd5 Merge pull request #1182 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-20 17:00:24 +01:00
stone wow
95e21cc112 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2023-01-20 16:09:32 +01:00
Sylvia van Os
d5f915a290 Merge pull request #1181 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-18 22:03:04 +01:00
HudobniVolk
42e89bb5cc Translated using Weblate (Slovenian)
Currently translated at 19.2% (22 of 114 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/sl/
2023-01-18 21:51:11 +01:00
Sylvia van Os
048fb48300 Fix reproducible build script 2023-01-16 20:32:42 +01:00
Sylvia van Os
b1c82dbae0 Merge pull request #1159 from CatimaLoyalty/feature/rb
Add script to build reproducibly
2023-01-16 19:48:56 +01:00
Sylvia van Os
ea8c6f96f7 Merge pull request #1180 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-16 19:05:26 +01:00
HudobniVolk
201ec78694 Translated using Weblate (Slovenian)
Currently translated at 7.0% (8 of 114 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/sl/
2023-01-16 18:53:07 +01:00
Dan
05a03455c1 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2023-01-16 18:53:07 +01:00
HudobniVolk
63f4cbb8ca Translated using Weblate (Slovenian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sl/
2023-01-16 18:53:07 +01:00
Sylvia van Os
a444607476 Merge pull request #1178 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-14 23:58:58 +01:00
Giovanni Donisi
89102ad0bf Translated using Weblate (Italian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2023-01-14 23:12:40 +01:00
Sylvia van Os
d2623b8690 Merge pull request #1177 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-13 23:08:03 +01:00
Jiri Grönroos
80ddd48184 Translated using Weblate (Finnish)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fi/
2023-01-13 18:50:22 +01:00
Sylvia van Os
410a619a70 Merge pull request #1175 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-08 12:04:45 +01:00
Jiri Grönroos
1771f42860 Translated using Weblate (Finnish)
Currently translated at 95.9% (263 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fi/
2023-01-08 11:51:01 +01:00
Sylvia van Os
1e7af7ab4e Merge pull request #1174 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2023-01-06 13:59:27 +01:00
Piotr Strebski
f4c5af04e3 Translated using Weblate (Polish)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2023-01-06 13:51:24 +01:00
Sylvia van Os
5bcd2cdc32 Merge pull request #1171 from CatimaLoyalty/dependabot/gradle/org.robolectric-robolectric-4.9.2
Bump robolectric from 4.9.1 to 4.9.2
2022-12-28 06:48:50 +00:00
dependabot[bot]
c69a5ae4d2 Bump robolectric from 4.9.1 to 4.9.2
Bumps [robolectric](https://github.com/robolectric/robolectric) from 4.9.1 to 4.9.2.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.9.1...robolectric-4.9.2)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-28 02:04:26 +00:00
Sylvia van Os
6bd750a60b Add script to build reproducibly 2022-12-22 22:57:55 +01:00
Sylvia van Os
8d77cc3565 Merge pull request #1169 from CatimaLoyalty/dependabot/gradle/org.robolectric-robolectric-4.9.1
Bump robolectric from 4.9 to 4.9.1
2022-12-21 12:25:35 +00:00
Sylvia van Os
7a99e0056d Merge pull request #1170 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-12-20 22:14:48 +00:00
Shailendra Maurya
03e07bc48d Translated using Weblate (Hindi)
Currently translated at 61.6% (169 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hi/
2022-12-20 22:43:29 +01:00
dependabot[bot]
460d6c2b71 Bump robolectric from 4.9 to 4.9.1
Bumps [robolectric](https://github.com/robolectric/robolectric) from 4.9 to 4.9.1.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.9...robolectric-4.9.1)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-20 02:04:38 +00:00
Sylvia van Os
9f946094db Merge pull request #1168 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-12-18 21:06:09 +00:00
wmilan 17
4e92f82176 Translated using Weblate (Hungarian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hu/
2022-12-18 21:48:04 +01:00
Sylvia van Os
7b905ac120 Translated using Weblate (English)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/en/
2022-12-17 11:46:57 +01:00
Tomasz Cukier
55c5ec929c Translated using Weblate (English)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/en/
2022-12-17 11:46:57 +01:00
Sylvia van Os
5441231f03 Merge pull request #1165 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-12-14 22:55:09 +01:00
ssantos
1818d24bc0 Translated using Weblate (Portuguese)
Currently translated at 100.0% (114 of 114 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2022-12-14 22:50:15 +01:00
Sylvia van Os
ca88c070c3 Merge pull request #1163 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-12-13 23:19:14 +01:00
gallegonovato
1be387c4ec Translated using Weblate (Spanish)
Currently translated at 11.4% (13 of 114 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/es/
2022-12-13 20:50:09 +01:00
Sylvia van Os
fa3a956d69 Merge pull request #1162 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-12-12 17:07:13 +01:00
gallegonovato
8fd244e3a3 Translated using Weblate (Spanish)
Currently translated at 8.7% (10 of 114 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/es/
2022-12-12 15:51:47 +01:00
Sylvia van Os
a0e2fe11dd Merge pull request #1160 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-12-11 15:50:06 +01:00
gallegonovato
893f34e72a Translated using Weblate (Spanish)
Currently translated at 7.0% (8 of 114 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/es/
2022-12-11 14:49:57 +01:00
Sylvia van Os
cf13a9fc60 Merge pull request #1158 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-12-09 22:00:23 +01:00
IllusiveMan196
c6e6d96313 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (114 of 114 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2022-12-09 21:50:03 +01:00
Sylvia van Os
20ed9cac88 Update Google Play badge
See https://github.com/cvzi/play
2022-12-06 19:34:51 +01:00
Sylvia van Os
ae6bd937a9 Move to main 2022-12-06 19:33:04 +01:00
Sylvia van Os
e4b69e5cc5 Release Catima 2.21.1 2022-12-06 19:13:02 +01:00
Sylvia van Os
5b1062b8d1 Merge pull request #1155 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-12-06 18:41:27 +01:00
Slávek Banko
e06009852e Translated using Weblate (Czech)
Currently translated at 100.0% (114 of 114 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2022-12-06 18:35:01 +01:00
Sylvia van Os
50268f6bd1 Merge pull request #1154 from CatimaLoyalty/create-pull-request/patch-1670271647
Update Fastlane changelogs
2022-12-05 21:21:13 +01:00
TheLastProject
a85e28d46d Update Fastlane changelogs 2022-12-05 20:20:47 +00:00
Sylvia van Os
78b6be911f Merge pull request #1153 from CatimaLoyalty/fix/localeQuickSpend
Fix/locale quick spend
2022-12-05 21:20:32 +01:00
Sylvia van Os
bb80478650 Update CHANGELOG 2022-12-05 21:14:07 +01:00
Sylvia van Os
e0c06cc480 Fix locale separator in quick spend dialog 2022-12-05 21:14:00 +01:00
Sylvia van Os
b8a508649c Merge pull request #1151 from CatimaLoyalty/create-pull-request/patch-1670133932
Update contributors
2022-12-04 09:38:51 +01:00
TheLastProject
a8ce37d936 Update contributors 2022-12-04 06:05:31 +00:00
Sylvia van Os
43015abbad Merge pull request #1147 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-12-02 08:09:44 +01:00
Mario M. Viscovich
47c8dff52d Translated using Weblate (Croatian)
Currently translated at 38.3% (105 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hr/
2022-12-02 03:47:15 +01:00
Sylvia van Os
436cf7a068 Merge pull request #1146 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-11-29 20:53:31 +01:00
IllusiveMan196
31cc3cd5d0 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (113 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2022-11-29 20:47:20 +01:00
gallegonovato
3c11c2ef1e Translated using Weblate (Spanish)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2022-11-29 20:47:15 +01:00
Sylvia van Os
fac70f0210 Merge pull request #1145 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-11-28 07:41:24 +01:00
IllusiveMan196
6e99a29312 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (113 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2022-11-28 02:49:19 +01:00
IllusiveMan196
5b67ecf157 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2022-11-28 02:49:19 +01:00
Sylvia van Os
312470cf20 Merge pull request #1144 from CatimaLoyalty/create-pull-request/patch-1669529773
Update contributors
2022-11-27 09:34:00 +01:00
TheLastProject
4371f46ff8 Update contributors 2022-11-27 06:16:12 +00:00
Sylvia van Os
5468415b04 Merge pull request #1143 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-11-26 16:40:26 +01:00
CherryMonster222
6a68ad5d19 Translated using Weblate (Arabic)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2022-11-26 15:48:38 +01:00
IllusiveMan196
7576505044 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (113 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2022-11-26 15:48:38 +01:00
Sylvia van Os
b34a43902a Merge pull request #1141 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-11-24 18:34:31 +01:00
안재범
d3524a50a3 Translated using Weblate (Korean)
Currently translated at 38.6% (106 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ko/
2022-11-24 16:46:55 +01:00
Sylvia van Os
6508a6d5f7 Merge pull request #1116 from pfaffenrodt/feature/pick-image-file
Add support to pick image from content provider
2022-11-22 19:04:48 +01:00
Sylvia van Os
49a6cf8ae3 Merge pull request #1140 from CatimaLoyalty/create-pull-request/patch-1668925172
Update contributors
2022-11-20 10:21:12 +01:00
TheLastProject
b4238e0072 Update contributors 2022-11-20 06:19:31 +00:00
Sylvia van Os
374170bf05 Merge pull request #1139 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-11-19 23:17:41 +01:00
Jacek
ab11345c3d Translated using Weblate (Polish)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2022-11-19 21:47:02 +01:00
Sylvia van Os
10498ce1a4 Prevent NullPointerException in onBackPressed
This crash seems to somehow only happen on Huawei and Xiaomi devices.
While fairly rare, it is the most common Catima crash currently logged
on Google Play Console (8 crashes over the last 28 days).

While I don't understand how this would happen, I think it should be
relatively safe to assume that if the searchview is null the user isn't
currently searching so running the normal back code should always be the
expected behaviour.
2022-11-16 21:42:52 +01:00
Sylvia van Os
28901487ff Merge pull request #1138 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-11-15 23:17:53 +01:00
Sylvia van Os
8414f51ee8 Translated using Weblate (Polish)
Currently translated at 39.8% (45 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pl/
2022-11-15 21:48:36 +01:00
Slávek Banko
94f8adb6d7 Translated using Weblate (Czech)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2022-11-15 21:48:35 +01:00
Sylvia van Os
844a921a1a Merge pull request #1134 from CatimaLoyalty/create-pull-request/patch-1668320636
Update contributors
2022-11-14 19:47:10 +01:00
Sylvia van Os
ae8be3eda8 Merge pull request #1135 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-11-14 06:27:25 +01:00
gallegonovato
c4c15dbef8 Translated using Weblate (Spanish)
Currently translated at 3.5% (4 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/es/
2022-11-13 23:48:54 +01:00
Evgeniy Khramov
ac72035500 Translated using Weblate (Russian)
Currently translated at 32.7% (37 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2022-11-13 23:48:54 +01:00
Freddo espresso
abff3bcd39 Translated using Weblate (Greek)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/el/
2022-11-13 23:48:54 +01:00
TheLastProject
05aea28602 Update contributors 2022-11-13 06:23:55 +00:00
Sylvia van Os
e4c4dbf5a0 Merge pull request #1133 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-11-11 23:02:41 +01:00
Sylvia van Os
bb2393b6c6 Translated using Weblate (Polish)
Currently translated at 99.2% (272 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2022-11-11 22:49:16 +01:00
Gediminas Murauskas
fb330d16b5 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2022-11-11 22:49:16 +01:00
Slávek Banko
c8f1b986ec Translated using Weblate (Czech)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2022-11-11 22:49:15 +01:00
Євгеній Нешта
49a2c93d28 Translated using Weblate (Ukrainian)
Currently translated at 99.1% (112 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2022-11-09 20:48:23 +01:00
Євгеній Нешта
0992ac4099 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2022-11-09 20:48:23 +01:00
truestorybaby
9ff29af616 Translated using Weblate (Polish)
Currently translated at 99.2% (272 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2022-11-09 20:48:23 +01:00
Sylvia van Os
fbc696047b Merge pull request #1124 from CatimaLoyalty/dependabot/gradle/com.google.zxing-core-3.5.1
Bump core from 3.5.0 to 3.5.1
2022-11-06 11:21:30 +01:00
Sylvia van Os
08a4d4b114 Release Catima 2.21.0 2022-11-06 11:16:07 +01:00
Sylvia van Os
329056301b Add Hindi to language picker 2022-11-06 10:53:39 +01:00
Sylvia van Os
fac8da69e7 Merge pull request #1127 from CatimaLoyalty/create-pull-request/patch-1667715884
Update contributors
2022-11-06 08:33:33 +01:00
TheLastProject
fad9eed43e Update contributors 2022-11-06 06:24:44 +00:00
Sylvia van Os
58a18bdd7b Merge pull request #1126 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-11-05 11:35:49 +01:00
Eric
90cb524560 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2022-11-05 11:05:28 +01:00
Sylvia van Os
ef4c57ce29 Merge pull request #1125 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-11-04 08:21:51 +01:00
Jean Mareilles
8872fad73e Translated using Weblate (French)
Currently translated at 99.1% (112 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2022-11-04 06:12:38 +01:00
dependabot[bot]
63c3330571 Bump core from 3.5.0 to 3.5.1
Bumps [core](https://github.com/zxing/zxing) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/zxing/zxing/releases)
- [Changelog](https://github.com/zxing/zxing/blob/master/CHANGES)
- [Commits](https://github.com/zxing/zxing/compare/zxing-3.5.0...zxing-3.5.1)

---
updated-dependencies:
- dependency-name: com.google.zxing:core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-03 02:03:03 +00:00
Sylvia van Os
37d1bb9477 Merge pull request #1118 from pfaffenrodt/feature/clean-about
Cleaning code in about page
2022-11-01 22:00:55 +01:00
Pfaffenrodt
8a67d1d02b Rename open to openBrowser 2022-11-01 10:52:11 +01:00
Pfaffenrodt
6f777068ab Remove map from id to link. make link handler more solid 2022-10-30 21:04:35 +01:00
Sylvia van Os
8607e1c23c Merge pull request #1120 from CatimaLoyalty/create-pull-request/patch-1667112218
Update contributors
2022-10-30 11:17:13 +01:00
Sylvia van Os
04a319066c Merge pull request #1119 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-10-30 11:02:06 +01:00
Sylvia van Os
39f89ca943 Also replace "smart quotes" in broken translation 2022-10-30 10:33:03 +01:00
Sylvia van Os
1092d7a9ba Fix broken translation 2022-10-30 10:29:30 +01:00
TheLastProject
b54052182d Update contributors 2022-10-30 06:43:37 +00:00
SC
b971c392cf Translated using Weblate (Portuguese)
Currently translated at 100.0% (113 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2022-10-29 21:01:09 +02:00
SC
cec9306387 Translated using Weblate (Portuguese)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2022-10-29 21:01:09 +02:00
元气
f6a5cbbf80 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2022-10-29 21:01:09 +02:00
pfaffenrodt
4b55c414f3 Fix spacings in custom view of alert dialogs (#1117) 2022-10-29 15:12:45 +02:00
Pfaffenrodt
1aafcdc6ae Revert to reading file. Missing encoding 2022-10-29 14:44:02 +02:00
Pfaffenrodt
332e37b2eb Extract page title to about content 2022-10-29 14:19:36 +02:00
Pfaffenrodt
dff33d3bab Simplify reading contributors file 2022-10-29 14:19:36 +02:00
Pfaffenrodt
85ddc9689c Extract common html link of third party info 2022-10-29 14:19:36 +02:00
Pfaffenrodt
d91c207b60 Extract last about content 2022-10-29 14:19:36 +02:00
Pfaffenrodt
653606fae3 Extract show credits dialog. remove empty listener 2022-10-29 14:19:36 +02:00
Pfaffenrodt
f5a0c8f375 Extract about content 2022-10-29 14:19:36 +02:00
Pfaffenrodt
c71019951c Extract open link handler 2022-10-29 14:19:36 +02:00
Pfaffenrodt
ed7b79ce17 Refactor AboutActivity to avoid leaks that hold activity as reference 2022-10-29 14:19:36 +02:00
Pfaffenrodt
08cfb490d4 Remove redundant title
setTitle was called twice
2022-10-29 14:19:36 +02:00
Pfaffenrodt
7d284a85bc Extract about content from onCreate 2022-10-29 14:19:36 +02:00
Pfaffenrodt
77ef0a2833 Extract same logic to enable back button of toolbar
ManageGroupActivity setDisplayShowHomeEnabled was redundant
2022-10-29 14:19:34 +02:00
Pfaffenrodt
80130654ec Remove unused field properties 2022-10-29 14:18:50 +02:00
Pfaffenrodt
e97f7c8645 Add support to pick image from content provider 2022-10-28 23:46:40 +02:00
Sylvia van Os
e489ff6a22 Merge pull request #1115 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-10-28 17:31:58 +02:00
Jean-Luc Tibaux
de549d724c Translated using Weblate (German)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2022-10-28 09:05:42 +02:00
Sylvia van Os
5fb2dbd252 Merge pull request #1111 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-10-26 18:04:56 +02:00
Yusril A
20013cf7b7 Translated using Weblate (Indonesian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/id/
2022-10-26 08:04:56 +02:00
J. Lavoie
78c3146c78 Translated using Weblate (French)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2022-10-26 08:04:56 +02:00
J. Lavoie
ddd7bb9968 Translated using Weblate (German)
Currently translated at 98.9% (271 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2022-10-26 08:04:56 +02:00
Tong Liu
68935f1489 Closes #1092 - Fixed contents cut off on smaller screen issue. (#1095) 2022-10-25 19:38:02 +02:00
Sylvia van Os
d9a25e1eb9 Merge pull request #1108 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-10-24 20:54:17 +02:00
Oğuz Ersen
73a837bab5 Translated using Weblate (Turkish)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2022-10-24 20:42:31 +02:00
109247019824
03be45f5a2 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2022-10-24 20:42:31 +02:00
Eric
692adafd8e Translated using Weblate (Chinese (Simplified))
Currently translated at 97.0% (266 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2022-10-24 20:42:31 +02:00
Slávek Banko
4ff9eb5219 Translated using Weblate (Czech)
Currently translated at 100.0% (113 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2022-10-24 20:42:31 +02:00
solokot
286e9fa315 Translated using Weblate (Russian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2022-10-24 20:42:31 +02:00
Heimen Stoffels
e0b6773d2a Translated using Weblate (Dutch)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2022-10-24 20:42:31 +02:00
Allan Nordhøy
a7cb8a51a3 Translated using Weblate (Norwegian Bokmål)
Currently translated at 97.0% (266 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2022-10-24 20:42:31 +02:00
Gediminas Murauskas
56c7ffa4df Translated using Weblate (Lithuanian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2022-10-24 20:42:31 +02:00
Michael Moroni
1498f902c2 Translated using Weblate (Italian)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2022-10-24 20:42:31 +02:00
gallegonovato
eea0dd9081 Translated using Weblate (Spanish)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2022-10-24 20:42:31 +02:00
Slávek Banko
1a8c8c07aa Translated using Weblate (Czech)
Currently translated at 100.0% (274 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2022-10-24 20:42:31 +02:00
Allan Nordhøy
3901172757 Translated using Weblate (English)
Currently translated at 99.2% (272 of 274 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/en/
2022-10-24 20:42:31 +02:00
Sylvia van Os
3c9507cb7f Merge pull request #1107 from vanogrid/fix/expiryFieldTextRemainingRed
Fix Expiry field text remaining red after the card is no longer expired
2022-10-24 19:13:53 +02:00
Alexander Ivanov
bfc38807c8 Fix Expiry field text remaining red after the card is no longer expired
Signed-off-by: Alexander Ivanov <vanogrid@gmail.com>
2022-10-24 02:14:43 +03:00
Sylvia van Os
6dc3a28026 Merge pull request #1105 from CatimaLoyalty/create-pull-request/patch-1666508787
Update contributors
2022-10-23 11:58:29 +02:00
Sylvia van Os
eeb507f04e Merge pull request #1104 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-10-23 11:58:08 +02:00
Sylvia van Os
2746547194 Merge pull request #1103 from vanogrid/fix/storingDateAt12pm
Fix DatePickerDialog sometimes storing dates at 12 PM instead of 12 AM
2022-10-23 11:55:25 +02:00
TheLastProject
c9a8e81047 Update contributors 2022-10-23 07:06:27 +00:00
huang ivan
d87b8ddd4b Translated using Weblate (Chinese (Simplified))
Currently translated at 97.0% (265 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2022-10-23 06:00:18 +02:00
Alexander Ivanov
7dfa7071e3 Fix DatePickerDialog sometimes storing dates at 12:00 PM instead of 12:00 AM 2022-10-22 20:46:22 +03:00
Sylvia van Os
92f0091b1d Merge pull request #1086 from recursiveribbons/refactor-importer
Refactor Importer to not read entire file as String
2022-10-22 18:13:38 +02:00
Tomer Ben-Rachel
54d8f30bf1 Offer import when users click on supported import files (#1096) 2022-10-22 12:13:06 +02:00
bors[bot]
f7ef13d594 Merge #1101
1101: Translations update from Hosted Weblate r=TheLastProject a=weblate

Translations update from [Hosted Weblate](https://hosted.weblate.org) for [Catima/Android](https://hosted.weblate.org/projects/catima/catima/).


It also includes following components:

* [Catima/Android (Fastlane)](https://hosted.weblate.org/projects/catima/fastlane/)



Current translation status:

![Weblate translation status](https://hosted.weblate.org/widgets/catima/-/catima/horizontal-auto.svg)

Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Gediminas Murauskas <muziejusinfo@gmail.com>
Co-authored-by: Mindaugas <mindaugasjurgelenas1997@gmail.com>
Co-authored-by: Angela Enogieru <angys1may@gmail.com>
Co-authored-by: SKULD <ala20031028@163.com>
Co-authored-by: AnimeshChatterjee1 <animesh.chatterjee02@gmail.com>
Co-authored-by: Rishi Agarwal <rishiagarwal130903@gmail.com>
Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2022-10-21 18:02:41 +00:00
Rishi Agarwal
2a1157256b Translated using Weblate (Hindi)
Currently translated at 54.5% (149 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hi/
2022-10-21 19:57:29 +02:00
Sylvia van Os
213ef5060f Translated using Weblate (Slovak)
Currently translated at 74.7% (204 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sk/
2022-10-21 19:57:28 +02:00
Gediminas Murauskas
bc24e263b9 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2022-10-21 19:57:28 +02:00
Gediminas Murauskas
8da70c41b2 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2022-10-21 16:36:01 +02:00
Rishi Agarwal
4d81846fe0 Translated using Weblate (Hindi)
Currently translated at 44.3% (121 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hi/
2022-10-21 16:36:01 +02:00
AnimeshChatterjee1
2afdedd0b6 Translated using Weblate (Hindi)
Currently translated at 44.3% (121 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hi/
2022-10-21 16:36:01 +02:00
SKULD
8d944cbb24 Translated using Weblate (Chinese (Simplified))
Currently translated at 97.0% (265 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2022-10-21 16:36:01 +02:00
Angela Enogieru
3ffec94b47 Translated using Weblate (Slovak)
Currently translated at 75.0% (205 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sk/
2022-10-21 16:36:01 +02:00
Mindaugas
9176dc98ee Translated using Weblate (Lithuanian)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2022-10-21 16:36:01 +02:00
Gediminas Murauskas
9881854d13 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2022-10-21 16:36:01 +02:00
J. Lavoie
2e4d1fa448 Translated using Weblate (Italian)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2022-10-21 16:36:01 +02:00
J. Lavoie
97ca1440b0 Translated using Weblate (French)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2022-10-21 16:36:01 +02:00
J. Lavoie
a4688c4450 Translated using Weblate (German)
Currently translated at 98.9% (270 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2022-10-21 16:36:01 +02:00
Sylvia van Os
a7ae2a333a Merge pull request #1100 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-10-20 19:03:44 +02:00
Laura Ferraz
823e99bd90 Translated using Weblate (Portuguese)
Currently translated at 97.8% (267 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2022-10-20 16:06:34 +02:00
Oğuz Ersen
e32fccc694 Translated using Weblate (Turkish)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2022-10-20 16:06:34 +02:00
109247019824
dd568ab51d Translated using Weblate (Bulgarian)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2022-10-20 16:06:34 +02:00
Max
17f55e577b Translated using Weblate (Polish)
Currently translated at 39.8% (45 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pl/
2022-10-20 16:06:33 +02:00
solokot
3f77223e65 Translated using Weblate (Russian)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2022-10-20 16:06:33 +02:00
Max
28aad933c5 Translated using Weblate (Polish)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2022-10-20 16:06:33 +02:00
Heimen Stoffels
52ca8396db Translated using Weblate (Dutch)
Currently translated at 99.6% (272 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2022-10-20 16:06:33 +02:00
Michael Moroni
bc941544ae Translated using Weblate (Italian)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2022-10-20 16:06:33 +02:00
gallegonovato
e3c3b176eb Translated using Weblate (Spanish)
Currently translated at 100.0% (273 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2022-10-20 16:06:33 +02:00
Max
3b0b92b954 Translated using Weblate (English)
Currently translated at 99.2% (271 of 273 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/en/
2022-10-20 16:06:33 +02:00
diksha-2911
bfcae03420 Translated using Weblate (Hindi)
Currently translated at 34.9% (93 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hi/
2022-10-20 16:06:33 +02:00
Md. Al-Amin
ad4db1ef37 Translated using Weblate (Bengali)
Currently translated at 33.4% (89 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn/
2022-10-20 16:06:33 +02:00
Ágata Leuck
fa1a7fd2f1 Translated using Weblate (Portuguese)
Currently translated at 100.0% (113 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2022-10-20 16:06:33 +02:00
Gediminas Murauskas
7eac08d0a1 Translated using Weblate (Lithuanian)
Currently translated at 80.0% (213 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2022-10-20 16:06:33 +02:00
Ágata Leuck
dab984b0d4 Translated using Weblate (Portuguese)
Currently translated at 95.5% (108 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pt/
2022-10-20 16:06:33 +02:00
Arnis Jaundzeikars
66361dede2 Translated using Weblate (Latvian)
Currently translated at 1.7% (2 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/lv/
2022-10-20 16:06:33 +02:00
Arnis Jaundzeikars
628c62fd4b Translated using Weblate (Latvian)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lv/
2022-10-20 16:06:33 +02:00
Nicolas
84a7e95856 Translated using Weblate (French)
Currently translated at 99.1% (112 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2022-10-20 16:06:33 +02:00
Sylvia van Os
fc256d2c4a Merge pull request #1097 from pfaffenrodt/feature/security-maven-repos
Add limitation for jitpack maven repository
2022-10-19 18:34:57 +02:00
Pfaffenrodt
7f81ceeb7e Add limitation for jitpack maven repository 2022-10-18 21:11:50 +02:00
Tong Liu
3179644fbc Issue #1084 - adding text for permission denial. (#1085) 2022-10-16 19:58:29 +02:00
Sylvia van Os
274a58bcb0 Merge pull request #1093 from CatimaLoyalty/create-pull-request/patch-1665923209
Update Fastlane changelogs
2022-10-16 14:27:21 +02:00
TheLastProject
dc7f42b0b6 Update Fastlane changelogs 2022-10-16 12:26:48 +00:00
Sylvia van Os
f859627d7f Document quick spend feature 2022-10-16 14:26:34 +02:00
polarhun
ccf12bf028 #1044 - Automatic Balance Update (#1073) 2022-10-16 14:25:26 +02:00
Sylvia van Os
c34e2fdd70 Merge pull request #1091 from CatimaLoyalty/fix/crashCancelScanActivity
Fix crash on cancelling ScanActivity
2022-10-16 11:41:58 +02:00
Sylvia van Os
ea482c6fad Fix crash on cancelling ScanActivity
Introduced in https://github.com/CatimaLoyalty/Android/pull/1078
2022-10-16 11:07:40 +02:00
Sylvia van Os
54f223b5b0 Merge pull request #1090 from CatimaLoyalty/create-pull-request/patch-1665903989
Update contributors
2022-10-16 10:12:22 +02:00
TheLastProject
74e083bb62 Update contributors 2022-10-16 07:06:28 +00:00
Robin Syl
a9c36cd171 A more reliable and customizable method to parse version from an import file 2022-10-15 20:06:49 +02:00
Sylvia van Os
876b0beb2f Merge pull request #1088 from CatimaLoyalty/fix/cursorAdapterDRY
Reduce repeated code in LoyaltyCardCursorAdapter
2022-10-15 14:40:38 +02:00
Sylvia van Os
1f73beb895 Reduce repeated code in LoyaltyCardCursorAdapter
This also more explicitly sets the text colour to prevent RecyclerView
state bugs
2022-10-15 14:30:42 +02:00
Sylvia van Os
b13aaacdff Merge pull request #1087 from CatimaLoyalty/create-pull-request/patch-1665820428
Update Fastlane changelogs
2022-10-15 09:54:07 +02:00
TheLastProject
ba67c122fa Update Fastlane changelogs 2022-10-15 07:53:48 +00:00
Sylvia van Os
f16550aa9c Document new share intenet receiver in changelog 2022-10-15 09:53:28 +02:00
Robin Syl
ba57fbbf85 Close inputstream in importData 2022-10-14 21:36:02 +02:00
Simon Rusinov
ebedb43e72 issue-614 add receiver for share intent (#1078) 2022-10-14 21:33:59 +02:00
Robin Syl
c10f859919 Refactor Importer to not read entire file as String 2022-10-14 16:56:35 +02:00
Sylvia van Os
8e6e83dfc6 Merge pull request #1080 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-10-10 21:36:16 +02:00
Jen Kung-chih
326379d222 Translated using Weblate (Chinese (Traditional))
Currently translated at 99.6% (265 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hant/
2022-10-10 20:07:48 +02:00
Sylvia van Os
105e85cc63 Translated using Weblate (Spanish)
Currently translated at 2.6% (3 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/es/
2022-10-10 20:07:48 +02:00
Sylvia van Os
e21dbc85e8 Translated using Weblate (Romanian)
Currently translated at 2.6% (3 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ro/
2022-10-10 20:07:47 +02:00
Simon Rusinov
78348a6f9c issue-1054 handle all deprecation warnings (#1072) 2022-10-10 18:28:35 +02:00
Sneakyturtle22
f98b98b4f3 Translated using Weblate (Hindi)
Currently translated at 27.4% (73 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hi/
2022-10-10 15:24:11 +02:00
Arnis Jaundzeikars
d362305a25 Translated using Weblate (Latvian)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lv/
2022-10-10 15:24:11 +02:00
Sylvia van Os
623cfc671c Translated using Weblate (Indonesian)
Currently translated at 17.6% (20 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/id/
2022-10-10 15:24:11 +02:00
Magnitudee
456e2112b8 Translated using Weblate (Indonesian)
Currently translated at 98.8% (263 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/id/
2022-10-10 15:24:11 +02:00
gallegonovato
af2fbd1ce3 Translated using Weblate (Spanish)
Currently translated at 2.6% (3 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/es/
2022-10-10 15:24:11 +02:00
Sylvia van Os
91211f07cb Translated using Weblate (Polish)
Currently translated at 36.2% (41 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pl/
2022-10-10 15:24:11 +02:00
BootVirtual
9c183e84dd Translated using Weblate (Romanian)
Currently translated at 2.6% (3 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ro/
2022-10-10 15:24:11 +02:00
Thomas Cruveilher
5e3cebf4a1 Translated using Weblate (French)
Currently translated at 63.7% (72 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2022-10-10 15:24:11 +02:00
Piotr Zet
9437d23e6e Translated using Weblate (Polish)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2022-10-10 15:24:11 +02:00
Sneakyturtle22
925a66a12a Added translation using Weblate (Hindi) 2022-10-10 15:24:11 +02:00
gallegonovato
5db8af72a1 Translated using Weblate (Spanish)
Currently translated at 2.6% (3 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/es/
2022-10-10 15:24:11 +02:00
Mawuena M. KODZO A
2b605eb193 Translated using Weblate (French)
Currently translated at 44.2% (50 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2022-10-10 15:24:11 +02:00
BootVirtual
f16d10995c Translated using Weblate (Romanian)
Currently translated at 51.1% (136 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ro/
2022-10-10 15:24:11 +02:00
Sylvia van Os
3ef17404b7 Merge pull request #1077 from CatimaLoyalty/fix/groupNameValidation
Improve group name validation flow
2022-10-09 17:19:20 +02:00
Sylvia van Os
1316ac731c Improve group name validation flow 2022-10-09 16:45:54 +02:00
Sylvia van Os
6283a90217 Merge pull request #1075 from CatimaLoyalty/create-pull-request/patch-1665298778
Update contributors
2022-10-09 10:42:13 +02:00
TheLastProject
84e8857067 Update contributors 2022-10-09 06:59:37 +00:00
Sylvia van Os
05a53d7985 Add missing languages to language chooser 2022-10-07 19:41:35 +02:00
Sylvia van Os
94b13b7145 Merge pull request #1071 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-10-07 19:09:23 +02:00
Mohamed A. Salah
3e55a147c7 Translated using Weblate (Arabic)
Currently translated at 99.2% (264 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2022-10-07 17:20:03 +02:00
109247019824
f05ed2571f Translated using Weblate (Bulgarian)
Currently translated at 12.3% (14 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/bg/
2022-10-07 17:20:03 +02:00
Sylvia van Os
c1a37eb2a4 Translated using Weblate (Spanish)
Currently translated at 1.7% (2 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/es/
2022-10-07 17:20:02 +02:00
Katarzyna
4d8d863780 Translated using Weblate (Polish)
Currently translated at 36.2% (41 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pl/
2022-10-07 17:20:02 +02:00
Slávek Banko
d56eec4ba9 Translated using Weblate (Czech)
Currently translated at 100.0% (113 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2022-10-07 17:20:00 +02:00
Thomas Cruveilher
a05356d0e1 Translated using Weblate (French)
Currently translated at 43.3% (49 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2022-10-07 17:19:56 +02:00
TenTraicion
4eea6f7f53 Translated using Weblate (Bengali)
Currently translated at 25.5% (68 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn/
2022-10-06 22:43:18 +02:00
Tapu
24e19cc5f8 Translated using Weblate (Bengali)
Currently translated at 25.5% (68 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn/
2022-10-06 22:43:18 +02:00
gallegonovato
cd7631451b Translated using Weblate (Spanish)
Currently translated at 1.7% (2 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/es/
2022-10-06 22:43:18 +02:00
이정희
d140130b0d Translated using Weblate (Korean)
Currently translated at 39.8% (106 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ko/
2022-10-06 22:43:18 +02:00
BMN
f0453943da Translated using Weblate (German)
Currently translated at 100.0% (113 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/de/
2022-10-06 22:43:18 +02:00
Mawuena M. KODZO A
42152ccbb5 Translated using Weblate (French)
Currently translated at 32.7% (37 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2022-10-06 22:43:18 +02:00
Mohamed A. Salah
27f8647243 Added translation using Weblate (Arabic (Najdi)) 2022-10-06 22:43:18 +02:00
Sylvia van Os
b7d520ded6 Merge pull request #1069 from CatimaLoyalty/create-pull-request/patch-1665000141
Update Fastlane changelogs
2022-10-05 22:03:15 +02:00
TheLastProject
04088ff366 Update Fastlane changelogs 2022-10-05 20:02:21 +00:00
Sylvia van Os
d4dcec1a9b Document switch to MaterialAlertDialog 2022-10-05 22:01:56 +02:00
Sylvia van Os
c8306616e3 Merge pull request #1067 from theimpulson/alertDialogImprovements
Alert dialog improvements
2022-10-05 22:01:13 +02:00
Sylvia van Os
b34bdebb5c Merge pull request #1068 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-10-05 10:42:25 +02:00
Lucas da Costa
9643cb9f94 Translated using Weblate (Portuguese)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2022-10-05 07:58:58 +02:00
Tapu
645b29226e Translated using Weblate (Bengali (India))
Currently translated at 48.8% (130 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bn_IN/
2022-10-05 07:58:58 +02:00
Tarik Dzambic
c56faba922 Translated using Weblate (Bosnian)
Currently translated at 17.6% (20 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/bs/
2022-10-05 07:58:58 +02:00
Tarik Dzambic
55a19eacc9 Translated using Weblate (Bosnian)
Currently translated at 53.3% (142 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bs/
2022-10-05 07:58:58 +02:00
Katarzyna
464a2350ae Translated using Weblate (Polish)
Currently translated at 36.2% (41 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pl/
2022-10-05 07:58:58 +02:00
Lisa
c44f737c99 Translated using Weblate (Italian)
Currently translated at 57.5% (65 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/it/
2022-10-05 07:58:58 +02:00
Mawuena M. KODZO A
a8794ce60c Translated using Weblate (French)
Currently translated at 25.6% (29 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/fr/
2022-10-05 07:58:58 +02:00
gallegonovato
11329ba786 Translated using Weblate (Spanish)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2022-10-05 07:58:58 +02:00
Tapu
e568bd1af9 Added translation using Weblate (Bengali) 2022-10-05 07:58:58 +02:00
Aayush Gupta
b3fbfdbf9d ManageGroupsActivity: Add spacing between EditText and AlertDialog bounds
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2022-10-05 11:04:40 +05:30
Aayush Gupta
aec4292203 Catima: Migrate to MaterialAlertDialogBuilder everywhere
This follows Material theme and looks much better compared to AlertDialog

Ref: https://developer.android.com/reference/com/google/android/material/dialog/MaterialAlertDialogBuilder

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2022-10-05 10:37:03 +05:30
Sylvia van Os
82733ca414 Merge pull request #1053 from theimpulson/gradle-improvements
Misc Gradle improvements
2022-10-04 21:03:31 +02:00
Aayush Gupta
887424af80 spotbugs: Exclude gradle generated view binding classes
Spot bugs complains about EI_EXPOSE_REP and BC_UNCONFIRMED_CAST bugs in these
classes but they are being generated by Gradle and are out of our control if
we want to use view binding to interact with the views.

Ref: https://developer.android.com/topic/libraries/view-binding

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2022-10-05 00:20:31 +05:30
Aayush Gupta
f63a25f582 gradle: Move lint params to specific config
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2022-10-05 00:20:31 +05:30
Aayush Gupta
635ec748b3 Catima: Migrate to view binding
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2022-10-05 00:20:31 +05:30
Aayush Gupta
fa510e3ffa gradle: Switch to new Int only SDK version properties
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2022-10-05 00:20:31 +05:30
Aayush Gupta
24a5efd5f8 gradle: Migrate to new plugins and dependency management system
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2022-10-05 00:20:31 +05:30
Aayush Gupta
547dd55240 gradle: Drop buildToolsVersion
Not required as the latest one is always used

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2022-10-05 00:20:31 +05:30
bors[bot]
774705d9ad Merge #1065
1065: Remove CodeQL r=TheLastProject a=TheLastProject

It's getting in the way of #1053 and in a year of usage has not once given any type of alert

Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2022-10-04 18:40:08 +00:00
Sylvia van Os
3d756e271c Remove CodeQL
It's getting in the way of #1053 and in a year of usage has not once given any type of alert
2022-10-04 20:39:39 +02:00
Sylvia van Os
2da9a9c1a8 Merge pull request #1064 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-10-03 22:05:32 +02:00
Lisa
cd67d3c919 Translated using Weblate (Italian)
Currently translated at 18.5% (21 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/it/
2022-10-03 19:48:19 +02:00
Aya Elsaadany
c080fdb244 Translated using Weblate (Arabic)
Currently translated at 99.2% (264 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ar/
2022-10-03 19:48:19 +02:00
Arnis Jaundzeikars
9ee61812b8 Translated using Weblate (Latvian)
Currently translated at 94.7% (252 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lv/
2022-10-03 19:48:19 +02:00
Oğuz Ersen
bccf0a656b Translated using Weblate (Turkish)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2022-10-03 19:48:19 +02:00
109247019824
47ca66e9c7 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2022-10-03 19:48:19 +02:00
Eric
972315ad00 Translated using Weblate (Chinese (Simplified))
Currently translated at 98.8% (263 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hans/
2022-10-03 19:48:19 +02:00
Katarzyna
0aa8b63c0c Translated using Weblate (Polish)
Currently translated at 15.9% (18 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/pl/
2022-10-03 19:48:18 +02:00
Slávek Banko
e77cf403eb Translated using Weblate (Czech)
Currently translated at 100.0% (113 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2022-10-03 19:48:18 +02:00
Jacopo Gennaro Esposito
df89ab29eb Translated using Weblate (Italian)
Currently translated at 17.6% (20 of 113 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/it/
2022-10-03 19:48:18 +02:00
IllusiveMan196
6c6829bfd5 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2022-10-03 19:48:18 +02:00
solokot
fa531dce81 Translated using Weblate (Russian)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2022-10-03 19:48:18 +02:00
Katarzyna
61bc7ad24a Translated using Weblate (Polish)
Currently translated at 99.6% (265 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pl/
2022-10-03 19:48:18 +02:00
Heimen Stoffels
ce0964e6a7 Translated using Weblate (Dutch)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2022-10-03 19:48:18 +02:00
Allan Nordhøy
4979ac9d34 Translated using Weblate (Norwegian Bokmål)
Currently translated at 97.7% (260 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2022-10-03 19:48:18 +02:00
Michael Moroni
912bcdf7f7 Translated using Weblate (Italian)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2022-10-03 19:48:18 +02:00
J. Lavoie
09174e646b Translated using Weblate (French)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2022-10-03 19:48:18 +02:00
J. Lavoie
0c729cb092 Translated using Weblate (German)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2022-10-03 19:48:18 +02:00
Slávek Banko
61faa4aa09 Translated using Weblate (Czech)
Currently translated at 100.0% (266 of 266 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2022-10-03 19:48:18 +02:00
Sylvia van Os
0e7a5428f6 Merge pull request #1062 from CatimaLoyalty/dependabot/gradle/org.robolectric-robolectric-4.9
Bump robolectric from 4.8.2 to 4.9
2022-10-03 18:18:38 +02:00
dependabot[bot]
8030eb52f3 Bump robolectric from 4.8.2 to 4.9
Bumps [robolectric](https://github.com/robolectric/robolectric) from 4.8.2 to 4.9.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.8.2...robolectric-4.9)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-03 02:36:38 +00:00
Sylvia van Os
9fc315158f Name Weblate in CONTRIBUTING.md 2022-10-02 19:24:48 +02:00
Sylvia van Os
971f68b0a1 Merge pull request #1059 from CatimaLoyalty/create-pull-request/patch-1664690892
Update contributors
2022-10-02 10:10:22 +02:00
TheLastProject
adfc17d5c2 Update contributors 2022-10-02 06:08:12 +00:00
Sylvia van Os
5ee2852e4c Merge pull request #1058 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-10-02 00:48:46 +02:00
J. Lavoie
ea1d42fa35 Translated using Weblate (Finnish)
Currently translated at 98.1% (259 of 264 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fi/
2022-10-01 21:20:34 +02:00
Lisa
f8b90f2c07 Translated using Weblate (Italian)
Currently translated at 16.9% (19 of 112 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/it/
2022-10-01 21:20:34 +02:00
J. Lavoie
6dc9821891 Translated using Weblate (French)
Currently translated at 100.0% (264 of 264 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2022-10-01 21:20:34 +02:00
J. Lavoie
93a2e9cdbf Translated using Weblate (Spanish)
Currently translated at 99.6% (263 of 264 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2022-10-01 21:20:34 +02:00
Sylvia van Os
6a9d54d6f0 Merge pull request #1055 from CatimaLoyalty/create-pull-request/patch-1664626344
Update Fastlane changelogs
2022-10-01 14:13:08 +02:00
TheLastProject
28f0b407b5 Update Fastlane changelogs 2022-10-01 12:12:24 +00:00
Sylvia van Os
89ed31ffe0 Update CHANGELOG 2022-10-01 14:12:08 +02:00
Manan Jhaveri
aa481ea094 View photos in gallery when Long Pressed (#1052)
* Open Native Image Viewer on long pressing a photo inside LoyaltyCardViewActivity

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

Signed-off-by: Manan Jhaveri <incrediblemanan@gmail.com>
2022-10-01 14:11:15 +02:00
bors[bot]
523aaef650 Merge #1051
1051: Translations update from Hosted Weblate r=TheLastProject a=weblate

Translations update from [Hosted Weblate](https://hosted.weblate.org) for [Catima/Android](https://hosted.weblate.org/projects/catima/catima/).


It also includes following components:

* [Catima/Android (Fastlane)](https://hosted.weblate.org/projects/catima/fastlane/)



Current translation status:

![Weblate translation status](https://hosted.weblate.org/widgets/catima/-/catima/horizontal-auto.svg)

Co-authored-by: Tomer Ben Rachel <tomerpacific@gmail.com>
Co-authored-by: Evgeniy Khramov <thejenjagamertjg@gmail.com>
Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2022-10-01 09:50:55 +00:00
Sylvia van Os
a56c4d449d Remove broken translation 2022-10-01 11:50:22 +02:00
Evgeniy Khramov
1468130477 Translated using Weblate (Russian)
Currently translated at 28.5% (32 of 112 strings)

Translation: Catima/Android (Fastlane)
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/ru/
2022-09-28 21:16:13 +02:00
Tomer Ben Rachel
0b5571a065 Translated using Weblate (Hebrew (Israel))
Currently translated at 35.2% (93 of 264 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/he_IL/
2022-09-28 21:16:13 +02:00
Sylvia van Os
002c221390 Merge pull request #1050 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-09-26 21:25:16 +02:00
Oğuz Ersen
2272c88d04 Translated using Weblate (English)
Currently translated at 98.8% (261 of 264 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/en/
2022-09-26 20:28:50 +02:00
Wanath
6a58bd632f Translated using Weblate (Korean)
Currently translated at 35.9% (95 of 264 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ko/
2022-09-26 20:28:50 +02:00
Wanath
027a7f798d Translated using Weblate (English)
Currently translated at 98.8% (261 of 264 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/en/
2022-09-26 20:28:50 +02:00
Sylvia van Os
dd4ad6d860 Merge pull request #1048 from CatimaLoyalty/create-pull-request/patch-1664085704
Update contributors
2022-09-25 10:27:46 +02:00
TheLastProject
3342b8f83f Update contributors 2022-09-25 06:01:43 +00:00
Sylvia van Os
5951c74fc4 Merge pull request #1047 from weblate/weblate-catima-catima
Translations update from Hosted Weblate
2022-09-24 12:46:35 +02:00
Nate Higgers
2cae83c84f Translated using Weblate (Chinese (Traditional))
Currently translated at 93.1% (246 of 264 strings)

Translation: Catima/Android
Translate-URL: https://hosted.weblate.org/projects/catima/catima/zh_Hant/
2022-09-24 12:27:25 +02:00
1404 changed files with 20180 additions and 8318 deletions

View File

@@ -1,11 +1,10 @@
# 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
- package-ecosystem: "gradle"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@@ -1,41 +1,54 @@
name: Android CI
on:
workflow_dispatch:
push:
branches:
- master
- main
- staging
- trying
pull_request:
branches:
- master
- main
permissions:
actions: none
checks: none
contents: read
deployments: none
discussions: none
id-token: none
issues: none
packages: none
pages: none
pull-requests: none
repository-projects: none
security-events: none
statuses: none
env:
JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4.0.0
- name: Fail on bad translations
run: if grep -ri "&lt;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
with:
distribution: 'adopt'
java-version: '11'
- name: set up OpenJDK 17
run: |
sudo apt-get update
sudo apt-get install -y openjdk-17-jdk-headless
sudo update-alternatives --auto java
- name: Build
run: ./gradlew assembleRelease
- name: Check lint
run: ./gradlew lintRelease
- name: Run unit tests
run: ./gradlew testReleaseUnitTest || ./gradlew testReleaseUnitTest
run: timeout 5m ./gradlew testReleaseUnitTest || { ./gradlew --stop && timeout 5m ./gradlew testReleaseUnitTest; }
- name: SpotBugs
run: ./gradlew spotbugsRelease
- name: Archive test results
if: always()
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3.1.3
with:
name: test-results
path: app/build/reports

View File

@@ -1,24 +0,0 @@
name: 'Close issues and PRs needing info for too long'
on:
schedule:
- cron: '30 1 * * *'
permissions:
issues: write
pull-requests: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v4
with:
days-before-stale: -1
days-before-close: 90
close-issue-message: 'This issue is missing necessary information and cannot be worked on in its current state. It has therefore been closed to keep the issue tracker clean. If you have more information, feel free to reopen it.'
close-pr-message: 'This PR is missing necessary information and cannot be merged in its current state. It has therefore been closed to keep the issue tracker clean. If you have more information, feel free to reopen it.'
only-labels: 'state: needs info'
stale-issue-label: 'state: needs info'
stale-pr-label: 'state: needs info'
remove-stale-when-updated: false
enable-statistics: true

View File

@@ -1,34 +0,0 @@
name: Compress Images on Push to Master
on:
push:
branches:
- master
paths:
- '**.jpg'
- '**.jpeg'
- '**.png'
- '**.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@v2
- name: Compress Images
id: calibre
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@v3
with:
title: Compressed Images
branch-suffix: timestamp
commit-message: Compressed Images
body: ${{ steps.calibre.outputs.markdown }}

View File

@@ -1,9 +1,25 @@
name: Convert CHANGELOG to Fastlane
on:
workflow_dispatch:
push:
branches:
- master
- main
paths:
- 'CHANGELOG.md'
permissions:
actions: none
checks: none
contents: write
deployments: none
discussions: none
id-token: none
issues: none
packages: none
pages: none
pull-requests: write
repository-projects: none
security-events: none
statuses: none
jobs:
convert_changelog_to_fastlane:
runs-on: ubuntu-latest
@@ -11,15 +27,15 @@ jobs:
steps:
- name: Checkout repo
id: checkout
uses: actions/checkout@v2
uses: actions/checkout@v4.0.0
- name: Setup Python
uses: actions/setup-python@v2
uses: actions/setup-python@v4.7.0
with:
python-version: '3.x'
- name: Run converter script
run: python .scripts/changelog_to_fastlane.py
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
uses: peter-evans/create-pull-request@v5.0.2
with:
title: "Update Fastlane changelogs"
commit-message: "Update Fastlane changelogs"

View File

@@ -1,73 +0,0 @@
# 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

View File

@@ -1,24 +1,38 @@
name: Write contributors to file
on:
workflow_dispatch:
schedule:
- cron: '3 4 * * 0'
permissions:
actions: none
checks: none
contents: write
deployments: none
discussions: none
id-token: none
issues: none
packages: none
pages: none
pull-requests: write
repository-projects: none
security-events: none
statuses: none
jobs:
contributors_to_file:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
if: github.ref == 'refs/heads/main'
name: Write contributors to file
steps:
- name: Checkout repo
id: checkout
uses: actions/checkout@v2
uses: actions/checkout@v4.0.0
- name: Update contributors
id: update_contributors
uses: TheLastProject/contributors-to-file-action@v2
uses: TheLastProject/contributors-to-file-action@v3.0.1
with:
file_in_repo: app/src/main/res/raw/contributors.txt
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
uses: peter-evans/create-pull-request@v5.0.2
with:
title: "Update contributors"
commit-message: "Update contributors"

View File

@@ -0,0 +1,77 @@
name: Generate feature graphic
on:
workflow_dispatch:
push:
branches:
- main
paths:
- 'fastlane/**/title.txt'
permissions:
actions: none
checks: none
contents: write
deployments: none
discussions: none
id-token: none
issues: none
packages: none
pages: none
pull-requests: write
repository-projects: none
security-events: none
statuses: none
jobs:
generate-feature-graphic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.0.0
- name: Install requirements
run: |
sudo apt-get update
sudo apt-get install optipng mat2
# Install 200 weight versions of relevant Noto (to use for languages not supported by Lexend Deca)
sudo apt-get install fonts-noto-extra fonts-noto-cjk-extra
# Custom fonts
mkdir "$HOME/.fonts"
find .scripts/generate_feature_graphic/fonts -name '*.ttf' -exec cp {} "$HOME/.fonts" \;
fc-cache
- name: Generate featureGraphic.png for each language
run: |
for lang in fastlane/metadata/android/*; do
pushd "$lang"
# Place temporary copy for editing if needed
cp ../../../../.scripts/generate_feature_graphic/featureGraphic.svg featureGraphic.svg
# Extract text after 'Catima - '
export subtext="$(grep -oP '(?<=Catima \S ).*' title.txt || true)"
# If there is subtext, change the .svg accordingly
if [ -n "$subtext" ]; then
perl -pi -e 's/Loyalty Card Wallet/$ENV{subtext}/' featureGraphic.svg
# Set correct font for language if needed (Lexend Deca has limited support)
# We specifically need the Serif version because of the 200 weight
case "$(basename "$lang")" in
bg|el-GR|ru-RU|uk) sed -i "s/Lexend Deca/Noto Serif/" featureGraphic.svg ;;
ja-JP) sed -i "s/Lexend Deca/Noto Serif CJK JP/" featureGraphic.svg ;;
ko) sed -i "s/Lexend Deca/Noto Serif CJK KR/" featureGraphic.svg ;;
zh-CN) sed -i "s/Lexend Deca/Noto Serif CJK SC/" featureGraphic.svg ;;
zh-TW) sed -i "s/Lexend Deca/Noto Serif CJK TC/" featureGraphic.svg ;;
*) ;;
esac
fi
# Ensure images directory exists
mkdir -p images
# Generate .png
convert featureGraphic.svg images/featureGraphic.png
# Optimize .png
optipng images/featureGraphic.png
# Remove metadata (timestamps) from .png
mat2 --inplace images/featureGraphic.png
# Remove temporary .svg
rm featureGraphic.svg
popd
done
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5.0.2
with:
title: "Update feature graphic"
commit-message: "Update feature graphic"
branch-suffix: timestamp

35
.github/workflows/update-locales.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Update locales
on:
workflow_dispatch:
push:
branches:
- main
paths:
- app/src/main/res/values/settings.xml
permissions:
actions: none
checks: none
contents: write
deployments: none
discussions: none
id-token: none
issues: none
packages: none
pages: none
pull-requests: write
repository-projects: none
security-events: none
statuses: none
jobs:
update-locales:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.0.0
- name: Update locales
run: .scripts/locales.py
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5.0.2
with:
title: "Update locales"
commit-message: "Update locales"
branch-suffix: timestamp

5
.gitignore vendored
View File

@@ -8,3 +8,8 @@ captures/
**/release
**/debug
app/*.log
# Bundle
/.bundle/
/vendor/bundle
/lib/bundler/man/

44
.scripts/dump_stocard_stores.py Executable file
View File

@@ -0,0 +1,44 @@
#!/usr/bin/python3
import csv
import json
import msgpack
MSGPACK = "bootstrapdata.msgpack"
OUTFILE = "stocard_stores.csv"
def load(fh):
data = []
for r in msgpack.Unpacker(fh, raw=False):
if r["collection"] == "/loyalty-card-providers/":
d = json.loads(r["data"])
data.append([r["resource_id"], d["name"], d["default_barcode_format"]])
return data
def save(data, output_file=OUTFILE):
with open(output_file, "w") as fh:
writer = csv.writer(fh, lineterminator="\n")
writer.writerow(["_id", "name", "barcodeFormat"])
for row in data:
writer.writerow(row)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(
epilog=f"INPUT_FILE must be a .msgpack or .apk and defaults to {MSGPACK}; "
f"OUTPUT_FILE defaults to {OUTFILE}")
parser.add_argument("input_file", metavar="INPUT_FILE", nargs="?", default=MSGPACK)
parser.add_argument("output_file", metavar="OUTPUT_FILE", nargs="?", default=OUTFILE)
args = parser.parse_args()
if args.input_file.lower().endswith(".apk"):
import zipfile
with zipfile.ZipFile(args.input_file) as zf:
with zf.open(f"assets/{MSGPACK}") as fh:
data = load(fh)
else:
with open(args.input_file, "rb") as fh:
data = load(fh)
save(data, args.output_file)

View File

@@ -0,0 +1,15 @@
<svg width="1024" height="500" viewBox="0 0 1024 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="1024" height="500" fill="#223355"/>
<text fill="white" xml:space="preserve" style="" font-family="Yesteryear" font-size="150" letter-spacing="0em"><tspan x="470.082" y="285.511">Catima
</tspan></text>
<path d="M381.046 147.001L236.3 211.446L276.524 301.79L421.27 237.345L381.046 147.001Z" fill="#F0F0F0" stroke="#C80000" stroke-width="2"/>
<path d="M402.077 219.13L240.07 147L191.984 255.004L353.99 327.135L402.077 219.13Z" fill="#F0F0F0" stroke="#C80000" stroke-width="2"/>
<path d="M437.17 236.241L251.831 183.096L220.071 293.855L405.41 347L437.17 236.241Z" fill="#C80000" stroke="#C80000" stroke-width="6" stroke-linejoin="round"/>
<path d="M412.879 178.633H220.071V293.855H412.879V178.633Z" fill="#FF0000" stroke="#FF0000" stroke-width="6" stroke-linejoin="round"/>
<path d="M221.482 296.217C238.316 296.217 251.963 269.366 251.963 236.244C251.963 203.121 238.316 176.27 221.482 176.27C204.647 176.27 191 203.121 191 236.244C191 269.366 204.647 296.217 221.482 296.217Z" fill="#FF0000" stroke="#FF0000" stroke-width="3.44232" stroke-linejoin="round"/>
<path d="M307.256 250.444C307.256 253.187 306.289 255.842 304.526 257.944C302.763 260.045 300.316 261.458 297.614 261.934C294.913 262.41 292.13 261.92 289.755 260.548C287.379 259.177 285.563 257.012 284.625 254.435" stroke="#F0F0F0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M330.301 254.298C329.363 256.875 327.547 259.04 325.171 260.411C322.796 261.783 320.013 262.273 317.312 261.797C314.61 261.321 312.163 259.908 310.4 257.807C308.637 255.706 307.671 253.05 307.671 250.307" stroke="#F0F0F0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M248.345 225.937L266.818 207.465L285.29 225.937" stroke="#F0F0F0" stroke-width="2"/>
<path d="M329.625 225.937L348.098 207.465L366.571 225.937" stroke="#F0F0F0" stroke-width="2"/>
<text fill="white" xml:space="preserve" style="" font-family="Lexend Deca" font-size="35" font-weight="200" letter-spacing="0em"><tspan x="466" y="340">Loyalty Card Wallet</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,93 @@
Copyright 2018 The Lexend Project Authors (https://github.com/googlefonts/lexend), with Reserved Font Name “RevReading Lexend”.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@@ -0,0 +1,94 @@
Copyright (c) 2011 by Brian J. Bonislawsky DBA Astigmatic (AOETI)
(astigma@astigmatic.com), with Reserved Font Names "Yesteryear"
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

Binary file not shown.

36
.scripts/locales.py Executable file
View File

@@ -0,0 +1,36 @@
#!/usr/bin/python3
import subprocess
import xml.etree.ElementTree as ET
root = ET.parse("app/src/main/res/values/settings.xml").getroot()
for e in root.findall("string-array"):
if e.get("name") == "locale_values":
locales = [x.text for x in e if x.text]
break
locales = [
# e.g. de or es-rAR (not es-AR)
loc.replace("-", "-r") if "-" in loc and loc[loc.index("-") + 1] != "r" else loc
for loc in locales
]
res = ", ".join(f'"{loc}"' for loc in locales)
sed = [
"sed",
"-i",
f"s/resourceConfigurations .*/resourceConfigurations += [{res}]/",
"app/build.gradle"
]
subprocess.run(sed, check=True)
with open("app/src/main/res/xml/locales_config.xml", "w") as fh:
fh.write('<?xml version="1.0" encoding="utf-8"?>\n')
fh.write('<locale-config xmlns:android="http://schemas.android.com/apk/res/android">\n')
fh.write(' <locale android:name="en-US" />\n')
for loc in locales:
if loc != "en":
# e.g. de or en-AR (not es-rAR)
loc = loc.replace("-r", "-")
fh.write(f' <locale android:name="{loc}" />\n')
fh.write('</locale-config>\n')

View File

@@ -1,22 +1,116 @@
# Changelog
## v2.20.0 - 114
## Unreleased - 132
- Refine "Add card" workflow
- Validation flow improvements
## v2.26.0 - 131 (2023-09-14)
- Move "Archive mode" into "Display options" (previously "Show details") menu
- Android 13 per-app language support
- Embed privacy policy, changelog and license in the app
## v2.25.3 - 130 (2023-08-25)
- Minor UI fixes
- Fix valid from and expiry dates being reset when rotating the card editing screen
- Fix crash when rotating screen while the color picker is shown
- Stocard import fixes
## v2.25.2 - 129 (2023-07-27)
- Improved Catima importer (fixes cards missing when importing)
- Fix crash when rotating screen while setting valid from/expiry date
- Minor UI tweaks
## v2.25.1 - 128 (2023-07-17)
- Fix rare crash
## v2.25.0 - 127 (2023-07-09)
- Barcode rendering improvements
- Basic interoperability with external apps (Android 6.0+)
- Reorganized settings screen
- Fix importing from some browsers that add a trailing / to the share URL
## v2.24.2 - 126 (2023-06-18)
- Various RTL fixes
## v2.24.1 - 125 (2023-06-11)
- Deal more gracefully with missing header colours
## v2.24.0 - 124 (2023-06-10)
- Support selecting exactly which details to view in card overview
## v2.23.3 - 123 (2023-06-03)
- Minor UI improvements
- Fix new design not being usable on devices with square screens
## v2.23.2 - 122 (2023-05-30)
- Long-press card icon in view activity to change it
- Improve button styling in Groups screen
- Fix long barcode values causing barcode to scale down to nothing
## v2.23.1 - 121 (2023-05-27)
- Update used libraries
## v2.23.0 - 120 (2023-05-25)
- Complete redesign of main and loyalty card view screens
- Material You design for the settings screen
- Fix crash when using "Take a photo" with disabled camera app
## v2.22.1 - 119 (2023-04-14)
- Use Material You colours on more devices (Google library update)
## v2.22.0 - 118 (2023-03-18)
- Support setting start of card validity
- Fix Stocard import (Stocard's export format changed)
## v2.21.2 - 117 (2023-01-27)
- Remove unnecessary permissions
- Target Android 13
## v2.21.1 - 116 (2022-12-06)
- Fix quick spend dialog not allowing , separator
- Support loading image from file manager
## v2.21.0 - 115 (2022-11-06)
- Open image in gallery on long-press
- Apply Material style to dialogs
- Support creating card by sharing an image to Catima
- Add quick spend button to card screen
## v2.20.0 - 114 (2022-09-21)
- Add Monochrome icon for Android 13
- Improve first launch screen
- Fidme import fixes
## v2.19.0 - 113
## v2.19.0 - 113 (2022-08-14)
- Add previous and next buttons to the loyalty card view
- Fix foreground colour on edit button
- Replace floppy disk save icon with checkmark
## v2.18.2 - 112
## v2.18.2 - 112 (2022-07-29)
- Make the possibility to set a custom header more visible
## v2.18.1 - 111
## v2.18.1 - 111 (2022-07-24)
- Arabic language support
- Display archived card count in group overview
@@ -26,11 +120,11 @@
- Fix crash when leaving cardview in RTL layouts for cards with expiry or balance
- Fix back arrow in card view pointing the wrong way in RTL layouts
## v2.17.1 - 109
## v2.17.1 - 109 (2022-06-28)
- Fix incorrect text colour on "No barcode" button
## v2.17.0 - 108
## v2.17.0 - 108 (2022-06-24)
- Add card duplication feature
- Don't allow choosing expiry before 1970 (they never worked anyway)
@@ -592,7 +686,7 @@ Additional 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))
- Back button on Input/Export view now works, moving user to main view
- Back button on Import/Export view now works, moving user to main view
## v0.6 - 6 (2016-05-23)

View File

@@ -8,7 +8,20 @@ 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.
## Test Your Code
## Translation Changes
Translation changes are managed through [Weblate](https://hosted.weblate.org/projects/catima/).
Please do not supply translation updates directly through GitHub.
Weblate requires an account to translate changes, so please log in before
you start translating.
While using Weblate, please do not ignore any of its warnings. They exist
for good reason.
## Code Changes
### Test Your Code
There are four possible tests you can run to verify your code. The first
is unit tests, which check the basic functionality of the application, and
@@ -28,14 +41,14 @@ and SpotBugs, run using:
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
### Make Sure Your Code is Tested
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.
## Explain Your Work
### Explain Your Work
At the top of every patch you should include a description of the problem you
are trying to solve, how you solved it, and why you chose the solution you
@@ -44,7 +57,7 @@ if you can describe/include a reproducer for the problem in the description as
well as instructions on how to test for the bug and verify that it has been
fixed.
## Sign Your Work
### Sign Your Work
The sign-off is a simple line at the end of the patch description, which
certifies that you wrote it or otherwise have the right to pass it on as an
@@ -82,10 +95,10 @@ your real name, saying:
Signed-off-by: Random J Developer <random@developer.example.org>
## Submit Patch(es) for Review
### 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 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
Changes need to apply cleanly onto the main branch and pass all
unit tests and produce no errors during static analysis.

View File

@@ -1,27 +1,27 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.5)
CFPropertyList (3.0.6)
rexml
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.597.0)
aws-sdk-core (3.131.1)
aws-partitions (1.824.0)
aws-sdk-core (3.181.1)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.57.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (1.71.0)
aws-sdk-core (~> 3, >= 3.177.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.114.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-s3 (1.134.0)
aws-sdk-core (~> 3, >= 3.181.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.0)
aws-sigv4 (~> 1.6)
aws-sigv4 (1.6.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
@@ -30,14 +30,14 @@ GEM
commander (4.6.0)
highline (~> 2.0.0)
declarative (0.0.20)
digest-crc (0.6.4)
digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.92.3)
faraday (1.10.0)
excon (0.103.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@@ -65,8 +65,8 @@ GEM
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.206.2)
fastimage (2.2.7)
fastlane (2.215.1)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@@ -87,10 +87,11 @@ GEM
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
http-cookie (~> 1.0.5)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (~> 2.0.0)
multipart-post (>= 2.0.0, < 3.0.0)
naturally (~> 2.2)
optparse (~> 0.1.1)
plist (>= 3.1.0, < 4.0.0)
@@ -98,7 +99,7 @@ GEM
security (= 0.1.3)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0)
terminal-table (~> 3)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
@@ -106,9 +107,9 @@ GEM
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.21.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-core (0.5.0)
google-apis-androidpublisher_v3 (0.49.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.1)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -117,30 +118,29 @@ GEM
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.10.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-playcustomapp_v1 (0.7.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-storage_v1 (0.14.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-iamcredentials_v1 (0.17.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-playcustomapp_v1 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.19.0)
google-apis-core (>= 0.9.0, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.2.0)
google-cloud-storage (1.36.2)
google-cloud-errors (1.3.1)
google-cloud-storage (1.44.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.19.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.1.3)
googleauth (1.8.0)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
@@ -148,42 +148,41 @@ GEM
http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.6.1)
json (2.6.2)
jwt (2.4.1)
memoist (0.16.2)
mini_magick (4.11.0)
mini_mime (1.1.2)
jmespath (1.6.2)
json (2.6.3)
jwt (2.7.1)
mini_magick (4.12.0)
mini_mime (1.1.5)
multi_json (1.15.0)
multipart-post (2.0.0)
multipart-post (2.3.0)
nanaimo (0.3.0)
naturally (2.2.1)
optparse (0.1.1)
os (1.1.4)
plist (3.6.0)
public_suffix (4.0.7)
plist (3.7.0)
public_suffix (5.0.3)
rake (13.0.6)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.2.5)
rexml (3.2.6)
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.16.1)
signet (0.18.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.0)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.8)
simctl (1.6.10)
CFPropertyList
naturally
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.1)
@@ -193,10 +192,10 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
webrick (1.7.0)
unicode-display_width (2.4.2)
webrick (1.8.1)
word_wrap (1.0.0)
xcodeproj (1.21.0)
xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
@@ -215,4 +214,4 @@ DEPENDENCIES
fastlane
BUNDLED WITH
2.1.4
2.3.26

18
PRIVACY.md Normal file
View File

@@ -0,0 +1,18 @@
**Last updated**
August 30 2023
# Privacy Policy
Catima does not collect or transmit any personal information.
To ensure correct app functionality, we require access to the following:
- Camera: We need access to your camera to be able to scan barcodes. The app can still be used when camera access is denied, but you will have to manually type the barcode information.
- Storage (Android 5 and 6 only): We need access to your device storage to create or import backups. The app can still be used when storage access is denied, but you will not be able to create or import backups.
Catima offers a feature to share cards with other users. All the relevant data is in the generated shareable URLs and never transmitted to our servers. When viewed through catima.app, the data in the URL is rendered using client-side Javascript to further ensure no data is ever transmitted to us.
# Changes
This Privacy Policy may be updated from time to time for any reason. We will notify you of any changes to our Privacy Policy by posting the new Privacy Policy to https://catima.app/privacy-policy/. A snapshot of the Privacy Policy is available within the Catima app, though it may be outdated. When the Privacy Policy on the website and in the app differ, the website should be considered leading. You are advised to consult the Privacy Policy regularly for any changes, as continued use is deemed approval of all changes.
# Contact us
If you have any questions regarding privacy while using the Application, or have questions about our practices, please contact us via email at catima.g9ex3@hackerchick.me.

13
SECURITY.md Normal file
View File

@@ -0,0 +1,13 @@
# Security Policy
Catima is designed to use as little permissions as possible to limit both the attack surface as well as the damage that can be done when abusing a security flaw.
## Supported Versions
Only the most recent stable release is supported.
## Reporting a Vulnerability
Security vulnerabilities can be reported through [GitHub Security Advisories](https://github.com/CatimaLoyalty/Android/security/advisories) or [the contact info written on my personal website](https://sylviavanos.nl/#contact). Currently, Matrix is the only end-to-end encrypted option.
Please note that only security vulnerabilities in Catima should be reported as stated above. For other issues, including antivirus false positives and malicious applications trying to trick people into granting them Catima's "Read Cards" permission, please use [regular issues](https://github.com/CatimaLoyalty/Android/issues).

View File

@@ -1,7 +1,9 @@
import com.github.spotbugs.snom.SpotBugsTask
apply plugin: 'com.android.application'
apply plugin: 'com.github.spotbugs'
plugins {
id 'com.android.application'
id 'com.github.spotbugs'
}
spotbugs {
ignoreFailures = false
@@ -11,18 +13,19 @@ spotbugs {
}
android {
compileSdkVersion 31
buildToolsVersion "31.0.0"
compileSdk 33
defaultConfig {
applicationId "me.hackerchick.catima"
minSdkVersion 21
targetSdkVersion 31
versionCode 114
versionName "2.20.0"
minSdk 21
targetSdk 33
versionCode 131
versionName "2.26.0"
vectorDrawables.useSupportLibrary true
multiDexEnabled true
resourceConfigurations += ["ar", "bg", "bn", "bn-rIN", "bs", "cs", "da", "de", "el-rGR", "en", "eo", "es", "es-rAR", "fi", "fr", "he-rIL", "hi", "hr", "hu", "in-rID", "is", "it", "ja", "ko", "lt", "lv", "nb-rNO", "nl", "oc", "pl", "pt", "ro-rRO", "ru", "sk", "sl", "sv", "tr", "uk", "zh-rTW", "zh-rCN"]
}
buildTypes {
@@ -37,6 +40,10 @@ android {
}
}
buildFeatures {
viewBinding true
}
bundle {
language {
enableSplit = false
@@ -53,10 +60,6 @@ android {
targetCompatibility JavaVersion.VERSION_11
}
lintOptions {
disable "GoogleAppIndexingWarning", "ButtonStyle", "AlwaysShowAction",
"MissingTranslation", "MissingPrefix"
}
sourceSets {
test {
@@ -76,37 +79,40 @@ android {
includeAndroidResources true
}
}
lint {
lintConfig file('lint.xml')
}
namespace 'protect.card_locker'
}
dependencies {
// AndroidX
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.exifinterface:exifinterface:1.3.3'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.exifinterface:exifinterface:1.3.6'
implementation 'androidx.palette:palette:1.0.0'
implementation 'androidx.preference:preference:1.2.0'
implementation 'com.google.android.material:material:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'com.github.yalantis:ucrop:2.2.8'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
// Splash Screen
implementation 'androidx.core:core-splashscreen:1.0.0'
implementation 'androidx.core:core-splashscreen:1.0.1'
// Third-party
implementation 'com.journeyapps:zxing-android-embedded:4.3.0@aar'
implementation 'com.google.zxing:core:3.5.0'
implementation 'com.google.zxing:core:3.5.2'
implementation 'org.apache.commons:commons-csv:1.9.0'
implementation 'com.jaredrummler:colorpicker:1.1.0'
implementation 'com.github.invissvenska:NumberPickerPreference:1.0.4'
implementation 'net.lingala.zip4j:zip4j:2.11.2'
implementation 'net.lingala.zip4j:zip4j:2.11.5'
// SpotBugs
implementation 'io.wcm.tooling.spotbugs:io.wcm.tooling.spotbugs.annotations:1.0.0'
// Testing
testImplementation 'androidx.test:core:1.4.0'
testImplementation 'androidx.test:core:1.5.0'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.8.2'
testImplementation 'org.robolectric:robolectric:4.10.3'
}
tasks.withType(SpotBugsTask) {
@@ -123,3 +129,18 @@ tasks.withType(SpotBugsTask) {
html.enabled = true
}
}
tasks.register('copyRawResFiles', Copy) {
from layout.projectDirectory.file("../CHANGELOG.md"),
layout.projectDirectory.file("../PRIVACY.md")
into layout.projectDirectory.dir("src/main/res/raw")
rename { String fileName -> fileName.toLowerCase() }
}
project.afterEvaluate {
tasks.each { task ->
if (task != copyRawResFiles) {
task.dependsOn(copyRawResFiles)
}
}
}

View File

@@ -6,5 +6,8 @@
<Match>
<Class name="~.*Manifest\$.*"/>
</Match>
<Match>
<Class name="~.*Binding" />
</Match>
</FindBugsFilter>

8
app/lint.xml Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<issue id="AlwaysShowAction" severity="ignore" />
<issue id="ButtonStyle" severity="ignore" />
<issue id="GoogleAppIndexingWarning" severity="ignore" />
<issue id="MissingTranslation" severity="ignore" />
<issue id="MissingPrefix" severity="ignore" />
</lint>

View File

@@ -1,13 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="protect.card_locker">
xmlns:tools="http://schemas.android.com/tools">
<permission
android:description="@string/permissionReadCardsDescription"
android:icon="@drawable/ic_launcher_foreground"
android:label="@string/permissionReadCardsLabel"
android:name="${applicationId}.READ_CARDS"
android:protectionLevel="dangerous" />
<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-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="23" />
<uses-feature
android:name="android.hardware.camera"
@@ -22,7 +27,8 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:localeConfig="@xml/locales_config">
<activity
android:name=".MainActivity"
android:exported="true"
@@ -33,6 +39,12 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
<activity
android:name=".AboutActivity"
@@ -102,7 +114,39 @@
<activity
android:name=".ImportExportActivity"
android:label="@string/importExport"
android:theme="@style/AppTheme.NoActionBar" />
android:exported="true"
android:theme="@style/AppTheme.NoActionBar">
<!-- ZIP Intent Filter -->
<intent-filter
android:label="@string/importCards">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/zip" />
<data android:scheme="content"/>
<data android:host="*"/>
</intent-filter>
<!-- JSON Intent Filter -->
<intent-filter
android:label="@string/importCards">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/json" />
<data android:scheme="content"/>
<data android:host="*"/>
</intent-filter>
<!-- CSV Intent Filter -->
<intent-filter
android:label="@string/importCards">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content"/>
<data android:host="*" />
<data android:mimeType="text/comma-separated-values" />
</intent-filter>
</activity>
<activity
android:name=".CardShortcutConfigure"
android:exported="true"
@@ -119,6 +163,12 @@
android:name=".UCropWrapper"
android:theme="@style/AppTheme.NoActionBar" />
<provider
android:name=".contentprovider.CardsContentProvider"
android:authorities="${applicationId}.contentprovider.cards"
android:exported="true"
android:readPermission="${applicationId}.READ_CARDS"/>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}"
@@ -135,4 +185,4 @@
</intent-filter>
</service>
</application>
</manifest>
</manifest>

View File

@@ -1,138 +1,57 @@
package protect.card_locker;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.text.Spanned;
import android.view.MenuItem;
import android.view.View;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
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.annotation.StringRes;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.text.HtmlCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import protect.card_locker.databinding.AboutActivityBinding;
public class AboutActivity extends CatimaAppCompatActivity {
public class AboutActivity extends CatimaAppCompatActivity implements View.OnClickListener {
private static final String TAG = "Catima";
ConstraintLayout version_history, translate, license, repo, privacy, error, credits, rate;
private AboutActivityBinding binding;
private AboutContent content;
@Override
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) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
binding = AboutActivityBinding.inflate(getLayoutInflater());
content = new AboutContent(this);
setTitle(content.getPageTitle());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
enableToolbarBackButton();
StringBuilder contributors = new StringBuilder().append("<br/>");
TextView copyright = binding.creditsSub;
copyright.setText(content.getCopyrightShort());
TextView versionHistory = binding.versionHistorySub;
versionHistory.setText(content.getVersionHistory());
BufferedReader reader = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.contributors), StandardCharsets.UTF_8));
binding.versionHistory.setTag("https://catima.app/changelog/");
binding.translate.setTag("https://hosted.weblate.org/engage/catima/");
binding.license.setTag("https://github.com/CatimaLoyalty/Android/blob/main/LICENSE");
binding.repo.setTag("https://github.com/CatimaLoyalty/Android/");
binding.privacy.setTag("https://catima.app/privacy-policy/");
binding.reportError.setTag("https://github.com/CatimaLoyalty/Android/issues");
binding.rate.setTag("https://play.google.com/store/apps/details?id=me.hackerchick.catima");
binding.donate.setTag("https://catima.app/contribute/#donating");
try {
while (true) {
String tmp = reader.readLine();
boolean installedFromGooglePlay = Utils.installedFromGooglePlay(this);
// Hide Google Play rate button if not on Google Play
binding.rate.setVisibility(installedFromGooglePlay ? View.VISIBLE : View.GONE);
// Hide donate button on Google Play (Google Play doesn't allow donation links)
binding.donate.setVisibility(installedFromGooglePlay ? View.GONE : View.VISIBLE);
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"));
USED_LIBRARIES.add(new ThirdPartyInfo("NumberPickerPreference", "https://github.com/invissvenska/NumberPickerPreference", "GNU LGPL 3.0"));
USED_LIBRARIES.add(new ThirdPartyInfo("uCrop", "https://github.com/Yalantis/uCrop", "Apache 2.0"));
USED_LIBRARIES.add(new ThirdPartyInfo("Zip4j", "https://github.com/srikanth-lingala/zip4j", "Apache 2.0"));
USED_LIBRARIES.add(new ThirdPartyInfo("ZXing", "https://github.com/zxing/zxing", "Apache 2.0"));
USED_LIBRARIES.add(new ThirdPartyInfo("ZXing Android Embedded", "https://github.com/journeyapps/zxing-android-embedded", "Apache 2.0"));
final List<ThirdPartyInfo> USED_ASSETS = new ArrayList<>();
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(")");
}
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(")");
}
String appName = getString(R.string.app_name);
int year = Calendar.getInstance().get(Calendar.YEAR);
String version = "?";
try {
PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0);
version = pi.versionName;
} 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));
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());
bindClickListeners();
}
@Override
@@ -145,36 +64,79 @@ public class AboutActivity extends CatimaAppCompatActivity implements View.OnCli
}
@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/CatimaLoyalty/Android/blob/master/LICENSE";
} else if (id == R.id.repo) {
url = "https://github.com/CatimaLoyalty/Android/";
} else if (id == R.id.privacy) {
url = "https://catima.app/privacy-policy/";
} else if (id == R.id.report_error) {
url = "https://github.com/CatimaLoyalty/Android/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));
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.failedToOpenUrl, Toast.LENGTH_LONG).show();
Log.e(TAG, "No activity found to handle intent", e);
}
protected void onDestroy() {
super.onDestroy();
content.destroy();
clearClickListeners();
binding = null;
}
private void bindClickListeners() {
binding.versionHistory.setOnClickListener(this::showHistory);
binding.translate.setOnClickListener(this::openExternalBrowser);
binding.license.setOnClickListener(this::showLicense);
binding.repo.setOnClickListener(this::openExternalBrowser);
binding.privacy.setOnClickListener(this::showPrivacy);
binding.reportError.setOnClickListener(this::openExternalBrowser);
binding.rate.setOnClickListener(this::openExternalBrowser);
binding.donate.setOnClickListener(this::openExternalBrowser);
binding.credits.setOnClickListener(view -> showCredits());
}
private void clearClickListeners() {
binding.versionHistory.setOnClickListener(null);
binding.translate.setOnClickListener(null);
binding.license.setOnClickListener(null);
binding.repo.setOnClickListener(null);
binding.privacy.setOnClickListener(null);
binding.reportError.setOnClickListener(null);
binding.rate.setOnClickListener(null);
binding.donate.setOnClickListener(null);
binding.credits.setOnClickListener(null);
}
private void showCredits() {
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.credits)
.setMessage(content.getContributorInfo())
.setPositiveButton(R.string.ok, null)
.show();
}
private void showHistory(View view) {
showHTML(R.string.version_history, content.getHistoryInfo(), view);
}
private void showLicense(View view) {
showHTML(R.string.license, content.getLicenseInfo(), view);
}
private void showPrivacy(View view) {
showHTML(R.string.privacy_policy, content.getPrivacyInfo(), view);
}
private void showHTML(@StringRes int title, final Spanned text, View view) {
int dialogContentPadding = getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_padding);
TextView textView = new TextView(this);
textView.setText(text);
Utils.makeTextViewLinksClickable(textView, text);
ScrollView scrollView = new ScrollView(this);
scrollView.addView(textView);
scrollView.setPadding(dialogContentPadding, dialogContentPadding / 2, dialogContentPadding, 0);
new MaterialAlertDialogBuilder(this)
.setTitle(title)
.setView(scrollView)
.setPositiveButton(R.string.ok, null)
.setNeutralButton(R.string.view_online, (dialog, which) -> openExternalBrowser(view))
.show();
}
private void openExternalBrowser(View view) {
Object tag = view.getTag();
if (tag instanceof String && ((String) tag).startsWith("https://")) {
(new OpenWebLinkHandler()).openBrowser(this, (String) tag);
}
}
}

View File

@@ -0,0 +1,162 @@
package protect.card_locker;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.text.Spanned;
import android.util.Log;
import androidx.core.text.HtmlCompat;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
public class AboutContent {
public static final String TAG = "Catima";
public Context context;
public AboutContent(Context context) {
this.context = context;
}
public void destroy() {
this.context = null;
}
public String getPageTitle() {
return String.format(context.getString(R.string.about_title_fmt), context.getString(R.string.app_name));
}
public String getAppVersion() {
String version = "?";
try {
PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
version = pi.versionName;
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Package name not found", e);
}
return version;
}
public int getCurrentYear() {
return Calendar.getInstance().get(Calendar.YEAR);
}
public String getCopyright() {
return String.format(context.getString(R.string.app_copyright_fmt), getCurrentYear());
}
public String getCopyrightShort() {
return context.getString(R.string.app_copyright_short);
}
public String getContributors() {
String contributors;
try {
contributors = "<br/>" + Utils.readTextFile(context, R.raw.contributors);
} catch (IOException ignored) {
return "";
}
return contributors.replace("\n", "<br />");
}
public String getHistory() {
String versionHistory;
try {
versionHistory = Utils.readTextFile(context, R.raw.changelog)
.replace("# Changelog\n\n", "");
} catch (IOException ignored) {
return "";
}
return Utils.linkify(Utils.basicMDToHTML(versionHistory))
.replace("\n", "<br />");
}
public String getLicense() {
try {
return Utils.readTextFile(context, R.raw.license);
} catch (IOException ignored) {
return "";
}
}
public String getPrivacy() {
String privacyPolicy;
try {
privacyPolicy = Utils.readTextFile(context, R.raw.privacy)
.replace("# Privacy Policy\n", "");
} catch (IOException ignored) {
return "";
}
return Utils.linkify(Utils.basicMDToHTML(privacyPolicy))
.replace("\n", "<br />");
}
public String getThirdPartyLibraries() {
final List<ThirdPartyInfo> usedLibraries = new ArrayList<>();
usedLibraries.add(new ThirdPartyInfo("Color Picker", "https://github.com/jaredrummler/ColorPicker", "Apache 2.0"));
usedLibraries.add(new ThirdPartyInfo("Commons CSV", "https://commons.apache.org/proper/commons-csv/", "Apache 2.0"));
usedLibraries.add(new ThirdPartyInfo("NumberPickerPreference", "https://github.com/invissvenska/NumberPickerPreference", "GNU LGPL 3.0"));
usedLibraries.add(new ThirdPartyInfo("uCrop", "https://github.com/Yalantis/uCrop", "Apache 2.0"));
usedLibraries.add(new ThirdPartyInfo("Zip4j", "https://github.com/srikanth-lingala/zip4j", "Apache 2.0"));
usedLibraries.add(new ThirdPartyInfo("ZXing", "https://github.com/zxing/zxing", "Apache 2.0"));
usedLibraries.add(new ThirdPartyInfo("ZXing Android Embedded", "https://github.com/journeyapps/zxing-android-embedded", "Apache 2.0"));
StringBuilder result = new StringBuilder("<br/>");
for (ThirdPartyInfo entry : usedLibraries) {
result.append("<br/>")
.append(entry.toHtml());
}
return result.toString();
}
public String getUsedThirdPartyAssets() {
final List<ThirdPartyInfo> usedAssets = new ArrayList<>();
usedAssets.add(new ThirdPartyInfo("Android icons", "https://fonts.google.com/icons?selected=Material+Icons", "Apache 2.0"));
StringBuilder result = new StringBuilder().append("<br/>");
for (ThirdPartyInfo entry : usedAssets) {
result.append("<br/>")
.append(entry.toHtml());
}
return result.toString();
}
public String getContributorInfo() {
StringBuilder contributorInfo = new StringBuilder();
contributorInfo.append(getCopyright());
contributorInfo.append("\n\n");
contributorInfo.append(context.getString(R.string.app_copyright_old));
contributorInfo.append("\n\n");
contributorInfo.append(HtmlCompat.fromHtml(String.format(context.getString(R.string.app_contributors), getContributors()), HtmlCompat.FROM_HTML_MODE_COMPACT));
contributorInfo.append("\n\n");
contributorInfo.append(HtmlCompat.fromHtml(String.format(context.getString(R.string.app_libraries), getThirdPartyLibraries()), HtmlCompat.FROM_HTML_MODE_COMPACT));
contributorInfo.append("\n\n");
contributorInfo.append(HtmlCompat.fromHtml(String.format(context.getString(R.string.app_resources), getUsedThirdPartyAssets()), HtmlCompat.FROM_HTML_MODE_COMPACT));
return contributorInfo.toString();
}
public Spanned getHistoryInfo() {
return HtmlCompat.fromHtml(getHistory(), HtmlCompat.FROM_HTML_MODE_COMPACT);
}
public Spanned getLicenseInfo() {
return HtmlCompat.fromHtml(getLicense(), HtmlCompat.FROM_HTML_MODE_LEGACY);
}
public Spanned getPrivacyInfo() {
return HtmlCompat.fromHtml(getPrivacy(), HtmlCompat.FROM_HTML_MODE_COMPACT);
}
public String getVersionHistory() {
return String.format(context.getString(R.string.debug_version_fmt), getAppVersion());
}
}

View File

@@ -0,0 +1,5 @@
package protect.card_locker;
public interface BarcodeImageWriterResultCallback {
void onBarcodeImageWriterResult(boolean success);
}

View File

@@ -41,13 +41,15 @@ public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
private final CatimaBarcode format;
private final int imageHeight;
private final int imageWidth;
private final int imagePadding;
private final boolean widthPadding;
private final boolean showFallback;
private final Runnable callback;
private final BarcodeImageWriterResultCallback callback;
BarcodeImageWriterTask(
Context context, ImageView imageView, String cardIdString,
CatimaBarcode barcodeFormat, TextView textView,
boolean showFallback, Runnable callback, boolean roundCornerPadding
boolean showFallback, BarcodeImageWriterResultCallback callback, boolean roundCornerPadding
) {
mContext = context;
@@ -61,32 +63,39 @@ public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
cardId = cardIdString;
format = barcodeFormat;
int padding = 0;
int imageViewHeight = imageView.getHeight();
int imageViewWidth = imageView.getWidth();
// Some barcodes already have internal whitespace and shouldn't get extra padding
// TODO: Get rid of this hack by somehow detecting this extra whitespace
if (roundCornerPadding && !barcodeFormat.hasInternalPadding()) {
padding = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, context.getResources().getDisplayMetrics()));
imagePadding = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, context.getResources().getDisplayMetrics()));
} else {
imagePadding = 0;
}
if (format.isSquare() && imageViewWidth > imageViewHeight) {
imageViewWidth -= imagePadding;
widthPadding = true;
} else {
imageViewHeight -= imagePadding;
widthPadding = false;
}
final int MAX_WIDTH = getMaxWidth(format);
int tempImageHeight;
int tempImageWidth;
if (imageView.getWidth() < MAX_WIDTH) {
tempImageHeight = imageView.getHeight();
tempImageWidth = imageView.getWidth();
if (format.isSquare()) {
imageHeight = imageWidth = Math.min(imageViewHeight, Math.min(MAX_WIDTH, imageViewWidth));
} else if (imageView.getWidth() < MAX_WIDTH) {
imageHeight = imageViewHeight;
imageWidth = imageViewWidth;
} else {
// Scale down the image to reduce the memory needed to produce it
tempImageWidth = MAX_WIDTH;
double ratio = (double) MAX_WIDTH / (double) imageView.getWidth();
tempImageHeight = (int) (imageView.getHeight() * ratio);
imageWidth = MAX_WIDTH;
double ratio = (double) MAX_WIDTH / (double) imageViewWidth;
imageHeight = (int) (imageViewHeight * ratio);
}
// Ensure space for padding if wanted
imageWidth = tempImageWidth;
imageHeight = tempImageHeight - padding;
this.showFallback = showFallback;
}
@@ -94,12 +103,15 @@ public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
switch (format.format()) {
// 2D barcodes
case AZTEC:
case DATA_MATRIX:
case MAXICODE:
case PDF_417:
case QR_CODE:
return MAX_WIDTH_2D;
// 2D but rectangular versions get blurry otherwise
case DATA_MATRIX:
return MAX_WIDTH_1D;
// 1D barcodes:
case CODABAR:
case CODE_39:
@@ -261,6 +273,11 @@ public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
if (result != null) {
Log.i(TAG, "Displaying barcode");
if (widthPadding) {
imageView.setPadding(imagePadding / 2, 0, imagePadding / 2, 0);
} else {
imageView.setPadding(0, imagePadding / 2, 0, imagePadding / 2);
}
imageView.setVisibility(View.VISIBLE);
if (isSuccesful) {
@@ -282,7 +299,7 @@ public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
}
if (callback != null) {
callback.run();
callback.onBarcodeImageWriterResult(isSuccesful);
}
}

View File

@@ -16,9 +16,10 @@ import com.google.zxing.BarcodeFormat;
import java.util.ArrayList;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import protect.card_locker.databinding.BarcodeSelectorActivityBinding;
/**
* This activity is callable and will allow a user to enter
* barcode data and generate all barcodes possible for
@@ -26,6 +27,7 @@ import androidx.appcompat.widget.Toolbar;
* data and type will be returned to the caller.
*/
public class BarcodeSelectorActivity extends CatimaAppCompatActivity implements BarcodeSelectorAdapter.BarcodeSelectorListener {
private BarcodeSelectorActivityBinding binding;
private static final String TAG = "Catima";
// Result this activity will return
@@ -40,17 +42,15 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity implements
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = BarcodeSelectorActivityBinding.inflate(getLayoutInflater());
setTitle(R.string.selectBarcodeTitle);
setContentView(R.layout.barcode_selector_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setContentView(binding.getRoot());
Toolbar toolbar = binding.toolbar;
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
enableToolbarBackButton();
EditText cardId = findViewById(R.id.cardId);
ListView mBarcodeList = findViewById(R.id.barcodes);
EditText cardId = binding.cardId;
ListView mBarcodeList = binding.barcodes;
mAdapter = new BarcodeSelectorAdapter(this, new ArrayList<>(), this);
mBarcodeList.setAdapter(mAdapter);
@@ -65,10 +65,6 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity implements
runOnUiThread(() -> {
generateBarcodes(s.toString());
View noBarcodeButtonView = findViewById(R.id.noBarcode);
setButtonListener(noBarcodeButtonView, s.toString());
noBarcodeButtonView.setEnabled(s.length() > 0);
});
}, INPUT_DELAY);
}
@@ -94,17 +90,6 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity implements
mAdapter.setBarcodes(barcodes);
}
private void setButtonListener(final View button, final String cardId) {
button.setOnClickListener(view -> {
Log.d(TAG, "Selected no barcode");
Intent result = new Intent();
result.putExtra(BARCODE_FORMAT, "");
result.putExtra(BARCODE_CONTENTS, cardId);
BarcodeSelectorActivity.this.setResult(RESULT_OK, result);
finish();
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {

View File

@@ -13,6 +13,7 @@ import android.widget.TextView;
import java.util.ArrayList;
import protect.card_locker.async.TaskHandler;
import protect.card_locker.databinding.BarcodeLayoutBinding;
public class BarcodeSelectorAdapter extends ArrayAdapter<CatimaBarcodeWithValue> {
private static final String TAG = "Catima";
@@ -51,9 +52,10 @@ public class BarcodeSelectorAdapter extends ArrayAdapter<CatimaBarcodeWithValue>
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.barcode_layout, parent, false);
viewHolder.image = convertView.findViewById(R.id.barcodeImage);
viewHolder.text = convertView.findViewById(R.id.barcodeName);
BarcodeLayoutBinding barcodeLayoutBinding = BarcodeLayoutBinding.inflate(inflater, parent, false);
convertView = barcodeLayoutBinding.getRoot();
viewHolder.image = barcodeLayoutBinding.barcodeImage;
viewHolder.text = barcodeLayoutBinding.barcodeName;
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();

View File

@@ -14,10 +14,13 @@ import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import protect.card_locker.databinding.SimpleToolbarListActivityBinding;
/**
* The configuration screen for creating a shortcut.
*/
public class CardShortcutConfigure extends CatimaAppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener {
private SimpleToolbarListActivityBinding binding;
static final String TAG = "Catima";
private SQLiteDatabase mDatabase;
private LoyaltyCardCursorAdapter mAdapter;
@@ -25,15 +28,15 @@ public class CardShortcutConfigure extends CatimaAppCompatActivity implements Lo
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
binding = SimpleToolbarListActivityBinding.inflate(getLayoutInflater());
mDatabase = new DBHelper(this).getReadableDatabase();
// Set the result to CANCELED. This will cause nothing to happen if the
// aback button is pressed.
setResult(RESULT_CANCELED);
setContentView(R.layout.simple_toolbar_list_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setContentView(binding.getRoot());
Toolbar toolbar = binding.toolbar;
toolbar.setTitle(R.string.shortcutSelectCard);
setSupportActionBar(toolbar);
@@ -44,25 +47,19 @@ public class CardShortcutConfigure extends CatimaAppCompatActivity implements Lo
finish();
}
// If all cards are archived, bail
if (DBHelper.getArchivedCardsCount(mDatabase) == cardCount) {
Toast.makeText(this, R.string.noUnarchivedCardsMessage, Toast.LENGTH_LONG).show();
finish();
}
final RecyclerView cardList = findViewById(R.id.list);
final RecyclerView cardList = binding.list;
GridLayoutManager layoutManager = (GridLayoutManager) cardList.getLayoutManager();
if (layoutManager != null) {
layoutManager.setSpanCount(getResources().getInteger(R.integer.main_view_card_columns));
}
Cursor cardCursor = DBHelper.getLoyaltyCardCursor(mDatabase, DBHelper.LoyaltyCardArchiveFilter.Unarchived);
mAdapter = new LoyaltyCardCursorAdapter(this, cardCursor, this);
Cursor cardCursor = DBHelper.getLoyaltyCardCursor(mDatabase, DBHelper.LoyaltyCardArchiveFilter.All);
mAdapter = new LoyaltyCardCursorAdapter(this, cardCursor, this, null);
cardList.setAdapter(mAdapter);
}
private void onClickAction(int position) {
Cursor selected = DBHelper.getLoyaltyCardCursor(mDatabase, DBHelper.LoyaltyCardArchiveFilter.Unarchived);
Cursor selected = DBHelper.getLoyaltyCardCursor(mDatabase, DBHelper.LoyaltyCardArchiveFilter.All);
selected.moveToPosition(position);
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
@@ -78,7 +75,7 @@ public class CardShortcutConfigure extends CatimaAppCompatActivity implements Lo
@Override
public boolean onCreateOptionsMenu(Menu inputMenu) {
getMenuInflater().inflate(R.menu.card_details_menu, inputMenu);
Utils.updateMenuCardDetailsButtonState(inputMenu.findItem(R.id.action_unfold), mAdapter.showingDetails());
return super.onCreateOptionsMenu(inputMenu);
}
@@ -86,8 +83,8 @@ public class CardShortcutConfigure extends CatimaAppCompatActivity implements Lo
public boolean onOptionsItemSelected(MenuItem inputItem) {
int id = inputItem.getItemId();
if (id == R.id.action_unfold) {
mAdapter.showDetails(!mAdapter.showingDetails());
if (id == R.id.action_display_options) {
mAdapter.showDisplayOptionsDialog();
invalidateOptionsMenu();
return true;

View File

@@ -1,6 +1,5 @@
package protect.card_locker;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -69,10 +68,9 @@ public class CardsOnPowerScreenService extends ControlsProviderService {
subscriber.onSubscribe(new NoOpSubscription());
for (String controlId : controlIds) {
Control control;
try {
Integer cardId = this.controlIdToCardId(controlId);
LoyaltyCard card = DBHelper.getLoyaltyCard(mDatabase, cardId);
Integer cardId = this.controlIdToCardId(controlId);
LoyaltyCard card = DBHelper.getLoyaltyCard(mDatabase, cardId);
if (card != null) {
Intent openIntent = new Intent(this, LoyaltyCardViewActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra("id", card.id);
@@ -85,7 +83,7 @@ public class CardsOnPowerScreenService extends ControlsProviderService {
.setControlTemplate(new StatelessTemplate(controlId))
.setCustomIcon(Icon.createWithBitmap(getIcon(this, card)))
.build();
} catch (NullPointerException ignored) {
} else {
Intent mainScreenIntent = new Intent(this, MainActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(getBaseContext(), -1, mainScreenIntent, PendingIntent.FLAG_IMMUTABLE);
@@ -137,7 +135,7 @@ public class CardsOnPowerScreenService extends ControlsProviderService {
closePowerScreenOnAndroid11();
}
@SuppressLint({"MissingPermission", "deprecation"})
@SuppressWarnings({"MissingPermission", "deprecation"})
private void closePowerScreenOnAndroid11() {
// Android 12 will auto-close the power screen, but earlier versions won't
// Lint complains about this but on Android 11 the permission is not needed

View File

@@ -6,8 +6,11 @@ import android.os.Build;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.WindowInsetsControllerCompat;
public class CatimaAppCompatActivity extends AppCompatActivity {
@Override
@@ -29,8 +32,10 @@ public class CatimaAppCompatActivity extends AppCompatActivity {
// XXX changing this in onCreate causes issues with the splash screen activity, so doing this here
boolean darkMode = Utils.isDarkModeEnabled(this);
if (Build.VERSION.SDK_INT >= 23) {
View decorView = getWindow().getDecorView();
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(getWindow(), decorView);
wic.setAppearanceLightStatusBars(!darkMode);
getWindow().setStatusBarColor(Color.TRANSPARENT);
getWindow().getDecorView().setSystemUiVisibility(darkMode ? 0 : View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
// icons are always white back then
getWindow().setStatusBarColor(darkMode ? Color.TRANSPARENT : Color.argb(127, 0, 0, 0));
@@ -38,4 +43,14 @@ public class CatimaAppCompatActivity extends AppCompatActivity {
// XXX android 9 and below has a nasty rendering bug if the theme was patched earlier
Utils.postPatchColors(this);
}
protected void enableToolbarBackButton() {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
public void onMockedRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
}
}

View File

@@ -67,7 +67,6 @@ public class CatimaBarcode {
public boolean isSquare() {
return mBarcodeFormat == BarcodeFormat.AZTEC
|| mBarcodeFormat == BarcodeFormat.DATA_MATRIX
|| mBarcodeFormat == BarcodeFormat.MAXICODE
|| mBarcodeFormat == BarcodeFormat.QR_CODE;
}

View File

@@ -16,12 +16,17 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Currency;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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 = 15;
public static final int DATABASE_VERSION = 16;
// NB: changing this value requires a migration
public static final int DEFAULT_ZOOM_LEVEL = 100;
public static class LoyaltyCardDbGroups {
public static final String TABLE = "groups";
@@ -33,6 +38,7 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String TABLE = "cards";
public static final String ID = "_id";
public static final String STORE = "store";
public static final String VALID_FROM = "validfrom";
public static final String EXPIRY = "expiry";
public static final String BALANCE = "balance";
public static final String BALANCE_TYPE = "balancetype";
@@ -95,6 +101,7 @@ public class DBHelper extends SQLiteOpenHelper {
LoyaltyCardDbIds.ID + " INTEGER primary key autoincrement," +
LoyaltyCardDbIds.STORE + " TEXT not null," +
LoyaltyCardDbIds.NOTE + " TEXT not null," +
LoyaltyCardDbIds.VALID_FROM + " INTEGER," +
LoyaltyCardDbIds.EXPIRY + " INTEGER," +
LoyaltyCardDbIds.BALANCE + " TEXT not null DEFAULT '0'," +
LoyaltyCardDbIds.BALANCE_TYPE + " TEXT," +
@@ -104,7 +111,7 @@ public class DBHelper extends SQLiteOpenHelper {
LoyaltyCardDbIds.BARCODE_TYPE + " TEXT," +
LoyaltyCardDbIds.STAR_STATUS + " INTEGER DEFAULT '0'," +
LoyaltyCardDbIds.LAST_USED + " INTEGER DEFAULT '0', " +
LoyaltyCardDbIds.ZOOM_LEVEL + " INTEGER DEFAULT '100', " +
LoyaltyCardDbIds.ZOOM_LEVEL + " INTEGER DEFAULT '" + DEFAULT_ZOOM_LEVEL + "', " +
LoyaltyCardDbIds.ARCHIVE_STATUS + " INTEGER DEFAULT '0' )");
// create associative table for cards in groups
@@ -314,6 +321,26 @@ public class DBHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
+ " ADD COLUMN " + LoyaltyCardDbIds.ARCHIVE_STATUS + " INTEGER DEFAULT '0' ");
}
if (oldVersion < 16 && newVersion >= 16) {
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
+ " ADD COLUMN " + LoyaltyCardDbIds.VALID_FROM + " INTEGER");
}
}
public static Set<String> imageFiles(Context context, final SQLiteDatabase database) {
Set<String> files = new HashSet<>();
Cursor cardCursor = getLoyaltyCardCursor(database);
while (cardCursor.moveToNext()) {
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cardCursor);
for (ImageLocationType imageLocationType : ImageLocationType.values()) {
String name = Utils.getCardImageFileName(card.id, imageLocationType);
if (Utils.retrieveCardImageAsFile(context, name).exists()) {
files.add(name);
}
}
}
return files;
}
private static ContentValues generateFTSContentValues(final int id, final String store, final String note) {
@@ -358,8 +385,8 @@ public class DBHelper extends SQLiteOpenHelper {
}
public static long insertLoyaltyCard(
final SQLiteDatabase database, final String store, final String note, final Date expiry,
final BigDecimal balance, final Currency balanceType, final String cardId,
final SQLiteDatabase database, final String store, final String note, final Date validFrom,
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, final int archiveStatus) {
database.beginTransaction();
@@ -368,6 +395,7 @@ public class DBHelper extends SQLiteOpenHelper {
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbIds.STORE, store);
contentValues.put(LoyaltyCardDbIds.NOTE, note);
contentValues.put(LoyaltyCardDbIds.VALID_FROM, validFrom != null ? validFrom.getTime() : null);
contentValues.put(LoyaltyCardDbIds.EXPIRY, expiry != null ? expiry.getTime() : null);
contentValues.put(LoyaltyCardDbIds.BALANCE, balance.toString());
contentValues.put(LoyaltyCardDbIds.BALANCE_TYPE, balanceType != null ? balanceType.getCurrencyCode() : null);
@@ -391,9 +419,10 @@ public class DBHelper extends SQLiteOpenHelper {
public static long insertLoyaltyCard(
final SQLiteDatabase database, 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 CatimaBarcode barcodeType,
final Integer headerColor, final int starStatus, final Long lastUsed, final int archiveStatus) {
final Date validFrom, 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, final int archiveStatus) {
database.beginTransaction();
// Card
@@ -401,6 +430,7 @@ public class DBHelper extends SQLiteOpenHelper {
contentValues.put(LoyaltyCardDbIds.ID, id);
contentValues.put(LoyaltyCardDbIds.STORE, store);
contentValues.put(LoyaltyCardDbIds.NOTE, note);
contentValues.put(LoyaltyCardDbIds.VALID_FROM, validFrom != null ? validFrom.getTime() : null);
contentValues.put(LoyaltyCardDbIds.EXPIRY, expiry != null ? expiry.getTime() : null);
contentValues.put(LoyaltyCardDbIds.BALANCE, balance.toString());
contentValues.put(LoyaltyCardDbIds.BALANCE_TYPE, balanceType != null ? balanceType.getCurrencyCode() : null);
@@ -424,15 +454,17 @@ public class DBHelper extends SQLiteOpenHelper {
public static boolean updateLoyaltyCard(
SQLiteDatabase database, 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 CatimaBarcode barcodeType,
final Integer headerColor, final int starStatus, final Long lastUsed, final int archiveStatus) {
final Date validFrom, 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, final int archiveStatus) {
database.beginTransaction();
// Card
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbIds.STORE, store);
contentValues.put(LoyaltyCardDbIds.NOTE, note);
contentValues.put(LoyaltyCardDbIds.VALID_FROM, validFrom != null ? validFrom.getTime() : null);
contentValues.put(LoyaltyCardDbIds.EXPIRY, expiry != null ? expiry.getTime() : null);
contentValues.put(LoyaltyCardDbIds.BALANCE, balance.toString());
contentValues.put(LoyaltyCardDbIds.BALANCE_TYPE, balanceType != null ? balanceType.getCurrencyCode() : null);
@@ -494,6 +526,15 @@ public class DBHelper extends SQLiteOpenHelper {
return (rowsUpdated == 1);
}
public static boolean updateLoyaltyCardBalance(SQLiteDatabase database, final int id, final BigDecimal newBalance) {
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbIds.BALANCE, newBalance.toString());
int rowsUpdated = database.update(LoyaltyCardDbIds.TABLE, contentValues,
whereAttrs(LoyaltyCardDbIds.ID),
withArgs(id));
return (rowsUpdated == 1);
}
public static LoyaltyCard getLoyaltyCard(SQLiteDatabase database, final int id) {
Cursor data = database.query(LoyaltyCardDbIds.TABLE, null, whereAttrs(LoyaltyCardDbIds.ID), withArgs(id), null, null, null);

View File

@@ -7,15 +7,17 @@ import android.database.sqlite.SQLiteDatabase;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageButton;
import androidx.recyclerview.widget.RecyclerView;
import protect.card_locker.databinding.GroupLayoutBinding;
import protect.card_locker.preferences.Settings;
public class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.GroupListItemViewHolder> {
Settings mSettings;
public final Context mContext;
private final GroupAdapterListener mListener;
SQLiteDatabase mDatabase;
@@ -23,7 +25,6 @@ public class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.Gro
public GroupCursorAdapter(Context inputContext, Cursor inputCursor, GroupAdapterListener inputListener) {
super(inputCursor, DBHelper.LoyaltyCardDbGroups.ORDER);
setHasStableIds(true);
mSettings = new Settings(inputContext);
mContext = inputContext;
mListener = inputListener;
mDatabase = new DBHelper(inputContext).getReadableDatabase();
@@ -33,9 +34,14 @@ public class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.Gro
@NonNull
@Override
public GroupCursorAdapter.GroupListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType) {
View itemView = LayoutInflater.from(inputParent.getContext()).inflate(R.layout.group_layout, inputParent, false);
return new GroupListItemViewHolder(itemView);
public GroupCursorAdapter.GroupListItemViewHolder onCreateViewHolder(@NonNull ViewGroup inputParent, int inputViewType) {
return new GroupListItemViewHolder(
GroupLayoutBinding.inflate(
LayoutInflater.from(inputParent.getContext()),
inputParent,
false
)
);
}
public void onBindViewHolder(GroupListItemViewHolder inputHolder, Cursor inputCursor) {
@@ -56,8 +62,6 @@ public class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.Gro
}
inputHolder.mCardCount.setText(cardCountText);
inputHolder.mName.setTextSize(mSettings.getFontSizeMax(mSettings.getMediumFont()));
inputHolder.mCardCount.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
applyClickEvents(inputHolder);
}
@@ -81,16 +85,16 @@ public class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.Gro
public static class GroupListItemViewHolder extends RecyclerView.ViewHolder {
public TextView mName, mCardCount;
public AppCompatImageButton mMoveUp, mMoveDown, mEdit, mDelete;
public Button mMoveUp, mMoveDown, mEdit, mDelete;
public GroupListItemViewHolder(View inputView) {
super(inputView);
mName = inputView.findViewById(R.id.name);
mCardCount = inputView.findViewById(R.id.cardCount);
mMoveUp = inputView.findViewById(R.id.moveUp);
mMoveDown = inputView.findViewById(R.id.moveDown);
mEdit = inputView.findViewById(R.id.edit);
mDelete = inputView.findViewById(R.id.delete);
public GroupListItemViewHolder(GroupLayoutBinding groupLayoutBinding) {
super(groupLayoutBinding.getRoot());
mName = groupLayoutBinding.name;
mCardCount = groupLayoutBinding.cardCount;
mMoveUp = groupLayoutBinding.moveUp;
mMoveDown = groupLayoutBinding.moveDown;
mEdit = groupLayoutBinding.edit;
mDelete = groupLayoutBinding.delete;
}
}
}

View File

@@ -24,21 +24,25 @@ import java.util.List;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import protect.card_locker.async.TaskHandler;
import protect.card_locker.databinding.ImportExportActivityBinding;
import protect.card_locker.importexport.DataFormat;
import protect.card_locker.importexport.ImportExportResult;
import protect.card_locker.importexport.ImportExportResultType;
public class ImportExportActivity extends CatimaAppCompatActivity {
private ImportExportActivityBinding binding;
private static final String TAG = "Catima";
private static final int PERMISSIONS_EXTERNAL_STORAGE = 1;
private ImportExportTask importExporter;
private String importAlertTitle;
@@ -55,26 +59,16 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ImportExportActivityBinding.inflate(getLayoutInflater());
setTitle(R.string.importExport);
setContentView(R.layout.import_export_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setContentView(binding.getRoot());
Toolbar toolbar = binding.toolbar;
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
enableToolbarBackButton();
// If the application does not have permissions to external
// storage, ask for it now
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) {
ActivityCompat.requestPermissions(ImportExportActivity.this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSIONS_EXTERNAL_STORAGE);
Intent fileIntent = getIntent();
if (fileIntent != null && fileIntent.getType() != null) {
chooseImportType(false, fileIntent.getData());
}
// would use ActivityResultContracts.CreateDocument() but mime type cannot be set
@@ -126,9 +120,9 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
intentCreateDocumentAction.setType("application/zip");
intentCreateDocumentAction.putExtra(Intent.EXTRA_TITLE, "catima.zip");
Button exportButton = findViewById(R.id.exportButton);
Button exportButton = binding.exportButton;
exportButton.setOnClickListener(v -> {
AlertDialog.Builder builder = new AlertDialog.Builder(ImportExportActivity.this);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(ImportExportActivity.this);
builder.setTitle(R.string.exportPassword);
FrameLayout container = new FrameLayout(ImportExportActivity.this);
@@ -158,12 +152,12 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
});
// Check that there is a file manager available
Button importFilesystem = findViewById(R.id.importOptionFilesystemButton);
importFilesystem.setOnClickListener(v -> chooseImportType(false));
Button importFilesystem = binding.importOptionFilesystemButton;
importFilesystem.setOnClickListener(v -> chooseImportType(false, null));
// Check that there is an app that data can be imported from
Button importApplication = findViewById(R.id.importOptionApplicationButton);
importApplication.setOnClickListener(v -> chooseImportType(true));
Button importApplication = binding.importOptionApplicationButton;
importApplication.setOnClickListener(v -> chooseImportType(true, null));
}
private void openFileForImport(Uri uri, char[] password) {
@@ -177,7 +171,9 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
}
}
private void chooseImportType(boolean choosePicker) {
private void chooseImportType(boolean choosePicker,
@Nullable Uri fileData) {
List<CharSequence> betaImportOptions = new ArrayList<>();
betaImportOptions.add("Fidme");
betaImportOptions.add("Stocard");
@@ -191,7 +187,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
importOptions.add(importOption);
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.chooseImportType)
.setItems(importOptions.toArray(new CharSequence[importOptions.size()]), (dialog, which) -> {
switch (which) {
@@ -229,7 +225,12 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
throw new IllegalArgumentException("Unknown DataFormat");
}
new AlertDialog.Builder(this)
if (fileData != null) {
openFileForImport(fileData, null);
return;
}
new MaterialAlertDialogBuilder(this)
.setTitle(importAlertTitle)
.setMessage(importAlertMessage)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@@ -296,30 +297,6 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
mTasks.executeTask(TaskHandler.TYPE.EXPORT, importExporter);
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSIONS_EXTERNAL_STORAGE) {
// If request is cancelled, the result arrays are empty.
boolean success = grantResults.length > 0;
for (int grant : grantResults) {
if (grant != PackageManager.PERMISSION_GRANTED) {
success = false;
}
}
if (!success) {
// External storage permission rejected, inform user that
// import/export is prevented
Toast.makeText(getApplicationContext(), R.string.noExternalStoragePermissionError,
Toast.LENGTH_LONG).show();
}
}
}
@Override
protected void onDestroy() {
mTasks.flushTaskList(TaskHandler.TYPE.IMPORT, true, false, false);
@@ -340,7 +317,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
}
private void retryWithPassword(DataFormat dataFormat, Uri uri) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.passwordRequired);
final EditText input = new EditText(this);
@@ -383,7 +360,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
return;
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(resultType == ImportExportResultType.Success ? R.string.importSuccessfulTitle : R.string.importFailedTitle);
builder.setMessage(buildResultDialogMessage(result, true));
builder.setNeutralButton(R.string.ok, (dialog, which) -> dialog.dismiss());
@@ -394,7 +371,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
private void onExportComplete(ImportExportResult result, final Uri path) {
ImportExportResultType resultType = result.resultType();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(resultType == ImportExportResultType.Success ? R.string.exportSuccessfulTitle : R.string.exportFailedTitle);
builder.setMessage(buildResultDialogMessage(result, false));
builder.setNeutralButton(R.string.ok, (dialog, which) -> dialog.dismiss());

View File

@@ -18,6 +18,7 @@ import java.util.List;
public class ImportURIHelper {
private static final String STORE = DBHelper.LoyaltyCardDbIds.STORE;
private static final String NOTE = DBHelper.LoyaltyCardDbIds.NOTE;
private static final String VALID_FROM = DBHelper.LoyaltyCardDbIds.VALID_FROM;
private static final String EXPIRY = DBHelper.LoyaltyCardDbIds.EXPIRY;
private static final String BALANCE = DBHelper.LoyaltyCardDbIds.BALANCE;
private static final String BALANCE_TYPE = DBHelper.LoyaltyCardDbIds.BALANCE_TYPE;
@@ -45,8 +46,11 @@ public class ImportURIHelper {
}
private boolean isImportUri(Uri uri) {
// Remove trailing slash added by some browsers (if it exists)
final String uriPath = uri.getPath().replaceAll("/$", "");
for (int i = 0; i < hosts.length; i++) {
if (uri.getHost().equals(hosts[i]) && uri.getPath().equals(paths[i])) {
if (uri.getHost().equals(hosts[i]) && uriPath.equals(paths[i])) {
return true;
}
}
@@ -62,6 +66,7 @@ public class ImportURIHelper {
try {
// These values are allowed to be null
CatimaBarcode barcodeType = null;
Date validFrom = null;
Date expiry = null;
BigDecimal balance = new BigDecimal("0");
Currency balanceType = null;
@@ -106,6 +111,10 @@ public class ImportURIHelper {
if (unparsedBalanceType != null && !unparsedBalanceType.equals("")) {
balanceType = Currency.getInstance(unparsedBalanceType);
}
String unparsedValidFrom = kv.get(VALID_FROM);
if (unparsedValidFrom != null && !unparsedValidFrom.equals("")) {
validFrom = new Date(Long.parseLong(unparsedValidFrom));
}
String unparsedExpiry = kv.get(EXPIRY);
if (unparsedExpiry != null && !unparsedExpiry.equals("")) {
expiry = new Date(Long.parseLong(unparsedExpiry));
@@ -116,8 +125,8 @@ public class ImportURIHelper {
headerColor = Integer.parseInt(unparsedHeaderColor);
}
return new LoyaltyCard(-1, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, 0, Utils.getUnixTime(), 100,0);
} catch (NullPointerException | NumberFormatException | UnsupportedEncodingException ex) {
return new LoyaltyCard(-1, store, note, validFrom, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, 0, Utils.getUnixTime(), 100, 0);
} catch (NumberFormatException | UnsupportedEncodingException | ArrayIndexOutOfBoundsException ex) {
throw new InvalidObjectException("Not a valid import URI");
}
}
@@ -149,6 +158,9 @@ public class ImportURIHelper {
if (loyaltyCard.balanceType != null) {
fragment = appendFragment(fragment, BALANCE_TYPE, loyaltyCard.balanceType.getCurrencyCode());
}
if (loyaltyCard.validFrom != null) {
fragment = appendFragment(fragment, VALID_FROM, String.valueOf(loyaltyCard.validFrom.getTime()));
}
if (loyaltyCard.expiry != null) {
fragment = appendFragment(fragment, EXPIRY, String.valueOf(loyaltyCard.expiry.getTime()));
}

View File

@@ -8,39 +8,41 @@ import java.math.BigDecimal;
import java.util.Currency;
import java.util.Date;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class LoyaltyCard implements Parcelable {
public final int id;
public final String store;
public final String note;
@Nullable
public final Date validFrom;
@Nullable
public final Date expiry;
public final BigDecimal balance;
@Nullable
public final Currency balanceType;
public final String cardId;
@Nullable
public final String barcodeId;
@Nullable
public final CatimaBarcode barcodeType;
@Nullable
public final Integer headerColor;
public final int starStatus;
public final int archiveStatus;
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 CatimaBarcode barcodeType,
public LoyaltyCard(final int id, final String store, final String note, @Nullable final Date validFrom,
@Nullable final Date expiry, final BigDecimal balance, @Nullable final Currency balanceType,
final String cardId, @Nullable final String barcodeId, @Nullable final CatimaBarcode barcodeType,
@Nullable final Integer headerColor, final int starStatus,
final long lastUsed, final int zoomLevel, final int archiveStatus) {
this.id = id;
this.store = store;
this.note = note;
this.validFrom = validFrom;
this.expiry = expiry;
this.balance = balance;
this.balanceType = balanceType;
@@ -58,6 +60,8 @@ public class LoyaltyCard implements Parcelable {
id = in.readInt();
store = in.readString();
note = in.readString();
long tmpValidFrom = in.readLong();
validFrom = tmpValidFrom != -1 ? new Date(tmpValidFrom) : null;
long tmpExpiry = in.readLong();
expiry = tmpExpiry != -1 ? new Date(tmpExpiry) : null;
balance = (BigDecimal) in.readValue(BigDecimal.class.getClassLoader());
@@ -79,6 +83,7 @@ public class LoyaltyCard implements Parcelable {
parcel.writeInt(id);
parcel.writeString(store);
parcel.writeString(note);
parcel.writeLong(validFrom != null ? validFrom.getTime() : -1);
parcel.writeLong(expiry != null ? expiry.getTime() : -1);
parcel.writeValue(balance);
parcel.writeValue(balanceType);
@@ -96,6 +101,7 @@ public class LoyaltyCard implements Parcelable {
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));
long validFromLong = cursor.getLong(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.VALID_FROM));
long expiryLong = cursor.getLong(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.EXPIRY));
BigDecimal balance = new BigDecimal(cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BALANCE)));
String cardId = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.CARD_ID));
@@ -111,6 +117,7 @@ public class LoyaltyCard implements Parcelable {
CatimaBarcode barcodeType = null;
Currency balanceType = null;
Date validFrom = null;
Date expiry = null;
Integer headerColor = null;
@@ -122,6 +129,10 @@ public class LoyaltyCard implements Parcelable {
balanceType = Currency.getInstance(cursor.getString(balanceTypeColumn));
}
if (validFromLong > 0) {
validFrom = new Date(validFromLong);
}
if (expiryLong > 0) {
expiry = new Date(expiryLong);
}
@@ -130,7 +141,25 @@ public class LoyaltyCard implements Parcelable {
headerColor = cursor.getInt(headerColorColumn);
}
return new LoyaltyCard(id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starred, lastUsed, zoomLevel,archived);
return new LoyaltyCard(id, store, note, validFrom, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starred, lastUsed, zoomLevel, archived);
}
public static boolean isDuplicate(final LoyaltyCard a, final LoyaltyCard b) {
// Skip lastUsed & zoomLevel
return a.id == b.id && // non-nullable int
a.store.equals(b.store) && // non-nullable String
a.note.equals(b.note) && // non-nullable String
Utils.equals(a.validFrom, b.validFrom) && // nullable Date
Utils.equals(a.expiry, b.expiry) && // nullable Date
a.balance.equals(b.balance) && // non-nullable BigDecimal
Utils.equals(a.balanceType, b.balanceType) && // nullable Currency
a.cardId.equals(b.cardId) && // non-nullable String
Utils.equals(a.barcodeId, b.barcodeId) && // nullable String
Utils.equals(a.barcodeType == null ? null : a.barcodeType.format(),
b.barcodeType == null ? null : b.barcodeType.format()) && // nullable CatimaBarcode with no overridden .equals(), so we need to check .format()
Utils.equals(a.headerColor, b.headerColor) && // nullable Integer
a.starStatus == b.starStatus && // non-nullable int
a.archiveStatus == b.archiveStatus; // non-nullable int
}
@Override
@@ -138,6 +167,31 @@ public class LoyaltyCard implements Parcelable {
return id;
}
@NonNull
@Override
public String toString() {
return String.format(
"LoyaltyCard{%n id=%s,%n store=%s,%n note=%s,%n validFrom=%s,%n expiry=%s,%n"
+ " balance=%s,%n balanceType=%s,%n cardId=%s,%n barcodeId=%s,%n barcodeType=%s,%n"
+ " headerColor=%s,%n starStatus=%s,%n lastUsed=%s,%n zoomLevel=%s,%n archiveStatus=%s%n}",
this.id,
this.store,
this.note,
this.validFrom,
this.expiry,
this.balance,
this.balanceType,
this.cardId,
this.barcodeId,
this.barcodeType != null ? this.barcodeType.format() : null,
this.headerColor,
this.starStatus,
this.lastUsed,
this.zoomLevel,
this.archiveStatus
);
}
public static final Creator<LoyaltyCard> CREATOR = new Creator<LoyaltyCard>() {
@Override
public LoyaltyCard createFromParcel(Parcel in) {

View File

@@ -1,7 +1,6 @@
package protect.card_locker;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -17,75 +16,65 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.google.android.material.card.MaterialCardView;
import com.google.android.material.color.MaterialColors;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Currency;
import java.util.Date;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.BlendModeColorFilterCompat;
import androidx.core.graphics.BlendModeCompat;
import androidx.recyclerview.widget.RecyclerView;
import protect.card_locker.preferences.Settings;
import protect.card_locker.databinding.LoyaltyCardLayoutBinding;
public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder> {
private int mCurrentSelectedIndex = -1;
Settings mSettings;
boolean mDarkModeEnabled;
public final Context mContext;
private final CardAdapterListener mListener;
private final LoyaltyCardListDisplayOptionsManager mLoyaltyCardListDisplayOptions;
protected SparseBooleanArray mSelectedItems;
protected SparseBooleanArray mAnimationItemsIndex;
private boolean mReverseAllAnimations = false;
private boolean mShowDetails;
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener) {
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener, Runnable inputSwapCursorCallback) {
super(inputCursor, DBHelper.LoyaltyCardDbIds.ID);
setHasStableIds(true);
mSettings = new Settings(inputContext);
mContext = inputContext;
mListener = inputListener;
Runnable refreshCardsCallback = () -> notifyDataSetChanged();
mLoyaltyCardListDisplayOptions = new LoyaltyCardListDisplayOptionsManager(mContext, refreshCardsCallback, inputSwapCursorCallback);
mSelectedItems = new SparseBooleanArray();
mAnimationItemsIndex = new SparseBooleanArray();
mDarkModeEnabled = Utils.isDarkModeEnabled(inputContext);
refreshState();
swapCursor(inputCursor);
}
public void refreshState() {
// Retrieve user details preference
SharedPreferences cardDetailsPref = mContext.getSharedPreferences(
mContext.getString(R.string.sharedpreference_card_details),
Context.MODE_PRIVATE);
mShowDetails = cardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_show), true);
public void showDisplayOptionsDialog() {
mLoyaltyCardListDisplayOptions.showDisplayOptionsDialog();
}
public void showDetails(boolean show) {
mShowDetails = show;
notifyDataSetChanged();
// Store in Shared Preference to restore next adapter launch
SharedPreferences cardDetailsPref = mContext.getSharedPreferences(
mContext.getString(R.string.sharedpreference_card_details),
Context.MODE_PRIVATE);
SharedPreferences.Editor cardDetailsPrefEditor = cardDetailsPref.edit();
cardDetailsPrefEditor.putBoolean(mContext.getString(R.string.sharedpreference_card_details_show), show);
cardDetailsPrefEditor.apply();
}
public boolean showingDetails() {
return mShowDetails;
public boolean showingArchivedCards() {
return mLoyaltyCardListDisplayOptions.showingArchivedCards();
}
@NonNull
@Override
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, mListener);
public LoyaltyCardListItemViewHolder onCreateViewHolder(@NonNull ViewGroup inputParent, int inputViewType) {
LoyaltyCardLayoutBinding loyaltyCardLayoutBinding = LoyaltyCardLayoutBinding.inflate(
LayoutInflater.from(inputParent.getContext()),
inputParent,
false
);
return new LoyaltyCardListItemViewHolder(loyaltyCardLayoutBinding, mListener);
}
public LoyaltyCard getCard(int position) {
@@ -95,39 +84,47 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
public void onBindViewHolder(LoyaltyCardListItemViewHolder inputHolder, Cursor inputCursor) {
// Invisible until we want to show something more
boolean showDivider = false;
inputHolder.mDivider.setVisibility(View.GONE);
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(inputCursor);
Bitmap icon = Utils.retrieveCardImage(mContext, loyaltyCard.id, ImageLocationType.icon);
inputHolder.setStoreField(loyaltyCard.store);
if (mShowDetails && !loyaltyCard.note.isEmpty()) {
if (mLoyaltyCardListDisplayOptions.showingNameBelowThumbnail() && icon != null) {
showDivider = true;
inputHolder.setStoreField(loyaltyCard.store);
} else {
inputHolder.setStoreField(null);
}
if (mLoyaltyCardListDisplayOptions.showingNote() && !loyaltyCard.note.isEmpty()) {
showDivider = true;
inputHolder.setNoteField(loyaltyCard.note);
} else {
inputHolder.setNoteField(null);
}
if (mShowDetails && !loyaltyCard.balance.equals(new BigDecimal("0"))) {
inputHolder.setBalanceField(loyaltyCard.balance, loyaltyCard.balanceType);
if (mLoyaltyCardListDisplayOptions.showingBalance() && !loyaltyCard.balance.equals(new BigDecimal("0"))) {
inputHolder.setExtraField(inputHolder.mBalanceField, Utils.formatBalance(mContext, loyaltyCard.balance, loyaltyCard.balanceType), null, showDivider);
} else {
inputHolder.setBalanceField(null, null);
inputHolder.setExtraField(inputHolder.mBalanceField, null, null, false);
}
if (mShowDetails && loyaltyCard.expiry != null) {
inputHolder.setExpiryField(loyaltyCard.expiry);
if (mLoyaltyCardListDisplayOptions.showingValidity() && loyaltyCard.validFrom != null) {
inputHolder.setExtraField(inputHolder.mValidFromField, DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.validFrom), Utils.isNotYetValid(loyaltyCard.validFrom) ? Color.RED : null, showDivider);
} else {
inputHolder.setExpiryField(null);
inputHolder.setExtraField(inputHolder.mValidFromField, null, null, false);
}
setHeaderHeight(inputHolder, mShowDetails);
Bitmap cardIcon = Utils.retrieveCardImage(mContext, loyaltyCard.id, ImageLocationType.icon);
if (cardIcon != null) {
inputHolder.mCardIcon.setImageBitmap(cardIcon);
inputHolder.mCardIcon.setScaleType(ImageView.ScaleType.CENTER_CROP);
if (mLoyaltyCardListDisplayOptions.showingValidity() && loyaltyCard.expiry != null) {
inputHolder.setExtraField(inputHolder.mExpiryField, DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.expiry), Utils.hasExpired(loyaltyCard.expiry) ? Color.RED : null, showDivider);
} else {
inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, loyaltyCard.store, loyaltyCard.headerColor).getLetterTile());
inputHolder.mCardIcon.setScaleType(ImageView.ScaleType.FIT_CENTER);
inputHolder.setExtraField(inputHolder.mExpiryField, null, null, false);
}
inputHolder.setIconBackgroundColor(loyaltyCard.headerColor != null ? loyaltyCard.headerColor : R.attr.colorPrimary);
inputHolder.mCardIcon.setContentDescription(loyaltyCard.store);
Utils.setIconOrTextWithBackground(mContext, loyaltyCard, icon, inputHolder.mCardIcon, inputHolder.mCardText);
inputHolder.setIconBackgroundColor(Utils.getHeaderColor(mContext, loyaltyCard));
inputHolder.toggleCardStateIcon(loyaltyCard.starStatus != 0, loyaltyCard.archiveStatus != 0, itemSelected(inputCursor.getPosition()));
@@ -139,19 +136,6 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
inputHolder.mRow.requestLayout();
}
private void setHeaderHeight(LoyaltyCardListItemViewHolder inputHolder, boolean expanded) {
int iconHeight;
if (expanded) {
iconHeight = ViewGroup.LayoutParams.MATCH_PARENT;
} else {
iconHeight = (int) mContext.getResources().getDimension(R.dimen.cardThumbnailSize);
}
inputHolder.mIconLayout.getLayoutParams().height = expanded ? 0 : iconHeight;
inputHolder.mCardIcon.getLayoutParams().height = iconHeight;
inputHolder.mTickIcon.getLayoutParams().height = iconHeight;
}
private void applyClickEvents(LoyaltyCardListItemViewHolder inputHolder, final int inputPosition) {
inputHolder.mRow.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition));
@@ -227,32 +211,32 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
public class LoyaltyCardListItemViewHolder extends RecyclerView.ViewHolder {
public TextView mStoreField, mNoteField, mBalanceField, mExpiryField;
public TextView mCardText, mStoreField, mNoteField, mBalanceField, mValidFromField, mExpiryField;
public ImageView mCardIcon, mStarBackground, mStarBorder, mTickIcon, mArchivedBackground;
public MaterialCardView mRow, mIconLayout;
public MaterialCardView mRow;
public ConstraintLayout mStar, mArchived;
public View mDivider;
private int mIconBackgroundColor;
protected LoyaltyCardListItemViewHolder(View inputView, CardAdapterListener inputListener) {
super(inputView);
mRow = inputView.findViewById(R.id.row);
mDivider = inputView.findViewById(R.id.info_divider);
mStoreField = inputView.findViewById(R.id.store);
mNoteField = inputView.findViewById(R.id.note);
mBalanceField = inputView.findViewById(R.id.balance);
mExpiryField = inputView.findViewById(R.id.expiry);
mIconLayout = inputView.findViewById(R.id.icon_layout);
mCardIcon = inputView.findViewById(R.id.thumbnail);
mStar = inputView.findViewById(R.id.star);
mStarBackground = inputView.findViewById(R.id.star_background);
mStarBorder = inputView.findViewById(R.id.star_border);
mArchived = inputView.findViewById(R.id.archivedIcon);
mArchivedBackground = inputView.findViewById(R.id.archive_background);
mTickIcon = inputView.findViewById(R.id.selected_thumbnail);
protected LoyaltyCardListItemViewHolder(LoyaltyCardLayoutBinding loyaltyCardLayoutBinding, CardAdapterListener inputListener) {
super(loyaltyCardLayoutBinding.getRoot());
View inputView = loyaltyCardLayoutBinding.getRoot();
mRow = loyaltyCardLayoutBinding.row;
mDivider = loyaltyCardLayoutBinding.infoDivider;
mStoreField = loyaltyCardLayoutBinding.store;
mNoteField = loyaltyCardLayoutBinding.note;
mBalanceField = loyaltyCardLayoutBinding.balance;
mValidFromField = loyaltyCardLayoutBinding.validFrom;
mExpiryField = loyaltyCardLayoutBinding.expiry;
mCardIcon = loyaltyCardLayoutBinding.thumbnail;
mCardText = loyaltyCardLayoutBinding.thumbnailText;
mStar = loyaltyCardLayoutBinding.star;
mStarBackground = loyaltyCardLayoutBinding.starBackground;
mStarBorder = loyaltyCardLayoutBinding.starBorder;
mArchived = loyaltyCardLayoutBinding.archivedIcon;
mArchivedBackground = loyaltyCardLayoutBinding.archiveBackground;
mTickIcon = loyaltyCardLayoutBinding.selectedThumbnail;
inputView.setOnLongClickListener(view -> {
inputListener.onRowClicked(getAdapterPosition());
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
@@ -260,9 +244,46 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
});
}
private void setExtraField(TextView field, String text, Integer color, boolean showDivider) {
// If text is null, hide the field
// If iconColor is null, use the default text and icon color based on theme
if (text == null) {
field.setVisibility(View.GONE);
field.requestLayout();
return;
}
// Shown when there is a name and/or note and at least 1 extra field
if (showDivider) {
mDivider.setVisibility(View.VISIBLE);
}
field.setText(text);
field.setTextColor(color != null ? color : MaterialColors.getColor(mContext, com.google.android.material.R.attr.colorSecondary, ContextCompat.getColor(mContext, mDarkModeEnabled ? R.color.md_theme_dark_secondary : R.color.md_theme_light_secondary)));
field.setVisibility(View.VISIBLE);
Drawable icon = field.getCompoundDrawables()[0];
if (icon != null) {
icon.mutate();
field.setCompoundDrawablesRelative(icon, null, null, null);
if (color != null) {
icon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_ATOP));
} else {
icon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(mDarkModeEnabled ? Color.WHITE : Color.BLACK, BlendModeCompat.SRC_ATOP));
}
}
field.requestLayout();
}
public void setStoreField(String text) {
mStoreField.setText(text);
mStoreField.setTextSize(mSettings.getFontSizeMax(mSettings.getMediumFont()));
if (text == null) {
mStoreField.setVisibility(View.GONE);
} else {
mStoreField.setVisibility(View.VISIBLE);
mStoreField.setText(text);
}
mStoreField.requestLayout();
}
@@ -272,60 +293,10 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
} else {
mNoteField.setVisibility(View.VISIBLE);
mNoteField.setText(text);
mNoteField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
}
mNoteField.requestLayout();
}
public void setBalanceField(BigDecimal balance, Currency balanceType) {
if (balance == null) {
mBalanceField.setVisibility(View.GONE);
} else {
int size = mSettings.getFontSizeMax(mSettings.getSmallFont());
int drawableSize = dpToPx((size * 24) / 14, mContext);
mDivider.setVisibility(View.VISIBLE);
mBalanceField.setVisibility(View.VISIBLE);
Drawable balanceIcon = mBalanceField.getCompoundDrawables()[0];
if (balanceIcon != null) {
balanceIcon.setBounds(0, 0, drawableSize, drawableSize);
mBalanceField.setCompoundDrawablesRelative(balanceIcon, null, null, null);
if (mDarkModeEnabled) {
balanceIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP));
}
}
mBalanceField.setText(Utils.formatBalance(mContext, balance, balanceType));
mBalanceField.setTextSize(size);
}
mBalanceField.requestLayout();
}
public void setExpiryField(Date expiry) {
if (expiry == null) {
mExpiryField.setVisibility(View.GONE);
} else {
int size = mSettings.getFontSizeMax(mSettings.getSmallFont());
int drawableSize = dpToPx((size * 24) / 14, mContext);
mDivider.setVisibility(View.VISIBLE);
mExpiryField.setVisibility(View.VISIBLE);
Drawable expiryIcon = mExpiryField.getCompoundDrawables()[0];
if (expiryIcon != null) {
expiryIcon.setBounds(0, 0, drawableSize, drawableSize);
mExpiryField.setCompoundDrawablesRelative(expiryIcon, null, null, null);
if (Utils.hasExpired(expiry)) {
expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.RED, BlendModeCompat.SRC_ATOP));
} else if (mDarkModeEnabled) {
expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP));
}
}
mExpiryField.setText(DateFormat.getDateInstance(DateFormat.LONG).format(expiry));
if (Utils.hasExpired(expiry)) {
mExpiryField.setTextColor(Color.RED);
}
mExpiryField.setTextSize(size);
}
mExpiryField.requestLayout();
}
public void toggleCardStateIcon(boolean enableStar, boolean enableArchive, boolean colorByTheme) {
/* the below code does not work in android 5! hence the change of drawable instead
boolean needDarkForeground = Utils.needsDarkForeground(mIconBackgroundColor);

View File

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@ public enum LoyaltyCardField {
id,
store,
note,
validFrom,
expiry,
balance,
balanceType,

View File

@@ -0,0 +1,176 @@
package protect.card_locker;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class LoyaltyCardListDisplayOptionsManager {
public static class LoyaltyCardDisplayOption {
public String name;
public boolean value;
public Consumer<Boolean> callback;
LoyaltyCardDisplayOption(String name, boolean value, Consumer<Boolean> callback) {
this.name = name;
this.value = value;
this.callback = callback;
}
}
public final Context mContext;
private final Runnable mRefreshCardsCallback;
private final Runnable mSwapCursorCallback;
protected SharedPreferences mCardDetailsPref;
private boolean mShowNameBelowThumbnail;
private boolean mShowNote;
private boolean mShowBalance;
private boolean mShowValidity;
private boolean mShowArchivedCards;
public LoyaltyCardListDisplayOptionsManager(Context context, @NonNull Runnable refreshCardsCallback, @Nullable Runnable swapCursorCallback) {
mContext = context;
mRefreshCardsCallback = refreshCardsCallback;
mSwapCursorCallback = swapCursorCallback;
// Retrieve user details preference
mCardDetailsPref = mContext.getSharedPreferences(
mContext.getString(R.string.sharedpreference_card_details),
Context.MODE_PRIVATE);
mShowNameBelowThumbnail = mCardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_show_name_below_thumbnail), false);
mShowNote = mCardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_show_note), true);
mShowBalance = mCardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_show_balance), true);
mShowValidity = mCardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_show_validity), true);
mShowArchivedCards = mCardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_show_archived_cards), true);
}
void saveDetailState(int stateId, boolean value) {
SharedPreferences.Editor cardDetailsPrefEditor = mCardDetailsPref.edit();
cardDetailsPrefEditor.putBoolean(mContext.getString(stateId), value);
cardDetailsPrefEditor.apply();
}
public void showNameBelowThumbnail(boolean show) {
mShowNameBelowThumbnail = show;
mRefreshCardsCallback.run();
saveDetailState(R.string.sharedpreference_card_details_show_name_below_thumbnail, show);
}
public boolean showingNameBelowThumbnail() {
return mShowNameBelowThumbnail;
}
public void showNote(boolean show) {
mShowNote = show;
mRefreshCardsCallback.run();
saveDetailState(R.string.sharedpreference_card_details_show_note, show);
}
public boolean showingNote() {
return mShowNote;
}
public void showBalance(boolean show) {
mShowBalance = show;
mRefreshCardsCallback.run();
saveDetailState(R.string.sharedpreference_card_details_show_balance, show);
}
public boolean showingBalance() {
return mShowBalance;
}
public void showValidity(boolean show) {
mShowValidity = show;
mRefreshCardsCallback.run();
saveDetailState(R.string.sharedpreference_card_details_show_validity, show);
}
public boolean showingValidity() {
return mShowValidity;
}
public void showArchivedCards(boolean show) {
if (mSwapCursorCallback == null) {
throw new IllegalStateException("No swap cursor callback is available, can not manage archive state");
}
mShowArchivedCards = show;
mSwapCursorCallback.run();
saveDetailState(R.string.sharedpreference_card_details_show_archived_cards, show);
}
public boolean showingArchivedCards() {
if (mSwapCursorCallback == null) {
throw new IllegalStateException("No swap cursor callback is available, can not manage archive state");
}
return mShowArchivedCards;
}
public void showDisplayOptionsDialog() {
List<LoyaltyCardDisplayOption> displayOptions = new ArrayList<>();
displayOptions.add(new LoyaltyCardDisplayOption(
mContext.getString(R.string.show_name_below_image_thumbnail),
showingNameBelowThumbnail(),
this::showNameBelowThumbnail
));
displayOptions.add(new LoyaltyCardDisplayOption(
mContext.getString(R.string.show_note),
showingNote(),
this::showNote
));
displayOptions.add(new LoyaltyCardDisplayOption(
mContext.getString(R.string.show_balance),
showingBalance(),
this::showBalance
));
displayOptions.add(new LoyaltyCardDisplayOption(
mContext.getString(R.string.show_validity),
showingValidity(),
this::showValidity
));
// Hide "Show archived cards" option unless the callback exists
if (mSwapCursorCallback != null) {
displayOptions.add(new LoyaltyCardDisplayOption(
mContext.getString(R.string.show_archived_cards),
showingArchivedCards(),
this::showArchivedCards
));
}
// We need to convert Boolean[] to boolean[]
boolean[] values = new boolean[displayOptions.size()];
for (int i = 0; i < values.length; i++) values[i] = displayOptions.get(i).value;
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(mContext);
builder.setTitle(R.string.action_display_options);
builder.setMultiChoiceItems(
displayOptions.stream().map(x -> x.name).toArray(String[]::new),
values,
(dialogInterface, i, b) -> displayOptions.get(i).callback.accept(b)
);
builder.setPositiveButton(R.string.ok, (dialog, i) -> dialog.dismiss());
AlertDialog dialog = builder.create();
dialog.show();
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -9,55 +9,55 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.database.CursorIndexOutOfBoundsException;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
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.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.splashscreen.SplashScreen;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.tabs.TabLayout;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import protect.card_locker.databinding.ContentMainBinding;
import protect.card_locker.databinding.MainActivityBinding;
import protect.card_locker.databinding.SortingOptionBinding;
import protect.card_locker.preferences.SettingsActivity;
public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener, GestureDetector.OnGestureListener {
public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener {
private MainActivityBinding binding;
private ContentMainBinding contentMainBinding;
private static final String TAG = "Catima";
public static final String RESTART_ACTIVITY_INTENT = "restart_activity_intent";
private static final int MEDIUM_SCALE_FACTOR_DIP = 460;
private SQLiteDatabase mDatabase;
private LoyaltyCardCursorAdapter mAdapter;
private ActionMode mCurrentActionMode;
private SearchView mSearchView;
private GestureDetector mGestureDetector;
private int mLoyaltyCardCount = 0;
protected String mFilter = "";
protected Object mGroup = null;
@@ -68,9 +68,9 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
private View mHelpSection;
private View mNoMatchingCardsText;
private View mNoGroupCardsText;
private TabLayout groupsTabLayout;
private boolean mArchiveMode;
public static final String BUNDLE_ARCHIVE_MODE = "archiveMode";
private Runnable mSwapLoyaltyCardListCursor;
private ActivityResultLauncher<Intent> mBarcodeScannerLauncher;
private ActivityResultLauncher<Intent> mSettingsLauncher;
@@ -141,7 +141,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
inputMode.finish();
return true;
} else if (inputItem.getItemId() == R.id.action_delete) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(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".
// So while in English the extra non-plural form seems unnecessary duplication, it is necessary to give translators enough flexibility.
@@ -163,7 +163,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
ShortcutHelper.removeShortcut(MainActivity.this, loyaltyCard.id);
}
TabLayout.Tab tab = ((TabLayout) findViewById(R.id.groups)).getTabAt(selectedTab);
TabLayout.Tab tab = groupsTabLayout.getTabAt(selectedTab);
mGroup = tab != null ? tab.getTag() : null;
updateLoyaltyCardList(true);
@@ -175,28 +175,25 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
dialog.show();
return true;
}
else if(inputItem.getItemId() == R.id.action_archive){
} else if (inputItem.getItemId() == R.id.action_archive) {
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
Log.d(TAG, "Archiving card: " + loyaltyCard.id);
DBHelper.updateLoyaltyCardArchiveStatus(mDatabase, loyaltyCard.id,1);
DBHelper.updateLoyaltyCardArchiveStatus(mDatabase, loyaltyCard.id, 1);
updateLoyaltyCardList(false);
inputMode.finish();
invalidateOptionsMenu();
}
return true;
}
else if(inputItem.getItemId() == R.id.action_unarchive){
} else if (inputItem.getItemId() == R.id.action_unarchive) {
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
Log.d(TAG, "Unarchiving card: " + loyaltyCard.id);
DBHelper.updateLoyaltyCardArchiveStatus(mDatabase, loyaltyCard.id,0);
DBHelper.updateLoyaltyCardArchiveStatus(mDatabase, loyaltyCard.id, 0);
updateLoyaltyCardList(false);
inputMode.finish();
invalidateOptionsMenu();
}
return true;
}
else if(inputItem.getItemId() == R.id.action_star){
} else if (inputItem.getItemId() == R.id.action_star) {
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
Log.d(TAG, "Starring card: " + loyaltyCard.id);
DBHelper.updateLoyaltyCardStarStatus(mDatabase, loyaltyCard.id, 1);
@@ -204,8 +201,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
inputMode.finish();
}
return true;
}
else if(inputItem.getItemId() == R.id.action_unstar){
} else if (inputItem.getItemId() == R.id.action_unstar) {
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
Log.d(TAG, "Unstarring card: " + loyaltyCard.id);
DBHelper.updateLoyaltyCardStarStatus(mDatabase, loyaltyCard.id, 0);
@@ -230,28 +226,25 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
extractIntentFields(getIntent());
SplashScreen.installSplashScreen(this);
super.onCreate(inputSavedInstanceState);
if(!mArchiveMode) {
setTitle(R.string.app_name);
setContentView(R.layout.main_activity);
}
else{
setTitle(R.string.archiveList);
setContentView(R.layout.archive_activity);
}
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if(mArchiveMode){
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
binding = MainActivityBinding.inflate(getLayoutInflater());
setTitle(R.string.app_name);
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
groupsTabLayout = binding.groups;
contentMainBinding = ContentMainBinding.bind(binding.include.getRoot());
mDatabase = new DBHelper(this).getWritableDatabase();
TabLayout groupsTabLayout = findViewById(R.id.groups);
mSwapLoyaltyCardListCursor = () -> {
Group group = null;
if (mGroup != null) {
group = (Group) mGroup;
}
mAdapter.swapCursor(DBHelper.getLoyaltyCardCursor(mDatabase, mFilter, group, mOrder, mOrderDirection, mAdapter.showingArchivedCards() ? DBHelper.LoyaltyCardArchiveFilter.All : DBHelper.LoyaltyCardArchiveFilter.Unarchived));
};
groupsTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
@@ -279,20 +272,12 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
});
mGestureDetector = new GestureDetector(this, this);
mHelpSection = contentMainBinding.helpSection;
mNoMatchingCardsText = contentMainBinding.noMatchingCardsText;
mNoGroupCardsText = contentMainBinding.noGroupCardsText;
mCardList = contentMainBinding.list;
View.OnTouchListener gestureTouchListener = (v, event) -> mGestureDetector.onTouchEvent(event);
mHelpSection = findViewById(R.id.helpSection);
mNoMatchingCardsText = findViewById(R.id.noMatchingCardsText);
mNoGroupCardsText = findViewById(R.id.noGroupCardsText);
mCardList = findViewById(R.id.list);
mNoMatchingCardsText.setOnTouchListener(gestureTouchListener);
mCardList.setOnTouchListener(gestureTouchListener);
mNoGroupCardsText.setOnTouchListener(gestureTouchListener);
mAdapter = new LoyaltyCardCursorAdapter(this, null, this);
mAdapter = new LoyaltyCardCursorAdapter(this, null, this, mSwapLoyaltyCardListCursor);
mCardList.setAdapter(mAdapter);
registerForContextMenu(mCardList);
@@ -331,21 +316,17 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
*/
mBarcodeScannerLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
// Exit early if the user cancelled the scan (pressed back/home)
if (result.getResultCode() != RESULT_OK) {
return;
}
Intent intent = result.getData();
BarcodeValues barcodeValues = Utils.parseSetBarcodeActivityResult(Utils.BARCODE_SCAN, result.getResultCode(), intent, this);
if (!barcodeValues.isEmpty()) {
Intent newIntent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle newBundle = new Bundle();
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_BARCODETYPE, barcodeValues.format());
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_CARDID, barcodeValues.content());
Bundle inputBundle = intent.getExtras();
if (inputBundle != null && inputBundle.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP) != null) {
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, inputBundle.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP));
}
newIntent.putExtras(newBundle);
startActivity(newIntent);
}
Bundle inputBundle = intent.getExtras();
String group = inputBundle != null ? inputBundle.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP) : null;
processBarcodeValues(barcodeValues, group);
});
mSettingsLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
@@ -362,8 +343,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
protected void onResume() {
super.onResume();
mAdapter.refreshState();
if (mCurrentActionMode != null) {
mAdapter.clearSelections();
mCurrentActionMode.finish();
@@ -374,21 +353,30 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
// Start of active tab logic
TabLayout groupsTabLayout = findViewById(R.id.groups);
updateTabGroups(groupsTabLayout);
// Restore settings from Shared Preference
// Restore selected tab 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);
// Restore sort preferences from Shared Preferences
// If one of the sorting prefererences has never been set or is set to an invalid value,
// stick to the defaults.
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) {
String orderString = sortPref.getString(getString(R.string.sharedpreference_sort_order), null);
String orderDirectionString = sortPref.getString(getString(R.string.sharedpreference_sort_direction), null);
if (orderString != null && orderDirectionString != null) {
try {
mOrder = DBHelper.LoyaltyCardOrder.valueOf(orderString);
mOrderDirection = DBHelper.LoyaltyCardOrderDirection.valueOf(orderDirectionString);
} catch (IllegalArgumentException ignored) {
}
}
mGroup = null;
@@ -402,30 +390,30 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
groupsTabLayout.selectTab(tab);
assert tab != null;
mGroup = tab.getTag();
} else {
scaleScreen();
}
updateLoyaltyCardList(true);
// End of active tab logic
if (!mArchiveMode) {
FloatingActionButton addButton = findViewById(R.id.fabAdd);
FloatingActionButton addButton = binding.fabAdd;
addButton.setOnClickListener(v -> {
Intent intent = new Intent(getApplicationContext(), ScanActivity.class);
Bundle bundle = new Bundle();
if (selectedTab != 0) {
bundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, groupsTabLayout.getTabAt(selectedTab).getText().toString());
}
intent.putExtras(bundle);
mBarcodeScannerLauncher.launch(intent);
});
addButton.bringToFront();
}
addButton.setOnClickListener(v -> {
Intent intent = new Intent(getApplicationContext(), ScanActivity.class);
Bundle bundle = new Bundle();
if (selectedTab != 0) {
bundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, groupsTabLayout.getTabAt(selectedTab).getText().toString());
}
intent.putExtras(bundle);
mBarcodeScannerLauncher.launch(intent);
});
addButton.bringToFront();
}
@Override
public void onBackPressed() {
if (!mSearchView.isIconified()) {
if (mSearchView != null && !mSearchView.isIconified()) {
mSearchView.setIconified(true);
return;
}
@@ -434,7 +422,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
private void displayCardSetupOptions(Menu menu, boolean shouldShow) {
for (int id : new int[]{R.id.action_search, R.id.action_unfold, R.id.action_sort}) {
for (int id : new int[]{R.id.action_search, R.id.action_display_options, R.id.action_sort}) {
menu.findItem(id).setVisible(shouldShow);
}
}
@@ -444,12 +432,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
private void updateLoyaltyCardList(boolean updateCount) {
Group group = null;
if (mGroup != null) {
group = (Group) mGroup;
}
mAdapter.swapCursor(DBHelper.getLoyaltyCardCursor(mDatabase, mFilter, group, mOrder, mOrderDirection, mArchiveMode ? DBHelper.LoyaltyCardArchiveFilter.Archived : DBHelper.LoyaltyCardArchiveFilter.Unarchived));
mSwapLoyaltyCardListCursor.run();
if (updateCount) {
updateLoyaltyCardCount();
@@ -480,12 +463,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
}
} else {
if (mArchiveMode) {
// If an user deletes the last card in archive mode, we should close the activity
// This will move us back to the main view
finish();
}
mCardList.setVisibility(View.GONE);
mHelpSection.setVisibility(View.VISIBLE);
@@ -498,9 +475,68 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
}
private void processBarcodeValues(BarcodeValues barcodeValues, String group) {
if (barcodeValues.isEmpty()) {
throw new IllegalArgumentException("barcodesValues may not be empty");
}
Intent newIntent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle newBundle = new Bundle();
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_BARCODETYPE, barcodeValues.format());
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_CARDID, barcodeValues.content());
if (group != null) {
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, group);
}
newIntent.putExtras(newBundle);
startActivity(newIntent);
}
private void onSharedIntent(Intent intent) {
String receivedAction = intent.getAction();
String receivedType = intent.getType();
// Check if an image was shared to us
if (Intent.ACTION_SEND.equals(receivedAction)) {
if (!receivedType.startsWith("image/")) {
Log.e(TAG, "Wrong mime-type");
return;
}
BarcodeValues barcodeValues;
Bitmap bitmap;
Uri data = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (data == null) {
Toast.makeText(this, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
finish();
return;
}
try {
bitmap = Utils.retrieveImageFromUri(this, data);
} catch (IOException e) {
Log.e(TAG, "Error getting data from image file");
e.printStackTrace();
Toast.makeText(this, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
finish();
return;
}
barcodeValues = Utils.getBarcodeFromBitmap(bitmap);
if (barcodeValues.isEmpty()) {
Log.i(TAG, "No barcode found in image file");
Toast.makeText(this, R.string.noBarcodeFound, Toast.LENGTH_LONG).show();
finish();
return;
}
processBarcodeValues(barcodeValues, null);
}
}
private void extractIntentFields(Intent intent) {
final Bundle b = intent.getExtras();
mArchiveMode = b != null && b.getBoolean(BUNDLE_ARCHIVE_MODE, false);
onSharedIntent(intent);
}
public void updateTabGroups(TabLayout groupsTabLayout) {
@@ -532,13 +568,8 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
@Override
public boolean onCreateOptionsMenu(Menu inputMenu) {
if(!mArchiveMode)
getMenuInflater().inflate(R.menu.main_menu, inputMenu);
else{
getMenuInflater().inflate(R.menu.archive_menu, inputMenu);
}
getMenuInflater().inflate(R.menu.main_menu, inputMenu);
Utils.updateMenuCardDetailsButtonState(inputMenu.findItem(R.id.action_unfold), mAdapter.showingDetails());
displayCardSetupOptions(inputMenu, mLoyaltyCardCount > 0);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
@@ -562,7 +593,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
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;
@@ -573,14 +603,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
});
}
if(!mArchiveMode) {
if (DBHelper.getArchivedCardsCount(mDatabase) == 0) {
inputMenu.findItem(R.id.action_archived).setVisible(false);
} else {
inputMenu.findItem(R.id.action_archived).setVisible(true);
}
}
return super.onCreateOptionsMenu(inputMenu);
}
@@ -592,8 +614,8 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
onBackPressed();
}
if (id == R.id.action_unfold) {
mAdapter.showDetails(!mAdapter.showingDetails());
if (id == R.id.action_display_options) {
mAdapter.showDisplayOptionsDialog();
invalidateOptionsMenu();
return true;
@@ -609,13 +631,15 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(MainActivity.this);
builder.setTitle(R.string.sort_by);
final View customLayout = getLayoutInflater().inflate(R.layout.sorting_option, null);
SortingOptionBinding sortingOptionBinding = SortingOptionBinding
.inflate(LayoutInflater.from(MainActivity.this), null, false);
final View customLayout = sortingOptionBinding.getRoot();
builder.setView(customLayout);
CheckBox showReversed = (CheckBox) customLayout.findViewById(R.id.checkBox_reverse);
CheckBox showReversed = sortingOptionBinding.checkBoxReverse;
showReversed.setChecked(mOrderDirection == DBHelper.LoyaltyCardOrderDirection.Descending);
@@ -647,15 +671,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
return true;
}
if (id == R.id.action_archived) {
Intent i = new Intent(getApplicationContext(), MainActivity.class);
Bundle bundle = new Bundle();
bundle.putBoolean("archiveMode", true);
i.putExtras(bundle);
startActivity(i);
return true;
}
if (id == R.id.action_import_export) {
Intent i = new Intent(getApplicationContext(), ImportExportActivity.class);
startActivity(i);
@@ -696,84 +711,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
updateLoyaltyCardList(false);
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@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");
// Don't swipe if we have too much vertical movement
if (Math.abs(velocityY) > (0.75 * Math.abs(velocityX))) {
return false;
}
TabLayout groupsTabLayout = findViewById(R.id.groups);
if (groupsTabLayout.getTabCount() < 2) {
return false;
}
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()) {
groupsTabLayout.selectTab(groupsTabLayout.getTabAt(0));
} else {
groupsTabLayout.selectTab(groupsTabLayout.getTabAt(nextTab));
}
return true;
}
// Swipe left
if (velocityX > 150) {
Log.d("onFling", "Left Swipe detected " + velocityX);
Integer nextTab = currentTab - 1;
if (nextTab < 0) {
groupsTabLayout.selectTab(groupsTabLayout.getTabAt(groupsTabLayout.getTabCount() - 1));
} else {
groupsTabLayout.selectTab(groupsTabLayout.getTabAt(nextTab));
}
return true;
}
return false;
}
@Override
public void onRowLongClicked(int inputPosition) {
enableActionMode(inputPosition);
@@ -786,6 +723,16 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
toggleSelection(inputPosition);
}
private void scaleScreen() {
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenHeight = displayMetrics.heightPixels;
float mediumSizePx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,MEDIUM_SCALE_FACTOR_DIP,getResources().getDisplayMetrics());
boolean shouldScaleSmaller = screenHeight < mediumSizePx;
binding.include.welcomeIcon.setVisibility(shouldScaleSmaller ? View.GONE : View.VISIBLE);
}
private void toggleSelection(int inputPosition) {
mAdapter.toggleSelection(inputPosition);
int count = mAdapter.getSelectedItemCount();
@@ -803,31 +750,31 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
boolean hasStarred = false;
boolean hasUnstarred = false;
if(!mArchiveMode) {
unarchiveItem.setVisible(false);
archiveItem.setVisible(true);
}
else{
unarchiveItem.setVisible(true);
archiveItem.setVisible(false);
}
boolean hasArchived = false;
boolean hasUnarchived = false;
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
if (loyaltyCard.starStatus == 1) {
hasStarred = true;
} else {
hasUnstarred = true;
}
if (hasStarred && hasUnstarred) {
hasStarred = true;
hasUnstarred = true;
if (loyaltyCard.archiveStatus == 1) {
hasArchived = true;
} else {
hasUnarchived = true;
}
// We have all types, no need to keep checking
if (hasStarred && hasUnstarred && hasArchived && hasUnarchived) {
break;
}
}
unarchiveItem.setVisible(hasArchived);
archiveItem.setVisible(hasUnarchived);
if (count == 1) {
starItem.setVisible(!hasStarred);
unstarItem.setVisible(!hasUnstarred);

View File

@@ -13,6 +13,7 @@ import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
@@ -20,13 +21,14 @@ 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 {
import protect.card_locker.databinding.ActivityManageGroupBinding;
public class ManageGroupActivity extends CatimaAppCompatActivity implements ManageGroupCursorAdapter.CardAdapterListener {
private ActivityManageGroupBinding binding;
private SQLiteDatabase mDatabase;
private ManageGroupCursorAdapter mAdapter;
@@ -43,17 +45,18 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana
@Override
protected void onCreate(Bundle inputSavedInstanceState) {
super.onCreate(inputSavedInstanceState);
setContentView(R.layout.activity_manage_group);
Toolbar toolbar = findViewById(R.id.toolbar);
binding = ActivityManageGroupBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
Toolbar toolbar = binding.toolbar;
setSupportActionBar(toolbar);
mDatabase = new DBHelper(this).getWritableDatabase();
noGroupCardsText = findViewById(R.id.noGroupCardsText);
mCardList = findViewById(R.id.list);
FloatingActionButton saveButton = findViewById(R.id.fabSave);
noGroupCardsText = binding.include.noGroupCardsText;
mCardList = binding.include.list;
FloatingActionButton saveButton = binding.fabSave;
mGroupNameText = findViewById(R.id.editTextGroupName);
mGroupNameText = binding.editTextGroupName;
mGroupNameText.addTextChangedListener(new TextWatcher() {
@Override
@@ -96,7 +99,7 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana
}
mGroupNameText.setText(mGroup._id);
setTitle(getString(R.string.editGroup, mGroup._id));
mAdapter = new ManageGroupCursorAdapter(this, null, this, mGroup);
mAdapter = new ManageGroupCursorAdapter(this, null, this, mGroup, null);
mCardList.setAdapter(mAdapter);
registerForContextMenu(mCardList);
@@ -105,12 +108,7 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana
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);
enableToolbarBackButton();
saveButton.setOnClickListener(v -> {
String currentGroupName = mGroupNameText.getText().toString().trim();
@@ -160,7 +158,7 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana
@Override
public boolean onCreateOptionsMenu(Menu inputMenu) {
getMenuInflater().inflate(R.menu.card_details_menu, inputMenu);
Utils.updateMenuCardDetailsButtonState(inputMenu.findItem(R.id.action_unfold), mAdapter.showingDetails());
return super.onCreateOptionsMenu(inputMenu);
}
@@ -168,8 +166,8 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana
public boolean onOptionsItemSelected(MenuItem inputItem) {
int id = inputItem.getItemId();
if (id == R.id.action_unfold) {
mAdapter.showDetails(!mAdapter.showingDetails());
if (id == R.id.action_display_options) {
mAdapter.showDisplayOptionsDialog();
invalidateOptionsMenu();
return true;
@@ -200,7 +198,7 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana
private void leaveWithoutSaving() {
if (hasChanged()) {
AlertDialog.Builder builder = new AlertDialog.Builder(ManageGroupActivity.this);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(ManageGroupActivity.this);
builder.setTitle(R.string.leaveWithoutSaveTitle);
builder.setMessage(R.string.leaveWithoutSaveConfirmation);
builder.setPositiveButton(R.string.confirm, (dialog, which) -> finish());

View File

@@ -16,8 +16,8 @@ public class ManageGroupCursorAdapter extends LoyaltyCardCursorAdapter {
final private Group mGroup;
final private SQLiteDatabase mDatabase;
public ManageGroupCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener, Group group) {
super(inputContext, inputCursor, inputListener);
public ManageGroupCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener, Group group, Runnable inputSwapCursorCallback) {
super(inputContext, inputCursor, inputListener, inputSwapCursorCallback);
mGroup = new Group(group._id, group.order);
mInGroupOverlay = new HashMap<>();
mDatabase = new DBHelper(inputContext).getWritableDatabase();

View File

@@ -8,23 +8,27 @@ import android.os.Bundle;
import android.text.InputType;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.List;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import protect.card_locker.databinding.ManageGroupsActivityBinding;
public class ManageGroupsActivity extends CatimaAppCompatActivity implements GroupCursorAdapter.GroupAdapterListener {
private ManageGroupsActivityBinding binding;
private static final String TAG = "Catima";
private SQLiteDatabase mDatabase;
@@ -35,14 +39,12 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ManageGroupsActivityBinding.inflate(getLayoutInflater());
setTitle(R.string.groups);
setContentView(R.layout.manage_groups_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setContentView(binding.getRoot());
Toolbar toolbar = binding.toolbar;
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
enableToolbarBackButton();
mDatabase = new DBHelper(this).getWritableDatabase();
}
@@ -51,12 +53,12 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro
protected void onResume() {
super.onResume();
FloatingActionButton addButton = findViewById(R.id.fabAdd);
FloatingActionButton addButton = binding.fabAdd;
addButton.setOnClickListener(v -> createGroup());
addButton.bringToFront();
mGroupList = findViewById(R.id.list);
mHelpText = findViewById(R.id.helpText);
mGroupList = binding.include.list;
mHelpText = binding.include.helpText;
// Init group list
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
@@ -109,28 +111,67 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro
}
private void createGroup() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
// Header
builder.setTitle(R.string.enter_group_name);
// Layout
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
int contentPadding = getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_padding);
params.leftMargin = contentPadding;
params.topMargin = contentPadding / 2;
params.rightMargin = contentPadding;
// EditText with spacing
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);
builder.setView(input);
input.setLayoutParams(params);
layout.addView(input);
// Set layout
builder.setView(layout);
// Buttons
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
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 (DBHelper.getGroup(mDatabase, inputString) != null) {
Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT).show();
return;
}
DBHelper.insertGroup(mDatabase, inputString);
DBHelper.insertGroup(mDatabase, input.getText().toString().trim());
updateGroupList();
});
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
AlertDialog dialog = builder.create();
// Now that the dialog exists, we can bind something that affects the OK button
input.addTextChangedListener(new SimpleTextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
String groupName = s.toString().trim();
if (groupName.length() == 0) {
input.setError(getString(R.string.group_name_is_empty));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
return;
}
if (DBHelper.getGroup(mDatabase, groupName) != null) {
input.setError(getString(R.string.group_name_already_in_use));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
return;
}
input.setError(null);
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
}
});
dialog.show();
// Disable button (must be done **after** dialog is shown to prevent crash
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
// Set focus on input field
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
input.requestFocus();
}
@@ -193,7 +234,7 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro
public void onDeleteButtonClicked(View view) {
final String groupName = getGroupName(view);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.deleteConfirmationGroup);
builder.setMessage(groupName);

View File

@@ -0,0 +1,29 @@
package protect.card_locker;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class OpenWebLinkHandler {
private static final String TAG = "Catima";
public void openBrowser(AppCompatActivity activity, String url) {
if (url == null) {
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
try {
activity.startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(activity, R.string.failedToOpenUrl, Toast.LENGTH_LONG).show();
Log.e(TAG, "No activity found to handle intent", e);
}
}
}

View File

@@ -0,0 +1,94 @@
package protect.card_locker;
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class PermissionUtils {
/**
* Check if storage read permission is needed.
*
* This is only necessary on Android 6.0 (Marshmallow) and below. See
* https://github.com/CatimaLoyalty/Android/issues/979 for more info.
*
* @param activity
* @return
*/
private static boolean needsStorageReadPermission(Activity activity) {
// Testing showed this permission wasn't needed for anything Catima did past Marshmallow
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return false;
}
return ContextCompat.checkSelfPermission(activity, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
}
/**
* Check if camera permission is needed.
*
* @param activity
* @return
*/
public static boolean needsCameraPermission(Activity activity) {
// Android only introduced the runtime permission system in Marshmallow (Android 6.0)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return false;
}
return ContextCompat.checkSelfPermission(activity, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED;
}
/**
* Call onRequestPermissionsResult after storage read permission was granted.
* Mocks a successful grant if a grant is not necessary.
*
* @param activity
* @param requestCode
*/
public static void requestStorageReadPermission(CatimaAppCompatActivity activity, int requestCode) {
String[] permissions = new String[]{ android.Manifest.permission.READ_EXTERNAL_STORAGE };
int[] mockedResults = new int[]{ PackageManager.PERMISSION_GRANTED };
if (needsStorageReadPermission(activity)) {
ActivityCompat.requestPermissions(activity, permissions, requestCode);
} else {
// FIXME: This points to onMockedRequestPermissionResult instead of to
// onRequestPermissionResult because onRequestPermissionResult was only introduced in
// Android 6.0 (SDK 23) and we and to support Android 5.0 (SDK 21) too.
//
// When minSdk becomes 23, this should point to onRequestPermissionResult directly and
// the activity input variable should be changed from CatimaAppCompatActivity to
// Activity.
activity.onMockedRequestPermissionsResult(requestCode, permissions, mockedResults);
}
}
/**
* Call onRequestPermissionsResult after camera permission was granted.
* Mocks a successful grant if a grant is not necessary.
*
* @param activity
* @param requestCode
*/
public static void requestCameraPermission(CatimaAppCompatActivity activity, int requestCode) {
String[] permissions = new String[]{ Manifest.permission.CAMERA };
int[] mockedResults = new int[]{ PackageManager.PERMISSION_GRANTED };
if (needsCameraPermission(activity)) {
ActivityCompat.requestPermissions(activity, permissions, requestCode);
} else {
// FIXME: This points to onMockedRequestPermissionResult instead of to
// onRequestPermissionResult because onRequestPermissionResult was only introduced in
// Android 6.0 (SDK 23) and we and to support Android 5.0 (SDK 21) too.
//
// When minSdk becomes 23, this should point to onRequestPermissionResult directly and
// the activity input variable should be changed from CatimaAppCompatActivity to
// Activity.
activity.onMockedRequestPermissionsResult(requestCode, permissions, mockedResults);
}
}
}

View File

@@ -1,17 +1,41 @@
package protect.card_locker;
import static protect.card_locker.BarcodeSelectorActivity.BARCODE_CONTENTS;
import static protect.card_locker.BarcodeSelectorActivity.BARCODE_FORMAT;
import android.Manifest;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.text.InputType;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.zxing.ResultPoint;
import com.google.zxing.client.android.Intents;
import com.journeyapps.barcodescanner.BarcodeCallback;
@@ -21,10 +45,8 @@ import com.journeyapps.barcodescanner.DecoratedBarcodeView;
import java.util.List;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import protect.card_locker.databinding.CustomBarcodeScannerBinding;
import protect.card_locker.databinding.ScanActivityBinding;
/**
* Custom Scannner Activity extending from Activity to display a custom layout form scanner view.
@@ -33,8 +55,15 @@ import androidx.appcompat.widget.Toolbar;
* originally licensed under Apache 2.0
*/
public class ScanActivity extends CatimaAppCompatActivity {
private ScanActivityBinding binding;
private CustomBarcodeScannerBinding customBarcodeScannerBinding;
private static final String TAG = "Catima";
private static final int MEDIUM_SCALE_FACTOR_DIP = 460;
private static final int COMPAT_SCALE_FACTOR_DIP = 320;
private static final int PERMISSION_SCAN_ADD_FROM_IMAGE = 100;
private CaptureManager capture;
private DecoratedBarcodeView barcodeScannerView;
@@ -46,6 +75,9 @@ public class ScanActivity extends CatimaAppCompatActivity {
// can't use the pre-made contract because that launches the file manager for image type instead of gallery
private ActivityResultLauncher<Intent> photoPickerLauncher;
static final String STATE_SCANNER_ACTIVE = "scannerActive";
private boolean mScannerActive = true;
private void extractIntentFields(Intent intent) {
final Bundle b = intent.getExtras();
cardId = b != null ? b.getString(LoyaltyCardEditActivity.BUNDLE_CARDID) : null;
@@ -56,23 +88,50 @@ public class ScanActivity extends CatimaAppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ScanActivityBinding.inflate(getLayoutInflater());
customBarcodeScannerBinding = CustomBarcodeScannerBinding.bind(binding.zxingBarcodeScanner);
setTitle(R.string.scanCardBarcode);
setContentView(R.layout.scan_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setContentView(binding.getRoot());
Toolbar toolbar = binding.toolbar;
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
enableToolbarBackButton();
extractIntentFields(getIntent());
manualAddLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> handleActivityResult(Utils.SELECT_BARCODE_REQUEST, result.getResultCode(), result.getData()));
photoPickerLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> handleActivityResult(Utils.BARCODE_IMPORT_FROM_IMAGE_FILE, result.getResultCode(), result.getData()));
findViewById(R.id.add_from_image).setOnClickListener(this::addFromImage);
findViewById(R.id.add_manually).setOnClickListener(this::addManually);
customBarcodeScannerBinding.fabOtherOptions.setOnClickListener(view -> {
setScannerActive(false);
barcodeScannerView = findViewById(R.id.zxing_barcode_scanner);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ScanActivity.this);
builder.setTitle(getString(R.string.add_a_card_in_a_different_way));
builder.setItems(
new CharSequence[]{
getString(R.string.addWithoutBarcode),
getString(R.string.addManually),
getString(R.string.addFromImage)
},
(dialogInterface, i) -> {
switch (i) {
case 0:
addWithoutBarcode();
break;
case 1:
addManually();
break;
case 2:
addFromImage();
break;
default:
throw new IllegalArgumentException("Unknown 'Add a card in a different way' dialog option");
}
}
);
builder.setOnCancelListener(dialogInterface -> setScannerActive(true));
builder.show();
});
barcodeScannerView = binding.zxingBarcodeScanner;
// Even though we do the actual decoding with the barcodeScannerView
// CaptureManager needs to be running to show the camera and scanning bar
@@ -88,8 +147,8 @@ public class ScanActivity extends CatimaAppCompatActivity {
public void barcodeResult(BarcodeResult result) {
Intent scanResult = new Intent();
Bundle scanResultBundle = new Bundle();
scanResultBundle.putString(BarcodeSelectorActivity.BARCODE_CONTENTS, result.getText());
scanResultBundle.putString(BarcodeSelectorActivity.BARCODE_FORMAT, result.getBarcodeFormat().name());
scanResultBundle.putString(BARCODE_CONTENTS, result.getText());
scanResultBundle.putString(BARCODE_FORMAT, result.getBarcodeFormat().name());
if (addGroup != null) {
scanResultBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, addGroup);
}
@@ -108,7 +167,15 @@ public class ScanActivity extends CatimaAppCompatActivity {
@Override
protected void onResume() {
super.onResume();
capture.onResume();
if (mScannerActive) {
capture.onResume();
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
showCameraPermissionMissingText(false);
}
scaleScreen();
}
@Override
@@ -124,9 +191,18 @@ public class ScanActivity extends CatimaAppCompatActivity {
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
capture.onSaveInstanceState(outState);
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
capture.onSaveInstanceState(savedInstanceState);
savedInstanceState.putBoolean(STATE_SCANNER_ACTIVE, mScannerActive);
}
@Override
public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mScannerActive = savedInstanceState.getBoolean(STATE_SCANNER_ACTIVE);
}
@Override
@@ -168,33 +244,106 @@ public class ScanActivity extends CatimaAppCompatActivity {
return super.onOptionsItemSelected(item);
}
private void setScannerActive(boolean isActive) {
if (isActive) {
barcodeScannerView.resume();
} else {
barcodeScannerView.pause();
}
mScannerActive = isActive;
}
private void returnResult(String barcodeContents, String barcodeFormat) {
Intent manualResult = new Intent();
Bundle manualResultBundle = new Bundle();
manualResultBundle.putString(BARCODE_CONTENTS, barcodeContents);
manualResultBundle.putString(BARCODE_FORMAT, barcodeFormat);
if (addGroup != null) {
manualResultBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, addGroup);
}
manualResult.putExtras(manualResultBundle);
ScanActivity.this.setResult(RESULT_OK, manualResult);
finish();
}
private void handleActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
BarcodeValues barcodeValues;
BarcodeValues barcodeValues = Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this);
try {
barcodeValues = Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this);
} catch (NullPointerException e) {
Toast.makeText(this, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
if (barcodeValues.isEmpty()) {
setScannerActive(true);
return;
}
if (!barcodeValues.isEmpty()) {
Intent manualResult = new Intent();
Bundle manualResultBundle = new Bundle();
manualResultBundle.putString(BarcodeSelectorActivity.BARCODE_CONTENTS, barcodeValues.content());
manualResultBundle.putString(BarcodeSelectorActivity.BARCODE_FORMAT, barcodeValues.format());
if (addGroup != null) {
manualResultBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, addGroup);
}
manualResult.putExtras(manualResultBundle);
ScanActivity.this.setResult(RESULT_OK, manualResult);
finish();
}
returnResult(barcodeValues.content(), barcodeValues.format());
}
public void addManually(View view) {
private void addWithoutBarcode() {
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
builder.setOnCancelListener(dialogInterface -> setScannerActive(true));
// Header
builder.setTitle(R.string.addWithoutBarcode);
// Layout
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
int contentPadding = getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_padding);
params.leftMargin = contentPadding;
params.topMargin = contentPadding / 2;
params.rightMargin = contentPadding;
// Description
TextView currentTextview = new TextView(this);
currentTextview.setText(getString(R.string.enter_card_id));
currentTextview.setLayoutParams(params);
layout.addView(currentTextview);
// EditText with spacing
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setLayoutParams(params);
layout.addView(input);
// Set layout
builder.setView(layout);
// Buttons
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
returnResult(input.getText().toString(), "");
});
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
AlertDialog dialog = builder.create();
// Now that the dialog exists, we can bind something that affects the OK button
input.addTextChangedListener(new SimpleTextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length() == 0) {
input.setError(getString(R.string.card_id_must_not_be_empty));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
} else {
input.setError(null);
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
}
}
});
dialog.show();
// Disable button (must be done **after** dialog is shown to prevent crash
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
// Set focus on input field
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
input.requestFocus();
}
public void addManually() {
Intent i = new Intent(getApplicationContext(), BarcodeSelectorActivity.class);
if (cardId != null) {
final Bundle b = new Bundle();
@@ -204,14 +353,77 @@ public class ScanActivity extends CatimaAppCompatActivity {
manualAddLauncher.launch(i);
}
public void addFromImage(View view) {
public void addFromImage() {
PermissionUtils.requestStorageReadPermission(this, PERMISSION_SCAN_ADD_FROM_IMAGE);
}
private void addFromImageAfterPermission() {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
Intent contentIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentIntent.setType("image/*");
Intent chooserIntent = Intent.createChooser(photoPickerIntent, getString(R.string.addFromImage));
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { contentIntent });
try {
photoPickerLauncher.launch(photoPickerIntent);
photoPickerLauncher.launch(chooserIntent);
} catch (ActivityNotFoundException e) {
setScannerActive(true);
Toast.makeText(getApplicationContext(), R.string.failedLaunchingPhotoPicker, Toast.LENGTH_LONG).show();
Log.e(TAG, "No activity found to handle intent", e);
}
}
private void showCameraPermissionMissingText(boolean show) {
customBarcodeScannerBinding.cameraPermissionDeniedLayout.cameraPermissionDeniedClickableArea.setOnClickListener(show ? v -> {
navigateToSystemPermissionSetting();
} : null);
customBarcodeScannerBinding.cardInputContainer.setBackgroundColor(show ? obtainThemeAttribute(com.google.android.material.R.attr.colorSurface) : Color.TRANSPARENT);
customBarcodeScannerBinding.cameraPermissionDeniedLayout.getRoot().setVisibility(show ? View.VISIBLE : View.GONE);
}
private void scaleScreen() {
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenHeight = displayMetrics.heightPixels;
float mediumSizePx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,MEDIUM_SCALE_FACTOR_DIP,getResources().getDisplayMetrics());
boolean shouldScaleSmaller = screenHeight < mediumSizePx;
customBarcodeScannerBinding.cameraPermissionDeniedLayout.cameraPermissionDeniedIcon.setVisibility(shouldScaleSmaller ? View.GONE : View.VISIBLE);
customBarcodeScannerBinding.cameraPermissionDeniedLayout.cameraPermissionDeniedTitle.setVisibility(shouldScaleSmaller ? View.GONE : View.VISIBLE);
}
private int obtainThemeAttribute(int attribute) {
TypedValue typedValue = new TypedValue();
getTheme().resolveAttribute(attribute, typedValue, true);
return typedValue.data;
}
private void navigateToSystemPermissionSetting() {
Intent permissionIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", getPackageName(), null));
permissionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(permissionIntent);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
onMockedRequestPermissionsResult(requestCode, permissions, grantResults);
}
public void onMockedRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
if (requestCode == CaptureManager.getCameraPermissionReqCode()) {
showCameraPermissionMissingText(!granted);
} else if (requestCode == PERMISSION_SCAN_ADD_FROM_IMAGE) {
if (granted) {
addFromImageAfterPermission();
} else {
setScannerActive(true);
Toast.makeText(this, R.string.storageReadPermissionRequired, Toast.LENGTH_LONG).show();
}
}
}
}

View File

@@ -33,7 +33,6 @@ class ShortcutHelper {
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);
/**
@@ -71,19 +70,13 @@ class ShortcutHelper {
ShortcutInfoCompat found = list.remove(foundIndex.intValue());
list.addFirst(found);
} 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) {
list.pollLast();
}
// The item is new to the list. We add it and trim the list later.
ShortcutInfoCompat shortcut = createShortcutBuilder(context, card).build();
list.addFirst(shortcut);
}
LinkedList<ShortcutInfoCompat> finalList = new LinkedList<>();
int rank = 0;
// The ranks are now updated; the order in the list is the rank.
for (int index = 0; index < list.size(); index++) {
@@ -91,11 +84,20 @@ class ShortcutHelper {
LoyaltyCard loyaltyCard = DBHelper.getLoyaltyCard(database, Integer.parseInt(prevShortcut.getId()));
ShortcutInfoCompat updatedShortcut = createShortcutBuilder(context, loyaltyCard)
.setRank(index)
.build();
// skip outdated cards that no longer exist
if (loyaltyCard != null) {
ShortcutInfoCompat updatedShortcut = createShortcutBuilder(context, loyaltyCard)
.setRank(rank)
.build();
finalList.addLast(updatedShortcut);
finalList.addLast(updatedShortcut);
rank++;
// trim the list
if (rank >= MAX_SHORTCUTS) {
break;
}
}
}
ShortcutManagerCompat.setDynamicShortcuts(context, finalList);
@@ -145,7 +147,7 @@ class ShortcutHelper {
if (iconBitmap == null) {
iconBitmap = Utils.generateIcon(context, loyaltyCard, true).getLetterTile();
} else {
iconBitmap = createAdaptiveBitmap(iconBitmap, loyaltyCard.headerColor == null ? PADDING_COLOR : loyaltyCard.headerColor);
iconBitmap = createAdaptiveBitmap(iconBitmap, Utils.getHeaderColor(context, loyaltyCard));
}
IconCompat icon = IconCompat.createWithAdaptiveBitmap(iconBitmap);

View File

@@ -22,4 +22,8 @@ public class ThirdPartyInfo {
public String license() {
return mLicense;
}
public String toHtml() {
return String.format("<a href=\"%s\">%s</a> (%s)", url(), name(), license());
}
}

View File

@@ -18,6 +18,7 @@ import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
import androidx.core.view.WindowInsetsControllerCompat;
public class UCropWrapper extends UCropActivity {
public static final String UCROP_TOOLBAR_TYPEFACE_STYLE = "ucop_toolbar_typeface_style";
@@ -28,7 +29,9 @@ public class UCropWrapper extends UCropActivity {
boolean darkMode = Utils.isDarkModeEnabled(this);
// setup status bar to look like the rest of the app
if (Build.VERSION.SDK_INT >= 23) {
getWindow().getDecorView().setSystemUiVisibility(darkMode ? 0 : View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
View decorView = getWindow().getDecorView();
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(getWindow(), decorView);
wic.setAppearanceLightStatusBars(!darkMode);
} else {
// icons are always white back then
if (!darkMode) {
@@ -50,8 +53,8 @@ public class UCropWrapper extends UCropActivity {
AppCompatImageView controlsBackgroundImage = (AppCompatImageView) check;
// everything gathered and are as expected, now perform color patching
Utils.patchColors(this);
int colorSurface = MaterialColors.getColor(this, R.attr.colorSurface, ContextCompat.getColor(this, R.color.md_theme_light_surface));
int colorOnSurface = MaterialColors.getColor(this, R.attr.colorOnSurface, ContextCompat.getColor(this, R.color.md_theme_light_onSurface));
int colorSurface = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurface, ContextCompat.getColor(this, R.color.md_theme_light_surface));
int colorOnSurface = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurface, ContextCompat.getColor(this, R.color.md_theme_light_onSurface));
Drawable controlsBackgroundImageDrawable = controlsBackgroundImage.getBackground();
controlsBackgroundImageDrawable.mutate();

View File

@@ -1,5 +1,6 @@
package protect.card_locker;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
@@ -11,14 +12,29 @@ import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.ImageDecoder;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Build;
import android.os.LocaleList;
import android.provider.MediaStore;
import android.text.Layout;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.util.Log;
import android.util.TypedValue;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RawRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.graphics.ColorUtils;
import androidx.core.os.LocaleListCompat;
import androidx.exifinterface.media.ExifInterface;
import androidx.palette.graphics.Palette;
import com.google.android.material.color.DynamicColors;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.LuminanceSource;
@@ -28,27 +44,32 @@ import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
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.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Currency;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.graphics.ColorUtils;
import androidx.exifinterface.media.ExifInterface;
import androidx.palette.graphics.Palette;
import protect.card_locker.preferences.Settings;
public class Utils {
@@ -66,6 +87,8 @@ public class Utils {
public static final int CARD_IMAGE_FROM_FILE_BACK = 9;
public static final int CARD_IMAGE_FROM_FILE_ICON = 10;
public static final String CARD_IMAGE_FILENAME_REGEX = "^(card_)(\\d+)(_(?:front|back|icon)\\.png)$";
static final double LUMINANCE_MIDPOINT = 0.5;
static final int BITMAP_SIZE_SMALL = 512;
@@ -105,6 +128,17 @@ public class Utils {
return ColorUtils.calculateLuminance(backgroundColor) > LUMINANCE_MIDPOINT;
}
/**
* Returns the Barcode format and content based on the result of an activity.
* It shows toasts to notify the end-user as needed itself and will return an empty
* BarcodeValues object if the activity was cancelled or nothing could be found.
*
* @param requestCode
* @param resultCode
* @param intent
* @param context
* @return BarcodeValues
*/
static public BarcodeValues parseSetBarcodeActivityResult(int requestCode, int resultCode, Intent intent, Context context) {
String contents;
String format;
@@ -116,14 +150,16 @@ public class Utils {
if (requestCode == Utils.BARCODE_IMPORT_FROM_IMAGE_FILE) {
Log.i(TAG, "Received image file with possible barcode");
Uri data = intent.getData();
if (data == null) {
Log.e(TAG, "Intent did not contain any data");
Toast.makeText(context, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
return new BarcodeValues(null, null);
}
Bitmap bitmap;
try {
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());
}
bitmap = retrieveImageFromUri(context, data);
} catch (IOException e) {
Log.e(TAG, "Error getting data from image file");
e.printStackTrace();
@@ -163,6 +199,20 @@ public class Utils {
throw new UnsupportedOperationException("Unknown request code for parseSetBarcodeActivityResult");
}
static public Bitmap retrieveImageFromUri(Context context, Uri data) throws IOException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ImageDecoder.Source image_source = ImageDecoder.createSource(context.getContentResolver(), data);
return ImageDecoder.decodeBitmap(image_source, (decoder, info, source) -> decoder.setMutableRequired(true));
} else {
return getBitmapSdkLessThan29(data, context);
}
}
@SuppressWarnings("deprecation")
private static Bitmap getBitmapSdkLessThan29(Uri data, Context context) throws IOException {
return MediaStore.Images.Media.getBitmap(context.getContentResolver(), data);
}
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++) {
@@ -196,7 +246,21 @@ public class Utils {
}
}
static public Boolean isNotYetValid(Date validFromDate) {
// The note in `hasExpired` does not apply here, since the bug was fixed before this feature was added.
return validFromDate.after(getStartOfToday().getTime());
}
static public Boolean hasExpired(Date expiryDate) {
// Note: In #1083 it was discovered that `DatePickerFragment` may sometimes store the expiryDate
// at 12:00 PM instead of 12:00 AM in the DB. While this has been fixed and the 12-hour difference
// is not a problem for the way the comparison currently works, it's good to keep in mind such
// dates may exist in the DB in case the comparison changes in the future and the new one relies
// on both dates being set at 12:00 AM.
return expiryDate.before(getStartOfToday().getTime());
}
static private Calendar getStartOfToday() {
// today
Calendar date = new GregorianCalendar();
// reset hour, minutes, seconds and millis
@@ -204,8 +268,7 @@ public class Utils {
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);
return expiryDate.before(date.getTime());
return date;
}
static public String formatBalance(Context context, BigDecimal value, Currency currency) {
@@ -330,6 +393,31 @@ public class Utils {
return cardImageFileNameBuilder.toString();
}
/**
* Returns a card image filename (string) with the ID replaced according to the map if the input is a valid card image filename (string), otherwise null.
*
* @param fileName e.g. "card_1_front.png"
* @param idMap e.g. Map.of(1, 2)
* @return String e.g. "card_2_front.png"
*/
static public String getRenamedCardImageFileName(final String fileName, final Map<Integer, Integer> idMap) {
Pattern pattern = Pattern.compile(CARD_IMAGE_FILENAME_REGEX);
Matcher matcher = pattern.matcher(fileName);
if (matcher.matches()) {
StringBuilder cardImageFileNameBuilder = new StringBuilder();
cardImageFileNameBuilder.append(matcher.group(1));
try {
int id = Integer.parseInt(matcher.group(2));
cardImageFileNameBuilder.append(idMap.getOrDefault(id, id));
} catch (NumberFormatException _e) {
return null;
}
cardImageFileNameBuilder.append(matcher.group(3));
return cardImageFileNameBuilder.toString();
}
return null;
}
static public void saveCardImage(Context context, Bitmap bitmap, String fileName) throws FileNotFoundException {
if (bitmap == null) {
context.deleteFile(fileName);
@@ -345,6 +433,14 @@ public class Utils {
saveCardImage(context, bitmap, getCardImageFileName(loyaltyCardId, type));
}
public static File retrieveCardImageAsFile(Context context, String fileName) {
return context.getFileStreamPath(fileName);
}
public static File retrieveCardImageAsFile(Context context, int loyaltyCardId, ImageLocationType type) {
return retrieveCardImageAsFile(context, getCardImageFileName(loyaltyCardId, type));
}
static public Bitmap retrieveCardImage(Context context, String fileName) {
FileInputStream in;
try {
@@ -385,18 +481,85 @@ public class Utils {
Locale chosenLocale = settings.getLocale();
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();
// New API is broken on Android 6 and lower when selecting locales with both language and country, so still keeping this
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
configuration.locale = chosenLocale != null ? chosenLocale : Locale.getDefault();
res.updateConfiguration(configuration, res.getDisplayMetrics());
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();
setLocalesSdkLessThan24(chosenLocale, configuration, res);
return context;
}
LocaleList localeList = chosenLocale != null ? new LocaleList(chosenLocale) : LocaleList.getDefault();
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);
return context.createConfigurationContext(configuration);
/* Documentation at https://developer.android.com/reference/androidx/appcompat/app/AppCompatDelegate#setApplicationLocales(androidx.core.os.LocaleListCompat)
For API levels below that, the developer has two options:
- They can opt-in to automatic storage handled through the library...
- The second option is that they can choose to handle storage themselves.
In order to do so they must use this API to initialize locales during app-start up and provide their stored locales.
In this case, API should be called before Activity.onCreate() in the activity lifecycle, e.g. in attachBaseContext().
Note: Developers should gate this to API versions <33.
We are handling storage ourselves (courtesy of the in-app language picker), so we take the second approach.
So according to docs, we should have the API < 33 check.
*/
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
AppCompatDelegate.setApplicationLocales(chosenLocale != null ? LocaleListCompat.create(chosenLocale) : LocaleListCompat.getEmptyLocaleList());
}
return context;
}
@SuppressWarnings("deprecation")
private static void setLocalesSdkLessThan24(Locale chosenLocale, Configuration configuration, Resources res) {
configuration.locale = chosenLocale != null ? chosenLocale : Locale.getDefault();
res.updateConfiguration(configuration, res.getDisplayMetrics());
}
/**
* Android 13 settings seems to "force" the user to select country of locale, but many app-supported locales either only have language, not country
* or have a country the user doesn't want, which creates a mismatch between the app's supported locales and the system locale.
* <br>
* Example: The user chooses Espanol (Espana) in system settings, but the app only supports Espanol (Argentina) and the "plain" Espanol.
* <br>
* This method returns the app-supported locale that is most similar to the system one.
* @param appLocales Locales supported by the app
* @param sysLocale Per-app locale in system settings
* @return The app-supported locale that best matches the system per-app locale
*/
@NonNull
public static Locale getBestMatchLocale(@NonNull List<Locale> appLocales, @NonNull Locale sysLocale) {
int highestMatchMagnitude = appLocales.stream()
.mapToInt(appLocale -> calculateMatchMagnitudeOfTwoLocales(appLocale, sysLocale))
.max()
.orElseThrow(() -> new IllegalArgumentException("appLocales is empty"));
for (int i = 0; i < appLocales.size(); i++) {
Locale appLocale = appLocales.get(i);
if (calculateMatchMagnitudeOfTwoLocales(appLocale, sysLocale) == highestMatchMagnitude) {
return appLocale;
}
}
throw new AssertionError("This is not possible; there must be a locale whose match magnitude == " + highestMatchMagnitude + " with " + sysLocale.toLanguageTag());
}
private static int calculateMatchMagnitudeOfTwoLocales(@NonNull Locale appLocale, @NonNull Locale sysLocale) {
List<String> appLocaleAdjusted = new ArrayList<>();
List<String> sysLocaleAdjusted = new ArrayList<>();
appLocaleAdjusted.add(appLocale.getLanguage());
sysLocaleAdjusted.add(sysLocale.getLanguage());
if (!appLocale.getCountry().isEmpty() && !sysLocale.getCountry().isEmpty()) {
appLocaleAdjusted.add(appLocale.getCountry());
sysLocaleAdjusted.add(sysLocale.getCountry());
}
if (!appLocale.getVariant().isEmpty() && !sysLocale.getVariant().isEmpty()) {
appLocaleAdjusted.add(appLocale.getVariant());
sysLocaleAdjusted.add(sysLocale.getVariant());
}
if (!appLocale.getScript().isEmpty() && !sysLocale.getScript().isEmpty()) {
appLocaleAdjusted.add(appLocale.getScript());
sysLocaleAdjusted.add(sysLocale.getScript());
}
if (appLocaleAdjusted.equals(sysLocaleAdjusted)) {
return appLocaleAdjusted.size();
}
return 0;
}
static public long getUnixTime() {
@@ -418,6 +581,18 @@ public class Utils {
return new File(context.getCacheDir() + "/" + name);
}
public static File copyToTempFile(Context context, InputStream input, String name) throws IOException {
File file = createTempFile(context, name);
try (input; FileOutputStream out = new FileOutputStream(file)) {
byte[] buf = new byte[4096];
int len;
while ((len = input.read(buf)) != -1) {
out.write(buf, 0, len);
}
return file;
}
}
public static String saveTempImage(Context context, Bitmap in, String name, Bitmap.CompressFormat format) {
File image = createTempFile(context, name);
try (FileOutputStream out = new FileOutputStream(image)) {
@@ -480,7 +655,7 @@ public class Utils {
} else {
// final catch all in case of invalid theme value from older versions
// also handles R.string.settings_key_system_theme
DynamicColors.applyIfAvailable(activity);
DynamicColors.applyToActivityIfAvailable(activity);
}
if (isDarkModeEnabled(activity) && settings.getOledDark()) {
@@ -497,22 +672,12 @@ public class Utils {
activity.findViewById(android.R.id.content).setBackgroundColor(typedValue.data);
}
public static void updateMenuCardDetailsButtonState(MenuItem item, boolean currentlyExpanded) {
if (currentlyExpanded) {
item.setIcon(R.drawable.ic_baseline_unfold_less_24);
item.setTitle(R.string.action_hide_details);
} else {
item.setIcon(R.drawable.ic_baseline_unfold_more_24);
item.setTitle(R.string.action_show_details);
}
}
public static int getHeaderColorFromImage(Bitmap image, int fallback) {
if (image == null) {
return fallback;
}
return new Palette.Builder(image).generate().getDominantColor(R.attr.colorPrimary);
return new Palette.Builder(image).generate().getDominantColor(androidx.appcompat.R.attr.colorPrimary);
}
public static int getRandomHeaderColor(Context context) {
@@ -520,4 +685,133 @@ public class Utils {
final int color = (int) (Math.random() * colors.length());
return colors.getColor(color, Color.BLACK);
}
public static String readTextFile(Context context, @RawRes int resourceId) throws IOException {
InputStream input = context.getResources().openRawResource(resourceId);
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
StringBuilder result = new StringBuilder();
while (true) {
String nextLine = reader.readLine();
if (nextLine == null) {
reader.close();
break;
}
result.append("\n");
result.append(nextLine);
}
return result.toString();
}
// Very crude Markdown to HTML conversion.
// Only supports what's currently being used in CHANGELOG.md and PRIVACY.md.
// May break easily.
public static String basicMDToHTML(final String input) {
return input
.replaceAll("(?m)^#\\s+(.*)", "<h1>$1</h1>")
.replaceAll("(?m)^##\\s+(.*)", "<h2>$1</h2>")
.replaceAll("\\[([^]]+)\\]\\((https?://[\\w@#%&+=:?/.-]+)\\)", "<a href=\"$2\">$1</a>")
.replaceAll("\\*\\*([^*]+)\\*\\*", "<b>$1</b>")
.replaceAll("(?m)^-\\s+(.*)", "<ul><li>&nbsp;$1</li></ul>")
.replace("</ul>\n<ul>", "");
}
// Very crude autolinking.
// Only supports what's currently being used in CHANGELOG.md and PRIVACY.md.
// May break easily.
public static String linkify(final String input) {
return input
.replaceAll("([\\w.-]+@[\\w-]+(\\.[\\w-]+)+)", "<a href=\"mailto:$1\">$1</a>")
.replaceAll("(?<!href=\")\\b(https?://[\\w@#%&+=:?/.-]*[\\w@#%&+=:?/-])", "<a href=\"$1\">$1</a>");
}
public static void setIconOrTextWithBackground(Context context, LoyaltyCard loyaltyCard, Bitmap icon, ImageView backgroundOrIcon, TextView textWhenNoImage) {
if (icon != null) {
Log.d("onResume", "setting icon image");
textWhenNoImage.setVisibility(View.GONE);
backgroundOrIcon.setImageBitmap(icon);
backgroundOrIcon.setBackgroundColor(Color.TRANSPARENT);
} else {
textWhenNoImage.setVisibility(View.VISIBLE);
int headerColor = getHeaderColor(context, loyaltyCard);
backgroundOrIcon.setImageBitmap(null);
backgroundOrIcon.setBackgroundColor(headerColor);
textWhenNoImage.setText(loyaltyCard.store);
textWhenNoImage.setTextColor(Utils.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE);
}
}
public static boolean installedFromGooglePlay(Context context) {
try {
String packageName = context.getPackageName();
String installer;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
installer = context.getPackageManager().getInstallSourceInfo(packageName).getInstallingPackageName();
} else {
installer = context.getPackageManager().getInstallerPackageName(packageName);
}
return installer.equals("com.android.vending");
} catch (Throwable ignored) {
return false;
}
}
public static int getHeaderColor(Context context, LoyaltyCard loyaltyCard) {
return loyaltyCard.headerColor != null ? loyaltyCard.headerColor : LetterBitmap.getDefaultColor(context, loyaltyCard.store);
}
public static String checksum(InputStream input) throws IOException {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] buf = new byte[4096];
int len;
while ((len = input.read(buf)) != -1) {
md.update(buf, 0, len);
}
StringBuilder sb = new StringBuilder();
for (byte b : md.digest()) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException _e) {
return null;
}
}
public static boolean equals(final Object a, final Object b) {
if (a == null && b == null) {
return true;
} else if (a == null || b == null) {
return false;
}
return a.equals(b);
}
@SuppressLint("ClickableViewAccessibility")
public static void makeTextViewLinksClickable(final TextView textView, final Spanned text) {
textView.setOnTouchListener((v, event) -> {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX() - textView.getTotalPaddingLeft() + textView.getScrollX();
int y = (int) event.getY() - textView.getTotalPaddingTop() + textView.getScrollY();
Layout layout = textView.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] links = text.getSpans(off, off, ClickableSpan.class);
if (links.length != 0) {
ClickableSpan link = links[0];
if (action == MotionEvent.ACTION_UP) {
link.onClick(textView);
}
return true;
}
}
return false;
});
}
}

View File

@@ -15,7 +15,15 @@ import java.io.Reader;
import java.nio.charset.StandardCharsets;
public class ZipUtils {
static public String read(ZipInputStream zipInputStream) throws IOException {
public static Bitmap readImage(ZipInputStream zipInputStream) {
return BitmapFactory.decodeStream(zipInputStream);
}
public static JSONObject readJSON(ZipInputStream zipInputStream) throws IOException, JSONException {
return new JSONObject(read(zipInputStream));
}
private static String read(ZipInputStream zipInputStream) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
Reader reader = new BufferedReader(new InputStreamReader(zipInputStream, StandardCharsets.UTF_8));
int c;
@@ -24,12 +32,4 @@ public class ZipUtils {
}
return stringBuilder.toString();
}
static public Bitmap readImage(ZipInputStream zipInputStream) {
return BitmapFactory.decodeStream(zipInputStream);
}
static public JSONObject readJSON(ZipInputStream zipInputStream) throws IOException, JSONException {
return new JSONObject(read(zipInputStream));
}
}

View File

@@ -0,0 +1,172 @@
package protect.card_locker.contentprovider;
import static protect.card_locker.DBHelper.LoyaltyCardDbIds;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import protect.card_locker.BuildConfig;
import protect.card_locker.DBHelper;
import protect.card_locker.preferences.Settings;
public class CardsContentProvider extends ContentProvider {
private static final String TAG = "Catima";
public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".contentprovider.cards";
public static class Version {
public static final String MAJOR_COLUMN = "major";
public static final String MINOR_COLUMN = "minor";
public static final int MAJOR = 1;
public static final int MINOR = 0;
}
private static final int URI_VERSION = 0;
private static final int URI_CARDS = 1;
private static final int URI_GROUPS = 2;
private static final int URI_CARD_GROUPS = 3;
private static final String[] CARDS_DEFAULT_PROJECTION = new String[]{
LoyaltyCardDbIds.ID,
LoyaltyCardDbIds.STORE,
LoyaltyCardDbIds.VALID_FROM,
LoyaltyCardDbIds.EXPIRY,
LoyaltyCardDbIds.BALANCE,
LoyaltyCardDbIds.BALANCE_TYPE,
LoyaltyCardDbIds.NOTE,
LoyaltyCardDbIds.HEADER_COLOR,
LoyaltyCardDbIds.CARD_ID,
LoyaltyCardDbIds.BARCODE_ID,
LoyaltyCardDbIds.BARCODE_TYPE,
LoyaltyCardDbIds.STAR_STATUS,
LoyaltyCardDbIds.LAST_USED,
LoyaltyCardDbIds.ARCHIVE_STATUS,
};
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH) {{
addURI(AUTHORITY, "version", URI_VERSION);
addURI(AUTHORITY, "cards", URI_CARDS);
addURI(AUTHORITY, "groups", URI_GROUPS);
addURI(AUTHORITY, "card_groups", URI_CARD_GROUPS);
}};
@Override
public boolean onCreate() {
return true;
}
@Nullable
@Override
public Cursor query(@NonNull final Uri uri,
@Nullable final String[] projection,
@Nullable final String selection,
@Nullable final String[] selectionArgs,
@Nullable final String sortOrder) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// Disable the content provider on SDK < 23 since it grants dangerous
// permissions at install-time
Log.w(TAG, "Content provider read is only available for SDK >= 23");
return null;
}
final Settings settings = new Settings(getContext());
if (!settings.getAllowContentProviderRead()) {
Log.w(TAG, "Content provider read is disabled");
return null;
}
final String table;
String[] updatedProjection = projection;
switch (uriMatcher.match(uri)) {
case URI_VERSION:
return queryVersion();
case URI_CARDS:
table = DBHelper.LoyaltyCardDbIds.TABLE;
// Restrict columns to the default projection (omit internal columns such as zoom level)
if (projection == null) {
updatedProjection = CARDS_DEFAULT_PROJECTION;
} else {
final Set<String> defaultProjection = new HashSet<>(Arrays.asList(CARDS_DEFAULT_PROJECTION));
updatedProjection = Arrays.stream(projection).filter(defaultProjection::contains).toArray(String[]::new);
}
break;
case URI_GROUPS:
table = DBHelper.LoyaltyCardDbGroups.TABLE;
break;
case URI_CARD_GROUPS:
table = DBHelper.LoyaltyCardDbIdsGroups.TABLE;
break;
default:
Log.w(TAG, "Unrecognized URI " + uri);
return null;
}
final DBHelper dbHelper = new DBHelper(getContext());
final SQLiteDatabase database = dbHelper.getReadableDatabase();
return database.query(
table,
updatedProjection,
selection,
selectionArgs,
null,
null,
sortOrder
);
}
private Cursor queryVersion() {
final String[] columns = new String[]{Version.MAJOR_COLUMN, Version.MINOR_COLUMN};
final MatrixCursor matrixCursor = new MatrixCursor(columns);
matrixCursor.addRow(new Object[]{Version.MAJOR, Version.MINOR});
return matrixCursor;
}
@Nullable
@Override
public String getType(@NonNull final Uri uri) {
// MIME types are not relevant (for now at least)
return null;
}
@Nullable
@Override
public Uri insert(@NonNull final Uri uri,
@Nullable final ContentValues values) {
// This content provider is read-only for now, so we always return null
return null;
}
@Override
public int delete(@NonNull final Uri uri,
@Nullable final String selection,
@Nullable final String[] selectionArgs) {
// This content provider is read-only for now, so we always return 0
return 0;
}
@Override
public int update(@NonNull final Uri uri,
@Nullable final ContentValues values,
@Nullable final String selection,
@Nullable final String[] selectionArgs) {
// This content provider is read-only for now, so we always return 0
return 0;
}
}

View File

@@ -8,22 +8,14 @@ public class CSVHelpers {
/**
* Extract a string from the items array. The index into the array
* is determined by looking up the index in the fields map using the
* "key" as the key. If no such key exists, defaultValue is returned
* if it is not null. Otherwise, a FormatException is thrown.
* "key" as the key. If no such key exists, defaultValue is returned.
*/
static String extractString(String key, CSVRecord record, String defaultValue)
throws FormatException {
String toReturn = defaultValue;
static String extractString(String key, CSVRecord record, String defaultValue) {
if (record.isMapped(key)) {
toReturn = record.get(key);
} else {
if (defaultValue == null) {
throw new FormatException("Field not used but expected: " + key);
}
return record.get(key);
}
return toReturn;
return defaultValue;
}
/**
@@ -32,15 +24,15 @@ public class CSVHelpers {
* "key" as the key. If no such key exists, or the data is not a valid
* int, a FormatException is thrown.
*/
static Integer extractInt(String key, CSVRecord record, boolean nullIsOk)
static Integer extractInt(String key, CSVRecord record)
throws FormatException {
if (record.isMapped(key) == false) {
if (!record.isMapped(key)) {
throw new FormatException("Field not used but expected: " + key);
}
String value = record.get(key);
if (value.isEmpty() && nullIsOk) {
return null;
if (value.isEmpty()) {
throw new FormatException("Field is empty: " + key);
}
try {
@@ -56,15 +48,15 @@ public class CSVHelpers {
* "key" as the key. If no such key exists, or the data is not a valid
* int, a FormatException is thrown.
*/
static Long extractLong(String key, CSVRecord record, boolean nullIsOk)
static Long extractLong(String key, CSVRecord record)
throws FormatException {
if (record.isMapped(key) == false) {
if (!record.isMapped(key)) {
throw new FormatException("Field not used but expected: " + key);
}
String value = record.get(key);
if (value.isEmpty() && nullIsOk) {
return null;
if (value.isEmpty()) {
throw new FormatException("Field is empty: " + key);
}
try {

View File

@@ -127,6 +127,7 @@ public class CatimaExporter implements Exporter {
printer.printRecord(DBHelper.LoyaltyCardDbIds.ID,
DBHelper.LoyaltyCardDbIds.STORE,
DBHelper.LoyaltyCardDbIds.NOTE,
DBHelper.LoyaltyCardDbIds.VALID_FROM,
DBHelper.LoyaltyCardDbIds.EXPIRY,
DBHelper.LoyaltyCardDbIds.BALANCE,
DBHelper.LoyaltyCardDbIds.BALANCE_TYPE,
@@ -146,6 +147,7 @@ public class CatimaExporter implements Exporter {
printer.printRecord(card.id,
card.store,
card.note,
card.validFrom != null ? card.validFrom.getTime() : "",
card.expiry != null ? card.expiry.getTime() : "",
card.balance,
card.balanceType,

View File

@@ -13,7 +13,8 @@ import org.apache.commons.csv.CSVRecord;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -23,12 +24,17 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Currency;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import protect.card_locker.CatimaBarcode;
import protect.card_locker.DBHelper;
import protect.card_locker.FormatException;
import protect.card_locker.Group;
import protect.card_locker.ImageLocationType;
import protect.card_locker.LoyaltyCard;
import protect.card_locker.Utils;
import protect.card_locker.ZipUtils;
@@ -40,24 +46,42 @@ import protect.card_locker.ZipUtils;
* A header is expected for the each table showing the names of the columns.
*/
public class CatimaImporter implements Importer {
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password) throws IOException, FormatException, InterruptedException {
InputStream bufferedInputStream = new BufferedInputStream(input);
bufferedInputStream.mark(100);
public static class ImportedData {
public final List<LoyaltyCard> cards;
public final List<String> groups;
public final List<Map.Entry<Integer, String>> cardGroups;
ImportedData(final List<LoyaltyCard> cards, final List<String> groups, final List<Map.Entry<Integer, String>> cardGroups) {
this.cards = cards;
this.groups = groups;
this.cardGroups = cardGroups;
}
}
public void importData(Context context, SQLiteDatabase database, File inputFile, char[] password) throws IOException, FormatException, InterruptedException {
// Pass #1: get hashes and parse CSV
InputStream input1 = new FileInputStream(inputFile);
InputStream bufferedInputStream1 = new BufferedInputStream(input1);
bufferedInputStream1.mark(100);
ZipInputStream zipInputStream1 = new ZipInputStream(bufferedInputStream1, password);
// First, check if this is a zip file
ZipInputStream zipInputStream = new ZipInputStream(bufferedInputStream, password);
boolean isZipFile = false;
LocalFileHeader localFileHeader;
while ((localFileHeader = zipInputStream.getNextEntry()) != null) {
Map<String, String> imageChecksums = new HashMap<>();
ImportedData importedData = null;
while ((localFileHeader = zipInputStream1.getNextEntry()) != null) {
isZipFile = true;
String fileName = Uri.parse(localFileHeader.getFileName()).getLastPathSegment();
if (fileName.equals("catima.csv")) {
importCSV(context, database, new ByteArrayInputStream(ZipUtils.read(zipInputStream).getBytes(StandardCharsets.UTF_8)));
importedData = importCSV(zipInputStream1);
} else if (fileName.endsWith(".png")) {
Utils.saveCardImage(context, ZipUtils.readImage(zipInputStream), fileName);
if (!fileName.matches(Utils.CARD_IMAGE_FILENAME_REGEX)) {
throw new FormatException("Unexpected PNG file in import: " + fileName);
}
imageChecksums.put(fileName, Utils.checksum(zipInputStream1));
} else {
throw new FormatException("Unexpected file in import: " + fileName);
}
@@ -65,46 +89,110 @@ public class CatimaImporter implements Importer {
if (!isZipFile) {
// This is not a zip file, try importing as bare CSV
bufferedInputStream.reset();
importCSV(context, database, bufferedInputStream);
bufferedInputStream1.reset();
importedData = importCSV(bufferedInputStream1);
}
input1.close();
if (importedData == null) {
throw new FormatException("No imported data");
}
Map<Integer, Integer> idMap = saveAndDeduplicate(context, database, importedData, imageChecksums);
if (isZipFile) {
// Pass #2: save images
InputStream input2 = new FileInputStream(inputFile);
InputStream bufferedInputStream2 = new BufferedInputStream(input2);
ZipInputStream zipInputStream2 = new ZipInputStream(bufferedInputStream2, password);
while ((localFileHeader = zipInputStream2.getNextEntry()) != null) {
String fileName = Uri.parse(localFileHeader.getFileName()).getLastPathSegment();
if (fileName.endsWith(".png")) {
String newFileName = Utils.getRenamedCardImageFileName(fileName, idMap);
Utils.saveCardImage(context, ZipUtils.readImage(zipInputStream2), newFileName);
}
}
input2.close();
}
}
public void importCSV(Context context, SQLiteDatabase database, InputStream input) throws IOException, FormatException, InterruptedException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
public Map<Integer, Integer> saveAndDeduplicate(Context context, SQLiteDatabase database, final ImportedData data, final Map<String, String> imageChecksums) throws IOException {
Map<Integer, Integer> idMap = new HashMap<>();
Set<String> existingImages = DBHelper.imageFiles(context, database);
bufferedReader.mark(100);
Integer version = 1;
try {
version = Integer.parseInt(bufferedReader.readLine());
} catch (NumberFormatException _e) {
// Assume version 1
for (LoyaltyCard card : data.cards) {
LoyaltyCard existing = DBHelper.getLoyaltyCard(database, card.id);
if (existing == null) {
DBHelper.insertLoyaltyCard(database, card.id, card.store, card.note, card.validFrom, card.expiry, card.balance, card.balanceType,
card.cardId, card.barcodeId, card.barcodeType, card.headerColor, card.starStatus, card.lastUsed, card.archiveStatus);
} else if (!isDuplicate(context, existing, card, existingImages, imageChecksums)) {
long newId = DBHelper.insertLoyaltyCard(database, card.store, card.note, card.validFrom, card.expiry, card.balance, card.balanceType,
card.cardId, card.barcodeId, card.barcodeType, card.headerColor, card.starStatus, card.lastUsed, card.archiveStatus);
idMap.put(card.id, (int) newId);
}
}
bufferedReader.reset();
for (String group : data.groups) {
DBHelper.insertGroup(database, group);
}
for (Map.Entry<Integer, String> entry : data.cardGroups) {
int cardId = idMap.getOrDefault(entry.getKey(), entry.getKey());
String groupId = entry.getValue();
// For existing & newly imported cards, add the groups from the import to the internal state
List<Group> cardGroups = DBHelper.getLoyaltyCardGroups(database, cardId);
cardGroups.add(DBHelper.getGroup(database, groupId));
DBHelper.setLoyaltyCardGroups(database, cardId, cardGroups);
}
return idMap;
}
public boolean isDuplicate(Context context, final LoyaltyCard existing, final LoyaltyCard card, final Set<String> existingImages, final Map<String, String> imageChecksums) throws IOException {
if (!LoyaltyCard.isDuplicate(existing, card)) {
return false;
}
for (ImageLocationType imageLocationType : ImageLocationType.values()) {
String name = Utils.getCardImageFileName(existing.id, imageLocationType);
boolean exists = existingImages.contains(name);
if (exists != imageChecksums.containsKey(name)) {
return false;
}
if (exists) {
File file = Utils.retrieveCardImageAsFile(context, name);
if (!imageChecksums.get(name).equals(Utils.checksum(new FileInputStream(file)))) {
return false;
}
}
}
return true;
}
public ImportedData importCSV(InputStream input) throws IOException, FormatException, InterruptedException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
int version = parseVersion(bufferedReader);
switch (version) {
case 1:
parseV1(context, database, bufferedReader);
break;
return parseV1(bufferedReader);
case 2:
parseV2(context, database, bufferedReader);
break;
return parseV2(bufferedReader);
default:
throw new FormatException(String.format("No code to parse version %s", version));
}
bufferedReader.close();
}
public void parseV1(Context context, SQLiteDatabase database, BufferedReader input) throws IOException, FormatException, InterruptedException {
public ImportedData parseV1(BufferedReader input) throws IOException, FormatException, InterruptedException {
ImportedData data = new ImportedData(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
final CSVParser parser = new CSVParser(input, CSVFormat.RFC4180.builder().setHeader().build());
try {
for (CSVRecord record : parser) {
importLoyaltyCard(context, database, record);
LoyaltyCard card = importLoyaltyCard(record);
data.cards.add(card);
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
@@ -115,11 +203,17 @@ public class CatimaImporter implements Importer {
} catch (IllegalArgumentException | IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e);
}
return data;
}
public void parseV2(Context context, SQLiteDatabase database, BufferedReader input) throws IOException, FormatException, InterruptedException {
Integer part = 0;
String stringPart = "";
public ImportedData parseV2(BufferedReader input) throws IOException, FormatException, InterruptedException {
List<LoyaltyCard> cards = new ArrayList<>();
List<String> groups = new ArrayList<>();
List<Map.Entry<Integer, String>> cardGroups = new ArrayList<>();
int part = 0;
StringBuilder stringPart = new StringBuilder();
try {
while (true) {
@@ -135,7 +229,7 @@ public class CatimaImporter implements Importer {
break;
case 1:
try {
parseV2Groups(database, stringPart);
groups = parseV2Groups(stringPart.toString());
sectionParsed = true;
} catch (FormatException e) {
// We may have a multiline field, try again
@@ -143,7 +237,7 @@ public class CatimaImporter implements Importer {
break;
case 2:
try {
parseV2Cards(context, database, stringPart);
cards = parseV2Cards(stringPart.toString());
sectionParsed = true;
} catch (FormatException e) {
// We may have a multiline field, try again
@@ -151,7 +245,7 @@ public class CatimaImporter implements Importer {
break;
case 3:
try {
parseV2CardGroups(database, stringPart);
cardGroups = parseV2CardGroups(stringPart.toString());
sectionParsed = true;
} catch (FormatException e) {
// We may have a multiline field, try again
@@ -167,20 +261,22 @@ public class CatimaImporter implements Importer {
if (sectionParsed) {
part += 1;
stringPart = "";
stringPart = new StringBuilder();
} else {
stringPart += tmp + "\n";
stringPart.append(tmp).append('\n');
}
} else {
stringPart += tmp + "\n";
stringPart.append(tmp).append('\n');
}
}
} catch (FormatException e) {
throw new FormatException("Issue parsing CSV data", e);
}
return new ImportedData(cards, groups, cardGroups);
}
public void parseV2Groups(SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException {
public List<String> parseV2Groups(String data) throws IOException, FormatException, InterruptedException {
// Parse groups
final CSVParser groupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
@@ -200,12 +296,15 @@ public class CatimaImporter implements Importer {
groupParser.close();
}
List<String> groups = new ArrayList<>();
for (CSVRecord record : records) {
importGroup(database, record);
String group = importGroup(record);
groups.add(group);
}
return groups;
}
public void parseV2Cards(Context context, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException {
public List<LoyaltyCard> parseV2Cards(String data) throws IOException, FormatException, InterruptedException {
// Parse cards
final CSVParser cardParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
@@ -225,12 +324,15 @@ public class CatimaImporter implements Importer {
cardParser.close();
}
List<LoyaltyCard> cards = new ArrayList<>();
for (CSVRecord record : records) {
importLoyaltyCard(context, database, record);
LoyaltyCard card = importLoyaltyCard(record);
cards.add(card);
}
return cards;
}
public void parseV2CardGroups(SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException {
public List<Map.Entry<Integer, String>> parseV2CardGroups(String data) throws IOException, FormatException, InterruptedException {
// Parse card group mappings
final CSVParser cardGroupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
@@ -250,18 +352,49 @@ public class CatimaImporter implements Importer {
cardGroupParser.close();
}
List<Map.Entry<Integer, String>> cardGroups = new ArrayList<>();
for (CSVRecord record : records) {
importCardGroupMapping(database, record);
Map.Entry<Integer, String> entry = importCardGroupMapping(record);
cardGroups.add(entry);
}
return cardGroups;
}
/**
* Parse the version number of the import file
*
* @param reader the reader containing the import file
* @return the parsed version number, defaulting to 1 if none is found
* @throws IOException there was a problem reading the file
*/
private int parseVersion(BufferedReader reader) throws IOException {
reader.mark(10); // slightly over the search limit just to be sure
StringBuilder sb = new StringBuilder();
int searchLimit = 5; // gives you version numbers up to 99999
int codePoint;
// search until the next whitespace, indicating the end of the version
while (!Character.isWhitespace(codePoint = reader.read())) {
// we found something that isn't a digit, or we ran out of chars
if (!Character.isDigit(codePoint) || searchLimit <= 0) {
reader.reset();
return 1; // default value
}
sb.append((char) codePoint);
searchLimit--;
}
reader.reset();
if (sb.length() == 0) {
return 1;
}
return Integer.parseInt(sb.toString());
}
/**
* Import a single loyalty card into the database using the given
* session.
*/
private void importLoyaltyCard(Context context, SQLiteDatabase database, CSVRecord record)
throws IOException, FormatException {
int id = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ID, record, false);
private LoyaltyCard importLoyaltyCard(CSVRecord record) throws FormatException {
int id = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ID, record);
String store = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.STORE, record, "");
if (store.isEmpty()) {
@@ -269,19 +402,38 @@ public class CatimaImporter implements Importer {
}
String note = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.NOTE, record, "");
Date expiry = null;
Date validFrom = null;
Long validFromLong;
try {
expiry = new Date(CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.EXPIRY, record, true));
} catch (NullPointerException | FormatException e) {
validFromLong = CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.VALID_FROM, record);
} catch (FormatException ignored) {
validFromLong = null;
}
if (validFromLong != null) {
validFrom = new Date(validFromLong);
}
BigDecimal balance;
Date expiry = null;
Long expiryLong;
try {
balance = new BigDecimal(CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BALANCE, record, null));
} 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");
expiryLong = CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.EXPIRY, record);
} catch (FormatException ignored) {
expiryLong = null;
}
if (expiryLong != null) {
expiry = new Date(expiryLong);
}
// These fields did not exist in versions 1.8.1 and before
// We default to 0 so we can still import old backups
BigDecimal balance = new BigDecimal("0");
String balanceString = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BALANCE, record, null);
if (balanceString != null) {
try {
balance = new BigDecimal(CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BALANCE, record, null));
} catch (NumberFormatException ignored) {
}
}
Currency balanceType = null;
@@ -307,14 +459,14 @@ public class CatimaImporter implements Importer {
}
Integer headerColor = null;
if (record.isMapped(DBHelper.LoyaltyCardDbIds.HEADER_COLOR)) {
headerColor = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.HEADER_COLOR, record, true);
try {
headerColor = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.HEADER_COLOR, record);
} catch (FormatException ignored) {
}
int starStatus = 0;
try {
starStatus = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.STAR_STATUS, record, false);
starStatus = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.STAR_STATUS, record);
} 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
@@ -323,7 +475,7 @@ public class CatimaImporter implements Importer {
int archiveStatus = 0;
try {
archiveStatus = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ARCHIVE_STATUS, record, false);
archiveStatus = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ARCHIVE_STATUS, record);
} catch (FormatException _e) {
// This field did not exist in versions 2.16.3 and before
// We catch this exception so we can still import old backups
@@ -332,35 +484,41 @@ public class CatimaImporter implements Importer {
Long lastUsed = 0L;
try {
lastUsed = CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.LAST_USED, record, false);
lastUsed = CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.LAST_USED, record);
} 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
}
DBHelper.insertLoyaltyCard(database, id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starStatus, lastUsed,archiveStatus);
return new LoyaltyCard(id, store, note, validFrom, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starStatus, lastUsed, DBHelper.DEFAULT_ZOOM_LEVEL, archiveStatus);
}
/**
* Import a single group into the database using the given
* session.
*/
private void importGroup(SQLiteDatabase database, CSVRecord record) throws FormatException {
private String importGroup(CSVRecord record) throws FormatException {
String id = CSVHelpers.extractString(DBHelper.LoyaltyCardDbGroups.ID, record, null);
DBHelper.insertGroup(database, id);
if (id == null) {
throw new FormatException("Group has no ID: " + record);
}
return id;
}
/**
* Import a single card to group mapping into the database using the given
* session.
*/
private void importCardGroupMapping(SQLiteDatabase database, CSVRecord record) throws FormatException {
Integer cardId = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIdsGroups.cardID, record, false);
private Map.Entry<Integer, String> importCardGroupMapping(CSVRecord record) throws FormatException {
int cardId = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIdsGroups.cardID, record);
String groupId = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIdsGroups.groupID, record, null);
List<Group> cardGroups = DBHelper.getLoyaltyCardGroups(database, cardId);
cardGroups.add(DBHelper.getGroup(database, groupId));
DBHelper.setLoyaltyCardGroups(database, cardId, cardGroups);
if (groupId == null) {
throw new FormatException("Group has no ID: " + record);
}
return Map.entry(cardId, groupId);
}
}
}

View File

@@ -11,16 +11,21 @@ import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.json.JSONException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import protect.card_locker.CatimaBarcode;
import protect.card_locker.DBHelper;
import protect.card_locker.FormatException;
import protect.card_locker.LoyaltyCard;
import protect.card_locker.Utils;
/**
@@ -31,7 +36,16 @@ import protect.card_locker.Utils;
* A header is expected for the each table showing the names of the columns.
*/
public class FidmeImporter implements Importer {
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
public static class ImportedData {
public final List<LoyaltyCard> cards;
ImportedData(final List<LoyaltyCard> cards) {
this.cards = cards;
}
}
public void importData(Context context, SQLiteDatabase database, File inputFile, char[] password) throws IOException, FormatException, JSONException, ParseException {
InputStream input = new FileInputStream(inputFile);
// We actually retrieve a .zip file
ZipInputStream zipInputStream = new ZipInputStream(input, password);
@@ -54,10 +68,14 @@ public class FidmeImporter implements Importer {
}
final CSVParser fidmeParser = new CSVParser(new StringReader(loyaltyCards.toString()), CSVFormat.RFC4180.builder().setDelimiter(';').setHeader().build());
ImportedData importedData = new ImportedData(new ArrayList<>());
try {
for (CSVRecord record : fidmeParser) {
importLoyaltyCard(context, database, record);
LoyaltyCard card = importLoyaltyCard(context, record);
if (card != null) {
importedData.cards.add(card);
}
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
@@ -70,14 +88,16 @@ public class FidmeImporter implements Importer {
}
zipInputStream.close();
input.close();
saveAndDeduplicate(database, importedData);
}
/**
* Import a single loyalty card into the database using the given
* session.
*/
private void importLoyaltyCard(Context context, SQLiteDatabase database, CSVRecord record)
throws FormatException {
private LoyaltyCard importLoyaltyCard(Context context, CSVRecord record) throws FormatException {
// A loyalty card export from Fidme contains the following fields:
// Retailer (store name)
// Program (program name)
@@ -113,7 +133,7 @@ public class FidmeImporter implements Importer {
// Fidme deletes the card id if a card is expired
// Because Catima considers the card id a required field, we ignore these expired cards
// https://github.com/CatimaLoyalty/Android/issues/1005
return;
return null;
}
// Sadly, Fidme exports don't contain the card type
@@ -128,6 +148,17 @@ public class FidmeImporter implements Importer {
// TODO: Front and back image
DBHelper.insertLoyaltyCard(database, store, note, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, headerColor, starStatus, null,archiveStatus);
// use -1 for the ID, it will be ignored when inserting the card into the DB
return new LoyaltyCard(-1, store, note, null, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, headerColor, starStatus, Utils.getUnixTime(), DBHelper.DEFAULT_ZOOM_LEVEL, archiveStatus);
}
public void saveAndDeduplicate(SQLiteDatabase database, final ImportedData data) {
// This format does not have IDs that can cause conflicts
// Proper deduplication for all formats will be implemented later
for (LoyaltyCard card : data.cards) {
// Do not use card.id which is set to -1
DBHelper.insertLoyaltyCard(database, card.store, card.note, card.validFrom, card.expiry, card.balance, card.balanceType,
card.cardId, card.barcodeId, card.barcodeType, card.headerColor, card.starStatus, card.lastUsed, card.archiveStatus);
}
}
}

View File

@@ -5,8 +5,8 @@ import android.database.sqlite.SQLiteDatabase;
import org.json.JSONException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import protect.card_locker.FormatException;
@@ -23,5 +23,5 @@ public interface Importer {
* @throws IOException
* @throws FormatException
*/
void importData(Context context, SQLiteDatabase database, InputStream input, char[] password) throws IOException, FormatException, InterruptedException, JSONException, ParseException;
void importData(Context context, SQLiteDatabase database, File inputFile, char[] password) throws IOException, FormatException, InterruptedException, JSONException, ParseException;
}

View File

@@ -6,10 +6,15 @@ import android.util.Log;
import net.lingala.zip4j.exception.ZipException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import protect.card_locker.Utils;
public class MultiFormatImporter {
private static final String TAG = "Catima";
private static final String TEMP_ZIP_NAME = MultiFormatImporter.class.getSimpleName() + ".zip";
/**
* Attempts to import data from the input stream of the
@@ -42,23 +47,33 @@ public class MultiFormatImporter {
String error = null;
if (importer != null) {
database.beginTransaction();
File inputFile;
try {
importer.importData(context, database, input, password);
database.setTransactionSuccessful();
return new ImportExportResult(ImportExportResultType.Success);
} catch (ZipException e) {
if (e.getType().equals(ZipException.Type.WRONG_PASSWORD)) {
return new ImportExportResult(ImportExportResultType.BadPassword);
} else {
inputFile = Utils.copyToTempFile(context, input, TEMP_ZIP_NAME);
database.beginTransaction();
try {
importer.importData(context, database, inputFile, password);
database.setTransactionSuccessful();
return new ImportExportResult(ImportExportResultType.Success);
} catch (ZipException e) {
if (e.getType().equals(ZipException.Type.WRONG_PASSWORD)) {
return new ImportExportResult(ImportExportResultType.BadPassword);
} else {
Log.e(TAG, "Failed to import data", e);
error = e.toString();
}
} catch (Exception e) {
Log.e(TAG, "Failed to import data", e);
error = e.toString();
} finally {
database.endTransaction();
if (!inputFile.delete()) {
Log.w(TAG, "Failed to delete temporary ZIP file (should not be a problem) " + inputFile);
}
}
} catch (Exception e) {
Log.e(TAG, "Failed to import data", e);
} catch (IOException e) {
Log.e(TAG, "Failed to copy ZIP file", e);
error = e.toString();
} finally {
database.endTransaction();
}
} else {
error = "Unsupported data format imported: " + format.name();

View File

@@ -5,6 +5,8 @@ import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.zxing.BarcodeFormat;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
@@ -13,21 +15,30 @@ import net.lingala.zip4j.model.LocalFileHeader;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import protect.card_locker.CatimaBarcode;
import protect.card_locker.DBHelper;
import protect.card_locker.FormatException;
import protect.card_locker.ImageLocationType;
import protect.card_locker.LoyaltyCard;
import protect.card_locker.R;
import protect.card_locker.Utils;
import protect.card_locker.ZipUtils;
@@ -40,21 +51,78 @@ import protect.card_locker.ZipUtils;
* A header is expected for the each table showing the names of the columns.
*/
public class StocardImporter implements Importer {
public static class StocardProvider {
public String name = null;
public String barcodeFormat = null;
public Bitmap logo = null;
}
public static class StocardRecord {
public String providerId = null;
public String store = null;
public String label = null;
public String note = null;
public String cardId = null;
public String barcodeType = null;
public Long lastUsed = null;
public Bitmap frontImage = null;
public Bitmap backImage = null;
@NonNull
@Override
public String toString() {
return String.format(
"StocardRecord{%n providerId=%s,%n store=%s,%n label=%s,%n note=%s,%n cardId=%s,%n"
+ " barcodeType=%s,%n lastUsed=%s,%n frontImage=%s,%n backImage=%s%n}",
this.providerId,
this.store,
this.label,
this.note,
this.cardId,
this.barcodeType,
this.lastUsed,
this.frontImage,
this.backImage
);
}
}
public static class ZIPData {
public final Map<String, StocardRecord> cards;
public final Map<String, StocardProvider> providers;
ZIPData(final Map<String, StocardRecord> cards, final Map<String, StocardProvider> providers) {
this.cards = cards;
this.providers = providers;
}
}
public static class ImportedData {
public final List<LoyaltyCard> cards;
public final Map<Integer, Map<ImageLocationType, Bitmap>> images;
ImportedData(final List<LoyaltyCard> cards, final Map<Integer, Map<ImageLocationType, Bitmap>> images) {
this.cards = cards;
this.images = images;
}
}
public static final String PROVIDER_PREFIX = "/loyalty-card-providers/";
private static final String TAG = "Catima";
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
HashMap<String, HashMap<String, Object>> loyaltyCardHashMap = new HashMap<>();
HashMap<String, HashMap<String, Object>> providers = new HashMap<>();
public void importData(Context context, SQLiteDatabase database, File inputFile, char[] password) throws IOException, FormatException, JSONException, ParseException {
ZIPData zipData = new ZIPData(new HashMap<>(), new HashMap<>());
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) {
HashMap<String, Object> recordData = new HashMap<>();
recordData.put("name", record.get("name"));
recordData.put("barcodeFormat", record.get("barcodeFormat"));
StocardProvider provider = new StocardProvider();
provider.name = record.get("name").trim();
provider.barcodeFormat = record.get("barcodeFormat").trim();
providers.put(record.get("_id"), recordData);
zipData.providers.put(record.get("_id").trim(), provider);
}
parser.close();
@@ -62,160 +130,213 @@ public class StocardImporter implements Importer {
throw new FormatException("Issue parsing CSV data", e);
}
InputStream input = new FileInputStream(inputFile);
ZipInputStream zipInputStream = new ZipInputStream(input, password);
zipData = importZIP(zipInputStream, zipData);
zipInputStream.close();
input.close();
if (zipData.cards.keySet().size() == 0) {
throw new FormatException("Couldn't find any loyalty cards in this Stocard export.");
}
ImportedData importedData = importLoyaltyCardHashMap(context, zipData);
saveAndDeduplicate(context, database, importedData);
}
public ZIPData importZIP(ZipInputStream zipInputStream, final ZIPData zipData) throws IOException, FormatException, JSONException {
Map<String, StocardRecord> cards = zipData.cards;
Map<String, StocardProvider> providers = zipData.providers;
String[] providersFileName = null;
String[] customProvidersBaseName = null;
String customProviderId = "";
String[] cardBaseName = null;
String customProviderId = "";
String cardName = "";
LocalFileHeader localFileHeader;
while ((localFileHeader = zipInputStream.getNextEntry()) != null) {
String fileName = localFileHeader.getFileName();
String[] nameParts = fileName.split("/");
if (providersFileName == null) {
providersFileName = new String[]{
nameParts[0],
"sync",
"data",
"users",
nameParts[0],
"analytics-properties.json"
};
if (nameParts.length < 2) {
continue;
}
String userId = nameParts[1];
if (customProvidersBaseName == null) {
// FIXME: can we use the points-account/statement/content.json balance info somehow?
/*
Known files:
extracts/<user-UUID>/users/<user-UUID>/
analytics-properties/content.json
devices/<device-UUID>/
analytics-properties/content.json
content.json
ip-location-wifi/content.json
enabled-regions/<UUID>/content.json
loyalty-card-custom-providers/<provider-UUID>/content.json - custom providers
loyalty-cards/<card-UUID>/
card-linked-coupons/accounts/default/
content.json
user-coupons/<UUID>/content.json
content.json - card itself
images/back.png - back image (legacy)
images/back/back.jpg - back image
images/back/content.json
images/front.png - front image (legacy)
images/front/content.json
images/front/front.jpg - front image
notes/default/content.json - note
points-account/
content.json
statement/content.json
usages/<UUID>/content.json - timestamps
usage-statistics/content.json - timestamps
reward-program-balances/<UUID>/content.json
*/
customProvidersBaseName = new String[]{
nameParts[0],
"sync",
"data",
"extracts",
userId,
"users",
nameParts[0],
userId,
"loyalty-card-custom-providers"
};
cardBaseName = new String[]{
nameParts[0],
"sync",
"data",
"extracts",
userId,
"users",
nameParts[0],
userId,
"loyalty-cards"
};
}
if (startsWith(nameParts, customProvidersBaseName, 1)) {
// Extract providerId
customProviderId = nameParts[customProvidersBaseName.length].split("\\.", 2)[0];
customProviderId = nameParts[customProvidersBaseName.length];
StocardProvider provider = providers.get(customProviderId);
if (provider == null) {
provider = new StocardProvider();
providers.put(customProviderId, provider);
}
// Name file
if (nameParts.length == customProvidersBaseName.length + 1) {
// Ignore the .txt file
if (fileName.endsWith(".json")) {
JSONObject jsonObject = ZipUtils.readJSON(zipInputStream);
providers = appendToHashMap(
providers,
customProviderId,
"name",
jsonObject.getString("name")
);
}
if (fileName.endsWith(customProviderId + "/content.json")) {
JSONObject jsonObject = ZipUtils.readJSON(zipInputStream);
provider.name = jsonObject.getString("name");
} else if (fileName.endsWith("logo.png")) {
providers = appendToHashMap(
providers,
customProviderId,
"logo",
ZipUtils.readImage(zipInputStream)
);
provider.logo = ZipUtils.readImage(zipInputStream);
} else if (!fileName.endsWith("/")) {
Log.d(TAG, "Unknown or unused loyalty-card-custom-providers file " + fileName + ", skipping...");
}
}
if (startsWith(nameParts, cardBaseName, 1)) {
} else if (startsWith(nameParts, cardBaseName, 1)) {
// Extract cardName
cardName = nameParts[cardBaseName.length].split("\\.", 2)[0];
cardName = nameParts[cardBaseName.length];
StocardRecord record = cards.get(cardName);
if (record == null) {
record = new StocardRecord();
cards.put(cardName, record);
}
// This is the card itself
if (nameParts.length == cardBaseName.length + 1) {
// Ignore the .txt file
if (fileName.endsWith(".json")) {
JSONObject jsonObject = ZipUtils.readJSON(zipInputStream);
if (fileName.endsWith(cardName + "/content.json")) {
JSONObject jsonObject = ZipUtils.readJSON(zipInputStream);
record.cardId = jsonObject.getString("input_id");
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap,
cardName,
"cardId",
jsonObject.getString("input_id")
);
if (jsonObject.has("input_provider_name")) {
record.store = jsonObject.getString("input_provider_name");
}
// Provider ID can be either custom or not, extract whatever version is relevant
String customProviderPrefix = "/users/" + nameParts[0] + "/loyalty-card-custom-providers/";
String providerId = jsonObject
.getJSONObject("input_provider_reference")
.getString("identifier");
if (providerId.startsWith(customProviderPrefix)) {
providerId = providerId.substring(customProviderPrefix.length());
} else {
providerId = providerId.substring("/loyalty-card-providers/".length());
}
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap,
cardName,
"_providerId",
providerId
);
if (jsonObject.has("input_barcode_format")) {
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap,
cardName,
"barcodeType",
jsonObject.getString("input_barcode_format")
);
if (jsonObject.has("label")) {
String label = jsonObject.getString("label");
if (!label.isBlank()) {
record.label = label;
}
}
} else if (fileName.endsWith("notes/default.json")) {
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap,
cardName,
"note",
ZipUtils.readJSON(zipInputStream)
.getString("content")
);
} else if (fileName.endsWith("/images/front.png")) {
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap,
cardName,
"frontImage",
ZipUtils.readImage(zipInputStream)
);
} else if (fileName.endsWith("/images/back.png")) {
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap,
cardName,
"backImage",
ZipUtils.readImage(zipInputStream)
);
// Provider ID can be either custom or not, extract whatever version is relevant
String customProviderPrefix = "/users/" + userId + "/loyalty-card-custom-providers/";
String providerId = jsonObject
.getJSONObject("input_provider_reference")
.getString("identifier");
if (providerId.startsWith(customProviderPrefix)) {
providerId = providerId.substring(customProviderPrefix.length());
} else if (providerId.startsWith(PROVIDER_PREFIX)) {
providerId = providerId.substring(PROVIDER_PREFIX.length());
} else {
throw new FormatException("Unsupported provider ID format: " + providerId);
}
record.providerId = providerId;
if (jsonObject.has("input_barcode_format")) {
record.barcodeType = jsonObject.getString("input_barcode_format");
}
} else if (fileName.endsWith("notes/default/content.json")) {
record.note = ZipUtils.readJSON(zipInputStream).getString("content");
} else if (fileName.endsWith("usage-statistics/content.json")) {
JSONArray usages = ZipUtils.readJSON(zipInputStream).getJSONArray("usages");
for (int i = 0; i < usages.length(); i++) {
JSONObject lastUsedObject = usages.getJSONObject(i);
String lastUsedString = lastUsedObject.getJSONObject("time").getString("value");
long timeStamp = Instant.parse(lastUsedString).getEpochSecond();
if (record.lastUsed == null || timeStamp > record.lastUsed) {
record.lastUsed = timeStamp;
}
}
} else if (fileName.matches(".*/usages/[^/]+/content.json")) {
JSONObject lastUsedObject = ZipUtils.readJSON(zipInputStream);
String lastUsedString = lastUsedObject.getJSONObject("time").getString("value");
long timeStamp = Instant.parse(lastUsedString).getEpochSecond();
if (record.lastUsed == null || timeStamp > record.lastUsed) {
record.lastUsed = timeStamp;
}
} else if (fileName.endsWith("/images/front.png") || fileName.endsWith("/images/front/front.jpg")) {
record.frontImage = ZipUtils.readImage(zipInputStream);
} else if (fileName.endsWith("/images/back.png") || fileName.endsWith("/images/back/back.jpg")) {
record.backImage = ZipUtils.readImage(zipInputStream);
} else if (!fileName.endsWith("/")) {
Log.d(TAG, "Unknown or unused loyalty-cards file " + fileName + ", skipping...");
}
} else if (!fileName.endsWith("/")) {
Log.d(TAG, "Unknown or unused file " + fileName + ", skipping...");
}
}
if (loyaltyCardHashMap.keySet().size() == 0) {
throw new FormatException("Couldn't find any loyalty cards in this Stocard export.");
}
return new ZIPData(cards, providers);
}
for (HashMap<String, Object> loyaltyCardData : loyaltyCardHashMap.values()) {
String providerId = (String) loyaltyCardData.get("_providerId");
public ImportedData importLoyaltyCardHashMap(Context context, final ZIPData zipData) throws FormatException {
ImportedData importedData = new ImportedData(new ArrayList<>(), new HashMap<>());
int tempID = 0;
if (providerId == null) {
Log.d(TAG, "Missing providerId for card " + loyaltyCardData + ", ignoring...");
List<String> cardKeys = new ArrayList<>(zipData.cards.keySet());
Collections.sort(cardKeys);
for (String key : cardKeys) {
StocardRecord record = zipData.cards.get(key);
if (record.providerId == null) {
Log.d(TAG, "Missing providerId for card " + record + ", ignoring...");
continue;
}
HashMap<String, Object> providerData = providers.get(providerId);
if (record.cardId == null) {
throw new FormatException("No card ID listed, but is required");
}
StocardProvider provider = zipData.providers.get(record.providerId);
// Read store from card, if not available (old export), fall back to providerData
String store = record.store != null ? record.store : provider != null ? provider.name : record.providerId;
String note = record.note != null ? record.note : "";
String barcodeTypeString = record.barcodeType != null ? record.barcodeType : provider != null ? provider.barcodeFormat : null;
if (record.label != null && !record.label.equals(store) && !record.label.equals(note)) {
note = note.isEmpty() ? record.label : note + "\n" + record.label;
}
String store = providerData != null ? providerData.get("name").toString() : providerId;
String note = (String) Utils.mapGetOrDefault(loyaltyCardData, "note", "");
String cardId = (String) loyaltyCardData.get("cardId");
String barcodeTypeString = (String) Utils.mapGetOrDefault(loyaltyCardData, "barcodeType", providerData != null ? providerData.get("barcodeFormat") : null);
CatimaBarcode barcodeType = null;
if (barcodeTypeString != null && !barcodeTypeString.isEmpty()) {
if (barcodeTypeString.equals("RSS_DATABAR_EXPANDED")) {
@@ -228,27 +349,45 @@ public class StocardImporter implements Importer {
}
int headerColor = Utils.getRandomHeaderColor(context);
Bitmap cardIcon = null;
if (providerData != null && providerData.containsKey("logo")) {
cardIcon = (Bitmap) providerData.get("logo");
headerColor = Utils.getHeaderColorFromImage(cardIcon, headerColor);
if (provider != null && provider.logo != null) {
headerColor = Utils.getHeaderColorFromImage(provider.logo, headerColor);
}
long loyaltyCardInternalId = DBHelper.insertLoyaltyCard(database, store, note, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, headerColor, 0, null,0);
long lastUsed = record.lastUsed != null ? record.lastUsed : Utils.getUnixTime();
if (cardIcon != null) {
Utils.saveCardImage(context, cardIcon, (int) loyaltyCardInternalId, ImageLocationType.icon);
LoyaltyCard card = new LoyaltyCard(tempID, store, note, null, null, BigDecimal.valueOf(0), null, record.cardId, null, barcodeType, headerColor, 0, lastUsed, DBHelper.DEFAULT_ZOOM_LEVEL, 0);
importedData.cards.add(card);
Map<ImageLocationType, Bitmap> images = new HashMap<>();
if (provider != null && provider.logo != null) {
images.put(ImageLocationType.icon, provider.logo);
}
if (record.frontImage != null) {
images.put(ImageLocationType.front, record.frontImage);
}
if (record.backImage != null) {
images.put(ImageLocationType.back, record.backImage);
}
if (loyaltyCardData.containsKey("frontImage")) {
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("frontImage"), (int) loyaltyCardInternalId, ImageLocationType.front);
}
if (loyaltyCardData.containsKey("backImage")) {
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("backImage"), (int) loyaltyCardInternalId, ImageLocationType.back);
}
importedData.images.put(tempID, images);
tempID++;
}
zipInputStream.close();
return importedData;
}
public void saveAndDeduplicate(Context context, SQLiteDatabase database, final ImportedData data) throws IOException {
// This format does not have IDs that can cause conflicts
// Proper deduplication for all formats will be implemented later
for (LoyaltyCard card : data.cards) {
// card.id is temporary and only used to index the images Map
long id = DBHelper.insertLoyaltyCard(database, card.store, card.note, card.validFrom, card.expiry, card.balance, card.balanceType,
card.cardId, card.barcodeId, card.barcodeType, card.headerColor, card.starStatus, card.lastUsed, card.archiveStatus);
for (Map.Entry<ImageLocationType, Bitmap> entry : data.images.get(card.id).entrySet()) {
Utils.saveCardImage(context, entry.getValue(), (int) id, entry.getKey());
}
}
}
private boolean startsWith(String[] full, String[] start, int minExtraLength) {
@@ -264,16 +403,4 @@ public class StocardImporter implements Importer {
return true;
}
private HashMap<String, HashMap<String, Object>> appendToHashMap(HashMap<String, HashMap<String, Object>> loyaltyCardHashMap, String cardID, String key, Object value) {
HashMap<String, Object> loyaltyCardData = loyaltyCardHashMap.get(cardID);
if (loyaltyCardData == null) {
loyaltyCardData = new HashMap<>();
}
loyaltyCardData.put(key, value);
loyaltyCardHashMap.put(cardID, loyaltyCardData);
return loyaltyCardHashMap;
}
}
}

View File

@@ -12,6 +12,8 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -19,13 +21,16 @@ import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Currency;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import protect.card_locker.CatimaBarcode;
import protect.card_locker.DBHelper;
import protect.card_locker.FormatException;
import protect.card_locker.LoyaltyCard;
import protect.card_locker.Utils;
/**
@@ -36,7 +41,16 @@ import protect.card_locker.Utils;
* A header is expected for the each table showing the names of the columns.
*/
public class VoucherVaultImporter implements Importer {
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
public static class ImportedData {
public final List<LoyaltyCard> cards;
ImportedData(final List<LoyaltyCard> cards) {
this.cards = cards;
}
}
public void importData(Context context, SQLiteDatabase database, File inputFile, char[] password) throws IOException, FormatException, JSONException, ParseException {
InputStream input = new FileInputStream(inputFile);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
@@ -46,6 +60,16 @@ public class VoucherVaultImporter implements Importer {
}
JSONArray jsonArray = new JSONArray(sb.toString());
bufferedReader.close();
input.close();
ImportedData importedData = importJSON(jsonArray);
saveAndDeduplicate(database, importedData);
}
public ImportedData importJSON(JSONArray jsonArray) throws FormatException, JSONException, ParseException {
ImportedData importedData = new ImportedData(new ArrayList<>());
// See https://github.com/tim-smart/vouchervault/issues/4#issuecomment-788226503 for more info
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonCard = jsonArray.getJSONObject(i);
@@ -126,9 +150,20 @@ public class VoucherVaultImporter implements Importer {
throw new FormatException("Unknown colour type found: " + colorFromJSON);
}
DBHelper.insertLoyaltyCard(database, store, "", expiry, balance, balanceType, cardId, null, barcodeType, headerColor, 0, Utils.getUnixTime(),0);
// use -1 for the ID, it will be ignored when inserting the card into the DB
importedData.cards.add(new LoyaltyCard(-1, store, "", null, expiry, balance, balanceType, cardId, null, barcodeType, headerColor, 0, Utils.getUnixTime(), DBHelper.DEFAULT_ZOOM_LEVEL, 0));
}
bufferedReader.close();
return importedData;
}
public void saveAndDeduplicate(SQLiteDatabase database, final ImportedData data) {
// This format does not have IDs that can cause conflicts
// Proper deduplication for all formats will be implemented later
for (LoyaltyCard card : data.cards) {
// Do not use card.id which is set to -1
DBHelper.insertLoyaltyCard(database, card.store, card.note, card.validFrom, card.expiry, card.balance, card.balanceType,
card.cardId, card.barcodeId, card.barcodeType, card.headerColor, card.starStatus, card.lastUsed, card.archiveStatus);
}
}
}

View File

@@ -63,30 +63,6 @@ public class Settings {
return AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
}
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() {
return 14;
}
public int getMediumFont() {
return 28;
}
public int getLargeFont() {
return 40;
}
public int getFontSizeMin(int fontSize) {
return (int) (Math.round(fontSize / 2.0) - 1);
}
public int getFontSizeMax(int fontSize) {
return (int) Math.round(fontSize * getFontSizeScale());
}
public boolean useMaxBrightnessDisplayingBarcode() {
return getBoolean(R.string.settings_key_display_barcode_max_brightness, true);
}
@@ -103,6 +79,10 @@ public class Settings {
return getBoolean(R.string.settings_key_disable_lockscreen_while_viewing_card, true);
}
public boolean getAllowContentProviderRead() {
return getBoolean(R.string.settings_key_allow_content_provider_read, true);
}
public boolean getOledDark() {
return getBoolean(R.string.settings_key_oled_dark, false);
}

View File

@@ -3,46 +3,48 @@ package protect.card_locker.preferences;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.Toolbar;
import androidx.core.os.LocaleListCompat;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import com.google.android.material.color.DynamicColors;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Collectors;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.DialogFragment;
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.MainActivity;
import protect.card_locker.R;
import protect.card_locker.Utils;
import protect.card_locker.databinding.SettingsActivityBinding;
public class SettingsActivity extends CatimaAppCompatActivity {
private SettingsActivityBinding binding;
private final static String RELOAD_MAIN_STATE = "mReloadMain";
private SettingsFragment fragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = SettingsActivityBinding.inflate(getLayoutInflater());
setTitle(R.string.settings);
setContentView(R.layout.settings_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setContentView(binding.getRoot());
Toolbar toolbar = binding.toolbar;
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
enableToolbarBackButton();
// Display the fragment as the main content.
fragment = new SettingsFragment();
@@ -100,23 +102,8 @@ public class SettingsActivity extends CatimaAppCompatActivity {
// 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));
// Show pretty names and summaries
ListPreference themePreference = findPreference(getResources().getString(R.string.settings_key_theme));
assert themePreference != null;
themePreference.setOnPreferenceChangeListener((preference, o) -> {
if (o.toString().equals(getResources().getString(R.string.settings_key_light_theme))) {
@@ -130,10 +117,16 @@ public class SettingsActivity extends CatimaAppCompatActivity {
return true;
});
localePreference.setOnPreferenceChangeListener((preference, newValue) -> {
ListPreference themeColorPreference = findPreference(getResources().getString(R.string.setting_key_theme_color));
assert themeColorPreference != null;
themeColorPreference.setOnPreferenceChangeListener((preference, o) -> {
refreshActivity(true);
return true;
});
if (!DynamicColors.isDynamicColorAvailable()) {
themeColorPreference.setEntryValues(R.array.color_values_no_dynamic);
themeColorPreference.setEntries(R.array.color_value_strings_no_dynamic);
}
Preference oledDarkPreference = findPreference(getResources().getString(R.string.settings_key_oled_dark));
assert oledDarkPreference != null;
@@ -142,16 +135,61 @@ public class SettingsActivity extends CatimaAppCompatActivity {
return true;
});
ListPreference colorPreference = findPreference(getResources().getString(R.string.setting_key_theme_color));
assert colorPreference != null;
colorPreference.setOnPreferenceChangeListener((preference, o) -> {
refreshActivity(true);
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]));
// Make locale picker preference in sync with system settings
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Locale sysLocale = AppCompatDelegate.getApplicationLocales().get(0);
if (sysLocale == null) {
// Corresponds to "System"
localePreference.setValue("");
} else {
// Need to set preference's value to one of localePreference.getEntryValues() to match the locale.
// Locale.toLanguageTag() theoretically should be one of the values in localePreference.getEntryValues()...
// But it doesn't work for some locales. so trying something more heavyweight.
// Obtain all locales supported by the app.
List<Locale> appLocales = Arrays.stream(localePreference.getEntryValues())
.map(Objects::toString)
.map(Utils::stringToLocale)
.collect(Collectors.toList());
// Get the app locale that best matches the system one
Locale bestMatchLocale = Utils.getBestMatchLocale(appLocales, sysLocale);
// Get its index in supported locales
int index = appLocales.indexOf(bestMatchLocale);
// Set preference value to entry value at that index
localePreference.setValue(localePreference.getEntryValues()[index].toString());
}
}
localePreference.setOnPreferenceChangeListener((preference, newValue) -> {
// See corresponding comment in Utils.updateBaseContextLocale for Android 6- notes
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
refreshActivity(true);
return true;
}
String newLocale = (String) newValue;
// If newLocale is empty, that means "System" was selected
AppCompatDelegate.setApplicationLocales(newLocale.isEmpty() ? LocaleListCompat.getEmptyLocaleList() : LocaleListCompat.create(Utils.stringToLocale(newLocale)));
return true;
});
if (!DynamicColors.isDynamicColorAvailable()) {
colorPreference.setEntryValues(R.array.color_values_no_dynamic);
colorPreference.setEntries(R.array.color_value_strings_no_dynamic);
}
// Disable content provider on SDK < 23 since dangerous permissions
// are granted at install-time
Preference contentProviderReadPreference = findPreference(getResources().getString(R.string.settings_key_allow_content_provider_read));
assert contentProviderReadPreference != null;
contentProviderReadPreference.setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
}
private void refreshActivity(boolean reloadMain) {
@@ -161,25 +199,5 @@ public class SettingsActivity extends CatimaAppCompatActivity {
activity.recreate();
}
}
@Override
public void onDisplayPreferenceDialog(Preference preference) {
if (preference instanceof NumberDialogPreference) {
NumberDialogPreference dialogPreference = (NumberDialogPreference) preference;
DialogFragment dialogFragment = NumberPickerPreferenceDialogFragment
.newInstance(
dialogPreference.getKey(),
dialogPreference.getMinValue(),
dialogPreference.getMaxValue(),
dialogPreference.getStepValue(),
dialogPreference.getUnitText()
);
dialogFragment.setTargetFragment(this, 0);
dialogFragment.show(getParentFragmentManager(), DIALOG_FRAGMENT_TAG);
} else {
super.onDisplayPreferenceDialog(preference);
}
}
}
}

View File

@@ -1,9 +0,0 @@
<?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>

View File

@@ -1,5 +1,5 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
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="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
<path android:fillColor="@android:color/white" android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#BD0000"
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="M10.94,8.12L7.48,4.66L9,3h6l1.83,2H20c1.1,0 2,0.9 2,2v12c0,0.05 -0.01,0.1 -0.02,0.16l-5.1,-5.1C16.96,13.71 17,13.36 17,13c0,-2.76 -2.24,-5 -5,-5C11.64,8 11.29,8.04 10.94,8.12zM20.49,23.31L18.17,21H4c-1.1,0 -2,-0.9 -2,-2V7c0,-0.59 0.27,-1.12 0.68,-1.49l-2,-2L2.1,2.1l19.8,19.8L20.49,23.31zM14.49,17.32l-1.5,-1.5C12.67,15.92 12.35,16 12,16c-1.66,0 -3,-1.34 -3,-3c0,-0.35 0.08,-0.67 0.19,-0.98l-1.5,-1.5C7.25,11.24 7,12.09 7,13c0,2.76 2.24,5 5,5C12.91,18 13.76,17.75 14.49,17.32z"/>
</vector>

View File

@@ -0,0 +1,24 @@
<layer-list xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="?attr/colorSurface" />
<corners
android:bottomLeftRadius="28dp"
android:bottomRightRadius="28dp"
android:topLeftRadius="28dp"
android:topRightRadius="28dp" />
</shape>
</item>
<item>
<shape>
<solid android:color="@color/m3_popupmenu_overlay_color"
tools:ignore="PrivateResource" />
<corners
android:bottomLeftRadius="28dp"
android:bottomRightRadius="28dp"
android:topLeftRadius="28dp"
android:topRightRadius="28dp" />
</shape>
</item>
</layer-list>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="#FFFFFF"
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
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="M15.41,7.41L14,6l-6,6 6,6 1.41,-1.41L10.83,12z"/>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="#FFFFFF"
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
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="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>

View 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="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
</vector>

View File

@@ -1,5 +1,5 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
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="M7,14l5,-5 5,5z"/>
<path android:fillColor="@android:color/white" android:pathData="M7.41,8.59L12,13.17l4.59,-4.58L18,10l-6,6 -6,-6 1.41,-1.41z"/>
</vector>

View File

@@ -1,5 +1,5 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
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="M7,10l5,5 5,-5z"/>
<path android:fillColor="@android:color/white" android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
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="M7,18c-1.1,0 -1.99,0.9 -1.99,2S5.9,22 7,22s2,-0.9 2,-2 -0.9,-2 -2,-2zM1,2v2h2l3.6,7.59 -1.35,2.45c-0.16,0.28 -0.25,0.61 -0.25,0.96 0,1.1 0.9,2 2,2h12v-2L7.42,15c-0.14,0 -0.25,-0.11 -0.25,-0.25l0.03,-0.12 0.9,-1.63h7.45c0.75,0 1.41,-0.41 1.75,-1.03l3.58,-6.49c0.08,-0.14 0.12,-0.31 0.12,-0.48 0,-0.55 -0.45,-1 -1,-1L5.21,4l-0.94,-2L1,2zM17,18c-1.1,0 -1.99,0.9 -1.99,2s0.89,2 1.99,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

View File

@@ -1,5 +0,0 @@
<vector 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="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
</vector>

View File

@@ -1,5 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
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="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
<path android:fillColor="@android:color/white" android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
</vector>

View File

@@ -1,5 +1,5 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
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="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h1.9c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z"/>
<path android:fillColor="@android:color/white" android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
</vector>

View File

@@ -0,0 +1,16 @@
<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="M12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z" />
<path
android:fillColor="@android:color/white"
android:pathData="M18,15.782V22l4.886,-3.109z" />
<path
android:fillColor="@android:color/white"
android:pathData="M11.99,2C6.47,2 2,6.48 2,12C2,17.52 6.47,22 11.99,22C13.417,22 14.772,21.699 16,21.162L16,18.928C14.823,19.608 13.458,20 12,20C7.58,20 4,16.42 4,12C4,7.58 7.58,4 12,4C16.42,4 20,7.58 20,12C20,13.061 19.791,14.073 19.416,15L21.541,15C21.839,14.053 22,13.045 22,12C22,6.48 17.52,2 11.99,2zM11,7L11,13L16,16L16,15L16.951,15L17,14.92L12.5,12.25L12.5,7L11,7z" />
</vector>

View File

@@ -1,9 +0,0 @@
<?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>

View File

@@ -128,11 +128,10 @@
<TextView
android:id="@+id/translate_sub"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2dp"
android:text="@string/translate_platform"
android:layout_marginEnd="20dp"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/translate_main"/>
@@ -169,11 +168,10 @@
<TextView
android:id="@+id/license_sub"
android:layout_width="match_parent"
android:layout_width="wrap_content"
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"/>
@@ -271,6 +269,36 @@
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/donate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="@+id/donate_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:padding="2dp"
android:text="@string/donate"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:fontFamily="sans-serif-medium"
android:text="@string/arrow"
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"

View File

@@ -1,32 +0,0 @@
<?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.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/groups"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable"
android:visibility="gone"/>
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_main"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -34,7 +34,7 @@
app:layout_constraintBottom_toTopOf="@+id/barcodeIdLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:text="@string/enterBarcodeInstructions" />
android:text="@string/manually_enter_barcode_instructions" />
<LinearLayout
android:id="@+id/barcodeIdLayout"
android:orientation="horizontal"
@@ -42,7 +42,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/explanationText"
app:layout_constraintBottom_toTopOf="@+id/noBarcode"
app:layout_constraintBottom_toTopOf="@+id/barcodes"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView android:textSize="16.0sp"
@@ -65,21 +65,11 @@
android:minHeight="48dp"
tools:ignore="ContentDescription" />
</LinearLayout>
<Button
android:id="@+id/noBarcode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/barcodeIdLayout"
app:layout_constraintBottom_toTopOf="@+id/barcodes"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:text="@string/barcodeNoBarcode"
android:enabled="false" />
<ListView
android:id="@+id/barcodes"
android:layout_width="match_parent"
android:layout_height="fill_parent"
app:layout_constraintTop_toBottomOf="@+id/noBarcode"
app:layout_constraintTop_toBottomOf="@+id/barcodeIdLayout"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="protect.card_locker.MainActivity"
tools:showIn="@layout/custom_barcode_scanner">
<LinearLayout
android:id="@+id/camera_permission_denied_clickable_area"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/camera_permission_denied_icon"
android:layout_width="match_parent"
android:layout_height="84dp"
android:scaleType="fitCenter"
android:src="@drawable/camera_permission_denied" />
<TextView
android:id="@+id/camera_permission_denied_title"
style="@style/TextAppearance.Material3.HeadlineLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/cameraPermissionDeniedTitle" />
<TextView
android:id="@+id/camera_permission_denied_message"
style="@style/AppTheme.TextView.NoData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/noCameraPermissionDirectToSystemSetting" />
</LinearLayout>
</RelativeLayout>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout 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"
@@ -10,19 +9,21 @@
tools:showIn="@layout/main_activity">
<LinearLayout
android:visibility="gone"
android:id="@+id/helpSection"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
android:orientation="vertical">
<ImageView
android:id="@+id/welcome_icon"
android:layout_width="match_parent"
android:layout_height="184dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_launcher_foreground" />
<TextView
android:id="@+id/welcome_text"
style="@style/TextAppearance.Material3.HeadlineLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -30,40 +31,40 @@
android:text="@string/welcome" />
<TextView
android:id="@+id/add_card_instruction"
style="@style/AppTheme.TextView.NoData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/noGiftCards"/>
android:text="@string/noGiftCards" />
</LinearLayout>
<TextView
style="@style/AppTheme.TextView.NoData"
android:id="@+id/noMatchingCardsText"
style="@style/AppTheme.TextView.NoData"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/noMatchingGiftCards"
android:visibility="gone"/>
android:visibility="gone" />
<TextView
style="@style/AppTheme.TextView.NoData"
android:id="@+id/noGroupCardsText"
style="@style/AppTheme.TextView.NoData"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/noGroupCards"
android:visibility="gone"/>
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="@integer/main_view_card_columns"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="80dp"
android:clipToPadding="false"
android:paddingBottom="80dp"
android:scrollbars="vertical"
android:visibility="gone"/>
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="@integer/main_view_card_columns" />
</RelativeLayout>

View File

@@ -1,41 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Based on https://github.com/journeyapps/zxing-android-embedded/blob/0fdfbce9fb3285e985bad9971c5f7c0a7a334e7b/sample/src/main/res/layout/custom_barcode_scanner.xml originally released under Apache 2.0 -->
<?xml version="1.0" encoding="utf-8"?><!-- Based on https://github.com/journeyapps/zxing-android-embedded/blob/0fdfbce9fb3285e985bad9971c5f7c0a7a334e7b/sample/src/main/res/layout/custom_barcode_scanner.xml originally released under Apache 2.0 -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/fabOtherOptions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
app:icon="@drawable/ic_baseline_unfold_more_24"
android:text="@string/action_more_options"
android:layout_margin="16dp" />
<com.journeyapps.barcodescanner.BarcodeView
android:id="@+id/zxing_barcode_surface"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/zxing_barcode_surface"
app:zxing_framing_rect_width="250dp"
app:zxing_framing_rect_height="250dp"/>
app:zxing_framing_rect_height="250dp"
app:zxing_framing_rect_width="250dp" />
<com.journeyapps.barcodescanner.ViewfinderView
android:id="@+id/zxing_viewfinder_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/zxing_viewfinder_view"
app:zxing_possible_result_points="@color/zxing_custom_possible_result_points"
app:zxing_result_view="@color/zxing_custom_result_view"
app:zxing_viewfinder_laser="@color/zxing_custom_viewfinder_laser"
app:zxing_viewfinder_mask="@color/zxing_custom_viewfinder_mask"/>
app:zxing_viewfinder_mask="@color/zxing_custom_viewfinder_mask" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:gravity="center_horizontal"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/card_input_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/activity_scanner_padding">
<Button
android:id="@+id/add_from_image"
<include
android:id="@+id/camera_permission_denied_layout"
layout="@layout/camera_permission_failed_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/addFromImage" />
<Button
android:id="@+id/add_manually"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/addManually" />
</LinearLayout>
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</merge>

View File

@@ -37,36 +37,48 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageButton
<Button
android:id="@+id/moveUp"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
style="?attr/materialIconButtonFilledStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24"
app:icon="@drawable/ic_baseline_keyboard_arrow_up_24"
app:iconGravity="textStart"
app:tint="?attr/colorOnPrimary"
android:contentDescription="@string/moveUp"/>
<ImageButton
<Button
android:id="@+id/moveDown"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
style="?attr/materialIconButtonFilledStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat="@drawable/ic_baseline_arrow_drop_down_24"
app:icon="@drawable/ic_baseline_keyboard_arrow_down_24"
app:iconGravity="textStart"
app:tint="?attr/colorOnPrimary"
android:contentDescription="@string/moveDown"/>
<ImageButton
<Button
android:id="@+id/edit"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
style="?attr/materialIconButtonFilledStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat="@drawable/ic_mode_edit_white_24dp"
app:icon="@drawable/ic_mode_edit_white_24dp"
app:iconGravity="textStart"
app:tint="?attr/colorOnPrimary"
android:contentDescription="@string/edit"/>
<ImageButton
<Button
android:id="@+id/delete"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
style="?attr/materialIconButtonFilledStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat="@drawable/ic_delete_white_24dp"
app:icon="@drawable/ic_delete_white_24dp"
app:iconGravity="textStart"
app:tint="?attr/colorOnPrimary"
android:contentDescription="@string/delete"/>
</LinearLayout>

View File

@@ -288,7 +288,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:digits="0123456789.,$" />
android:digits="0123456789,." />
</com.google.android.material.textfield.TextInputLayout>
@@ -311,6 +311,32 @@
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<!-- Valid from -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/inputPadding"
android:paddingTop="@dimen/inputPadding"
android:orientation="horizontal">
<!-- Valid from -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/validFromView"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:hint="@string/validFromDate"
android:labelFor="@+id/validFromField">
<AutoCompleteTextView
android:id="@+id/validFromField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<!-- Expiration -->
<LinearLayout
android:layout_width="match_parent"

View File

@@ -2,15 +2,15 @@
<com.google.android.material.card.MaterialCardView 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"
style="?attr/materialCardViewElevatedStyle"
android:id="@+id/row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">
android:layout_margin="5dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp">
android:layout_height="wrap_content">
<com.google.android.material.card.MaterialCardView
android:id="@+id/icon_layout"
@@ -24,7 +24,6 @@
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:importantForAccessibility="no"
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -36,6 +35,20 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/thumbnail_text"
android:importantForAccessibility="no"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textStyle="bold"
app:autoSizeTextType="uniform"
app:autoSizeMinTextSize="12sp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeStepGranularity="2sp"
android:gravity="center"
android:maxLines="1"
android:layout_margin="20dp" />
<ImageView
android:importantForAccessibility="no"
android:id="@+id/selected_thumbnail"
@@ -124,7 +137,9 @@
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp"
android:textAppearance="?attr/textAppearanceHeadline1"
android:textAppearance="?attr/textAppearanceHeadlineSmall"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toBottomOf="@+id/icon_layout"
app:layout_constraintBottom_toTopOf="@+id/note"
app:layout_constraintEnd_toEndOf="parent"
@@ -139,7 +154,6 @@
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp"
android:textAppearance="?attr/textAppearanceBody2"
android:textColor="?android:attr/textColorSecondary"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toBottomOf="@+id/store"
@@ -167,34 +181,53 @@
android:id="@+id/balance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp"
android:textAppearance="?attr/textAppearanceBody2"
android:textColor="?android:attr/textColorSecondary"
app:drawableLeftCompat="@drawable/ic_baseline_payments_24"
android:drawablePadding="4dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/info_divider"
app:layout_constraintBottom_toTopOf="@+id/expiry"
app:layout_constraintBottom_toTopOf="@+id/validFrom"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible"
tools:text="525 points"/>
<TextView
android:id="@+id/expiry"
android:id="@+id/validFrom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp"
android:textAppearance="?attr/textAppearanceBody2"
android:textColor="?android:attr/textColorSecondary"
app:drawableLeftCompat="@drawable/ic_baseline_access_time_24"
app:drawableLeftCompat="@drawable/ic_valid_from_24dp"
android:drawablePadding="4dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/balance"
app:layout_constraintBottom_toTopOf="@+id/expiry"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible"
tools:text="Today"/>
<TextView
android:id="@+id/expiry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp"
android:textAppearance="?attr/textAppearanceBody2"
app:drawableLeftCompat="@drawable/ic_baseline_access_time_24"
android:drawablePadding="4dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/validFrom"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@@ -6,214 +6,200 @@
android:id="@+id/coordinator_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fitsSystemWindows="true">
android:fitsSystemWindows="false">
<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:fitsSystemWindows="true"
android:weightSum="1.0">
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
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:visibility="gone"
app:contentInsetStart="72.0dip"
app:layout_collapseMode="pin" />
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="fill_parent"
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
android:layout_marginBottom="100dp"
android:orientation="vertical"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp">
<LinearLayout
android:id="@+id/icon_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:minHeight="56.0dip"
app:contentScrim="?colorPrimary"
app:expandedTitleGravity="top"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp">
android:layout_marginBottom="20dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/storeName"
<Space
android:layout_width="50dp"
android:layout_height="0dp"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<com.google.android.material.card.MaterialCardView
android:id="@+id/icon_holder"
android:layout_width="match_parent"
android:layout_height="0dp"
app:cardCornerRadius="8dp"
android:layout_margin="10dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="85.6f:53.98f">
<ImageView
android:id="@+id/icon_image"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="@+id/icon_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textStyle="bold"
app:autoSizeTextType="uniform"
app:autoSizeMinTextSize="12sp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeStepGranularity="2sp"
android:gravity="center"
android:maxLines="1"
android:layout_margin="20dp" />
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
<Space
android:layout_width="50dp"
android:layout_height="0dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:layoutDirection="ltr">
<!-- We don't use these buttons for Talkback -->
<ImageButton
android:importantForAccessibility="no"
android:id="@+id/main_left_button"
android:layout_width="50dp"
android:layout_height="match_parent"
app:srcCompat="@drawable/ic_baseline_chevron_left_24"
android:background="@android:color/transparent"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/card_holder"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<com.google.android.material.card.MaterialCardView
android:id="@+id/main_card_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="8dp"
android:layout_margin="10dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="4dp"
android:orientation="vertical">
<ImageView
android:id="@+id/main_image"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:id="@+id/card_id_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/text_size_large"
android:ellipsize="end"
android:singleLine="true"
android:gravity="center"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- We don't use these buttons for Talkback -->
<ImageButton
android:importantForAccessibility="no"
android:id="@+id/main_right_button"
android:layout_width="50dp"
android:layout_height="match_parent"
app:srcCompat="@drawable/ic_baseline_chevron_right_24"
android:background="@android:color/transparent"/>
</LinearLayout>
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/fullscreen_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:importantForAccessibility="no"
android:id="@+id/fullscreen_image"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/scaler_guideline"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/scaler_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/fullscreen_button_minimize"
android:layout_marginBottom="25dp"
android:layout_marginStart="15.0dip"
android:layout_marginEnd="15.0dip">
<TextView
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/height"/>
<SeekBar
android:id="@+id/barcode_scaler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="?actionBarSize"
android:layout_marginBottom="?actionBarSize"
android:ellipsize="end"
android:maxLines="1"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textSize="40sp"
app:layout_collapseMode="parallax" />
android:contentDescription="@string/setBarcodeHeight"
android:max="100" />
</LinearLayout>
<androidx.appcompat.widget.Toolbar
android:id="@id/toolbar"
android:layout_width="fill_parent"
android:layout_height="?actionBarSize"
android:background="@android:color/transparent"
app:contentInsetStart="72.0dip"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</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" />
<FrameLayout
android:clipChildren="false"
android:clipToPadding="false"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/centerGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/scalerGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.75"/>
<ImageButton
android:id="@+id/maximizeButton"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginStart="15.0dip"
android:layout_marginTop="10dp"
android:layout_marginEnd="15.0dip"
android:background="?attr/colorPrimary"
android:contentDescription="@string/moveBarcodeToTopOfScreen"
android:padding="0dp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/mainImage"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24"
app:tint="?attr/colorOnPrimary"
tools:visibility="visible" />
<ImageView
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"
app:layout_constraintBottom_toTopOf="@+id/centerGuideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/maximizeButton"/>
<ImageButton
android:id="@+id/minimizeButton"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginStart="15.0dip"
android:layout_marginTop="10dp"
android:layout_marginEnd="15.0dip"
android:background="?attr/colorPrimary"
android:contentDescription="@string/moveBarcodeToCenterOfScreen"
android:padding="0dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/mainImage"
app:srcCompat="@drawable/ic_baseline_arrow_drop_down_24"
app:tint="?attr/colorOnPrimary"
tools:visibility="visible" />
<LinearLayout
android:id="@+id/dotIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="15.0dip"
android:layout_marginTop="10dp"
android:layout_marginEnd="15.0dip"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/minimizeButton"
tools:visibility="visible" />
<SeekBar
android:id="@+id/barcodeScaler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/inputPadding"
android:layout_marginStart="15.0dip"
android:layout_marginEnd="15.0dip"
android:contentDescription="@string/set_scale"
android:max="100"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/scalerGuideline" />
<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/dotIndicator"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:textAlignment="center"
app:autoSizeTextType="uniform"
app:autoSizeMinTextSize="@dimen/singleCardCardIdTextSizeMin"
app:autoSizeMaxTextSize="@dimen/singleCardCardIdTextSizeMax"
android:ellipsize="end"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<View
android:id="@+id/drop_shadow_actionbar"
android:layout_width="fill_parent"
android:layout_height="5.0dip"
android:layout_gravity="top"/>
</FrameLayout>
<ImageButton
android:id="@+id/fullscreen_button_minimize"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/ic_baseline_expand_more_24"
android:tooltipText="@string/moveDown"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="25dp"
android:background="@android:color/transparent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottom_app_bar"
@@ -228,41 +214,70 @@
app:contentInsetEnd="0dp"
app:fabAlignmentMode="center">
<ImageButton
android:id="@+id/button_previous"
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="left"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:background="@android:color/transparent"
android:src="@drawable/ic_baseline_chevron_left_24"
android:tooltipText="@string/previousCard"
android:visibility="gone" />
android:layoutDirection="ltr">
<ImageButton
android:id="@+id/button_show_info"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:background="@android:color/transparent"
android:src="@drawable/ic_baseline_info_24"
android:tooltipText="@string/showMoreInfo"
android:visibility="gone" />
<ImageButton
android:id="@+id/bottom_app_bar_previous_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:background="@android:color/transparent"
android:src="@drawable/ic_baseline_chevron_left_24"
android:tooltipText="@string/previousCard"
android:visibility="gone" />
<ImageButton
android:id="@+id/button_next"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:background="@android:color/transparent"
android:src="@drawable/ic_baseline_chevron_right_24"
android:tooltipText="@string/nextCard"
android:visibility="gone" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal"
android:layoutDirection="locale">
<ImageButton
android:id="@+id/bottom_app_bar_info_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:background="@android:color/transparent"
android:src="@drawable/ic_baseline_info_24"
android:tooltipText="@string/showMoreInfo"
android:visibility="gone" />
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<ImageButton
android:id="@+id/bottom_app_bar_update_balance_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:background="@android:color/transparent"
android:src="@drawable/ic_baseline_shopping_cart_24"
android:tooltipText="@string/updateBalance"
android:visibility="gone" />
</LinearLayout>
<ImageButton
android:id="@+id/bottom_app_bar_next_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:background="@android:color/transparent"
android:src="@drawable/ic_baseline_chevron_right_24"
android:tooltipText="@string/nextCard"
android:visibility="gone" />
</LinearLayout>
</com.google.android.material.bottomappbar.BottomAppBar>

View File

@@ -36,6 +36,8 @@
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_main"/>
<include
android:id="@+id/include"
layout="@layout/content_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -29,6 +29,8 @@
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/group_main"/>
<include
android:id="@+id/include"
layout="@layout/group_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.materialswitch.MaterialSwitch xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/switchWidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:focusable="false" />

View File

@@ -10,12 +10,13 @@
<CheckBox
android:id="@+id/checkBox_reverse"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:paddingLeft="20dp"
android:layout_marginStart="20dp"
android:paddingStart="20dp"
android:text="@string/reverse"
android:textSize="19sp"/>
android:textSize="16sp"
android:textColor="?attr/colorOnSurfaceVariant"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,24 +0,0 @@
<menu 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"
tools:context="protect.card_locker.MainActivity">
<item
android:id="@+id/action_search"
android:title="@string/action_search"
android:icon="@drawable/ic_search_white"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="always|collapseActionView"
android:visible="false"/>
<item
android:id="@+id/action_unfold"
android:title="@string/action_hide_details"
android:icon="@drawable/ic_baseline_unfold_less_24"
app:showAsAction="always"
android:visible="false"/>
<item
android:id="@+id/action_sort"
android:title="@string/sort"
android:icon="@drawable/ic_baseline_sort_24"
app:showAsAction="always"
android:visible="false"/>
</menu>

Some files were not shown because too many files have changed in this diff Show More