Compare commits

...

161 Commits

Author SHA1 Message Date
Sylvia van Os
e2f33bf4b4 Release Catima 2.8.1 2021-10-27 18:24:46 +02:00
bors[bot]
b1685ac90e Merge #549
549: Update Fastlane changelogs r=TheLastProject a=github-actions[bot]

Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action

Co-authored-by: TheLastProject <TheLastProject@users.noreply.github.com>
2021-10-27 15:40:23 +00:00
TheLastProject
394cc6b30f Update Fastlane changelogs 2021-10-27 15:38:49 +00:00
Sylvia van Os
75e320e108 Update CHANGELOG 2021-10-27 17:38:19 +02:00
bors[bot]
e8b38b3367 Merge #548
548: fix: Overlapping TextView and ImageView. r=TheLastProject a=KasinaDheeraj

fixes #542 

Co-authored-by: Dheeraj <dheerukd2002@gmail.com>
2021-10-27 15:30:33 +00:00
Dheeraj
ffb24c973a fix: Overlapping TextView and ImageView. 2021-10-27 19:21:09 +05:30
bors[bot]
d43693b1d8 Merge #547
547: Update Fastlane changelogs r=TheLastProject a=github-actions[bot]

Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action

Co-authored-by: TheLastProject <TheLastProject@users.noreply.github.com>
2021-10-27 11:13:39 +00:00
TheLastProject
b7f17181f9 Update Fastlane changelogs 2021-10-27 11:12:50 +00:00
Sylvia van Os
10dc84820c Update CHANGELOG.md 2021-10-27 13:12:30 +02:00
bors[bot]
5f0d92470e Merge #545
545: Update CHANGELOG r=TheLastProject a=TheLastProject

bors r+

Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2021-10-27 11:04:35 +00:00
Sylvia van Os
6bb4376e4d Update CHANGELOG 2021-10-27 12:57:24 +02:00
bors[bot]
92da792378 Merge #539
539: fix for #533, fix for #510 + LoyaltyCardViewActivity crashing on returning from day/night theme change r=TheLastProject a=Kethen

please review, fixes #533, and avoids a crash from loading LoyaltyCardViewActivity, switch out to settings and switch day/night mode, switch back, which fixes #510 as well

Co-authored-by: Katharine <kwchuiaa@connect.ust.hk>
2021-10-27 10:55:51 +00:00
Katharine
81499cd362 onProgressChanged handles only user input now, always store user zoom level input 2021-10-27 18:49:09 +08:00
Katharine
fc91f1ae63 avoid system theme change activity crash 2021-10-27 18:24:23 +08:00
Katharine
cec7bc880e view dots that respects themening in app settings 2021-10-27 18:24:23 +08:00
Katharine
4027df2119 refactor centerGuideLine resizing logic -sylvia 2021-10-27 18:24:23 +08:00
bors[bot]
93132961d3 Merge #544
544: fixing #320 by not recreating main activity returning from another activity, requires testing r=TheLastProject a=Kethen

targetting #320

Co-authored-by: Katharine <kwchuiaa@connect.ust.hk>
2021-10-27 09:34:24 +00:00
Katharine
638528d4fc do not recreate main activity returning from another activity 2021-10-27 15:22:31 +08:00
bors[bot]
67ef623761 Merge #543
543: Translations update from Weblate r=TheLastProject a=weblate

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



Current translation status:

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


Co-authored-by: mondstern <mondstern@snopyta.org>
Co-authored-by: Rosdyana Kusuma <rosdyana.kusuma@gmail.com>
2021-10-27 06:58:40 +00:00
mondstern
cb3afe1878 Translated using Weblate (Croatian)
Currently translated at 27.4% (61 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/hr/
2021-10-27 08:02:54 +02:00
mondstern
e3f4aec1c5 Translated using Weblate (Luxembourgish)
Currently translated at 51.8% (115 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lb/
2021-10-27 08:02:53 +02:00
Rosdyana Kusuma
d2f196da21 Translated using Weblate (Indonesian)
Currently translated at 98.6% (219 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/id/
2021-10-27 08:02:52 +02:00
mondstern
e491a960d7 Translated using Weblate (Icelandic)
Currently translated at 52.2% (116 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/is/
2021-10-27 08:02:52 +02:00
mondstern
f5c83793bf Translated using Weblate (Portuguese)
Currently translated at 33.3% (74 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2021-10-27 08:02:51 +02:00
bors[bot]
e334a5e454 Merge #538
538: Bump zxing-android-embedded from 4.2.0 to 4.3.0 r=TheLastProject a=dependabot[bot]

Bumps [zxing-android-embedded](https://github.com/journeyapps/zxing-android-embedded) from 4.2.0 to 4.3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/journeyapps/zxing-android-embedded/releases">zxing-android-embedded's releases</a>.</em></p>
<blockquote>
<h2>v4.3.0</h2>
<ul>
<li>Minimum SDK version 19, but requires additional config (see readme) for &lt; 24 compatibility.</li>
<li>Add ScanOptions and ScanContract for use with <code>registerForActivityResult()</code>.</li>
<li>Deprecates IntentIntegrator. It is still available, but <code>registerForActivityResult()</code> is recommended instead.</li>
<li>Use minimal AndroidX libraries.</li>
<li>Use zxing:core 3.4.1 by default.</li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/journeyapps/zxing-android-embedded/compare/v4.2.0...v4.3.0">https://github.com/journeyapps/zxing-android-embedded/compare/v4.2.0...v4.3.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/journeyapps/zxing-android-embedded/blob/master/CHANGES.md">zxing-android-embedded's changelog</a>.</em></p>
<blockquote>
<h3>4.3.0 (2021-10-25)</h3>
<ul>
<li>Minimum SDK version 19, but requires additional config (see readme) for &lt; 24 compatibility.</li>
<li>Add ScanOptions and ScanContract for use with <code>registerForActivityResult()</code>.</li>
<li>Deprecates IntentIntegrator.</li>
<li>Use minimal AndroidX libraries.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="24d02945fe"><code>24d0294</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/journeyapps/zxing-android-embedded/issues/665">#665</a> from journeyapps/fixes</li>
<li><a href="6ccf3a9d1a"><code>6ccf3a9</code></a> Fix lint report location.</li>
<li><a href="23f29e5a56"><code>23f29e5</code></a> Ignore lint error.</li>
<li><a href="1a8d949325"><code>1a8d949</code></a> Tweaks.</li>
<li><a href="f1554b7478"><code>f1554b7</code></a> Use GitHub Actions.</li>
<li><a href="cc12c103e0"><code>cc12c10</code></a> v4.3.0 and cleanup.</li>
<li><a href="a13ce2b161"><code>a13ce2b</code></a> Cleanup.</li>
<li><a href="0c97cf70cc"><code>0c97cf7</code></a> ScanOptions and ScanContract.</li>
<li><a href="9beeac7960"><code>9beeac7</code></a> minSdkVersion 19. Multidex and desugaring.</li>
<li><a href="cc34502f13"><code>cc34502</code></a> Smaller libs.</li>
<li>Additional commits viewable in <a href="https://github.com/journeyapps/zxing-android-embedded/compare/v4.2.0...v4.3.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=com.journeyapps:zxing-android-embedded&package-manager=gradle&previous-version=4.2.0&new-version=4.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting ``@dependabot` rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- ``@dependabot` rebase` will rebase this PR
- ``@dependabot` recreate` will recreate this PR, overwriting any edits that have been made to it
- ``@dependabot` merge` will merge this PR after your CI passes on it
- ``@dependabot` squash and merge` will squash and merge this PR after your CI passes on it
- ``@dependabot` cancel merge` will cancel a previously requested merge and block automerging
- ``@dependabot` reopen` will reopen this PR if it is closed
- ``@dependabot` close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- ``@dependabot` ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- ``@dependabot` ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- ``@dependabot` ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-26 19:19:40 +00:00
bors[bot]
cbbd071f4f Merge #541
541: Translations update from Weblate r=TheLastProject a=weblate

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



Current translation status:

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


Co-authored-by: mondstern <mondstern@snopyta.org>
Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2021-10-26 18:39:49 +00:00
Sylvia van Os
524a6b1ffb Add hr to language selector 2021-10-26 20:38:38 +02:00
mondstern
7954adf7e3 Added translation using Weblate (Croatian) 2021-10-26 20:11:22 +02:00
Sylvia van Os
0b31a08b9f Really fix 2021-10-26 19:23:39 +02:00
Sylvia van Os
a0884aa81c Fix empty changelog check 2021-10-26 19:20:11 +02:00
Sylvia van Os
46f64d1a61 Merge branch 'master' of github.com:TheLastProject/loyalty-card-locker 2021-10-26 19:12:26 +02:00
Sylvia van Os
81cb6ad4fd Don't generate fastlane file if changelog entry is empty 2021-10-26 19:12:05 +02:00
dependabot[bot]
f2f330e3e4 Bump zxing-android-embedded from 4.2.0 to 4.3.0
Bumps [zxing-android-embedded](https://github.com/journeyapps/zxing-android-embedded) from 4.2.0 to 4.3.0.
- [Release notes](https://github.com/journeyapps/zxing-android-embedded/releases)
- [Changelog](https://github.com/journeyapps/zxing-android-embedded/blob/master/CHANGES.md)
- [Commits](https://github.com/journeyapps/zxing-android-embedded/compare/v4.2.0...v4.3.0)

---
updated-dependencies:
- dependency-name: com.journeyapps:zxing-android-embedded
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-26 02:16:29 +00:00
Sylvia van Os
5b14670785 Fix changelog 2021-10-26 00:06:52 +02:00
bors[bot]
c5f68aa50f Merge #535
535: Translations update from Weblate r=TheLastProject a=weblate

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



Current translation status:

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


Co-authored-by: mondstern <mondstern@snopyta.org>
2021-10-25 18:12:29 +00:00
mondstern
5203f89e9d Added translation using Weblate (Luxembourgish) 2021-10-25 20:09:59 +02:00
Sylvia van Os
8f11d73649 Merge pull request #534 from weblate/weblate-catima-catima
Translations update from Weblate
2021-10-25 20:00:17 +02:00
mondstern
3d376e2a90 Translated using Weblate (Icelandic)
Currently translated at 31.9% (71 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/is/
2021-10-25 19:53:19 +02:00
Sylvia van Os
0e814c3359 Merge pull request #531 from weblate/weblate-catima-catima
Translations update from Weblate
2021-10-25 17:56:26 +02:00
Oğuz Ersen
4755cc3f7f Translated using Weblate (Turkish)
Currently translated at 17.0% (15 of 88 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/tr/
2021-10-25 17:55:10 +02:00
Sylvia van Os
7afbe41f95 Release Catima 2.8.0 2021-10-25 17:28:02 +02:00
Sylvia van Os
6d4cbee499 Merge pull request #529 from TheLastProject/create-pull-request/patch-1635175160
Update Fastlane changelogs
2021-10-25 17:20:22 +02:00
TheLastProject
f16a597b91 Update Fastlane changelogs 2021-10-25 15:19:19 +00:00
Sylvia van Os
3ba0649891 Add missing languages 2021-10-25 17:18:51 +02:00
Sylvia van Os
297ecc371e Merge branch 'master' of github.com:TheLastProject/loyalty-card-locker 2021-10-25 17:14:57 +02:00
Sylvia van Os
79c8570507 Work around a race condition crash 2021-10-25 17:11:19 +02:00
Ronak Upadhyay
8f81d2d141 Fixes #516 Image scale according to text size (#517) 2021-10-24 22:26:41 +02:00
bors[bot]
325535af12 Merge #528
528: Translations update from Weblate r=TheLastProject a=weblate

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



Current translation status:

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


Co-authored-by: Nyatsuki <Odamaki@yandex.ru>
2021-10-24 08:34:37 +00:00
Nyatsuki
f7af4169a3 Translated using Weblate (Japanese)
Currently translated at 98.6% (219 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ja/
2021-10-24 10:33:11 +02:00
bors[bot]
e5ec45f877 Merge #527
527: i18n: Add in-rID r=TheLastProject a=rosdyana

This PR adds localization strings for Bahasa Indonesia (in-rID) and adds the option to the locale menu.

Co-authored-by: Rosdyana Kusuma <rosdyana.kusuma@gmail.com>
2021-10-24 08:27:19 +00:00
bors[bot]
902a4e411b Merge #526
526: Update contributors r=TheLastProject a=github-actions[bot]

Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action

Co-authored-by: TheLastProject <TheLastProject@users.noreply.github.com>
2021-10-24 08:18:33 +00:00
Rosdyana Kusuma
03ec2b4492 Add localization for Bahasa Indonesia 2021-10-24 14:14:57 +08:00
TheLastProject
6a2f8a630a Update contributors 2021-10-24 05:15:59 +00:00
bors[bot]
78e998fad9 Merge #525
525: Translations update from Weblate r=TheLastProject a=weblate

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



Current translation status:

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


Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: mondstern <mondstern@snopyta.org>
2021-10-23 22:06:40 +00:00
mondstern
e6ccef8ad0 Translated using Weblate (Icelandic)
Currently translated at 25.6% (57 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/is/
2021-10-24 00:04:22 +02:00
Oğuz Ersen
acbd614b50 Translated using Weblate (Turkish)
Currently translated at 17.0% (15 of 88 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/tr/
2021-10-24 00:04:22 +02:00
bors[bot]
445e661fac Merge #523
523: i18n: Add zh-tw r=TheLastProject a=Still34

# Summary

This PR adds localization strings for Chinese (Taiwan) (`zh-TW`) and adds the option to the locale menu.

Co-authored-by: Still Hsu <dev@stillu.cc>
2021-10-23 21:59:30 +00:00
Still Hsu
d774231c05 Add zh-tw strings 2021-10-24 05:54:36 +08:00
bors[bot]
b5d2a5dbab Merge #522
522: Translations update from Weblate r=TheLastProject a=weblate

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



Current translation status:

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


Co-authored-by: mondstern <mondstern@snopyta.org>
2021-10-23 19:34:13 +00:00
mondstern
6ab61eb78a Added translation using Weblate (Icelandic) 2021-10-23 21:31:36 +02:00
bors[bot]
bbd8bb7d29 Merge #521
521: Update Fastlane changelogs r=TheLastProject a=github-actions[bot]

Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action

Co-authored-by: TheLastProject <TheLastProject@users.noreply.github.com>
2021-10-22 21:35:28 +00:00
TheLastProject
3e082b598f Update Fastlane changelogs 2021-10-22 21:34:15 +00:00
Sylvia van Os
70510ed9d1 Fix unit tests 2021-10-22 23:33:50 +02:00
Sylvia van Os
5da1c67dd6 Update CHANGELOG 2021-10-22 22:17:39 +02:00
Sylvia van Os
dfa237958e Fix several small sizing bugs 2021-10-22 22:17:13 +02:00
Ankit Tiwari
127d53e85a Save Size of code (#508) 2021-10-22 21:11:51 +02:00
bors[bot]
7cce782143 Merge #518
518: Translations update from Weblate r=TheLastProject a=weblate

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



Current translation status:

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


Co-authored-by: mondstern <mondstern@snopyta.org>
2021-10-21 20:51:42 +00:00
mondstern
662eb853d7 Translated using Weblate (Portuguese)
Currently translated at 23.8% (53 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/pt/
2021-10-21 22:37:14 +02:00
mondstern
d8e58f8b38 Translated using Weblate (Esperanto)
Currently translated at 52.2% (116 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/eo/
2021-10-21 22:37:14 +02:00
mondstern
4748e24dda Translated using Weblate (Romanian)
Currently translated at 59.0% (131 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ro/
2021-10-21 22:37:13 +02:00
bors[bot]
5af024f482 Merge #515
515: Translations update from Weblate r=TheLastProject a=weblate

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



Current translation status:

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


Co-authored-by: mondstern <mondstern@snopyta.org>
2021-10-20 19:45:55 +00:00
mondstern
8adc013330 Added translation using Weblate (Portuguese) 2021-10-20 21:44:55 +02:00
bors[bot]
4edfe962ef Merge #514
514: Translations update from Weblate r=TheLastProject a=weblate

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



Current translation status:

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


Co-authored-by: Petr Novák <nit.monkey@gmail.com>
Co-authored-by: IllusiveMan196 <hamsterrv@gmail.com>
Co-authored-by: mondstern <mondstern@snopyta.org>
2021-10-20 18:15:27 +00:00
mondstern
d80a71c852 Translated using Weblate (Danish)
Currently translated at 52.7% (117 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/da/
2021-10-20 20:07:38 +02:00
Petr Novák
299c9f2b4d Translated using Weblate (Czech)
Currently translated at 98.8% (87 of 88 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2021-10-20 20:07:37 +02:00
IllusiveMan196
03e3e45f07 Translated using Weblate (Ukrainian)
Currently translated at 3.4% (3 of 88 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/uk/
2021-10-20 20:07:34 +02:00
IllusiveMan196
c35c316788 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (222 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2021-10-20 20:07:33 +02:00
Petr Novák
d68f0c60d4 Translated using Weblate (Czech)
Currently translated at 100.0% (222 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2021-10-20 20:07:33 +02:00
waffshappen
5faa28a7e7 Replace AsyncTask with a Compatiblity Layer and further Compat Fixes (#511) 2021-10-20 19:47:06 +02:00
bors[bot]
2fffb89179 Merge #509
509: Translations update from Weblate r=TheLastProject a=weblate

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



Current translation status:

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


Co-authored-by: Gediminas Murauskas <muziejusinfo@gmail.com>
Co-authored-by: 109247019824 <stoyan@gmx.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
2021-10-19 16:02:41 +00:00
Oğuz Ersen
bd27ccd535 Translated using Weblate (Turkish)
Currently translated at 17.0% (15 of 88 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/tr/
2021-10-19 15:39:49 +02:00
109247019824
3149234f5d Translated using Weblate (Bulgarian)
Currently translated at 100.0% (222 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2021-10-19 15:39:48 +02:00
Gediminas Murauskas
dcf55c93a8 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (222 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2021-10-19 15:39:48 +02:00
bors[bot]
3f3394c1e9 Merge #507
507: feat/copyable-textview r=TheLastProject a=aditya3901

## Issue Fix
Fixes #389 
Made textviews copyable :)

Co-authored-by: aditya3901 <2020itb058.aditya@students.iiests.ac.in>
2021-10-18 16:06:10 +00:00
aditya3901
2b22dd4a1f feat/copyable-textview 2021-10-18 14:29:30 +05:30
bors[bot]
a70710ca6a Merge #504
504: Update Fastlane changelogs r=TheLastProject a=github-actions[bot]

Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action

Co-authored-by: TheLastProject <TheLastProject@users.noreply.github.com>
2021-10-17 17:09:24 +00:00
TheLastProject
cd3baf5bd9 Update Fastlane changelogs 2021-10-17 17:08:28 +00:00
Sylvia van Os
1138d6387e Update CHANGELOG 2021-10-17 19:08:08 +02:00
bors[bot]
b664fd391a Merge #503
503: Translations update from Weblate r=TheLastProject a=weblate

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



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: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Heimen Stoffels <vistausss@fastmail.com>
Co-authored-by: solokot <solokot@gmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
2021-10-17 15:51:25 +00:00
Oğuz Ersen
11cc65bae3 Translated using Weblate (Turkish)
Currently translated at 17.0% (15 of 88 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/tr/
2021-10-17 17:41:02 +02:00
Oğuz Ersen
eaafa56503 Translated using Weblate (Turkish)
Currently translated at 100.0% (222 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/tr/
2021-10-17 17:41:02 +02:00
solokot
09c6d58639 Translated using Weblate (Russian)
Currently translated at 100.0% (222 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2021-10-17 17:41:02 +02:00
Heimen Stoffels
1767a009a7 Translated using Weblate (Dutch)
Currently translated at 100.0% (222 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2021-10-17 17:41:02 +02:00
Allan Nordhøy
a2e25512ec Translated using Weblate (Norwegian Bokmål)
Currently translated at 99.5% (221 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2021-10-17 17:41:02 +02:00
J. Lavoie
824b931764 Translated using Weblate (Italian)
Currently translated at 100.0% (222 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2021-10-17 17:41:02 +02:00
J. Lavoie
0cb75fd421 Translated using Weblate (French)
Currently translated at 100.0% (222 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2021-10-17 17:41:02 +02:00
J. Lavoie
36f0d814f6 Translated using Weblate (German)
Currently translated at 100.0% (222 of 222 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2021-10-17 17:41:02 +02:00
bors[bot]
2aa0c46d30 Merge #502
502: Slovenian translations r=TheLastProject a=franga2000

Added some new strings and fixed a few obvious mistakes that I'm guessing came from machine translation

Co-authored-by: Miha Frangež <miha.frangez@gmail.com>
2021-10-17 15:35:00 +00:00
Miha Frangež
ff63dbfdaa Fixed bad machine translations 2021-10-17 17:16:44 +02:00
Miha Frangež
5cacdbd192 New Slovenian translations 2021-10-17 17:07:32 +02:00
Ankit Tiwari
c99bf206cc Dynamically size barcode based on their shape (square or rectangle) (#501) 2021-10-17 14:42:56 +02:00
bors[bot]
f546bb2681 Merge #500
500: Update contributors r=TheLastProject a=github-actions[bot]

Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action

Co-authored-by: TheLastProject <TheLastProject@users.noreply.github.com>
2021-10-17 08:56:26 +00:00
TheLastProject
bef750e047 Update contributors 2021-10-17 05:10:28 +00:00
bors[bot]
6998599377 Merge #499
499: Update Fastlane changelogs r=TheLastProject a=github-actions[bot]

Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action

Co-authored-by: TheLastProject <TheLastProject@users.noreply.github.com>
2021-10-16 15:23:34 +00:00
TheLastProject
11164f9a73 Update Fastlane changelogs 2021-10-16 15:21:38 +00:00
Sylvia van Os
b867795a08 Merge branch 'master' of github.com:TheLastProject/loyalty-card-locker 2021-10-16 17:21:18 +02:00
Sylvia van Os
9998205051 Update CHANGELOG 2021-10-16 17:21:05 +02:00
bors[bot]
7692f19ea6 Merge #494
494: Inter Related Code changes for exporting encrypted zip r=TheLastProject a=ankittiwari101

1. Created new method `multipleCardsExportImportPasswordProtected()` in ImportExportTest.java
2. Added 5th Parameter `char[] password` to exportData method of MultiFormater.java
3. From this new method passed password field to `importData` and `exportData` method calls.
4. In CatimaExporter.java added a password parameter to ZipOutputStream(output,password) if a non null char[] array of non zero length is received for password parameter and setEncryptFiles(true) using AES 256 Encryption(by default)"

Remaining - Dialogue Box for entering password.

Note - This is only a draft pull request, if everything here looks good, I'll work next on The Password Dialog which is the final piece in the puzzle.

Co-authored-by: Ankit Tiwari <ankitr.tiwari@gmail.com>
Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2021-10-16 15:13:11 +00:00
Sylvia van Os
d8361cc288 String improvements 2021-10-16 16:49:47 +02:00
bors[bot]
93d0724c60 Merge #498
498: Translations update from Weblate r=TheLastProject a=weblate

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



Current translation status:

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


Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2021-10-16 14:43:46 +00:00
Sylvia van Os
2c03f193f0 Translated using Weblate (Norwegian Bokmål)
Currently translated at 19.3% (17 of 88 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/nb_NO/
2021-10-16 16:40:17 +02:00
Ankit Tiwari
7028a1f4ca Changes to AlertDialog for entering password 2021-10-16 20:04:24 +05:30
Ankit Tiwari
32d62dd9ba Requested Modifications Made. 2021-10-16 01:34:44 +05:30
Ankit Tiwari
401fc98b4d Passing password to ZipInputStream constructor in importData method of CatimaImporter.java 2021-10-16 00:15:32 +05:30
Ankit Tiwari
993589427b Changed password parameter to a char[] instead of null in ImportExportTest.java line 613 2021-10-15 23:10:38 +05:30
Ankit Tiwari
2390568bdf Added Encrypted Backup feature.The Zip File is Password Protected, which is asked from the user at the time of export immediately on click of Export Button. 2021-10-15 22:51:52 +05:30
Allan Nordhøy
50ccf6da46 Translated using Weblate (Norwegian Bokmål)
Currently translated at 19.3% (17 of 88 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/nb_NO/
2021-10-15 15:45:28 +02:00
Ankit Tiwari
44066e6599 Extracted zip parameter logic into a new function and used it on imageZipParameters as well 2021-10-15 00:22:51 +05:30
Ankit Tiwari
fc9c616869 1.Created new method multipleCardsExportImportPasswordProtected() in ImportExportTest.java \n 2.Added 5th Paramete 2021-10-14 23:23:01 +05:30
bors[bot]
f09f35e44b Merge #493
493: Delete merged branch r=TheLastProject a=TheLastProject



Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2021-10-14 17:45:05 +00:00
Sylvia van Os
f81fb0c673 Delete merged branch 2021-10-14 19:44:36 +02:00
bors[bot]
b0b4e80da4 Merge #492
492: Setup bors r=TheLastProject a=TheLastProject



Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2021-10-14 17:37:40 +00:00
Sylvia van Os
923982e449 Don't override author info 2021-10-14 19:37:03 +02:00
Sylvia van Os
d05c97946d Setup bors 2021-10-14 19:07:24 +02:00
Sylvia van Os
504a1fd01b Prepare for Bors 2021-10-14 18:37:46 +02:00
Sylvia van Os
5efacec417 Merge pull request #491 from weblate/weblate-catima-catima
Translations update from Weblate
2021-10-13 20:03:00 +02:00
Oğuz Ersen
595d10fc44 Translated using Weblate (Turkish)
Currently translated at 17.0% (15 of 88 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/tr/
2021-10-13 19:55:32 +02:00
Sylvia van Os
2128f0a601 Merge pull request #490 from TheLastProject/create-pull-request/patch-1634144237
Update Fastlane changelogs
2021-10-13 19:07:15 +02:00
TheLastProject
0b0a45da05 Update Fastlane changelogs 2021-10-13 16:57:17 +00:00
Sylvia van Os
94fb4b4411 Update CHANGELOG 2021-10-13 18:56:54 +02:00
Sylvia van Os
fc7932d3bf Merge pull request #489 from ankittiwari101/fix-sliding-bug
Fixed Sliding Bug in MainActivity.java
2021-10-13 18:54:59 +02:00
Ankit Tiwari
97a5311593 Fixed Bug where an Empty List (consisting of only a single textview) within the Tab would not swipe left or right 2021-10-13 16:55:05 +05:30
Sylvia van Os
c7db676b2b Add IzzyOnDroid badge 2021-10-12 17:31:51 +02:00
Sylvia van Os
f8c8b3b2e6 Merge pull request #487 from TheLastProject/dependabot/gradle/com.android.tools.build-gradle-7.0.3
Bump gradle from 7.0.2 to 7.0.3
2021-10-12 17:23:04 +02:00
dependabot[bot]
df4cb5b189 Bump gradle from 7.0.2 to 7.0.3
Bumps gradle from 7.0.2 to 7.0.3.

---
updated-dependencies:
- dependency-name: com.android.tools.build:gradle
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-12 02:21:39 +00:00
Sylvia van Os
d2b2a53109 Merge pull request #485 from TacoTheDank/materialCardview
Use MaterialCardView
2021-10-11 21:27:30 +02:00
Sylvia van Os
5107f88998 Merge pull request #483 from TheLastProject/dependabot/gradle/gradle.plugin.com.github.spotbugs.snom-spotbugs-gradle-plugin-4.7.5
Bump spotbugs-gradle-plugin from 4.7.0 to 4.7.5
2021-10-11 21:25:48 +02:00
dependabot[bot]
78f2e1698f Bump spotbugs-gradle-plugin from 4.7.0 to 4.7.5
Bumps spotbugs-gradle-plugin from 4.7.0 to 4.7.5.

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 19:20:03 +00:00
Sylvia van Os
6887cd098b Merge branch 'master' of github.com:TheLastProject/loyalty-card-locker 2021-10-11 21:19:15 +02:00
Sylvia van Os
0881d745f5 Fix more spotbugs EI_EXPOSE_REP2 2021-10-11 21:18:22 +02:00
Sylvia van Os
94b3a07f90 Merge pull request #484 from weblate/weblate-catima-catima
Translations update from Weblate
2021-10-11 20:42:40 +02:00
Joel A
dc280b4023 Translated using Weblate (Swedish)
Currently translated at 2.2% (2 of 87 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/sv/
2021-10-11 20:22:20 +02:00
Joel A
edce6d6cd3 Translated using Weblate (Swedish)
Currently translated at 99.0% (218 of 220 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/sv/
2021-10-11 20:22:20 +02:00
solokot
23dc47a5b9 Translated using Weblate (Russian)
Currently translated at 100.0% (220 of 220 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2021-10-11 20:22:20 +02:00
Sylvia van Os
683b4f46d9 Fix spotbugs EI_EXPOSE_REP2 2021-10-11 20:22:06 +02:00
Sylvia van Os
ac021bce2a Merge branch 'master' of github.com:TheLastProject/loyalty-card-locker 2021-10-11 19:58:26 +02:00
Sylvia van Os
b0c34cbca0 Fix spotbugs RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE 2021-10-11 19:58:09 +02:00
TacoTheDank
4a0c8270ef Replace CardView with MaterialCardView 2021-10-10 22:34:53 -04:00
TacoTheDank
793f1e2f87 Remove unneeded MultiDex 2021-10-10 22:34:40 -04:00
avikkundu
0101b6fa25 added translation in bengali (#480) 2021-10-10 17:04:49 +02:00
Sylvia van Os
47dff850fb Merge pull request #479 from weblate/weblate-catima-catima
Translations update from Weblate
2021-10-10 12:33:11 +02:00
Oğuz Ersen
fe7503c3ac Translated using Weblate (Turkish)
Currently translated at 16.0% (14 of 87 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/tr/
2021-10-10 12:31:11 +02:00
Petr Novák
5df7d8a530 Translated using Weblate (Czech)
Currently translated at 98.8% (86 of 87 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2021-10-10 12:31:10 +02:00
Sylvia van Os
ee129a3373 Merge pull request #478 from TheLastProject/create-pull-request/patch-1633842920
Update contributors
2021-10-10 08:17:10 +02:00
TheLastProject
b979b1fc86 Update contributors 2021-10-10 05:15:20 +00:00
Sylvia van Os
361ebb8b80 Merge pull request #476 from TheLastProject/create-pull-request/patch-1633819619
Update Fastlane changelogs
2021-10-10 00:49:36 +02:00
TheLastProject
fd49466e0d Update Fastlane changelogs 2021-10-09 22:46:59 +00:00
Sylvia van Os
bf8f00f877 Merge branch 'master' of github.com:TheLastProject/loyalty-card-locker 2021-10-10 00:46:33 +02:00
Sylvia van Os
9f0b7604cb Fix botched migration and release 2.7.3 2021-10-10 00:46:20 +02:00
Sylvia van Os
6d151e7377 Merge pull request #474 from TheLastProject/create-pull-request/patch-1633816331
Update Fastlane changelogs
2021-10-10 00:02:54 +02:00
TheLastProject
6ecc94526e Update Fastlane changelogs 2021-10-09 21:52:10 +00:00
85 changed files with 2134 additions and 831 deletions

View File

@@ -2,9 +2,13 @@ name: Android CI
on:
push:
branches: [ master ]
branches:
- master
- staging
- trying
pull_request:
branches: [ master ]
branches:
- master
jobs:
build:

View File

@@ -2,7 +2,7 @@ name: 'Close issues and PRs needing info for too long'
on:
schedule:
- cron: '30 1 * * *'
permissions:
issues: write
pull-requests: write

View File

@@ -1,7 +1,8 @@
name: Convert CHANGELOG to Fastlane
on:
push:
branches: [ master ]
branches:
- master
jobs:
convert_changelog_to_fastlane:

View File

@@ -13,10 +13,12 @@ name: "CodeQL"
on:
push:
branches: [ master ]
branches:
- master
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
branches:
- master
schedule:
- cron: '33 1 * * 4'

View File

@@ -24,5 +24,10 @@ with open('CHANGELOG.md') as changelog:
text.append(re.sub(r'\[(.*?)\]\((.*?)\)', r'\1 (\2)', line))
for version, description in changelogs.items():
description = "".join(description).strip()
if not description:
continue
with open(os.path.join("fastlane", "metadata", "android", "en-US", "changelogs", f"{version}.txt"), "w") as fastlane_file:
fastlane_file.write("".join(description).strip())
fastlane_file.write(description)

View File

@@ -1,5 +1,26 @@
# Changelog
## Unreleased - 91
## v2.8.1 - 90 (2021-10-27)
- Fix dots in card view having the wrong colour when changing theme manually
- Fix crash in card view on rotation/theme change
- Fix flashing of cards list
- Fix text overlaying star icon
## v2.8.0 - 89 (2021-10-25)
- Fix swiping between groups not working on an empty group
- Allow password-protecting exports
- Improve usage of space for QR codes
- Save the last used zoom level per card
- Fix a crash when swiping right after a tap
## v2.7.3 - 88 (2021-10-10)
- Fix incorrect migration making first card become invisible
## v2.7.2 - 87 (2021-10-09)
- Fix regression breaking import/export

View File

@@ -18,8 +18,8 @@ android {
applicationId "me.hackerchick.catima"
minSdkVersion 21
targetSdkVersion 31
versionCode 87
versionName "2.7.2"
versionCode 90
versionName "2.8.1"
vectorDrawables.useSupportLibrary true
multiDexEnabled true
@@ -80,9 +80,7 @@ android {
dependencies {
// AndroidX
implementation "androidx.multidex:multidex:2.0.1"
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
implementation 'androidx.exifinterface:exifinterface:1.3.3'
implementation 'androidx.preference:preference:1.1.1'
@@ -93,7 +91,7 @@ dependencies {
implementation 'androidx.core:core-splashscreen:1.0.0-alpha02'
// Third-party
implementation 'com.journeyapps:zxing-android-embedded:4.2.0@aar'
implementation 'com.journeyapps:zxing-android-embedded:4.3.0@aar'
implementation 'com.google.zxing:core:3.4.1'
implementation 'org.apache.commons:commons-csv:1.9.0'
implementation 'com.jaredrummler:colorpicker:1.1.0'

View File

@@ -4,30 +4,29 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import java.lang.ref.WeakReference;
import protect.card_locker.async.CompatCallable;
/**
* This task will generate a barcode and load it into an ImageView.
* Only a weak reference of the ImageView is kept, so this class will not
* prevent the ImageView from being garbage collected.
*/
class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
{
public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
private static final String TAG = "Catima";
private static final int IS_VALID = 999;
private Context mContext;
private final Context mContext;
private boolean isSuccesful;
// When drawn in a smaller window 1D barcodes for some reason end up
@@ -44,10 +43,11 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
private final boolean showFallback;
private final Runnable callback;
BarcodeImageWriterTask(Context context, ImageView imageView, String cardIdString,
CatimaBarcode barcodeFormat, TextView textView,
boolean showFallback, Runnable callback)
{
BarcodeImageWriterTask(
Context context, ImageView imageView, String cardIdString,
CatimaBarcode barcodeFormat, TextView textView,
boolean showFallback, Runnable callback
) {
mContext = context;
isSuccesful = true;
@@ -62,26 +62,21 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
final int MAX_WIDTH = getMaxWidth(format);
if(imageView.getWidth() < MAX_WIDTH)
{
if (imageView.getWidth() < MAX_WIDTH) {
imageHeight = imageView.getHeight();
imageWidth = imageView.getWidth();
}
else
{
} else {
// Scale down the image to reduce the memory needed to produce it
imageWidth = MAX_WIDTH;
double ratio = (double)MAX_WIDTH / (double)imageView.getWidth();
imageHeight = (int)(imageView.getHeight() * ratio);
double ratio = (double) MAX_WIDTH / (double) imageView.getWidth();
imageHeight = (int) (imageView.getHeight() * ratio);
}
this.showFallback = showFallback;
}
private int getMaxWidth(CatimaBarcode format)
{
switch(format.format())
{
private int getMaxWidth(CatimaBarcode format) {
switch (format.format()) {
// 2D barcodes
case AZTEC:
case DATA_MATRIX:
@@ -108,10 +103,8 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
}
}
private String getFallbackString(CatimaBarcode format)
{
switch(format.format())
{
private String getFallbackString(CatimaBarcode format) {
switch (format.format()) {
// 2D barcodes
case AZTEC:
return "AZTEC";
@@ -144,23 +137,17 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
}
}
private Bitmap generate()
{
if (cardId.isEmpty())
{
private Bitmap generate() {
if (cardId.isEmpty()) {
return null;
}
MultiFormatWriter writer = new MultiFormatWriter();
BitMatrix bitMatrix;
try
{
try
{
try {
try {
bitMatrix = writer.encode(cardId, format.format(), imageWidth, imageHeight, null);
}
catch(Exception e)
{
} catch (Exception e) {
// Cast a wider net here and catch any exception, as there are some
// cases where an encoder may fail if the data is invalid for the
// barcode type. If this happens, we want to fail gracefully.
@@ -175,11 +162,9 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
int[] pixels = new int[bitMatrixWidth * bitMatrixHeight];
for (int y = 0; y < bitMatrixHeight; y++)
{
for (int y = 0; y < bitMatrixHeight; y++) {
int offset = y * bitMatrixWidth;
for (int x = 0; x < bitMatrixWidth; x++)
{
for (int x = 0; x < bitMatrixWidth; x++) {
int color = bitMatrix.get(x, y) ? BLACK : WHITE;
pixels[offset + x] = color;
}
@@ -199,19 +184,14 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
int widthScale = imageWidth / bitMatrixHeight;
int scalingFactor = Math.min(heightScale, widthScale);
if(scalingFactor > 1)
{
if (scalingFactor > 1) {
bitmap = Bitmap.createScaledBitmap(bitmap, bitMatrixWidth * scalingFactor, bitMatrixHeight * scalingFactor, false);
}
return bitmap;
}
catch (WriterException e)
{
} catch (WriterException e) {
Log.e(TAG, "Failed to generate barcode of type " + format + ": " + cardId, e);
}
catch(OutOfMemoryError e)
{
} catch (OutOfMemoryError e) {
Log.w(TAG, "Insufficient memory to render barcode, "
+ imageWidth + "x" + imageHeight + ", " + format.name()
+ ", length=" + cardId.length(), e);
@@ -220,29 +200,36 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
return null;
}
public Bitmap doInBackground(Void... params)
{
Bitmap bitmap = generate();
public Bitmap doInBackground(Void... params) {
// Only do the hard tasks if we've not already been cancelled
if (!Thread.currentThread().isInterrupted()) {
Bitmap bitmap = generate();
if (bitmap == null) {
isSuccesful = false;
if (bitmap == null) {
isSuccesful = false;
if (showFallback) {
Log.i(TAG, "Barcode generation failed, generating fallback...");
cardId = getFallbackString(format);
bitmap = generate();
if (showFallback && !Thread.currentThread().isInterrupted()) {
Log.i(TAG, "Barcode generation failed, generating fallback...");
cardId = getFallbackString(format);
bitmap = generate();
return bitmap;
}
} else {
return bitmap;
}
}
return bitmap;
// We've been interrupted - create a empty fallback
Bitmap.Config config = Bitmap.Config.ARGB_8888;
return Bitmap.createBitmap(imageWidth, imageHeight, config);
}
protected void onPostExecute(Bitmap result)
{
public void onPostExecute(Object castResult) {
Bitmap result = (Bitmap) castResult;
Log.i(TAG, "Finished generating barcode image of type " + format + ": " + cardId);
ImageView imageView = imageViewReference.get();
if(imageView == null)
{
if (imageView == null) {
// The ImageView no longer exists, nothing to do
return;
}
@@ -255,8 +242,7 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
imageView.setContentDescription(mContext.getString(R.string.barcodeImageDescriptionWithType, formatPrettyName));
TextView textView = textViewReference.get();
if(result != null)
{
if (result != null) {
Log.i(TAG, "Displaying barcode");
imageView.setVisibility(View.VISIBLE);
@@ -270,9 +256,7 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
textView.setVisibility(View.VISIBLE);
textView.setText(formatPrettyName);
}
}
else
{
} else {
Log.i(TAG, "Barcode generation failed, removing image from display");
imageView.setVisibility(View.GONE);
if (textView != null) {
@@ -284,4 +268,19 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
callback.run();
}
}
@Override
public void onPreExecute() {
// No Action
}
/**
* Provided to comply with Callable while keeping the original Syntax of AsyncTask
*
* @return generated Bitmap
*/
@Override
public Bitmap call() {
return doInBackground();
}
}

View File

@@ -2,8 +2,9 @@ package protect.card_locker;
import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.util.Pair;
import android.view.MenuItem;
@@ -16,24 +17,21 @@ import android.widget.Toast;
import com.google.zxing.BarcodeFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import protect.card_locker.async.TaskHandler;
/**
* This activity is callable and will allow a user to enter
* barcode data and generate all barcodes possible for
* the data. The user may then select any barcode, where its
* data and type will be returned to the caller.
*/
public class BarcodeSelectorActivity extends CatimaAppCompatActivity
{
public class BarcodeSelectorActivity extends CatimaAppCompatActivity {
private static final String TAG = "Catima";
// Result this activity will return
@@ -41,19 +39,21 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity
public static final String BARCODE_FORMAT = "format";
private Map<String, Pair<Integer, Integer>> barcodeViewMap;
private LinkedList<AsyncTask> barcodeGeneratorTasks = new LinkedList<>();
final private TaskHandler mTasks = new TaskHandler();
private final Handler typingDelayHandler = new Handler(Looper.getMainLooper());
public static final Integer INPUT_DELAY = 250;
@Override
protected void onCreate(Bundle savedInstanceState)
{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle(R.string.selectBarcodeTitle);
setContentView(R.layout.barcode_selector_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null)
{
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
@@ -72,26 +72,31 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity
barcodeViewMap.put(BarcodeFormat.UPC_E.name(), new Pair<>(R.id.upceBarcode, R.id.upceBarcodeText));
EditText cardId = findViewById(R.id.cardId);
cardId.addTextChangedListener(new SimpleTextWatcher()
{
cardId.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
Log.d(TAG, "Entered text: " + s);
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Delay the input processing so we avoid overload
typingDelayHandler.removeCallbacksAndMessages(null);
generateBarcodes(s.toString());
typingDelayHandler.postDelayed(() -> {
Log.d(TAG, "Entered text: " + s);
View noBarcodeButtonView = findViewById(R.id.noBarcode);
setButtonListener(noBarcodeButtonView, s.toString());
noBarcodeButtonView.setEnabled(s.length() > 0);
runOnUiThread(() -> {
generateBarcodes(s.toString());
View noBarcodeButtonView = findViewById(R.id.noBarcode);
setButtonListener(noBarcodeButtonView, s.toString());
noBarcodeButtonView.setEnabled(s.length() > 0);
});
}, INPUT_DELAY);
}
});
final Bundle b = getIntent().getExtras();
final String initialCardId = b != null ? b.getString("initialCardId") : null;
if(initialCardId != null)
{
if (initialCardId != null) {
cardId.setText(initialCardId);
} else {
generateBarcodes("");
@@ -99,24 +104,19 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity
}
private void generateBarcodes(String value) {
// Stop any async tasks which may not have been started yet
for(AsyncTask task : barcodeGeneratorTasks)
{
task.cancel(false);
}
barcodeGeneratorTasks.clear();
// Attempt to stop any async tasks which may not have been started yet
// TODO this can be very much optimized by only generating Barcodes visible to the User
mTasks.flushTaskList(TaskHandler.TYPE.BARCODE, true, false, false);
// Update barcodes
for(Map.Entry<String, Pair<Integer, Integer>> entry : barcodeViewMap.entrySet())
{
for (Map.Entry<String, Pair<Integer, Integer>> entry : barcodeViewMap.entrySet()) {
ImageView image = findViewById(entry.getValue().first);
TextView text = findViewById(entry.getValue().second);
createBarcodeOption(image, entry.getKey(), value, text);
}
}
private void setButtonListener(final View button, final String cardId)
{
private void setButtonListener(final View button, final String cardId) {
button.setOnClickListener(view -> {
Log.d(TAG, "Selected no barcode");
Intent result = new Intent();
@@ -127,8 +127,7 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity
});
}
private void createBarcodeOption(final ImageView image, final String formatType, final String cardId, final TextView text)
{
private void createBarcodeOption(final ImageView image, final String formatType, final String cardId, final TextView text) {
final CatimaBarcode format = CatimaBarcode.fromName(formatType);
image.setImageBitmap(null);
@@ -147,40 +146,32 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity
finish();
});
if(image.getHeight() == 0)
{
if (image.getHeight() == 0) {
// The size of the ImageView is not yet available as it has not
// yet been drawn. Wait for it to be drawn so the size is available.
image.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
Log.d(TAG, "Global layout finished, type: + " + formatType + ", width: " + image.getWidth());
image.getViewTreeObserver().removeOnGlobalLayoutListener(this);
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Log.d(TAG, "Global layout finished, type: + " + formatType + ", width: " + image.getWidth());
image.getViewTreeObserver().removeOnGlobalLayoutListener(this);
Log.d(TAG, "Generating barcode for type " + formatType);
BarcodeImageWriterTask task = new BarcodeImageWriterTask(getApplicationContext(), image, cardId, format, text, true, null);
barcodeGeneratorTasks.add(task);
task.execute();
}
});
}
else
{
Log.d(TAG, "Generating barcode for type " + formatType);
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), image, cardId, format, text, true, null);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
});
} else {
Log.d(TAG, "Generating barcode for type " + formatType);
BarcodeImageWriterTask task = new BarcodeImageWriterTask(getApplicationContext(), image, cardId, format, text, true, null);
barcodeGeneratorTasks.add(task);
task.execute();
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), image, cardId, format, text, true, null);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
if (item.getItemId() == android.R.id.home)
{
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
setResult(Activity.RESULT_CANCELED);
finish();
return true;

View File

@@ -63,6 +63,13 @@ public class CatimaBarcode {
return barcodeFormats.contains(mBarcodeFormat);
}
public boolean isSquare(){
return mBarcodeFormat == BarcodeFormat.AZTEC
|| mBarcodeFormat == BarcodeFormat.DATA_MATRIX
|| mBarcodeFormat == BarcodeFormat.MAXICODE
|| mBarcodeFormat == BarcodeFormat.QR_CODE;
}
public BarcodeFormat format() {
return mBarcodeFormat;
}

View File

@@ -8,6 +8,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.text.TextUtils;
import android.util.Log;
import java.io.FileNotFoundException;
import java.math.BigDecimal;
@@ -21,7 +22,7 @@ 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 = 12;
public static final int DATABASE_VERSION = 14;
public static class LoyaltyCardDbGroups
{
@@ -46,6 +47,7 @@ public class DBHelper extends SQLiteOpenHelper
public static final String BARCODE_TYPE = "barcodetype";
public static final String STAR_STATUS = "starstatus";
public static final String LAST_USED = "lastused";
public static final String ZOOM_LEVEL = "zoomlevel";
}
public static class LoyaltyCardDbIdsGroups
@@ -105,7 +107,8 @@ public class DBHelper extends SQLiteOpenHelper
LoyaltyCardDbIds.BARCODE_ID + " TEXT," +
LoyaltyCardDbIds.BARCODE_TYPE + " TEXT," +
LoyaltyCardDbIds.STAR_STATUS + " INTEGER DEFAULT '0'," +
LoyaltyCardDbIds.LAST_USED + " INTEGER DEFAULT '0')");
LoyaltyCardDbIds.LAST_USED + " INTEGER DEFAULT '0', "+
LoyaltyCardDbIds.ZOOM_LEVEL + " INTEGER DEFAULT '100' )");
// create associative table for cards in groups
db.execSQL("CREATE TABLE " + LoyaltyCardDbIdsGroups.TABLE + "(" +
@@ -119,6 +122,7 @@ public class DBHelper extends SQLiteOpenHelper
"tokenize=unicode61);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
@@ -290,10 +294,39 @@ public class DBHelper extends SQLiteOpenHelper
cursor.moveToFirst();
while (cursor.moveToNext()) {
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(cursor);
insertFTS(db, loyaltyCard.id, loyaltyCard.store, loyaltyCard.note);
int id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID));
String store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE));
String note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE));
insertFTS(db, id, store, note);
}
}
if(oldVersion < 13 && newVersion >= 13)
{
db.execSQL("DELETE FROM " + LoyaltyCardDbFTS.TABLE + ";");
Cursor cursor = db.rawQuery("SELECT * FROM " + LoyaltyCardDbIds.TABLE + ";", null, null);
if (cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID));
String store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE));
String note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE));
insertFTS(db, id, store, note);
while (cursor.moveToNext()) {
id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID));
store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE));
note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE));
insertFTS(db, id, store, note);
}
}
cursor.close();
}
if(oldVersion < 14 && newVersion >= 14){
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
+ " ADD COLUMN " + LoyaltyCardDbIds.ZOOM_LEVEL + " INTEGER DEFAULT '100' ");
}
}
private ContentValues generateFTSContentValues(final int id, final String store, final String note) {
@@ -490,6 +523,18 @@ public class DBHelper extends SQLiteOpenHelper
return (rowsUpdated == 1);
}
public boolean updateLoyaltyCardZoomLevel(int loyaltyCardId, int zoomLevel){
SQLiteDatabase db = getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbIds.ZOOM_LEVEL,zoomLevel);
Log.d("updateLoyaltyCardZLevel","Card Id = "+loyaltyCardId+" Zoom level= "+zoomLevel);
int rowsUpdated = db.update(LoyaltyCardDbIds.TABLE,contentValues,
whereAttrs(LoyaltyCardDbIds.ID),
withArgs(loyaltyCardId));
Log.d("updateLoyaltyCardZLevel","Rows changed = "+rowsUpdated);
return (rowsUpdated == 1);
}
public LoyaltyCard getLoyaltyCard(final int id)
{
SQLiteDatabase db = getReadableDatabase();
@@ -698,20 +743,22 @@ public class DBHelper extends SQLiteOpenHelper
}
public List<Group> getGroups() {
try(Cursor data = getGroupCursor()) {
List<Group> groups = new ArrayList<>();
Cursor data = getGroupCursor();
if (!data.moveToFirst()) {
return groups;
}
groups.add(Group.toGroup(data));
while (data.moveToNext()) {
groups.add(Group.toGroup(data));
}
List<Group> groups = new ArrayList<>();
if (!data.moveToFirst()) {
data.close();
return groups;
}
groups.add(Group.toGroup(data));
while (data.moveToNext()) {
groups.add(Group.toGroup(data));
}
data.close();
return groups;
}
public void reorderGroups(final List<Group> groups)

View File

@@ -42,7 +42,7 @@ class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.GroupListI
public GroupCursorAdapter.GroupListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType)
{
View itemView = LayoutInflater.from(inputParent.getContext()).inflate(R.layout.group_layout, inputParent, false);
return new GroupCursorAdapter.GroupListItemViewHolder(itemView);
return new GroupListItemViewHolder(itemView);
}
public Cursor getCursor()
@@ -80,7 +80,7 @@ class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.GroupListI
void onDeleteButtonClicked(View view);
}
public class GroupListItemViewHolder extends RecyclerView.ViewHolder
public static class GroupListItemViewHolder extends RecyclerView.ViewHolder
{
public TextView mName, mCardCount;
public AppCompatImageButton mMoveUp, mMoveDown, mEdit, mDelete;

View File

@@ -6,19 +6,19 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -31,11 +31,12 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import protect.card_locker.async.TaskHandler;
import protect.card_locker.importexport.DataFormat;
import protect.card_locker.importexport.ImportExportResult;
public class ImportExportActivity extends CatimaAppCompatActivity
{
public class ImportExportActivity extends CatimaAppCompatActivity {
private static final String TAG = "Catima";
private static final int PERMISSIONS_EXTERNAL_STORAGE = 1;
@@ -47,18 +48,19 @@ public class ImportExportActivity extends CatimaAppCompatActivity
private String importAlertTitle;
private String importAlertMessage;
private DataFormat importDataFormat;
private String exportPassword;
final private TaskHandler mTasks = new TaskHandler();
@Override
protected void onCreate(Bundle savedInstanceState)
{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle(R.string.importExport);
setContentView(R.layout.import_export_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null)
{
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
@@ -67,12 +69,11 @@ public class ImportExportActivity extends CatimaAppCompatActivity
if (ContextCompat.checkSelfPermission(ImportExportActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(ImportExportActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
{
ContextCompat.checkSelfPermission(ImportExportActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(ImportExportActivity.this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSIONS_EXTERNAL_STORAGE);
}
@@ -83,12 +84,31 @@ public class ImportExportActivity extends CatimaAppCompatActivity
intentCreateDocumentAction.putExtra(Intent.EXTRA_TITLE, "catima.zip");
Button exportButton = findViewById(R.id.exportButton);
exportButton.setOnClickListener(new View.OnClickListener()
{
exportButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
chooseFileWithIntent(intentCreateDocumentAction, CHOOSE_EXPORT_LOCATION);
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(ImportExportActivity.this);
builder.setTitle(R.string.exportPassword);
FrameLayout container = new FrameLayout(ImportExportActivity.this);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = 50;
params.rightMargin = 50;
final EditText input = new EditText(ImportExportActivity.this);
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
input.setLayoutParams(params);
input.setHint(R.string.exportPasswordHint);
container.addView(input);
builder.setView(container);
builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> {
exportPassword = input.getText().toString();
chooseFileWithIntent(intentCreateDocumentAction, CHOOSE_EXPORT_LOCATION);
});
builder.setNegativeButton(R.string.cancel, (dialogInterface, i) -> dialogInterface.cancel());
builder.show();
}
});
@@ -98,11 +118,9 @@ public class ImportExportActivity extends CatimaAppCompatActivity
intentGetContentAction.setType("*/*");
Button importFilesystem = findViewById(R.id.importOptionFilesystemButton);
importFilesystem.setOnClickListener(new View.OnClickListener()
{
importFilesystem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
public void onClick(View v) {
chooseImportType(intentGetContentAction);
}
});
@@ -111,11 +129,9 @@ public class ImportExportActivity extends CatimaAppCompatActivity
final Intent intentPickAction = new Intent(Intent.ACTION_PICK);
Button importApplication = findViewById(R.id.importOptionApplicationButton);
importApplication.setOnClickListener(new View.OnClickListener()
{
importApplication.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
public void onClick(View v) {
chooseImportType(intentPickAction);
}
});
@@ -177,24 +193,22 @@ public class ImportExportActivity extends CatimaAppCompatActivity
.setTitle(importAlertTitle)
.setMessage(importAlertMessage)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
chooseFileWithIntent(baseIntent, IMPORT);
}
})
@Override
public void onClick(DialogInterface dialog, int which) {
chooseFileWithIntent(baseIntent, IMPORT);
}
})
.setNegativeButton(R.string.cancel, null)
.show();
});
builder.show();
}
private void startImport(final InputStream target, final Uri targetUri, final DataFormat dataFormat, final char[] password, final boolean closeWhenDone)
{
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener()
{
private void startImport(final InputStream target, final Uri targetUri, final DataFormat dataFormat, final char[] password, final boolean closeWhenDone) {
mTasks.flushTaskList(TaskHandler.TYPE.IMPORT, true, false, false);
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener() {
@Override
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat)
{
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat) {
onImportComplete(result, targetUri, dataFormat);
if (closeWhenDone) {
try {
@@ -208,13 +222,12 @@ public class ImportExportActivity extends CatimaAppCompatActivity
importExporter = new ImportExportTask(ImportExportActivity.this,
dataFormat, target, password, listener);
importExporter.execute();
mTasks.executeTask(TaskHandler.TYPE.IMPORT, importExporter);
}
private void startExport(final OutputStream target, final Uri targetUri, final boolean closeWhenDone)
{
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener()
{
private void startExport(final OutputStream target, final Uri targetUri, char[] password, final boolean closeWhenDone) {
mTasks.flushTaskList(TaskHandler.TYPE.EXPORT, true, false, false);
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener() {
@Override
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat) {
onExportComplete(result, targetUri);
@@ -229,8 +242,8 @@ public class ImportExportActivity extends CatimaAppCompatActivity
};
importExporter = new ImportExportTask(ImportExportActivity.this,
DataFormat.Catima, target, listener);
importExporter.execute();
DataFormat.Catima, target, password, listener);
mTasks.executeTask(TaskHandler.TYPE.EXPORT, importExporter);
}
@Override
@@ -258,22 +271,17 @@ public class ImportExportActivity extends CatimaAppCompatActivity
}
@Override
protected void onDestroy()
{
if(importExporter != null && importExporter.getStatus() != AsyncTask.Status.RUNNING)
{
importExporter.cancel(true);
}
protected void onDestroy() {
mTasks.flushTaskList(TaskHandler.TYPE.IMPORT, true, false, false);
mTasks.flushTaskList(TaskHandler.TYPE.EXPORT, true, false, false);
super.onDestroy();
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == android.R.id.home)
{
if (id == android.R.id.home) {
finish();
return true;
}
@@ -307,13 +315,10 @@ public class ImportExportActivity extends CatimaAppCompatActivity
int messageId;
if (result == ImportExportResult.Success)
{
if (result == ImportExportResult.Success) {
builder.setTitle(R.string.importSuccessfulTitle);
messageId = R.string.importSuccessful;
}
else
{
} else {
builder.setTitle(R.string.importFailedTitle);
messageId = R.string.importFailed;
}
@@ -321,11 +326,9 @@ public class ImportExportActivity extends CatimaAppCompatActivity
final String message = getResources().getString(messageId);
builder.setMessage(message);
builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener()
{
builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which)
{
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
@@ -333,19 +336,15 @@ public class ImportExportActivity extends CatimaAppCompatActivity
builder.create().show();
}
private void onExportComplete(ImportExportResult result, final Uri path)
{
private void onExportComplete(ImportExportResult result, final Uri path) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
int messageId;
if(result == ImportExportResult.Success)
{
if (result == ImportExportResult.Success) {
builder.setTitle(R.string.exportSuccessfulTitle);
messageId = R.string.exportSuccessful;
}
else
{
} else {
builder.setTitle(R.string.exportFailedTitle);
messageId = R.string.exportFailed;
}
@@ -355,8 +354,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity
builder.setMessage(message);
builder.setNeutralButton(R.string.ok, (dialog, which) -> dialog.dismiss());
if(result == ImportExportResult.Success)
{
if (result == ImportExportResult.Success) {
final CharSequence sendLabel = ImportExportActivity.this.getResources().getText(R.string.sendLabel);
builder.setPositiveButton(sendLabel, (dialog, which) -> {
@@ -377,58 +375,42 @@ public class ImportExportActivity extends CatimaAppCompatActivity
builder.create().show();
}
private void chooseFileWithIntent(Intent intent, int requestCode)
{
try
{
private void chooseFileWithIntent(Intent intent, int requestCode) {
try {
startActivityForResult(intent, requestCode);
}
catch (ActivityNotFoundException e)
{
} catch (ActivityNotFoundException e) {
Toast.makeText(getApplicationContext(), R.string.failedOpeningFileManager, Toast.LENGTH_LONG).show();
Log.e(TAG, "No activity found to handle intent", e);
}
}
private void activityResultParser(int requestCode, int resultCode, Uri uri, char[] password) {
if (resultCode != RESULT_OK)
{
if (resultCode != RESULT_OK) {
Log.w(TAG, "Failed onActivityResult(), result=" + resultCode);
return;
}
if(uri == null)
{
if (uri == null) {
Log.e(TAG, "Activity returned a NULL URI");
return;
}
try
{
if (requestCode == CHOOSE_EXPORT_LOCATION)
{
try {
if (requestCode == CHOOSE_EXPORT_LOCATION) {
OutputStream writer;
if (uri.getScheme() != null)
{
if (uri.getScheme() != null) {
writer = getContentResolver().openOutputStream(uri);
}
else
{
} else {
writer = new FileOutputStream(new File(uri.toString()));
}
Log.e(TAG, "Starting file export with: " + uri.toString());
startExport(writer, uri, true);
}
else
{
startExport(writer, uri, exportPassword.toCharArray(), true);
} else {
InputStream reader;
if(uri.getScheme() != null)
{
if (uri.getScheme() != null) {
reader = getContentResolver().openInputStream(uri);
}
else
{
} else {
reader = new FileInputStream(new File(uri.toString()));
}
@@ -436,28 +418,21 @@ public class ImportExportActivity extends CatimaAppCompatActivity
startImport(reader, uri, importDataFormat, password, true);
}
}
catch(IOException e)
{
} catch (IOException e) {
Log.e(TAG, "Failed to import/export file: " + uri.toString(), e);
if (requestCode == CHOOSE_EXPORT_LOCATION)
{
if (requestCode == CHOOSE_EXPORT_LOCATION) {
onExportComplete(ImportExportResult.GenericFailure, uri);
}
else
{
} else {
onImportComplete(ImportExportResult.GenericFailure, uri, importDataFormat);
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(data == null)
{
if (data == null) {
Log.e(TAG, "Activity returned NULL data");
return;
}

View File

@@ -4,7 +4,6 @@ import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.util.Log;
import java.io.IOException;
@@ -13,13 +12,13 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import protect.card_locker.async.CompatCallable;
import protect.card_locker.importexport.DataFormat;
import protect.card_locker.importexport.ImportExportResult;
import protect.card_locker.importexport.MultiFormatExporter;
import protect.card_locker.importexport.MultiFormatImporter;
class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
{
public class ImportExportTask implements CompatCallable<ImportExportResult> {
private static final String TAG = "Catima";
private Activity activity;
@@ -35,14 +34,14 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
/**
* Constructor which will setup a task for exporting to the given file
*/
ImportExportTask(Activity activity, DataFormat format, OutputStream output,
TaskCompleteListener listener)
{
ImportExportTask(Activity activity, DataFormat format, OutputStream output, char[] password,
TaskCompleteListener listener) {
super();
this.activity = activity;
this.doImport = false;
this.format = format;
this.outputStream = output;
this.password = password;
this.listener = listener;
}
@@ -50,8 +49,7 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
* Constructor which will setup a task for importing from the given InputStream.
*/
ImportExportTask(Activity activity, DataFormat format, InputStream input, char[] password,
TaskCompleteListener listener)
{
TaskCompleteListener listener) {
super();
this.activity = activity;
this.doImport = true;
@@ -61,8 +59,7 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
this.listener = listener;
}
private ImportExportResult performImport(Context context, InputStream stream, DBHelper db, char[] password)
{
private ImportExportResult performImport(Context context, InputStream stream, DBHelper db, char[] password) {
ImportExportResult importResult = MultiFormatImporter.importData(context, db, stream, format, password);
Log.i(TAG, "Import result: " + importResult.name());
@@ -70,18 +67,14 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
return importResult;
}
private ImportExportResult performExport(Context context, OutputStream stream, DBHelper db)
{
private ImportExportResult performExport(Context context, OutputStream stream, DBHelper db, char[] password) {
ImportExportResult result = ImportExportResult.GenericFailure;
try
{
try {
OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8);
result = MultiFormatExporter.exportData(context, db, stream, format);
result = MultiFormatExporter.exportData(context, db, stream, format, password);
writer.close();
}
catch (IOException e)
{
} catch (IOException e) {
Log.e(TAG, "Unable to export file", e);
}
@@ -90,55 +83,55 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
return result;
}
protected void onPreExecute()
{
public void onPreExecute() {
progress = new ProgressDialog(activity);
progress.setTitle(doImport ? R.string.importing : R.string.exporting);
progress.setOnDismissListener(new DialogInterface.OnDismissListener()
{
progress.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog)
{
ImportExportTask.this.cancel(true);
public void onDismiss(DialogInterface dialog) {
ImportExportTask.this.stop();
}
});
progress.show();
}
protected ImportExportResult doInBackground(Void... nothing)
{
protected ImportExportResult doInBackground(Void... nothing) {
final DBHelper db = new DBHelper(activity);
ImportExportResult result;
if(doImport)
{
if (doImport) {
result = performImport(activity.getApplicationContext(), inputStream, db, password);
}
else
{
result = performExport(activity.getApplicationContext(), outputStream, db);
} else {
result = performExport(activity.getApplicationContext(), outputStream, db, password);
}
return result;
}
protected void onPostExecute(ImportExportResult result)
{
listener.onTaskComplete(result, format);
public void onPostExecute(Object castResult) {
listener.onTaskComplete((ImportExportResult) castResult, format);
progress.dismiss();
Log.i(TAG, (doImport ? "Import" : "Export") + " Complete");
}
protected void onCancelled()
{
protected void onCancelled() {
progress.dismiss();
Log.i(TAG, (doImport ? "Import" : "Export") + " Cancelled");
}
interface TaskCompleteListener
{
protected void stop() {
// Whelp
}
@Override
public ImportExportResult call() {
return doInBackground();
}
interface TaskCompleteListener {
void onTaskComplete(ImportExportResult result, DataFormat format);
}

View File

@@ -122,7 +122,7 @@ public class ImportURIHelper {
headerColor = Integer.parseInt(unparsedHeaderColor);
}
return new LoyaltyCard(-1, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, 0, Utils.getUnixTime());
return new LoyaltyCard(-1, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, 0, Utils.getUnixTime(),100);
} catch (NullPointerException | NumberFormatException | UnsupportedEncodingException ex) {
throw new InvalidObjectException("Not a valid import URI");
}

View File

@@ -30,11 +30,12 @@ public class LoyaltyCard implements Parcelable {
public final int starStatus;
public final long lastUsed;
public int zoomLevel;
public LoyaltyCard(final int id, final String store, final String note, final Date expiry,
final BigDecimal balance, final Currency balanceType, final String cardId,
@Nullable final String barcodeId, @Nullable final CatimaBarcode barcodeType,
@Nullable final Integer headerColor, final int starStatus, final long lastUsed)
@Nullable final Integer headerColor, final int starStatus, final long lastUsed,final int zoomLevel)
{
this.id = id;
this.store = store;
@@ -48,6 +49,7 @@ public class LoyaltyCard implements Parcelable {
this.headerColor = headerColor;
this.starStatus = starStatus;
this.lastUsed = lastUsed;
this.zoomLevel = zoomLevel;
}
protected LoyaltyCard(Parcel in) {
@@ -66,6 +68,7 @@ public class LoyaltyCard implements Parcelable {
headerColor = tmpHeaderColor != -1 ? tmpHeaderColor : null;
starStatus = in.readInt();
lastUsed = in.readLong();
zoomLevel = in.readInt();
}
@Override
@@ -82,6 +85,7 @@ public class LoyaltyCard implements Parcelable {
parcel.writeInt(headerColor != null ? headerColor : -1);
parcel.writeInt(starStatus);
parcel.writeLong(lastUsed);
parcel.writeInt(zoomLevel);
}
public static LoyaltyCard toLoyaltyCard(Cursor cursor)
@@ -95,6 +99,7 @@ public class LoyaltyCard implements Parcelable {
String barcodeId = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_ID));
int starred = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STAR_STATUS));
long lastUsed = cursor.getLong(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.LAST_USED));
int zoomLevel = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ZOOM_LEVEL));
int barcodeTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_TYPE);
int balanceTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BALANCE_TYPE);
@@ -125,7 +130,7 @@ public class LoyaltyCard implements Parcelable {
headerColor = cursor.getInt(headerColorColumn);
}
return new LoyaltyCard(id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starred, lastUsed);
return new LoyaltyCard(id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starred, lastUsed,zoomLevel);
}
@Override

View File

@@ -1,11 +1,12 @@
package protect.card_locker;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.util.SparseBooleanArray;
import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.View;
@@ -21,12 +22,13 @@ import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.ArrayList;
import androidx.cardview.widget.CardView;
import androidx.core.graphics.BlendModeColorFilterCompat;
import androidx.core.graphics.BlendModeCompat;
import androidx.recyclerview.widget.RecyclerView;
import protect.card_locker.preferences.Settings;
public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder>
{
public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder> {
private int mCurrentSelectedIndex = -1;
private Cursor mCursor;
Settings mSettings;
@@ -37,8 +39,7 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
private SparseBooleanArray mAnimationItemsIndex;
private boolean mReverseAllAnimations = false;
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener)
{
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener) {
super(inputCursor);
setHasStableIds(true);
mSettings = new Settings(inputContext);
@@ -47,7 +48,7 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
mSelectedItems = new SparseBooleanArray();
mAnimationItemsIndex = new SparseBooleanArray();
mDarkModeEnabled = MainActivity.isDarkModeEnabled(inputContext);
mDarkModeEnabled = Utils.isDarkModeEnabled(inputContext);
swapCursor(mCursor);
}
@@ -59,14 +60,12 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
}
@Override
public LoyaltyCardListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType)
{
public LoyaltyCardListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType) {
View itemView = LayoutInflater.from(inputParent.getContext()).inflate(R.layout.loyalty_card_layout, inputParent, false);
return new LoyaltyCardListItemViewHolder(itemView);
return new LoyaltyCardListItemViewHolder(itemView, mListener);
}
public Cursor getCursor()
{
public Cursor getCursor() {
return mCursor;
}
@@ -74,8 +73,10 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
// Invisible until we want to show something more
inputHolder.mDivider.setVisibility(View.GONE);
int size = mSettings.getFontSizeMax(mSettings.getSmallFont());
if (mDarkModeEnabled) {
inputHolder.mStarIcon.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
inputHolder.mStarIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP));
}
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(inputCursor);
@@ -85,49 +86,86 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
if (!loyaltyCard.note.isEmpty()) {
inputHolder.mNoteField.setVisibility(View.VISIBLE);
inputHolder.mNoteField.setText(loyaltyCard.note);
inputHolder.mNoteField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
inputHolder.mNoteField.setTextSize(size);
} else {
inputHolder.mNoteField.setVisibility(View.GONE);
}
if (!loyaltyCard.balance.equals(new BigDecimal("0"))) {
int drawableSize = dpToPx((size*24)/14, mContext);
inputHolder.mDivider.setVisibility(View.VISIBLE);
inputHolder.mBalanceField.setVisibility(View.VISIBLE);
Drawable balanceIcon = inputHolder.mBalanceField.getCompoundDrawables()[0];
balanceIcon.setBounds(0,0,drawableSize,drawableSize);
inputHolder.mBalanceField.setCompoundDrawablesRelative(balanceIcon, null, null, null);
if (mDarkModeEnabled) {
inputHolder.mBalanceField.getCompoundDrawables()[0].setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
balanceIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP));
}
inputHolder.mBalanceField.setText(Utils.formatBalance(mContext, loyaltyCard.balance, loyaltyCard.balanceType));
inputHolder.mBalanceField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
inputHolder.mBalanceField.setTextSize(size);
} else {
inputHolder.mBalanceField.setVisibility(View.GONE);
}
if (loyaltyCard.expiry != null) {
int drawableSize = dpToPx((size*24)/14, mContext);
inputHolder.mDivider.setVisibility(View.VISIBLE);
inputHolder.mExpiryField.setVisibility(View.VISIBLE);
Drawable expiryIcon = inputHolder.mExpiryField.getCompoundDrawables()[0];
expiryIcon.setBounds(0,0, drawableSize, drawableSize);
inputHolder.mExpiryField.setCompoundDrawablesRelative(expiryIcon, null, null, null);
if (Utils.hasExpired(loyaltyCard.expiry)) {
expiryIcon.setColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP);
expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.RED, BlendModeCompat.SRC_ATOP));
inputHolder.mExpiryField.setTextColor(Color.RED);
} else if (mDarkModeEnabled) {
expiryIcon.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP));
}
inputHolder.mExpiryField.setText(DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.expiry));
inputHolder.mExpiryField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
inputHolder.mExpiryField.setTextSize(size);
} else {
inputHolder.mExpiryField.setVisibility(View.GONE);
}
inputHolder.mStarIcon.setVisibility(loyaltyCard.starStatus != 0 ? View.VISIBLE : View.GONE);
inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, loyaltyCard.store, loyaltyCard.headerColor).getLetterTile());
int imageSize = dpToPx( (size*46)/14, mContext);
inputHolder.mCardIcon.getLayoutParams().height = imageSize;
inputHolder.mCardIcon.getLayoutParams().width = imageSize;
inputHolder.mStarIcon.getLayoutParams().height = imageSize;
inputHolder.mStarIcon.getLayoutParams().width = imageSize;
inputHolder.mTickIcon.getLayoutParams().height = imageSize;
inputHolder.mTickIcon.getLayoutParams().width = imageSize;
/* Changing Padding and Mragin of different views according to font size
* Views Included:
* a) InformationContainer padding
* b) Store left padding
* c) Divider Margin
* d) note top margin
* e) row margin
* */
int marginPaddingSize = dpToPx((size*16)/14, mContext );
inputHolder.mInformationContainer.setPadding(marginPaddingSize, marginPaddingSize, marginPaddingSize, marginPaddingSize);
inputHolder.mStoreField.setPadding(marginPaddingSize, 0, 0, 0);
LinearLayout.LayoutParams lpDivider = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT );
lpDivider.setMargins(0, marginPaddingSize, 0, marginPaddingSize);
inputHolder.mDivider.setLayoutParams(lpDivider);
LinearLayout.LayoutParams lpNoteField = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT );
lpNoteField.setMargins(0, marginPaddingSize/2, 0, 0);
inputHolder.mNoteField.setLayoutParams(lpNoteField);
LinearLayout.LayoutParams lpRow = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT );
lpRow.setMargins(marginPaddingSize/2, marginPaddingSize/2, marginPaddingSize/2, marginPaddingSize/2);
inputHolder.mRow.setLayoutParams(lpRow);
inputHolder.itemView.setActivated(mSelectedItems.get(inputCursor.getPosition(), false));
applyIconAnimation(inputHolder, inputCursor.getPosition());
applyClickEvents(inputHolder, inputCursor.getPosition());
}
private void applyClickEvents(LoyaltyCardListItemViewHolder inputHolder, final int inputPosition)
{
private void applyClickEvents(LoyaltyCardListItemViewHolder inputHolder, final int inputPosition) {
inputHolder.mRow.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition));
inputHolder.mInformationContainer.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition));
@@ -144,85 +182,68 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
});
}
private void applyIconAnimation(LoyaltyCardListItemViewHolder inputHolder, int inputPosition)
{
if (mSelectedItems.get(inputPosition, false))
{
private void applyIconAnimation(LoyaltyCardListItemViewHolder inputHolder, int inputPosition) {
if (mSelectedItems.get(inputPosition, false)) {
inputHolder.mThumbnailFrontContainer.setVisibility(View.GONE);
resetIconYAxis(inputHolder.mThumbnailBackContainer);
inputHolder.mThumbnailBackContainer.setVisibility(View.VISIBLE);
inputHolder.mThumbnailBackContainer.setAlpha(1);
if (mCurrentSelectedIndex == inputPosition)
{
if (mCurrentSelectedIndex == inputPosition) {
LoyaltyCardAnimator.flipView(mContext, inputHolder.mThumbnailBackContainer, inputHolder.mThumbnailFrontContainer, true);
resetCurrentIndex();
}
}
else
{
} else {
inputHolder.mThumbnailBackContainer.setVisibility(View.GONE);
resetIconYAxis(inputHolder.mThumbnailFrontContainer);
inputHolder.mThumbnailFrontContainer.setVisibility(View.VISIBLE);
inputHolder.mThumbnailFrontContainer.setAlpha(1);
if ((mReverseAllAnimations && mAnimationItemsIndex.get(inputPosition, false)) || mCurrentSelectedIndex == inputPosition)
{
if ((mReverseAllAnimations && mAnimationItemsIndex.get(inputPosition, false)) || mCurrentSelectedIndex == inputPosition) {
LoyaltyCardAnimator.flipView(mContext, inputHolder.mThumbnailBackContainer, inputHolder.mThumbnailFrontContainer, false);
resetCurrentIndex();
}
}
}
private void resetIconYAxis(View inputView)
{
if (inputView.getRotationY() != 0)
{
private void resetIconYAxis(View inputView) {
if (inputView.getRotationY() != 0) {
inputView.setRotationY(0);
}
}
public void resetAnimationIndex()
{
public void resetAnimationIndex() {
mReverseAllAnimations = false;
mAnimationItemsIndex.clear();
}
public void toggleSelection(int inputPosition)
{
public void toggleSelection(int inputPosition) {
mCurrentSelectedIndex = inputPosition;
if (mSelectedItems.get(inputPosition, false))
{
if (mSelectedItems.get(inputPosition, false)) {
mSelectedItems.delete(inputPosition);
mAnimationItemsIndex.delete(inputPosition);
}
else
{
} else {
mSelectedItems.put(inputPosition, true);
mAnimationItemsIndex.put(inputPosition, true);
}
notifyDataSetChanged();
}
public void clearSelections()
{
public void clearSelections() {
mReverseAllAnimations = true;
mSelectedItems.clear();
notifyDataSetChanged();
}
public int getSelectedItemCount()
{
public int getSelectedItemCount() {
return mSelectedItems.size();
}
public ArrayList<LoyaltyCard> getSelectedItems()
{
public ArrayList<LoyaltyCard> getSelectedItems() {
ArrayList<LoyaltyCard> result = new ArrayList<>();
int i;
for(i = 0; i < mSelectedItems.size(); i++)
{
for (i = 0; i < mSelectedItems.size(); i++) {
mCursor.moveToPosition(mSelectedItems.keyAt(i));
result.add(LoyaltyCard.toLoyaltyCard(mCursor));
}
@@ -230,29 +251,26 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
return result;
}
private void resetCurrentIndex()
{
private void resetCurrentIndex() {
mCurrentSelectedIndex = -1;
}
public interface CardAdapterListener
{
public interface CardAdapterListener {
void onRowClicked(int inputPosition);
void onRowLongClicked(int inputPosition);
}
public class LoyaltyCardListItemViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener
{
public static class LoyaltyCardListItemViewHolder extends RecyclerView.ViewHolder {
public TextView mStoreField, mNoteField, mBalanceField, mExpiryField;
public LinearLayout mInformationContainer;
public ImageView mCardIcon, mStarIcon;
public ImageView mCardIcon, mStarIcon, mTickIcon;
public MaterialCardView mRow;
public View mDivider;
public RelativeLayout mThumbnailFrontContainer, mThumbnailBackContainer;
public LoyaltyCardListItemViewHolder(View inputView)
{
public LoyaltyCardListItemViewHolder(View inputView, CardAdapterListener inputListener) {
super(inputView);
mRow = inputView.findViewById(R.id.row);
mDivider = inputView.findViewById(R.id.info_divider);
@@ -265,15 +283,18 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
mExpiryField = inputView.findViewById(R.id.expiry);
mCardIcon = inputView.findViewById(R.id.thumbnail);
mStarIcon = inputView.findViewById(R.id.star);
inputView.setOnLongClickListener(this);
}
@Override
public boolean onLongClick(View inputView)
{
mListener.onRowLongClicked(getAdapterPosition());
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
mTickIcon = inputView.findViewById(R.id.selected_thumbnail);
inputView.setOnLongClickListener(view -> {
inputListener.onRowClicked(getAdapterPosition());
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
});
}
}
}
public int dpToPx(int dp, Context mContext){
Resources r = mContext.getResources();
int px = (int)TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());
return px;
}
}

View File

@@ -41,7 +41,6 @@ import com.google.android.material.chip.ChipGroup;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
import com.google.zxing.BarcodeFormat;
import com.jaredrummler.android.colorpicker.ColorPickerDialog;
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;
@@ -72,8 +71,9 @@ import androidx.core.content.FileProvider;
import androidx.exifinterface.media.ExifInterface;
import androidx.fragment.app.DialogFragment;
public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
{
import protect.card_locker.async.TaskHandler;
public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
private static final String TAG = "Catima";
private final String STATE_TAB_INDEX = "savedTab";
@@ -141,6 +141,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
LoyaltyCard tempLoyaltyCard;
final private TaskHandler mTasks = new TaskHandler();
private static LoyaltyCard updateTempState(LoyaltyCard loyaltyCard, LoyaltyCardField fieldName, Object value) {
return new LoyaltyCard(
(int) (fieldName == LoyaltyCardField.id ? value : loyaltyCard.id),
@@ -154,7 +156,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
(CatimaBarcode) (fieldName == LoyaltyCardField.barcodeType ? value : loyaltyCard.barcodeType),
(Integer) (fieldName == LoyaltyCardField.headerColor ? value : loyaltyCard.headerColor),
(int) (fieldName == LoyaltyCardField.starStatus ? value : loyaltyCard.starStatus),
Utils.getUnixTime()
Utils.getUnixTime(),100
);
}
@@ -164,8 +166,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
hasChanged = true;
}
private void extractIntentFields(Intent intent)
{
private void extractIntentFields(Intent intent) {
final Bundle b = intent.getExtras();
loyaltyCardId = b != null ? b.getInt(BUNDLE_ID) : 0;
updateLoyaltyCard = b != null && b.getBoolean(BUNDLE_UPDATE, false);
@@ -205,8 +206,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null)
{
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
@@ -416,7 +416,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
} else if (s.toString().equals(getString(R.string.setBarcodeId))) {
if (!lastValue.toString().equals(getString(R.string.setBarcodeId))) {
barcodeIdField.setText(lastValue);
};
}
;
AlertDialog.Builder builder = new AlertDialog.Builder(LoyaltyCardEditActivity.this);
builder.setTitle(R.string.setBarcodeId);
@@ -471,7 +472,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
if (!barcodeFormat.isSupported()) {
Toast.makeText(LoyaltyCardEditActivity.this, getString(R.string.unsupportedBarcodeType), Toast.LENGTH_LONG).show();
}
} catch (IllegalArgumentException e) {}
} catch (IllegalArgumentException e) {
}
}
generateOrHideBarcode();
@@ -510,8 +512,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
}
@Override
public void onNewIntent(Intent intent)
{
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i(TAG, "Received new intent");
@@ -520,15 +521,14 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
@SuppressLint("DefaultLocale")
@Override
public void onResume()
{
public void onResume() {
super.onResume();
Log.i(TAG, "To view card: " + loyaltyCardId);
onResuming = true;
if(tempLoyaltyCard == null) {
if (tempLoyaltyCard == null) {
if (updateLoyaltyCard) {
tempLoyaltyCard = db.getLoyaltyCard(loyaltyCardId);
if (tempLoyaltyCard == null) {
@@ -551,7 +551,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
setTitle(R.string.addCardTitle);
} else {
// New card, use default values
tempLoyaltyCard = new LoyaltyCard(-1, "", "", null, new BigDecimal("0"), null, "", null, null, null, 0, Utils.getUnixTime());
tempLoyaltyCard = new LoyaltyCard(-1, "", "", null, new BigDecimal("0"), null, "", null, null, null, 0, Utils.getUnixTime(),100);
setTitle(R.string.addCardTitle);
}
}
@@ -564,8 +564,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
barcodeIdField.setText(tempLoyaltyCard.barcodeId != null ? tempLoyaltyCard.barcodeId : getString(R.string.sameAsCardId));
barcodeTypeField.setText(tempLoyaltyCard.barcodeType != null ? tempLoyaltyCard.barcodeType.prettyName() : getString(R.string.noBarcode));
if(groupsChips.getChildCount() == 0)
{
if (groupsChips.getChildCount() == 0) {
List<Group> existingGroups = db.getGroups();
List<Group> loyaltyCardGroups = db.getLoyaltyCardGroups(loyaltyCardId);
@@ -604,18 +603,17 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
}
// Generate random header color
if(tempLoyaltyCard.headerColor == null)
{
if (tempLoyaltyCard.headerColor == null) {
// Select a random color to start out with.
TypedArray colors = getResources().obtainTypedArray(R.array.letter_tile_colors);
final int color = (int)(Math.random() * colors.length());
final int color = (int) (Math.random() * colors.length());
updateTempState(LoyaltyCardField.headerColor, colors.getColor(color, Color.BLACK));
colors.recycle();
}
// It can't be null because we set it in updateTempState but SpotBugs insists it can be
// NP_NULL_ON_SOME_PATH: Possible null pointer dereference
if(tempLoyaltyCard.headerColor != null) {
if (tempLoyaltyCard.headerColor != null) {
thumbnail.setOnClickListener(new ColorSelectListener());
}
@@ -806,11 +804,9 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
startActivityForResult(i, type);
}
class EditCardIdAndBarcode implements View.OnClickListener
{
class EditCardIdAndBarcode implements View.OnClickListener {
@Override
public void onClick(View v)
{
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(), ScanActivity.class);
final Bundle b = new Bundle();
b.putString(LoyaltyCardEditActivity.BUNDLE_CARDID, cardIdFieldView.getText().toString());
@@ -819,11 +815,9 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
}
}
class ChooseCardImage implements View.OnClickListener
{
class ChooseCardImage implements View.OnClickListener {
@Override
public void onClick(View v) throws NoSuchElementException
{
public void onClick(View v) throws NoSuchElementException {
ImageView targetView = v.getId() == ID_IMAGE_FRONT ? cardImageFront : cardImageBack;
LinkedHashMap<String, Callable<Void>> cardOptions = new LinkedHashMap<>();
@@ -870,11 +864,9 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
}
}
class ColorSelectListener implements View.OnClickListener
{
class ColorSelectListener implements View.OnClickListener {
@Override
public void onClick(View v)
{
public void onClick(View v) {
ColorPickerDialog.Builder dialogBuilder = ColorPickerDialog.newBuilder();
if (tempLoyaltyCard.headerColor != null) {
@@ -882,19 +874,16 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
}
ColorPickerDialog dialog = dialogBuilder.create();
dialog.setColorPickerDialogListener(new ColorPickerDialogListener()
{
dialog.setColorPickerDialogListener(new ColorPickerDialogListener() {
@Override
public void onColorSelected(int dialogId, int color)
{
public void onColorSelected(int dialogId, int color) {
updateTempState(LoyaltyCardField.headerColor, color);
generateIcon(storeFieldEdit.getText().toString());
}
@Override
public void onDialogDismissed(int dialogId)
{
public void onDialogDismissed(int dialogId) {
// Nothing to do, no change made
}
});
@@ -955,20 +944,17 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
return;
}
if(tempLoyaltyCard.store.isEmpty())
{
if (tempLoyaltyCard.store.isEmpty()) {
Snackbar.make(storeFieldEdit, R.string.noStoreError, Snackbar.LENGTH_LONG).show();
return;
}
if(tempLoyaltyCard.cardId.isEmpty())
{
if (tempLoyaltyCard.cardId.isEmpty()) {
Snackbar.make(cardIdFieldView, R.string.noCardIdError, Snackbar.LENGTH_LONG).show();
return;
}
if(!validBalance)
{
if (!validBalance) {
Snackbar.make(balanceField, getString(R.string.parsingBalanceFailed, balanceField.getText().toString()), Snackbar.LENGTH_LONG).show();
return;
}
@@ -980,8 +966,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
selectedGroups.add((Group) chip.getTag());
}
if(updateLoyaltyCard)
{ //update of "starStatus" not necessary, since it cannot be changed in this activity (only in ViewActivity)
if (updateLoyaltyCard) { //update of "starStatus" not necessary, since it cannot be changed in this activity (only in ViewActivity)
db.updateLoyaltyCard(loyaltyCardId, tempLoyaltyCard.store, tempLoyaltyCard.note, tempLoyaltyCard.expiry, tempLoyaltyCard.balance, tempLoyaltyCard.balanceType, tempLoyaltyCard.cardId, tempLoyaltyCard.barcodeId, tempLoyaltyCard.barcodeType, tempLoyaltyCard.headerColor);
try {
Utils.saveCardImage(this, (Bitmap) cardImageFront.getTag(), loyaltyCardId, true);
@@ -990,9 +975,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
e.printStackTrace();
}
Log.i(TAG, "Updated " + loyaltyCardId + " to " + cardId);
}
else
{
} else {
loyaltyCardId = (int) db.insertLoyaltyCard(tempLoyaltyCard.store, tempLoyaltyCard.note, tempLoyaltyCard.expiry, tempLoyaltyCard.balance, tempLoyaltyCard.balanceType, tempLoyaltyCard.cardId, tempLoyaltyCard.barcodeId, tempLoyaltyCard.barcodeType, tempLoyaltyCard.headerColor, 0, tempLoyaltyCard.lastUsed);
try {
Utils.saveCardImage(this, (Bitmap) cardImageFront.getTag(), loyaltyCardId, true);
@@ -1008,14 +991,10 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
if(updateLoyaltyCard)
{
public boolean onCreateOptionsMenu(Menu menu) {
if (updateLoyaltyCard) {
getMenuInflater().inflate(R.menu.card_update_menu, menu);
}
else
{
} else {
getMenuInflater().inflate(R.menu.card_add_menu, menu);
}
@@ -1023,12 +1002,10 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id)
{
switch (id) {
case android.R.id.home:
askBeforeQuitIfChanged();
break;
@@ -1059,8 +1036,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent)
{
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == RESULT_OK) {
@@ -1143,6 +1119,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
}
private void generateBarcode(String cardIdString, CatimaBarcode barcodeFormat) {
mTasks.flushTaskList(TaskHandler.TYPE.BARCODE, true, false, false);
if (barcodeImage.getHeight() == 0) {
Log.d(TAG, "ImageView size is not known known at start, waiting for load");
// The size of the ImageView is not yet available as it has not
@@ -1154,12 +1132,14 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
barcodeImage.getViewTreeObserver().removeOnGlobalLayoutListener(this);
Log.d(TAG, "ImageView size now known");
new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, warnOnInvalidBarcodeType).execute();
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, warnOnInvalidBarcodeType);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
});
} else {
Log.d(TAG, "ImageView size known known, creating barcode");
new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, warnOnInvalidBarcodeType).execute();
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, warnOnInvalidBarcodeType);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
showBarcode();

View File

@@ -1,14 +1,18 @@
package protect.card_locker;
import android.app.Application;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.multidex.MultiDexApplication;
import protect.card_locker.preferences.Settings;
public class LoyaltyCardLockerApplication extends MultiDexApplication {
public class LoyaltyCardLockerApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Settings settings = new Settings(getApplicationContext());
Settings settings = new Settings(this);
AppCompatDelegate.setDefaultNightMode(settings.getTheme());
}
}

View File

@@ -30,7 +30,6 @@ import android.widget.Toast;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.zxing.BarcodeFormat;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
@@ -48,10 +47,11 @@ import androidx.constraintlayout.widget.Guideline;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.widget.TextViewCompat;
import protect.card_locker.async.TaskHandler;
import protect.card_locker.preferences.Settings;
public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements GestureDetector.OnGestureListener
{
public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements GestureDetector.OnGestureListener {
private static final String TAG = "Catima";
private GestureDetector mGestureDetector;
@@ -102,6 +102,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
static final String STATE_IMAGEINDEX = "imageIndex";
static final String STATE_FULLSCREEN = "isFullscreen";
final private TaskHandler mTasks = new TaskHandler();
@Override
public boolean onDown(MotionEvent e) {
return true;
@@ -182,42 +184,51 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
IMAGE_BACK
}
private void extractIntentFields(Intent intent)
{
private void extractIntentFields(Intent intent) {
final Bundle b = intent.getExtras();
loyaltyCardId = b != null ? b.getInt("id") : 0;
Log.d(TAG, "View activity: id=" + loyaltyCardId);
}
private Drawable getDotIcon(boolean active) {
private Drawable getDotIcon(boolean active, boolean darkMode) {
Drawable unwrappedIcon = AppCompatResources.getDrawable(this, active ? R.drawable.active_dot : R.drawable.inactive_dot);
assert unwrappedIcon != null;
Drawable wrappedIcon = DrawableCompat.wrap(unwrappedIcon);
DrawableCompat.setTint(wrappedIcon, ContextCompat.getColor(getApplicationContext(), R.color.iconColor));
if (darkMode){
DrawableCompat.setTint(wrappedIcon, Color.WHITE);
}else{
DrawableCompat.setTint(wrappedIcon, Color.BLACK);
}
return wrappedIcon;
}
private Drawable getIcon(int icon, boolean dark)
{
private Drawable getIcon(int icon, boolean dark) {
Drawable unwrappedIcon = AppCompatResources.getDrawable(this, icon);
assert unwrappedIcon != null;
Drawable wrappedIcon = DrawableCompat.wrap(unwrappedIcon);
if(dark)
{
if (dark) {
DrawableCompat.setTint(wrappedIcon, Color.BLACK);
}
else
{
} else {
DrawableCompat.setTintList(wrappedIcon, null);
}
return wrappedIcon;
}
private void setCenterGuideline(int zoomLevel) {
float scale = zoomLevel / 100f;
if (format != null && format.isSquare()) {
centerGuideline.setGuidelinePercent(0.75f * scale);
} else {
centerGuideline.setGuidelinePercent(0.5f * scale);
}
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
@@ -251,24 +262,28 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
appBarLayout = findViewById(R.id.app_bar_layout);
centerGuideline = findViewById(R.id.centerGuideline);
centerGuideline.setGuidelinePercent(0.5f);
barcodeScaler = findViewById(R.id.barcodeScaler);
barcodeScaler.setProgress(100);
maximizeButton.setBackgroundColor(getThemeColor());
minimizeButton.setBackgroundColor(getThemeColor());
bottomSheetButton.setBackgroundColor(getThemeColor());
barcodeScaler.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (!fromUser){
Log.d(TAG, "non user triggered onProgressChanged, ignoring, progress is " + progress);
return;
}
Log.d(TAG, "Progress is " + progress);
Log.d(TAG, "Max is " + barcodeScaler.getMax());
float scale = (float) progress / (float) barcodeScaler.getMax();
Log.d(TAG, "Scaling to " + scale);
if (imageTypes.get(mainImageIndex) == ImageType.BARCODE) {
redrawBarcodeAfterResize();
}
centerGuideline.setGuidelinePercent(0.5f * scale);
loyaltyCard.zoomLevel = progress;
db.updateLoyaltyCardZoomLevel(loyaltyCardId, loyaltyCard.zoomLevel);
setCenterGuideline(loyaltyCard.zoomLevel);
drawMainImage(mainImageIndex, true);
}
@Override
@@ -321,7 +336,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) { }
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
bottomSheetButton.setOnClickListener(v -> {
@@ -357,8 +373,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
@Override
public void onNewIntent(Intent intent)
{
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i(TAG, "Received new intent");
@@ -374,8 +389,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
@Override
public void onResume()
{
public void onResume() {
super.onResume();
Log.i(TAG, "To view card: " + loyaltyCardId);
@@ -384,12 +398,10 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
// '1' is the brightest. We attempt to maximize the brightness
// to help barcode readers scan the barcode.
Window window = getWindow();
if(window != null)
{
if (window != null) {
WindowManager.LayoutParams attributes = window.getAttributes();
if (settings.useMaxBrightnessDisplayingBarcode())
{
if (settings.useMaxBrightnessDisplayingBarcode()) {
attributes.screenBrightness = 1F;
}
@@ -398,7 +410,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
if (settings.getDisableLockscreenWhileViewingCard()) {
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD|
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
}
@@ -406,8 +418,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
loyaltyCard = db.getLoyaltyCard(loyaltyCardId);
if(loyaltyCard == null)
{
if (loyaltyCard == null) {
Log.w(TAG, "Could not lookup loyalty card " + loyaltyCardId);
Toast.makeText(this, R.string.noCardExistsError, Toast.LENGTH_LONG).show();
finish();
@@ -425,20 +436,17 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
settings.getFontSizeMin(settings.getLargeFont()), settings.getFontSizeMax(settings.getLargeFont()),
1, TypedValue.COMPLEX_UNIT_SP);
if(loyaltyCard.note.length() > 0)
{
if (loyaltyCard.note.length() > 0) {
noteView.setVisibility(View.VISIBLE);
noteView.setText(loyaltyCard.note);
noteView.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
}
else
{
} else {
noteView.setVisibility(View.GONE);
}
List<Group> loyaltyCardGroups = db.getLoyaltyCardGroups(loyaltyCardId);
if(loyaltyCardGroups.size() > 0) {
if (loyaltyCardGroups.size() > 0) {
List<String> groupNames = new ArrayList<>();
for (Group group : loyaltyCardGroups) {
groupNames.add(group._id);
@@ -447,35 +455,29 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
groupsView.setVisibility(View.VISIBLE);
groupsView.setText(getString(R.string.groupsList, TextUtils.join(", ", groupNames)));
groupsView.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
}
else
{
} else {
groupsView.setVisibility(View.GONE);
}
if(!loyaltyCard.balance.equals(new BigDecimal(0))) {
if (!loyaltyCard.balance.equals(new BigDecimal(0))) {
balanceView.setVisibility(View.VISIBLE);
balanceView.setText(getString(R.string.balanceSentence, Utils.formatBalance(this, loyaltyCard.balance, loyaltyCard.balanceType)));
balanceView.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
}
else
{
} else {
balanceView.setVisibility(View.GONE);
}
if(loyaltyCard.expiry != null) {
if (loyaltyCard.expiry != null) {
expiryView.setVisibility(View.VISIBLE);
int expiryString = R.string.expiryStateSentence;
if(Utils.hasExpired(loyaltyCard.expiry)) {
if (Utils.hasExpired(loyaltyCard.expiry)) {
expiryString = R.string.expiryStateSentenceExpired;
expiryView.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.alert));
}
expiryView.setText(getString(expiryString, DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.expiry)));
expiryView.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
}
else
{
} else {
expiryView.setVisibility(View.GONE);
}
expiryView.setTag(loyaltyCard.expiry);
@@ -494,12 +496,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
TypedValue.COMPLEX_UNIT_DIP);
int backgroundHeaderColor;
if(loyaltyCard.headerColor != null)
{
if (loyaltyCard.headerColor != null) {
backgroundHeaderColor = loyaltyCard.headerColor;
}
else
{
} else {
backgroundHeaderColor = LetterBitmap.getDefaultColor(this, loyaltyCard.store);
}
@@ -507,12 +506,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
appBarLayout.setBackgroundColor(backgroundHeaderColor);
int textColor;
if(Utils.needsDarkForeground(backgroundHeaderColor))
{
if (Utils.needsDarkForeground(backgroundHeaderColor)) {
textColor = Color.BLACK;
}
else
{
} else {
textColor = Color.WHITE;
}
storeName.setTextColor(textColor);
@@ -521,14 +517,12 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
// If the background is very bright, we should use dark icons
backgroundNeedsDarkIcons = Utils.needsDarkForeground(backgroundHeaderColor);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null)
{
if (actionBar != null) {
actionBar.setHomeAsUpIndicator(getIcon(R.drawable.ic_arrow_back_white, backgroundNeedsDarkIcons));
}
// Make notification area light if dark icons are needed
if(Build.VERSION.SDK_INT >= 23)
{
if (Build.VERSION.SDK_INT >= 23) {
window.getDecorView().setSystemUiVisibility(backgroundNeedsDarkIcons ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : 0);
}
window.setStatusBarColor(Color.TRANSPARENT);
@@ -564,10 +558,11 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
dotIndicator.removeAllViews();
if (imageTypes.size() >= 2) {
dots = new ImageView[imageTypes.size()];
boolean darkMode = Utils.isDarkModeEnabled(getApplicationContext());
for (int i = 0; i < imageTypes.size(); i++) {
dots[i] = new ImageView(this);
dots[i].setImageDrawable(getDotIcon(false));
dots[i].setImageDrawable(getDotIcon(false, darkMode));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(8, 0, 8, 0);
@@ -585,8 +580,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
@Override
public void onBackPressed() {
if (isFullscreen)
{
if (isFullscreen) {
setFullscreen(false);
return;
}
@@ -595,16 +589,14 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.card_view_menu, menu);
// Always calculate lockscreen icon, it may need a black color
boolean lockBarcodeScreenOrientation = settings.getLockBarcodeScreenOrientation();
MenuItem item = menu.findItem(R.id.action_lock_unlock);
setOrientatonLock(item, lockBarcodeScreenOrientation);
if(lockBarcodeScreenOrientation)
{
if (lockBarcodeScreenOrientation) {
item.setVisible(false);
}
@@ -623,8 +615,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
if (starred) {
menu.findItem(R.id.action_star_unstar).setIcon(getIcon(R.drawable.ic_starred_white, backgroundNeedsDarkIcons));
menu.findItem(R.id.action_star_unstar).setTitle(R.string.unstar);
}
else {
} else {
menu.findItem(R.id.action_star_unstar).setIcon(getIcon(R.drawable.ic_unstarred_white, backgroundNeedsDarkIcons));
menu.findItem(R.id.action_star_unstar).setTitle(R.string.star);
}
@@ -632,12 +623,10 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id)
{
switch (id) {
case android.R.id.home:
finish();
break;
@@ -652,12 +641,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
return true;
case R.id.action_lock_unlock:
if(rotationEnabled)
{
if (rotationEnabled) {
setOrientatonLock(item, true);
}
else
{
} else {
setOrientatonLock(item, false);
}
rotationEnabled = !rotationEnabled;
@@ -673,8 +659,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
return super.onOptionsItemSelected(item);
}
private void setupOrientation()
{
private void setupOrientation() {
Toolbar portraitToolbar = findViewById(R.id.toolbar);
Toolbar landscapeToolbar = findViewById(R.id.toolbar_landscape);
@@ -702,51 +687,44 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
ActionBar actionBar = getSupportActionBar();
if(actionBar != null)
{
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
private void setOrientatonLock(MenuItem item, boolean lock)
{
if(lock)
{
private void setOrientatonLock(MenuItem item, boolean lock) {
if (lock) {
item.setIcon(getIcon(R.drawable.ic_lock_outline_white_24dp, backgroundNeedsDarkIcons));
item.setTitle(R.string.unlockScreen);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
else
{
} else {
item.setIcon(getIcon(R.drawable.ic_lock_open_white_24dp, backgroundNeedsDarkIcons));
item.setTitle(R.string.lockScreen);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
}
private void makeBottomSheetVisibleIfUseful()
{
private void makeBottomSheetVisibleIfUseful() {
if (noteView.getVisibility() == View.VISIBLE || groupsView.getVisibility() == View.VISIBLE || balanceView.getVisibility() == View.VISIBLE || expiryView.getVisibility() == View.VISIBLE) {
bottomSheet.setVisibility(View.VISIBLE);
}
else
{
} else {
bottomSheet.setVisibility(View.GONE);
}
}
private void drawBarcode() {
mTasks.flushTaskList(TaskHandler.TYPE.BARCODE, true, false, false);
if (format != null) {
new BarcodeImageWriterTask(
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(
getApplicationContext(),
mainImage,
barcodeIdString != null ? barcodeIdString : cardIdString,
format,
null,
false,
null)
.execute();
null);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
}
@@ -762,7 +740,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
drawBarcode();
}
});
};
}
}
private void drawMainImage(int index, boolean waitForResize) {
@@ -772,8 +750,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
if (dots != null) {
boolean darkMode = Utils.isDarkModeEnabled(getApplicationContext());
for (int i = 0; i < dots.length; i++) {
dots[i].setImageDrawable(getDotIcon(i == index));
dots[i].setImageDrawable(getDotIcon(i == index, darkMode));
}
}
@@ -822,6 +801,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
* by machines which offer no space to insert the complete device.
*/
private void setFullscreen(boolean enabled) {
isFullscreen = enabled;
ActionBar actionBar = getSupportActionBar();
if (enabled && !imageTypes.isEmpty()) {
@@ -829,14 +809,16 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
drawMainImage(mainImageIndex, true);
barcodeScaler.setProgress(loyaltyCard.zoomLevel);
setCenterGuideline(loyaltyCard.zoomLevel);
// Hide maximize and show minimize button and scaler
maximizeButton.setVisibility(View.GONE);
minimizeButton.setVisibility(View.VISIBLE);
barcodeScaler.setVisibility(View.VISIBLE);
// Hide actionbar
if(actionBar != null)
{
if (actionBar != null) {
actionBar.hide();
}
@@ -861,13 +843,11 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_FULLSCREEN
);
}
else
{
} else {
Log.d(TAG, "Move out of fullscreen");
// Reset center guideline
barcodeScaler.setProgress(100);
setCenterGuideline(100);
drawMainImage(mainImageIndex, true);
@@ -878,8 +858,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
barcodeScaler.setVisibility(View.GONE);
// Show actionbar
if(actionBar != null)
{
if (actionBar != null) {
actionBar.show();
}
@@ -903,6 +882,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
);
}
isFullscreen = enabled;
Log.d("setFullScreen","Is full screen enabled? "+enabled+" Zoom Level = "+barcodeScaler.getProgress());
}
}

View File

@@ -8,7 +8,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.Cursor;
import android.net.Uri;
import android.database.CursorIndexOutOfBoundsException;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
@@ -195,9 +195,9 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
@Override
public void onTabSelected(TabLayout.Tab tab) {
selectedTab = tab.getPosition();
Log.d("onTabSelected","Tab Position "+tab.getPosition());
mGroup = tab.getTag();
updateLoyaltyCardList();
// Store active tab in Shared Preference to restore next app launch
SharedPreferences activeTabPref = getApplicationContext().getSharedPreferences(
getString(R.string.sharedpreference_active_tab),
@@ -230,6 +230,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
mHelpText.setOnTouchListener(gestureTouchListener);
mNoMatchingCardsText.setOnTouchListener(gestureTouchListener);
mCardList.setOnTouchListener(gestureTouchListener);
mNoGroupCardsText.setOnTouchListener(gestureTouchListener);
mAdapter = new LoyaltyCardCursorAdapter(this, null, this);
mCardList.setAdapter(mAdapter);
@@ -349,7 +350,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
MenuItem searchItem = mMenu.findItem(R.id.action_search);
searchItem.collapseActionView();
}
ActivityCompat.recreate(this);
updateLoyaltyCardList();
return;
}
@@ -601,13 +602,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
updateLoyaltyCardList();
}
protected static boolean isDarkModeEnabled(Context inputContext)
{
Configuration config = inputContext.getResources().getConfiguration();
int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
return (currentNightMode == Configuration.UI_MODE_NIGHT_YES);
}
@Override
public boolean onDown(MotionEvent e) {
return false;
@@ -633,6 +627,12 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
@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");
@@ -648,9 +648,10 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
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()) {
@@ -664,6 +665,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
// Swipe left
if (velocityX > 150) {
Log.d("onFling","Left Swipe detected "+velocityX);
Integer nextTab = currentTab - 1;
if (nextTab < 0) {
@@ -728,7 +730,21 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
{
Cursor selected = mAdapter.getCursor();
selected.moveToPosition(inputPosition);
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
// FIXME
//
// There is a really nasty edge case that can happen when someone taps a card but right
// after it swipes (very small window, hard to reproduce). The cursor gets replaced and
// may not have a card at the ID number that is returned from onRowClicked.
//
// The proper fix, obviously, would involve makes sure an onFling can't happen while a
// click is being processed. Sadly, I have not yet found a way to make that possible.
LoyaltyCard loyaltyCard;
try {
loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
} catch (CursorIndexOutOfBoundsException e) {
Log.w(TAG, "Prevented crash from tap + swipe on ID " + inputPosition + ": " + e);
return;
}
Intent i = new Intent(this, LoyaltyCardViewActivity.class);
i.setAction("");

View File

@@ -38,6 +38,7 @@ import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Map;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.graphics.ColorUtils;
import androidx.exifinterface.media.ExifInterface;
import protect.card_locker.preferences.Settings;
@@ -401,4 +402,18 @@ public class Utils {
static public long getUnixTime() {
return System.currentTimeMillis() / 1000;
}
static public boolean isDarkModeEnabled(Context inputContext)
{
int nightModeSetting = new Settings(inputContext).getTheme();
if (nightModeSetting == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {
Configuration config = inputContext.getResources().getConfiguration();
int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
return (currentNightMode == Configuration.UI_MODE_NIGHT_YES);
}else if (nightModeSetting == AppCompatDelegate.MODE_NIGHT_YES){
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,8 @@
package protect.card_locker.async;
import java.util.concurrent.Callable;
public interface CompatCallable<T> extends Callable<T> {
void onPostExecute(Object result);
void onPreExecute();
}

View File

@@ -0,0 +1,174 @@
package protect.card_locker.async;
import android.os.Handler;
import android.os.Looper;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* AsyncTask has been deprecated so this provides very rudimentary compatibility without
* needing to redo too many Parts.
*
* However this is a much, much more cooperative Behaviour than before so
* the callers need to ensure we do NOT rely on forced cancellation and feed less into the
* ThreadPools so we don't OOM/Overload the Users device
*
* This assumes single-threaded callers.
*/
public class TaskHandler {
public enum TYPE {
BARCODE,
IMPORT,
EXPORT
}
HashMap<TYPE, ThreadPoolExecutor> executors = generateExecutors();
final private HashMap<TYPE, LinkedList<Future<?>>> taskList = new HashMap<>();
private final Handler uiHandler = new Handler(Looper.getMainLooper());
private HashMap<TYPE, ThreadPoolExecutor> generateExecutors() {
HashMap<TYPE, ThreadPoolExecutor> initExecutors = new HashMap<>();
for (TYPE type : TYPE.values()) {
replaceExecutor(initExecutors, type, false, false);
}
return initExecutors;
}
/**
* Replaces (or initializes) an Executor with a clean (new) one
* @param executors Map Reference
* @param type Which Queue
* @param flushOld attempt shutdown
* @param waitOnOld wait for Termination
*/
private void replaceExecutor(HashMap<TYPE, ThreadPoolExecutor> executors, TYPE type, Boolean flushOld, Boolean waitOnOld) {
ThreadPoolExecutor oldExecutor = executors.get(type);
if (oldExecutor != null) {
if (flushOld) {
oldExecutor.shutdownNow();
}
if (waitOnOld) {
try {
//noinspection ResultOfMethodCallIgnored
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
executors.put(type, (ThreadPoolExecutor) Executors.newCachedThreadPool());
}
/**
* Queue a Pseudo-AsyncTask for execution
*
* @param type Queue
* @param callable PseudoAsyncTask
*/
public void executeTask(TYPE type, CompatCallable<?> callable) {
Runnable runner = () -> {
try {
// Run on the UI Thread
uiHandler.post(callable::onPreExecute);
// Background
final Object result = callable.call();
// Post results on UI Thread so we can show them
uiHandler.post(() -> {
callable.onPostExecute(result);
});
} catch (Exception e) {
e.printStackTrace();
}
};
LinkedList<Future<?>> list = taskList.get(type);
if (list == null) {
list = new LinkedList<>();
}
ThreadPoolExecutor executor = executors.get(type);
if (executor != null) {
Future<?> task = executor.submit(runner);
// Test Queue Cancellation:
// task.cancel(true);
list.push(task);
taskList.put(type, list);
}
}
/**
* This will attempt to cancel a currently running list of Tasks
* Useful to ignore scheduled tasks - but not able to hard-stop tasks that are running
*
* @param type Which Queue to target
* @param forceCancel attempt to close the Queue and force-replace it after
* @param waitForFinish wait and return after the old executor finished. Times out after 5s
* @param waitForCurrentlyRunning wait before cancelling tasks. Useful for tests.
*/
public void flushTaskList(TYPE type, Boolean forceCancel, Boolean waitForFinish, Boolean waitForCurrentlyRunning) {
// Only used for Testing
if (waitForCurrentlyRunning) {
ThreadPoolExecutor oldExecutor = executors.get(type);
if (oldExecutor != null) {
try {
//noinspection ResultOfMethodCallIgnored
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// Attempt to cancel known Tasks and clean the List
LinkedList<Future<?>> tasks = taskList.get(type);
if (tasks != null) {
for (Future<?> task : tasks) {
if (!task.isDone() || !task.isCancelled()) {
// Interrupt any Task we can
task.cancel(true);
}
}
}
tasks = new LinkedList<>();
taskList.put(type, tasks);
if (forceCancel || waitForFinish) {
ThreadPoolExecutor oldExecutor = executors.get(type);
if (oldExecutor != null) {
if (forceCancel) {
if (waitForFinish) {
try {
//noinspection ResultOfMethodCallIgnored
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
oldExecutor.shutdownNow();
replaceExecutor(executors, type, true, false);
} else {
try {
//noinspection ResultOfMethodCallIgnored
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}

View File

@@ -6,6 +6,7 @@ import android.graphics.Bitmap;
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.InternalZipConstants;
import org.apache.commons.csv.CSVFormat;
@@ -30,14 +31,21 @@ import protect.card_locker.Utils;
*/
public class CatimaExporter implements Exporter
{
public void exportData(Context context, DBHelper db, OutputStream output) throws IOException, InterruptedException
public void exportData(Context context, DBHelper db, OutputStream output,char[] password) throws IOException, InterruptedException
{
// Necessary vars
int readLen;
byte[] readBuffer = new byte[InternalZipConstants.BUFF_SIZE];
// Create zip output stream
ZipOutputStream zipOutputStream = new ZipOutputStream(output);
ZipOutputStream zipOutputStream;
if(password!=null && password.length>0){
zipOutputStream = new ZipOutputStream(output,password);
}
else{
zipOutputStream = new ZipOutputStream(output);
}
// Generate CSV
ByteArrayOutputStream catimaOutputStream = new ByteArrayOutputStream();
@@ -45,8 +53,7 @@ public class CatimaExporter implements Exporter
writeCSV(db, catimaOutputStreamWriter);
// Add CSV to zip file
ZipParameters csvZipParameters = new ZipParameters();
csvZipParameters.setFileNameInZip("catima.csv");
ZipParameters csvZipParameters = createZipParameters("catima.csv",password);
zipOutputStream.putNextEntry(csvZipParameters);
InputStream csvInputStream = new ByteArrayInputStream(catimaOutputStream.toByteArray());
while ((readLen = csvInputStream.read(readBuffer)) != -1) {
@@ -71,8 +78,7 @@ public class CatimaExporter implements Exporter
// If it exists, add to the .zip file
Bitmap image = Utils.retrieveCardImage(context, card.id, front);
if (image != null) {
ZipParameters imageZipParameters = new ZipParameters();
imageZipParameters.setFileNameInZip(Utils.getCardImageFileName(card.id, front));
ZipParameters imageZipParameters = createZipParameters(Utils.getCardImageFileName(card.id, front),password);
zipOutputStream.putNextEntry(imageZipParameters);
InputStream imageInputStream = new ByteArrayInputStream(Utils.bitmapToByteArray(image));
while ((readLen = imageInputStream.read(readBuffer)) != -1) {
@@ -86,6 +92,16 @@ public class CatimaExporter implements Exporter
zipOutputStream.close();
}
private ZipParameters createZipParameters(String fileName, char[] password){
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip(fileName);
if(password!=null && password.length>0){
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
}
return zipParameters;
}
private void writeCSV(DBHelper db, OutputStreamWriter output) throws IOException, InterruptedException {
CSVPrinter printer = new CSVPrinter(output, CSVFormat.RFC4180);

View File

@@ -48,7 +48,7 @@ public class CatimaImporter implements Importer
bufferedInputStream.mark(100);
// First, check if this is a zip file
ZipInputStream zipInputStream = new ZipInputStream(bufferedInputStream);
ZipInputStream zipInputStream = new ZipInputStream(bufferedInputStream,password);
boolean isZipFile = false;
@@ -104,7 +104,7 @@ public class CatimaImporter implements Importer
public void parseV1(Context context, DBHelper db, BufferedReader input) throws IOException, FormatException, InterruptedException
{
final CSVParser parser = new CSVParser(input, CSVFormat.RFC4180.withHeader());
final CSVParser parser = new CSVParser(input, CSVFormat.RFC4180.builder().setHeader().build());
SQLiteDatabase database = db.getWritableDatabase();
database.beginTransaction();
@@ -209,7 +209,7 @@ public class CatimaImporter implements Importer
public void parseV2Groups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
{
// Parse groups
final CSVParser groupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
final CSVParser groupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
List<CSVRecord> records = new ArrayList<>();
@@ -235,7 +235,7 @@ public class CatimaImporter implements Importer
public void parseV2Cards(Context context, DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
{
// Parse cards
final CSVParser cardParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
final CSVParser cardParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
List<CSVRecord> records = new ArrayList<>();
@@ -261,7 +261,7 @@ public class CatimaImporter implements Importer
public void parseV2CardGroups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
{
// Parse card group mappings
final CSVParser cardGroupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
final CSVParser cardGroupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
List<CSVRecord> records = new ArrayList<>();

View File

@@ -17,5 +17,5 @@ public interface Exporter
* Export the database to the output stream in a given format.
* @throws IOException
*/
void exportData(Context context, DBHelper db, OutputStream output) throws IOException, InterruptedException;
void exportData(Context context, DBHelper db, OutputStream output,char[] password) throws IOException, InterruptedException;
}

View File

@@ -32,8 +32,7 @@ import protect.card_locker.Utils;
* The database's loyalty cards are expected to appear in the CSV data.
* A header is expected for the each table showing the names of the columns.
*/
public class FidmeImporter implements Importer
{
public class FidmeImporter implements Importer {
public void importData(Context context, DBHelper db, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
// We actually retrieve a .zip file
ZipInputStream zipInputStream = new ZipInputStream(input, password);
@@ -59,7 +58,7 @@ public class FidmeImporter implements Importer
SQLiteDatabase database = db.getWritableDatabase();
database.beginTransaction();
final CSVParser fidmeParser = new CSVParser(new StringReader(loyaltyCards.toString()), CSVFormat.RFC4180.withDelimiter(';').withHeader());
final CSVParser fidmeParser = new CSVParser(new StringReader(loyaltyCards.toString()), CSVFormat.RFC4180.builder().setDelimiter(';').setHeader().build());
try {
for (CSVRecord record : fidmeParser) {
@@ -87,8 +86,7 @@ public class FidmeImporter implements Importer
* session.
*/
private void importLoyaltyCard(SQLiteDatabase database, DBHelper helper, CSVRecord record)
throws IOException, FormatException
{
throws IOException, FormatException {
// A loyalty card export from Fidme contains the following fields:
// Retailer (store name)
// Program (program name)
@@ -100,8 +98,7 @@ public class FidmeImporter implements Importer
// The store is called Retailer
String store = CSVHelpers.extractString("Retailer", record, "");
if (store.isEmpty())
{
if (store.isEmpty()) {
throw new FormatException("No store listed, but is required");
}
@@ -121,8 +118,7 @@ public class FidmeImporter implements Importer
// The ID is called reference
String cardId = CSVHelpers.extractString("Reference", record, "");
if(cardId.isEmpty())
{
if (cardId.isEmpty()) {
throw new FormatException("No card ID listed, but is required");
}

View File

@@ -22,7 +22,7 @@ public class MultiFormatExporter
* another ImportExportResult otherwise. If not Success, partial data may have been
* written to the output stream, and it should be discarded.
*/
public static ImportExportResult exportData(Context context, DBHelper db, OutputStream output, DataFormat format)
public static ImportExportResult exportData(Context context, DBHelper db, OutputStream output, DataFormat format,char[] password)
{
Exporter exporter = null;
@@ -40,7 +40,7 @@ public class MultiFormatExporter
{
try
{
exporter.exportData(context, db, output);
exporter.exportData(context, db, output,password);
return ImportExportResult.Success;
}
catch(IOException e)

View File

@@ -43,7 +43,7 @@ public class StocardImporter implements Importer
HashMap<String, HashMap<String, Object>> loyaltyCardHashMap = new HashMap<>();
HashMap<String, HashMap<String, String>> providers = new HashMap<>();
final CSVParser parser = new CSVParser(new InputStreamReader(context.getResources().openRawResource(R.raw.stocard_stores), StandardCharsets.UTF_8), CSVFormat.RFC4180.withHeader());
final CSVParser parser = new CSVParser(new InputStreamReader(context.getResources().openRawResource(R.raw.stocard_stores), StandardCharsets.UTF_8), CSVFormat.RFC4180.builder().setHeader().build());
try
{

View File

@@ -1,6 +1,7 @@
package protect.card_locker.preferences;
import android.content.Intent;
import android.os.Bundle;
import android.view.MenuItem;
@@ -41,7 +42,6 @@ public class SettingsActivity extends CatimaAppCompatActivity
// Display the fragment as the main content.
SettingsFragment fragment = new SettingsFragment();
fragment.setParentReference(this);
getSupportFragmentManager().beginTransaction()
.replace(R.id.settings_container, fragment)
.commit();
@@ -64,11 +64,6 @@ public class SettingsActivity extends CatimaAppCompatActivity
public static class SettingsFragment extends PreferenceFragmentCompat
{
private static final String DIALOG_FRAGMENT_TAG = "SettingsFragment";
private SettingsActivity parent;
public void setParentReference(SettingsActivity settingsActivity) {
parent = settingsActivity;
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@@ -120,8 +115,9 @@ public class SettingsActivity extends CatimaAppCompatActivity
});
localePreference.setOnPreferenceChangeListener((preference, newValue) -> {
// Refresh the activity
parent.finish();
startActivity(parent.getIntent());
Intent intent = new Intent(getContext(), SettingsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
getContext().startActivity(intent);
return true;
});

View File

@@ -68,7 +68,7 @@
android:paddingTop="@dimen/inputPadding"
android:orientation="horizontal">
<androidx.cardview.widget.CardView
<com.google.android.material.card.MaterialCardView
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_marginEnd="@dimen/activity_margin"
@@ -84,7 +84,7 @@
android:contentDescription="@string/thumbnailDescription"
android:src="@mipmap/ic_launcher"/>
</androidx.cardview.widget.CardView>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/storeNameField"
@@ -347,7 +347,7 @@
android:paddingTop="@dimen/inputPadding">
<!-- Front image -->
<androidx.cardview.widget.CardView
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
@@ -369,7 +369,7 @@
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_camera_white" />
</androidx.cardview.widget.CardView>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
<!-- Back image -->
@@ -382,7 +382,7 @@
android:paddingTop="@dimen/inputPadding">
<!-- Back image -->
<androidx.cardview.widget.CardView
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
@@ -404,7 +404,7 @@
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_camera_white" />
</androidx.cardview.widget.CardView>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</TableLayout>
</TableLayout>

View File

@@ -25,22 +25,29 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
<androidx.cardview.widget.CardView
<com.google.android.material.card.MaterialCardView
android:id="@+id/thumbnail_container"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
android:layout_alignParentStart="true">
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
>
<RelativeLayout
android:id="@+id/thumbnail_front"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/storeContainer"
android:layout_alignBottom="@+id/storeContainer"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/thumbnail"
android:scaleType="centerCrop"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_centerVertical="true"
android:contentDescription="@string/thumbnailDescription"
android:src="@mipmap/ic_launcher" />
@@ -48,40 +55,39 @@
<RelativeLayout
android:id="@+id/thumbnail_back"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/selected_thumbnail"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_centerHorizontal="true"
android:layout_centerInParent="true"
android:contentDescription="@string/thumbnailDescription"
android:scaleType="centerCrop"
app:srcCompat="@drawable/ic_done" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:minHeight="@dimen/cardThumbnailSize"
android:layout_height="wrap_content"
<TextView
android:id="@+id/store"
android:paddingStart="16dp"
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_gravity="center_vertical"
android:layout_toEndOf="@+id/thumbnail_container">
android:layout_height="wrap_content"
android:gravity="left"
android:layout_toRightOf="@+id/thumbnail_container"
android:layout_toLeftOf="@+id/star"
android:textAppearance="?attr/textAppearanceHeadline6" />
<TextView
android:id="@+id/store"
android:paddingStart="16dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="left"
android:textAppearance="?attr/textAppearanceHeadline6" />
</LinearLayout>
<ImageView
android:id="@+id/star"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_centerVertical="true"
android:scaleType="centerCrop"
app:srcCompat="@drawable/ic_starred_white"
android:contentDescription="@string/starImage"
app:tint="?attr/colorControlNormal"
@@ -114,6 +120,8 @@
android:id="@+id/balance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:paddingEnd="8dp"
android:textAppearance="?attr/textAppearanceBody2"
android:textColor="?android:attr/textColorSecondary"
@@ -125,6 +133,8 @@
android:id="@+id/expiry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:textAppearance="?attr/textAppearanceBody2"
android:textColor="?android:attr/textColorSecondary"
app:drawableLeftCompat="@drawable/ic_baseline_access_time_24"

View File

@@ -122,6 +122,10 @@
<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"
@@ -181,6 +185,10 @@
<TextView
android:id="@+id/noteView"
android:enabled="true"
android:textIsSelectable="true"
android:focusable="true"
android:longClickable="true"
android:autoLink="all"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -190,6 +198,10 @@
<TextView
android:id="@+id/groupsView"
android:enabled="true"
android:textIsSelectable="true"
android:focusable="true"
android:longClickable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
@@ -198,6 +210,10 @@
<TextView
android:id="@+id/balanceView"
android:enabled="true"
android:textIsSelectable="true"
android:focusable="true"
android:longClickable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
@@ -206,6 +222,10 @@
<TextView
android:id="@+id/expiryView"
android:enabled="true"
android:textIsSelectable="true"
android:focusable="true"
android:longClickable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"

View File

@@ -6,25 +6,28 @@ Heimen Stoffels
solokot
mondstern
Taco
Gediminas Murauskas
IllusiveMan196
Petr Novák
Oğuz Ersen
Gediminas Murauskas
Joel A
StoyanDimitrov
Samantaz Fox
Nyatsuki
arno-github
Ankit Tiwari
Sergio Paredes
StoyanDimitrov
Oğuz Ersen
Petr Novák
arshbeerSingh
huuhaa
Michael Moroni
Olivia (Zoe)
betsythefc
waffshappen
Miha Frangež
K. Herbert
Quentin PAGÈS
String E. Fighter
Yurical
waffshappen
Adolfo Jayme-Barrientos
Alessandro Mandelli
KovalevArtem
@@ -35,13 +38,15 @@ Jane Kong
Lukas Grassauer
Michalis
schirinowski
Thomas Bertels
inesre
lgasp
phlostically
Aditya Das
Kevin Sicong Jiang
Miha Frangež
Airat
BMN
Biren
Flav
Franciszek Stefan
Izzy
@@ -49,15 +54,18 @@ Karol Kosek
bittin
Maciej Błędkowski
Mattia
Michael Gangolf
pbeckmann
Peer Beckmann
QuangDNguyen2211
Rohan Babbar
Rose Liverman
Simone Dotto
Still Hsu
Subhashish Anand
Tymofii Lytvynenko
Tjipke van der Heide
avikkundu
opsik
psa-jforestier
Robin

View File

@@ -208,4 +208,6 @@
<string name="on_google_play">в Google Play</string>
<string name="and_data_usage">и използване на данни</string>
<string name="help_translate_this_app">Помогнете за превода на приложението</string>
<string name="exportPasswordHint">Въведете парола</string>
<string name="exportPassword">Задаване на парола за защита на изнесеното (по избор)</string>
</resources>

View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="save">সংরক্ষণ</string>
<string name="cancel">বাতিল</string>
<string name="unstar">তারা মুক্ত</string>
<string name="star">তারা</string>
<string name="barcodeNoBarcode">বারকোড না বারকোড</string>
<string name="barcodeType">বারকোড ধরন</string>
<string name="note">বিঃদ্রঃ</string>
<string name="storeName">দোকানের নাম</string>
<string name="noMatchingGiftCards">কোন ম্যাচিং উপহার কার্ড নেই</string>
<string name="noGiftCards">উপহার কার্ড নেই</string>
<string name="action_add">কর্ম যোগ</string>
<string name="all">সব</string>
<string name="noGroupCards">গোষ্ঠী কার্ড নেই</string>
<string name="noGroups">গোষ্ঠীগুলি নেই</string>
<string name="groups">গোষ্ঠীগুলি</string>
<string name="enter_group_name">গোষ্ঠী নাম লিখুন </string>
<string name="exportSuccessful">রপ্তানি সফল</string>
<string name="importSuccessful">আগম সফল</string>
<string name="intent_import_card_from_url_share_text">url শেয়ার টেক্সট থেকে ইন্টেন্ট ইম্পোর্ট কার্ড</string>
<string name="settings_disable_lockscreen_while_viewing_card"> কার্ড দেখা কালিন লকস্ক্রিন নিষ্ক্রিয়</string>
<string name="settings_keep_screen_on">সেটিংস পর্দা খোলা রাখুন</string>
<string name="settings_lock_barcode_orientation"> তালাবদ্ধ বার কোড অভিযোজন</string>
<string name="settings_max_font_size_scale">সর্বোচ্চ হরফ আকার</string>
<string name="settings_light_theme">সাদাটে থিম</string>
<string name="settings_system_theme">যন্ত্রর থিম</string>
<string name="settings_theme">থিম</string>
<string name="settings_category_title_ui">বিভাগ শিরোনাম</string>
<string name="starImage">তারা ছবি</string>
<string name="importCatima">ক্যাতিনা আগম</string>
<string name="importLoyaltyCardKeychain">আমদানি লয়্যালটি কার্ড কীচেন</string>
<string name="importStocard">স্টো কার্ড আমদানি করুন</string>
<string name="importVoucherVault">আমদানি ভাউচার ভল্ট</string>
<string name="barcodeId">বারকোড আইডি</string>
<string name="sameAsCardId">কার্ড আইডির মতো</string>
<string name="setBarcodeId">বারকোড আইডি সেট করুন</string>
<string name="unsupportedBarcodeType">অসমর্থিত বারকোড টাইপ</string>
<string name="wrongValueForBarcodeType">বারকোড টাইপের জন্য ভুল মান</string>
<string name="copy_to_clipboard_multiple_toast">ক্লিপবোর্ড একাধিক টোস্টে অনুলিপি করুন</string>
<string name="intent_import_card_from_url_share_multiple_text">url থেকে ইন্টেন্ট ইম্পোর্ট কার্ড একাধিক টেক্সট শেয়ার করে</string>
<string name="frontImageDescription">সামনের চিত্রের বর্ণনা</string>
<string name="backImageDescription">পিছনের চিত্রের বর্ণনা</string>
<string name="photos">ছবি</string>
<string name="setFrontImage">সদর ছবি স্থাপন</string>
<string name="setBackImage">পিছনের ছবি স্থাপন</string>
<string name="removeImage">ছবি অপসারণ</string>
<string name="takePhoto">ছবি নেত্তয়া</string>
<string name="updateBarcodeQuestionTitle">হালনাগাদ বারকোড প্রশ্ন শিরোনাম</string>
<string name="updateBarcodeQuestionText">হালনাগাদ বারকোড প্রশ্ন টেক্সট </string>
<string name="yes">হাঁ</string>
<string name="no">না</string>
<string name="passwordRequired">পাসওয়ার্ড প্রয়োজন</string>
<string name="failedGeneratingShareURL">শেয়ার ইউআরএল তৈরি করতে ব্যর্থ হয়েছে</string>
<string name="turn_flashlight_on">টর্চলাইট চালু করুন</string>
<string name="turn_flashlight_off">টর্চলাইট বন্ধ করুন</string>
<string name="settings_locale">লোকেল</string>
<string name="settings_system_locale">সিস্টেম লোকেল</string>
<string name="settings_theme_color">থিম রঙ</string>
<string name="settings_catima_theme">কটিমা থিম</string>
<string name="settings_pink_theme">গোলাপী থিম</string>
<string name="settings_magenta_theme">ম্যাজেন্টা থিম</string>
<string name="settings_violet_theme">ভায়োলেট থিম</string>
<string name="settings_blue_theme">নীল থিম</string>
<string name="settings_sky_blue_theme">আকাশী নীল থিম</string>
<string name="settings_green_theme">সবুজ থিম</string>
<string name="settings_brown_theme">বাদামী থিম</string>
<string name="sort">সাজান</string>
<string name="toggleMoreInfo">আরও তথ্য টগল করুন</string>
<string name="swipeToSwitchImages">ছবি পরিবর্তন করতে সোয়াইপ করুন</string>
<string name="sort_by_name">নামের দ্বারা সাজান</string>
<string name="sort_by_most_recently_used">সর্বাধিক সম্প্রতি ব্যবহৃত দ্বারা সাজান</string>
<string name="sort_by_expiry">মেয়াদ শেষ করে সাজান</string>
<string name="reverse">বিপরীত</string>
<string name="sort_by">ক্রমানুসার</string>
<string name="noCardExistsError">কোন কার্ড নেই ত্রুটি</string>
<string name="noStoreError">স্টোরেজ ত্রুটি নেই</string>
<string name="card_ids_copied">কার্ড আইডি কপি করা হয়েছে</string>
<string name="noCardsMessage">কোন কার্ড বার্তা নেই</string>
<string name="addCardTitle">কার্ডের শিরোনাম যোগ করুন</string>
<string name="editCardTitle">কার্ডের শিরোনাম সম্পাদনা করুন</string>
<string name="sendLabel">লেবেল পাঠান</string>
<string name="share">ভাগ</string>
<string name="copy_to_clipboard">নকল করুন ক্লিপবোর্ড এ</string>
<string name="deleteConfirmation">নিশ্চিতকরণ মুছে দিন</string>
<string name="unlockScreen">পর্দা আনলক করুন</string>
<string name="confirm">নিশ্চিত করুন</string>
<string name="delete">মুছে ফেলুন</string>
<string name="edit">সম্পাদনা</string>
</resources>

View File

@@ -212,4 +212,6 @@
<string name="help_translate_this_app">Pomozte s překladem této aplikace</string>
<string name="report_error">Nahlásit chybu</string>
<string name="on_google_play">na Google Play</string>
<string name="exportPassword">Nastavení hesla pro ochranu exportu (volitelné)</string>
<string name="exportPasswordHint">Zadejte heslo</string>
</resources>

View File

@@ -86,4 +86,11 @@
<string name="settings_disable_lockscreen_while_viewing_card">Forebyg låseskærm</string>
<string name="settings_keep_screen_on">LHold skærm tændt</string>
<string name="settings_lock_barcode_orientation">Lås stregkode-orientering</string>
<string name="moveUp">Bevæg dig opad</string>
<string name="leaveWithoutSaveConfirmation">Forlade uden at gemme\?</string>
<string name="settings_display_barcode_max_brightness">Lysere stregkodevisning</string>
<string name="failedOpeningFileManager">Installer først en filhåndteringsprogram.</string>
<string name="moveDown">Bevæger sig nedad</string>
<string name="leaveWithoutSaveTitle">Afslut</string>
<string name="addManually">Indtast kort-ID manuelt</string>
</resources>

View File

@@ -202,10 +202,12 @@
<string name="credits">Dank an</string>
<string name="help_translate_this_app">Hilfe bei der Übersetzung</string>
<string name="and_data_usage">und Datennutzung</string>
<string name="rate_this_app">Bewerte die App</string>
<string name="rate_this_app">Bewerte die Anwendung</string>
<string name="on_google_play">auf Google Play</string>
<string name="license">Lizenz</string>
<string name="source_repository">Quellcode</string>
<string name="on_github">auf GitHub</string>
<string name="report_error">Fehler melden</string>
<string name="exportPassword">Legen Sie ein Passwort fest, um Ihren Export zu schützen (optional)</string>
<string name="exportPasswordHint">Passwort eingeben</string>
</resources>

View File

@@ -79,4 +79,13 @@
<string name="unlockScreen">Malbloki Rotacio</string>
<string name="lockScreen">Bloko Rotacio</string>
<string name="star">Aldoni al miaj plej ŝatataj</string>
<string name="copy_to_clipboard_toast">Card ID kopiita al la tondujo</string>
<string name="settings_keep_screen_on">Teni sur ekrano</string>
<string name="importSuccessful">Karto datumo importitaj</string>
<string name="enter_group_name">Eniri nomo de la grupo</string>
<string name="noGroups">Klaki la + plus butonon por aldoni grupoj por categorization unua.</string>
<string name="all">Ĉiuj</string>
<string name="intent_import_card_from_url_share_text">Mi deziras dividi karto kun vi</string>
<string name="exportSuccessful">Karto datumo eksportita</string>
<string name="noGroupCards">Ĉi tiu grupo ne enhavas ajnan kartoj</string>
</resources>

View File

@@ -200,12 +200,14 @@
<string name="sort_by_balance">Solde</string>
<string name="report_error">Signaler une erreur</string>
<string name="on_google_play">sur Google Play</string>
<string name="rate_this_app">Notez cette app</string>
<string name="rate_this_app">Notez cette appli</string>
<string name="and_data_usage">utilisation des données</string>
<string name="on_github">sur GitHub</string>
<string name="source_repository">Dépôt source</string>
<string name="license">Licence</string>
<string name="help_translate_this_app">Aidez à traduire cette app</string>
<string name="help_translate_this_app">Aidez à traduire cette appli</string>
<string name="credits">Contributeurs</string>
<string name="version_history">Historique des versions</string>
<string name="exportPassword">Définissez un mot de passe pour protéger vos exportations (facultatif)</string>
<string name="exportPasswordHint">Entrez le mot de passe</string>
</resources>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="unstar">Ukloni iz favorita</string>
<string name="action_search">Pretraživanje</string>
<string name="save">Spremi</string>
<string name="edit">Uredi</string>
<string name="delete">Ukloni</string>
<string name="confirm">Potvrdi</string>
<string name="lockScreen">Rotacija bloka</string>
<string name="unlockScreen">Otključaj Rotaciju</string>
<string name="deleteTitle">Ukloni kartu</string>
<string name="deleteConfirmation">Izbrisati ovu karticu zauvijek\?</string>
<string name="copy_to_clipboard">Kopiraj ID u međuspremnik</string>
<string name="share">Podijeli</string>
<string name="sendLabel">Pošalji…</string>
<string name="editCardTitle">Uredi karticu</string>
<string name="addCardTitle">Dodaj Kartu</string>
<string name="scanCardBarcode">Skeniranje crtičnog koda kartice</string>
<string name="cardShortcut">Oznaka karte</string>
<string name="noCardsMessage">Najprije dodajte karticu</string>
<string name="card_ids_copied">Kopirani ID kartice</string>
<string name="noBarcode">Nema crtičnog koda</string>
<string name="star">Dodaj u favorite</string>
<string name="action_add">Dodaj</string>
<string name="storeName">Ime</string>
<string name="note">Napomena</string>
<string name="noMatchingGiftCards">Ništa nisam našao. Pokušajte promijeniti pretraživanje.</string>
<string name="cardId">ID kartice</string>
<string name="barcodeType">Vrsta crtičnog koda</string>
<string name="barcodeNoBarcode">Na ovoj kartici nema crtičnog koda</string>
<string name="cancel">Poništi</string>
</resources>

View File

@@ -0,0 +1,193 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" xmlns:tools="http://schemas.android.com/tools">
<string name="app_revision_url">https://github.com/TheLastProject/Catima/releases</string>
<string name="storeName">Nama</string>
<string name="note">Keterangan</string>
<string name="delete">Hapus</string>
<string name="edit">Ubah</string>
<string name="save">Simpan</string>
<string name="deleteTitle">Hapus kartu</string>
<string name="cardId">Kartu ID</string>
<string name="barcodeType">Tipe barcode</string>
<string name="star">Tambahkan ke favorit</string>
<string name="unstar">Hapus dari favorit</string>
<string name="action_add">Tambah</string>
<string name="action_search">Cari</string>
<string name="sort_by_name">Nama</string>
<string name="sort_by_balance">Saldo</string>
<string name="sort_by">Sortir dengan</string>
<string name="sort">Sortir</string>
<string name="credits">Kredit</string>
<string name="license">Lisensi</string>
<string name="settings">Pengaturan</string>
<string name="settings_system_theme">Sistem</string>
<string name="selectBarcodeTitle">Pilih Barcode</string>
<string name="deleteConfirmation">Hapus kartu ini secara permanen?</string>
<string name="ok">OK</string>
<string name="share">Bagikan</string>
<string name="editCardTitle">Ubah Kartu</string>
<string name="addCardTitle">Tambah Kartu</string>
<string name="scanCardBarcode">Pindai Kartu Barcode</string>
<string name="barcodeNoBarcode">Kartu ini tidak memiliki barcode</string>
<string name="cancel">Batalkan</string>
<string name="importExport">Import/Ekspor</string>
<string name="settings_category_title_ui">Tampilan Pengguna</string>
<string name="settings_theme">Tema</string>
<string name="all">Semua</string>
<string name="leaveWithoutSaveTitle">Keluar</string>
<string name="card">Kartu</string>
<string name="barcode">Barcode</string>
<string name="chooseExpiryDate">Pilih masa berlaku</string>
<string name="noBarcodeFound">Barcode tidak ditemukan</string>
<string name="errorReadingImage">TIdak dapat membaca gambar</string>
<string name="balance">Saldo</string>
<string name="currency">Mata uang</string>
<string name="chooseImportType">Impor data dari?</string>
<string name="accept">Terima</string>
<string name="importCatima">Impor dari Catima</string>
<string name="importFidme">Impor dari FidMe</string>
<string name="barcodeId">Nilai barcode</string>
<string name="sameAsCardId">Sama denga kartu ID</string>
<string name="setBarcodeId">Tentukan nilai barcode</string>
<string name="photos">Foto</string>
<string name="setFrontImage">Atur gambar bagian depan</string>
<string name="report_error">Lapor Kesalahan</string>
<string name="rate_this_app">Beri nilai pada aplikasi ini</string>
<string name="sort_by_expiry">Masa berlaku</string>
<string name="sort_by_most_recently_used">Paling banyak digunakan</string>
<string name="settings_catima_theme">Catima</string>
<string name="settings_pink_theme">Merah Muda</string>
<string name="settings_blue_theme">Biru</string>
<string name="settings_green_theme">Hijau</string>
<string name="settings_sky_blue_theme">Biru Langit</string>
<string name="settings_grey_theme">Abu-abu</string>
<string name="settings_brown_theme">Cokelat</string>
<string name="settings_violet_theme">Ungu</string>
<string name="settings_magenta_theme">Magenta</string>
<string name="settings_theme_color">Warna tema</string>
<string name="settings_system_locale">Sistem</string>
<string name="settings_locale">Bahasa</string>
<string name="turn_flashlight_on">Hidupkan lampu flash</string>
<string name="turn_flashlight_off">Matikan lampu flash</string>
<string name="exportPasswordHint">Masukan kata sandi</string>
<string name="yes">Ya</string>
<string name="no">Tidak</string>
<string name="takePhoto">Ambil foto</string>
<string name="removeImage">Hapus gambar</string>
<string name="setBackImage">Atur gambar bagian belakang</string>
<string name="intent_import_card_from_url_share_multiple_text">Saya ingin berbagi kartu dengan anda</string>
<string name="noGiftCards">Klik tanda + tombol tambah untuk menambahkan kartu, atau mengimpor beberapa kartu melalui menu ⋮ terlebih dahulu.</string>
<string name="noMatchingGiftCards">Tidak menemukan apapun. Coba untuk mengubah pencarian anda.</string>
<string name="noBarcode">Bukan barcode</string>
<string name="confirm">Konfirmasi</string>
<string name="copy_to_clipboard">Salin ID</string>
<string name="sendLabel">Kirim…</string>
<string name="noCardsMessage">Tambah kartu terlebih dahulu</string>
<string name="noStoreError">Nama masih kosong</string>
<string name="noCardIdError">Kartu ID masih kosong</string>
<string name="noCardExistsError">Tidak dapat menemukan kartu</string>
<string name="failedParsingImportUriError">Tidak dapat menguraikan alamat impor situs web</string>
<string name="exportName">Ekspor</string>
<string name="importSuccessfulTitle">Sudah diimpor</string>
<string name="importFailedTitle">Impor gagal</string>
<string name="importFailed">Tidak dapat mengimpor kartu</string>
<string name="exportSuccessfulTitle">Sudah diekspor</string>
<string name="exportFailedTitle">Ekspor gagal</string>
<string name="exportFailed">Tidak dapat mengekspor kartu</string>
<string name="importing">Mengimpor…</string>
<string name="exporting">Mengekspor…</string>
<string name="noExternalStoragePermissionError">Berikan izin penyimpanan eksternal untuk mengimpor atau mengekspor kartu terlebih dahulu</string>
<string name="exportOptionExplanation">The data will be written to a location of your choice.</string>
<string name="importOptionFilesystemTitle">Impor dari sistem</string>
<string name="importOptionFilesystemExplanation">Pilih file dari sistem</string>
<string name="importOptionFilesystemButton">Dari sistem</string>
<string name="importOptionApplicationTitle">Gunakan aplikasi lain</string>
<string name="importOptionApplicationExplanation">Gunakan aplikasi lain atau pengelola file favorit anda untuk membuka file.</string>
<string name="importOptionApplicationButton">Gunakan aplikasi lain</string>
<string name="about">Tentang</string>
<string name="app_copyright_fmt">Hak Cipta © 2019<xliff:g>%d</xliff:g> Sylvia van Os</string>
<string name="app_copyright_old">Berdasarkan Loyalty Card Keychain hak cipta © 20162020 Branden Archer</string>
<string name="app_license">Perangkat lunak bebas copyleft, berlisensi GPLv3+</string>
<string name="about_title_fmt">Tentang <xliff:g id="app_name">%s</xliff:g></string>
<string name="debug_version_fmt">Versi: <xliff:g id="version">%s</xliff:g></string>
<string name="app_revision_fmt">Info Revisi: <xliff:g id="app_revision_url">%s</xliff:g></string>
<string name="app_libraries">Pustaka pihak ketiga gratis: <xliff:g id="app_libraries_list">%s</xliff:g></string>
<string name="app_resources">Sumber daya pihak ketiga gratis: <xliff:g id="app_resources_list">%s</xliff:g></string>
<string name="enterBarcodeInstructions">Masukkan ID kartu, dan pilih jenis barcodenya di bawah atau \"Kartu ini tidak memiliki barcode\".</string>
<string name="copy_to_clipboard_toast">ID kartu telah disalin</string>
<string name="thumbnailDescription">Gambar tampilan untuk kartu</string>
<string name="starImage">Favorit</string>
<string name="settings_light_theme">Terang</string>
<string name="settings_dark_theme">Gelap</string>
<string name="settings_max_font_size_scale">Ukuran maksimal huruf</string>
<string name="settings_display_barcode_max_brightness">Terangkan tampilan barcode</string>
<string name="settings_lock_barcode_orientation">Kunci orientasi barcode</string>
<string name="settings_keep_screen_on">Biarkan layar menyala</string>
<string name="settings_disable_lockscreen_while_viewing_card">Mencegah layar menyala</string>
<string name="intent_import_card_from_url_share_text">Saya ingin berbagi kartu dengan anda</string>
<string name="importSuccessful">Data kartu terimpor</string>
<string name="exportSuccessful">Data kartu terekspor</string>
<string name="enter_group_name">Masukan nama grup</string>
<string name="groups">Grup</string>
<string name="noGroups">Klik pada tombol tambah + untuk menambahkan grup atau kategori terlebih dahulu.</string>
<string name="noGroupCards">Grup ini tidak memilik kartu</string>
<string name="deleteConfirmationGroup">Hapus grup?</string>
<string name="failedOpeningFileManager">Instal aplikasi pengelola file terlebih dahulu.</string>
<string name="moveUp">Pindah ke atas</string>
<string name="moveDown">Pindah ke bawah</string>
<string name="leaveWithoutSaveConfirmation">Keluar tanpa menyimpan?</string>
<string name="addManually">Masukan ID kartu</string>
<string name="addFromImage">Pilih gambar dari galeri</string>
<string name="groupsList">Grup: <xliff:g>%s</xliff:g></string>
<string name="expiryStateSentence">Masa ber: <xliff:g>%s</xliff:g></string>
<string name="expiryStateSentenceExpired">Kadaluwarsa: <xliff:g>%s</xliff:g></string>
<string name="balanceSentence">Saldo: <xliff:g>%s</xliff:g></string>
<string name="balancePoints"><xliff:g>%s</xliff:g> poin</string>
<string name="editBarcode">Ubah barcode</string>
<string name="expiryDate">Tanggal masa berlaku</string>
<string name="never">Tidak pernah</string>
<string name="moveBarcodeToTopOfScreen">Pindah barcode ke bagian paling depan</string>
<string name="moveBarcodeToCenterOfScreen">Pusatkan barcode pada layar</string>
<string name="points">Poin</string>
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> sepertinya bukan saldo yang valid.</string>
<string name="app_loyalty_card_keychain">Loyalty Card Keychain</string>
<string name="privacy_policy">Kebijakan Privasi</string>
<string name="privacy_policy_popup_text">Pemberitahuan kebijakan privasi (diperlukan oleh beberapa toko aplikasi): TIDAK ADA DATA YANG DIKUMPULKAN SAMA SEKALI, yang dapat dikonfirmasi oleh siapa pun karena aplikasi kami adalah perangkat lunak gratis.</string>
<string name="importCatimaMessage">Pilih ekspor <i>catima.zip</i> Anda dari Catima untuk diimpor. Buat dari menu Impor/Ekspor aplikasi Catima lain dengan menekan Ekspor di sana terlebih dahulu.</string>
<string name="importFidmeMessage">Pilih ekspor <i>fidme-export-request-xxxxxx.zip</i> Anda dari FidMe untuk diimpor, dan pilih jenis barcode secara manual setelahnya. Buat dari profil FidMe Anda dengan memilih Perlindungan Data lalu tekan Ekstrak data saya terlebih dahulu.</string>
<string name="importLoyaltyCardKeychain">Impor dari Loyalty Card Keychain</string>
<string name="importLoyaltyCardKeychainMessage">Pilih ekspor <i>LoyaltyCardKeychain.csv</i> Anda dari Loyalty Card Keychain untuk diimpor. Buat dari menu Import/Export di Loyalty Card Keychain dengan menekan Export terlebih dahulu.</string>
<string name="importStocard">Impor dari Stocard</string>
<string name="importStocardMessage">Pilih ekspor <i>***-sync.zip</i> Anda dari Stocard untuk diimpor. Dapatkan dengan mengirim email ke support@stocardapp.com untuk meminta ekspor data Anda.</string>
<string name="importVoucherVault">Impor dari Voucher Vault</string>
<string name="importVoucherVaultMessage">Pilih ekspor <i>vouchervault.json</i> Anda dari Vault Voucher untuk diimpor. Buat dengan menekan Ekspor di Vault Voucher terlebih dahulu.</string>
<string name="unsupportedBarcodeType">Jenis barcode ini belum dapat ditampilkan. Ini mungkin didukung di versi aplikasi yang lebih baru.</string>
<string name="wrongValueForBarcodeType">Nilai tidak berlaku untuk jenis barcode yang dipilih</string>
<string name="copy_to_clipboard_multiple_toast">ID kartu telah disalin</string>
<string name="frontImageDescription">Gambar depan kartu</string>
<string name="backImageDescription">Gambar belakang kartu</string>
<string name="updateBarcodeQuestionTitle">Perbarui barcode?</string>
<string name="updateBarcodeQuestionText">Anda mengubah ID kartu. Apakah Anda juga ingin memperbarui barcode untuk menggunakan nilai yang sama?</string>
<string name="passwordRequired">Silahkan masukan kata sandi</string>
<string name="exportPassword">Tetapkan kata sandi untuk melindungi ekspor anda (opsional)</string>
<string name="failedGeneratingShareURL">Tidak dapat membuat alamat berbagi. Mohon laporkan ini.</string>
<string name="app_contributors">Pengembangan dibantu oleh: <xliff:g id="app_contributors">%s</xliff:g></string>
<string name="toggleMoreInfo">Tampilkan info selengkapnya</string>
<string name="swipeToSwitchImages">Geser atau tekan yang lama untuk mengganti gambar</string>
<string name="reverse">Ubah urutan</string>
<string name="version_history">Riwayat Versi</string>
<string name="help_translate_this_app">Bantu terjemahkan aplikasi ini</string>
<string name="source_repository">Sumber Repositori</string>
<string name="on_github">di GitHub</string>
<string name="and_data_usage">dan penggunaan data</string>
<string name="on_google_play">di Google Play</string>
<string name="lockScreen">Blokir rotasi</string>
<string name="unlockScreen">Buka blokir rotasi</string>
<string name="cardShortcut">Pintasan kartu</string>
<string name="card_ids_copied">ID kartu yang tersalin</string>
<string name="barcodeImageDescriptionWithType">Gambar dari jenis barcode <xliff:g>%s</xliff:g></string>
<string name="importExportHelp">Mencadangkan kartu memungkinkan anda memindahkannya ke perangkat lain.</string>
<plurals name="selectedCardCount">
<item quantity="other"><xliff:g>%d</xliff:g> kartu dipilih</item>
</plurals>
</resources>

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="action_add">Bæta</string>
<string name="noBarcode">Nei strikamerkið</string>
<string name="action_search">Leita að</string>
<string name="delete">Eyða</string>
<string name="unlockScreen">Opna Snúningur</string>
<string name="noGiftCards">Smelltu á + plús takka til að bæta kort, eða að flytja inn sumir frá ⋮ matseðill fyrst.</string>
<string name="note">Athugið</string>
<string name="barcodeType">Strikamerkið tegund</string>
<string name="cancel">Hætta</string>
<string name="noMatchingGiftCards">Vissi ekki að finna neitt. Reyna að breyta leita.</string>
<string name="storeName">Nafnið</string>
<string name="barcodeNoBarcode">Þetta kort hefur ekki strikamerkið</string>
<string name="star">Bæta við eftirlæti</string>
<string name="unstar">Fjarlægja frá eftirlæti</string>
<string name="save">Sparaðu</string>
<string name="edit">Breyta</string>
<string name="confirm">Staðfesta</string>
<string name="lockScreen">Blokk Snúningur</string>
<string name="ok">OK</string>
<string name="sendLabel">Sendu…</string>
<string name="deleteConfirmation">Eyða þetta kort til frambúðar\?</string>
<string name="share">Deila</string>
<string name="editCardTitle">Breyta Kort</string>
<string name="addCardTitle">Bæta Kort</string>
<string name="scanCardBarcode">Skanna Kort Strikamerkið</string>
<string name="noCardsMessage">Bæta kort fyrstu</string>
<string name="exportFailedTitle">Flytja mistókst</string>
<string name="exportSuccessfulTitle">Flutt</string>
<string name="noStoreError">Ekkert nafn slegið</string>
<string name="noCardExistsError">Gæti ekki fundið kort</string>
<string name="failedParsingImportUriError">Get ekki lesið inn URI</string>
<string name="exportName">Flytja</string>
<string name="importExportHelp">Stuðningur upp spil gerir þér kleift að færa þá til annar tæki.</string>
<string name="importSuccessfulTitle">Flutt</string>
<string name="importFailedTitle">Innflutningur mistókst</string>
<string name="noExternalStoragePermissionError">Grant ytri geymslu leyfi til að flytja eða flytja spil fyrstu</string>
<string name="exportOptionExplanation">Gögnum verður skrifað á stað af eigin vali.</string>
<string name="importOptionFilesystemTitle">Innflutningur frá möppuna</string>
<string name="importOptionFilesystemExplanation">Velja ákveðna skrá frá möppuna.</string>
<string name="starImage">Uppáhalds stjörnu</string>
<string name="never">Aldrei</string>
<string name="currency">Mynt</string>
<string name="moveBarcodeToTopOfScreen">Færa strikamerkið að efst á skjánum</string>
<string name="moveBarcodeToCenterOfScreen">Miðju strikamerkið á skjánum</string>
<string name="errorReadingImage">Gat ekki lesið ímynd</string>
<string name="importOptionApplicationButton">Notaðu annan app</string>
<string name="about">Um</string>
<string name="settings">Stillingar</string>
<string name="settings_max_font_size_scale">Max. letrið</string>
<string name="settings_lock_barcode_orientation">Læsa strikamerkið stefnumörkun</string>
<string name="settings_keep_screen_on">Halda á skjánum</string>
<string name="settings_disable_lockscreen_while_viewing_card">Að koma í veg fyrir að læsa skjánum</string>
<string name="editBarcode">Breyta strikamerkið</string>
<string name="settings_light_theme">Ljós</string>
<string name="importOptionFilesystemButton">Frá möppuna</string>
<string name="chooseImportType">Flytja gögn úr\?</string>
<string name="balance">Jafnvægi</string>
<string name="points">Stig</string>
<string name="importOptionApplicationTitle">Notaðu annan app</string>
<string name="importOptionApplicationExplanation">Nota allir app eða uppáhalds skráasafn að opna skrá.</string>
<string name="selectBarcodeTitle">Veldu Strikamerkið</string>
<string name="thumbnailDescription">Þumalinn fyrir kort</string>
<string name="settings_theme">Þema</string>
<string name="app_license">Copylefted frítt hugbúnaður, leyfi GPLv3+</string>
<string name="noBarcodeFound">Nei strikamerkið var komist</string>
<string name="settings_category_title_ui">Notandi tengi</string>
<string name="settings_system_theme">Kerfi</string>
<string name="settings_dark_theme">Dökk</string>
<string name="settings_display_barcode_max_brightness">Bjartari strikamerkið skoða</string>
<string name="enter_group_name">Inn nafn hópur</string>
<string name="intent_import_card_from_url_share_text">Ég vil deila kort með þér</string>
<string name="importSuccessful">Kortið gögn flutt</string>
<string name="groups">Tekur</string>
<string name="exportSuccessful">Kortagögn flutt út</string>
<string name="failedOpeningFileManager">Setja skráasafn fyrst.</string>
<string name="moveUp">Fara upp</string>
<string name="leaveWithoutSaveTitle">Brottför</string>
<string name="leaveWithoutSaveConfirmation">Fara án þess að bjarga\?</string>
<string name="addFromImage">Veldu mynd frá gallerí</string>
<string name="card">Kort</string>
<string name="barcode">Strikamerkið</string>
<string name="expiryDate">Fyrningu</string>
<string name="moveDown">Fara neðar</string>
<string name="chooseExpiryDate">Velja rennur</string>
</resources>

View File

@@ -47,7 +47,7 @@
<string name="importOptionApplicationExplanation">Usa qualsiasi app o il tuo gestore di file preferito per aprire un file.</string>
<string name="importOptionApplicationButton">Usa unaltra app</string>
<string name="about">Informazioni</string>
<string name="app_license">Software libero con copyleft, licenza GPLv3+.</string>
<string name="app_license">Software libero con copyleft, licenza GPLv3+</string>
<string name="about_title_fmt">Informazioni su <xliff:g id="app_name">%s</xliff:g></string>
<string name="debug_version_fmt">Versione: <xliff:g id="version">%s</xliff:g></string>
<string name="app_revision_fmt">Informazioni sulla revisione: <xliff:g id="app_revision_url"> %s </xliff:g></string>
@@ -67,7 +67,7 @@
<string name="exportSuccessful">Dati della carta importati</string>
<string name="importSuccessful">Dati della carta importati</string>
<string name="app_copyright_old">Basato su Loyalty Card Keychain
\ncopyright © 20162020 Branden Archer.</string>
\ncopyright © 20162020 Branden Archer</string>
<string name="exportOptionExplanation">I dati verranno scritti in una posizione a tua scelta.</string>
<string name="barcodeType">Tipo di codice a barre</string>
<string name="unstar">Rimuovi dai preferiti</string>
@@ -116,16 +116,16 @@
\nNESSUN DATO VIENE RACCOLTO, cosa che chiunque può confermare dato che la nostra applicazione è un software libero.</string>
<string name="privacy_policy">Informativa sulla riservatezza</string>
<string name="importVoucherVaultMessage">Seleziona la tua esportazione <i>vouchervault.json</i> da Voucher Vault da importare.
\nOppure crealo premendo prima Esporta in Voucher Vault.</string>
\nCrealo premendo prima Esporta in Voucher Vault.</string>
<string name="importVoucherVault">Importa da Voucher Vault</string>
<string name="importLoyaltyCardKeychainMessage">Seleziona la tua esportazione <i>LoyaltyCardKeychain.csv</i> da Loyalty Card Keychain per importarla.
\nOppure createlo dal menù Importazione/Esportazione in Loyalty Card Keychain premendo prima su Esporta.</string>
\nCreatelo dal menù Importazione/Esportazione in Loyalty Card Keychain premendo prima su Esporta.</string>
<string name="importLoyaltyCardKeychain">Importa da Loyalty Card Keychain</string>
<string name="importFidmeMessage">Seleziona la tua esportazione <i>fidme-export-request-xxxxxx.zip</i> da FidMe per importare, e seleziona i tipi di codice a barre manualmente dopo.
\nOppure crearlo dal tuo profilo FidMe scegliendo Protezione Dati e poi premendo Estrai i miei dati prima.</string>
\nCrearlo dal tuo profilo FidMe scegliendo Protezione Dati e poi premendo Estrai i miei dati prima.</string>
<string name="importFidme">Importa da FidMe</string>
<string name="importCatimaMessage">Seleziona la tua esportazione <i>catima.zip</i> da Catima per importarla.
\nOppure crealo dal menù Importazione/Esportazione di un\'altra applicazione Catima premendo prima Esporta.</string>
\nCrealo dal menù Importazione/Esportazione di un\'altra applicazione Catima premendo prima Esporta.</string>
<string name="importCatima">Importa da Catima</string>
<string name="setBarcodeId">Imposta il valore del codice a barre</string>
<string name="sameAsCardId">Uguale all\'ID della carta</string>
@@ -138,7 +138,7 @@
<string name="wrongValueForBarcodeType">Il valore non è valido per il tipo di codice a barre selezionato</string>
<string name="app_resources">Risorse libre di terze parti: <xliff:g id="app_resources_list"> %s </xliff:g></string>
<string name="app_libraries">Librerie libre di terze parti: <xliff:g id="app_libraries_list"> %s </xliff:g></string>
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019<xliff:g>%d</xliff:g> Sylvia van Os.</string>
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019<xliff:g>%d</xliff:g> Sylvia van Os</string>
<string name="intent_import_card_from_url_share_multiple_text">Voglio condividere alcune carte con te</string>
<string name="copy_to_clipboard_multiple_toast">Numeri delle carte copiati negli appunti</string>
<string name="card_ids_copied">Numero/i della carta copiato/i</string>
@@ -155,7 +155,7 @@
<string name="frontImageDescription">Immagine frontale della carta</string>
<string name="passwordRequired">Si prega di inserire la password</string>
<string name="importStocardMessage">Seleziona la tua esportazione <i>***-sync.zip</i> da Stocard per importare.
\nOppure ottenerlo inviando un\'e-mail a support@stocardapp.com chiedendo un\'esportazione dei tuoi dati.</string>
\nOttienilo inviando un\'e-mail a support@stocardapp.com chiedendo un\'esportazione dei tuoi dati.</string>
<string name="importStocard">Importa da Stocard</string>
<string name="turn_flashlight_off">Spegni la torcia</string>
<string name="turn_flashlight_on">Accendi la torcia</string>
@@ -198,4 +198,16 @@
<string name="sort_by_most_recently_used">Usate più di recente</string>
<string name="sort_by_name">Nome</string>
<string name="sort">Ordina</string>
<string name="license">Licenza</string>
<string name="source_repository">Repository fonti</string>
<string name="on_github">su GitHub</string>
<string name="exportPasswordHint">Inserisci la password</string>
<string name="on_google_play">su Google Play</string>
<string name="exportPassword">Imposta una password per proteggere la tua esportazione (opzionale)</string>
<string name="version_history">Cronologia delle versioni</string>
<string name="credits">Crediti</string>
<string name="help_translate_this_app">Aiuta a tradurre questa app</string>
<string name="and_data_usage">e utilizzo dei dati</string>
<string name="rate_this_app">Valuta questa applicazione</string>
<string name="report_error">Segnala un errore</string>
</resources>

View File

@@ -76,10 +76,10 @@
<string name="app_revision_fmt">Revision Info: <xliff:g id="app_revision_url">%s</xliff:g></string>
<string name="debug_version_fmt">Version: <xliff:g id="version">%s</xliff:g></string>
<string name="about_title_fmt">About <xliff:g id="app_name">%s</xliff:g></string>
<string name="app_license">Copylefted libre software, licensed GPLv3+.</string>
<string name="app_license">Copylefted libre software, licensed GPLv3+</string>
<string name="app_copyright_old">Based on Loyalty Card Keychain
\ncopyright © 20162020 Branden Archer.</string>
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019<xliff:g>%d</xliff:g> Sylvia van Os.</string>
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019<xliff:g>%d</xliff:g> Sylvia van Os</string>
<string name="app_resources">Libre third-party resources: <xliff:g id="app_resources_list">%s</xliff:g></string>
<string name="about">Catimaについて</string>
<string name="importOptionApplicationButton">外部のアプリを使う</string>
@@ -95,7 +95,7 @@
<string name="exportFailed">カードをエクスポートできませんでした</string>
<string name="exportFailedTitle">エクスポートに失敗しました</string>
<string name="exportSuccessfulTitle">エクスポートしました</string>
<string name="sameAsCardId">カードの表記と同一</string>
<string name="sameAsCardId">カード番号に合わせる</string>
<string name="barcodeId">バーコード番号</string>
<string name="importVoucherVaultMessage">Voucher Vaultでエクスポートした <i>vouchervault.json</i>ファイルを選択してください。
\nファイルがない場合、Voucher Vaultでファイルをエクスポートしてください。</string>
@@ -152,10 +152,10 @@
<string name="takePhoto">写真を撮影する</string>
<string name="removeImage">画像を削除</string>
<string name="setBackImage">裏面の画像を設定</string>
<string name="setFrontImage">面の画像を設定</string>
<string name="setFrontImage">オモテ面の画像を設定</string>
<string name="photos">フォト</string>
<string name="backImageDescription">裏面</string>
<string name="frontImageDescription"></string>
<string name="backImageDescription">カードの裏面</string>
<string name="frontImageDescription">カードのオモテ</string>
<string name="importStocardMessage">Stocardでエクスポートした<i>***-sync.zip</i>ファイルを選択してください。
\nファイルがない場合、e-mailing support@stocardapp.comにデータのエクスポートを要求してください。</string>
<string name="importStocard">Stocardからインポート</string>
@@ -183,7 +183,7 @@
<string name="settings_pink_theme">Pink</string>
<string name="settings_catima_theme">Catima</string>
<string name="settings_theme_color">テーマカラー</string>
<string name="settings_system_locale">システム</string>
<string name="settings_system_locale">システムに従う</string>
<string name="settings_locale">言語</string>
<string name="noGroupCards">このグループにはカードがありません</string>
<string name="swipeToSwitchImages">画像を切り替えるには長押し、またはスワイプ</string>
@@ -192,5 +192,18 @@
<string name="sort_by_expiry">期限</string>
<string name="sort_by_most_recently_used">最近使用したカード</string>
<string name="sort_by_name">名前</string>
<string name="sort">ソート</string>
<string name="sort">並び替え</string>
<string name="rate_this_app">このアプリを評価する</string>
<string name="on_github">GitHub</string>
<string name="source_repository">ソースリポジトリ</string>
<string name="exportPassword">パスワードを設定してエクスポートしたファイルを保護する(任意)</string>
<string name="exportPasswordHint">パスワードを入力してください</string>
<string name="version_history">更新履歴</string>
<string name="credits">貢献者</string>
<string name="help_translate_this_app">このアプリの翻訳を手伝う</string>
<string name="license">ライセンス</string>
<string name="on_google_play">Google Play</string>
<string name="report_error">エラーを報告する</string>
<string name="reverse">逆順</string>
<string name="and_data_usage">and data usage</string>
</resources>

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="deleteTitle">Kaart läschen</string>
<string name="action_search">Sichen</string>
<string name="action_add">Derbäisetzen</string>
<string name="noBarcode">Kee barcode</string>
<string name="star">An meng Favoriten bäisetzen</string>
<string name="unstar">Aus Favoriten ewechhuelen</string>
<string name="cancel">Stornieren</string>
<string name="save">Späicheren</string>
<string name="edit">Änneren</string>
<string name="delete">Läschen</string>
<string name="confirm">Bestätegen</string>
<string name="lockScreen">Blockrotation</string>
<string name="unlockScreen">Déblockéieren Rotatioun</string>
<string name="deleteConfirmation">Dës Kaart dauerhaft läschen\?</string>
<string name="ok">Okay</string>
<string name="share">Aktie</string>
<string name="sendLabel">Schécken…</string>
<string name="editCardTitle">Kaart änneren</string>
<string name="addCardTitle">Kaart derbäisetzen</string>
<string name="cardShortcut">Kaart Bréck</string>
<string name="exportSuccessfulTitle">Exportéieren</string>
<string name="exportFailedTitle">Export fehlgeschlagen</string>
<string name="exportFailed">Kaarten konnten net exportéiert ginn</string>
<string name="importing">Importéieren…</string>
<string name="importOptionFilesystemTitle">Import aus dem Dateisystem</string>
<string name="importOptionFilesystemExplanation">Wielt eng bestëmmte Datei aus dem Dateisystem.</string>
<string name="importOptionFilesystemButton">Aus dem Dateisystem</string>
<string name="importOptionApplicationTitle">Benotzt eng aner app</string>
<string name="importOptionApplicationButton">Benotzt eng aner app</string>
<string name="app_license">Ënner Copyleft stehende fräi software, lizenséiert GPLv3+</string>
<string name="groups">Gruppen</string>
<string name="importCatima">Import aus Catima</string>
<string name="importFidme">Import aus FidMe</string>
<string name="importVoucherVault">Import aus Voucher Vault</string>
<string name="barcodeId">Barcode-Wäert</string>
<string name="sameAsCardId">Déiselwecht wéi kaart ID</string>
<string name="frontImageDescription">Vorderes Bild vun der Kaart</string>
<string name="backImageDescription">D \' hënnescht Bild vun der Kaart</string>
<string name="photos">Fotoen</string>
<string name="setFrontImage">Vorderes Bild einstellen</string>
<string name="setBackImage">Bild zerécksetzen</string>
<string name="removeImage">Bild ewechhuelen</string>
<string name="takePhoto">Mach eng Foto</string>
<string name="no">Neen</string>
<string name="exportPassword">Leeë Si e Passwuert fir de Schutz vun Hirem Exports fest (optional)</string>
<string name="exportPasswordHint">Passwuert aginn</string>
<string name="noMatchingGiftCards">Ech hunn näischt fonnt. Probéieren Iech, Är Sich ze änneren.</string>
<string name="note">Beuechten</string>
<string name="barcodeNoBarcode">Dës Kaart huet kee Barcode</string>
<string name="importExportHelp">Wann Dir Är Kaarten sécheren, kënnen Si se op een anert Instrument réckelen.</string>
<string name="about">Iwwer</string>
<string name="selectBarcodeTitle">Wielt Barcode</string>
<string name="intent_import_card_from_url_share_multiple_text">Ech wëll e puer Kaarten mat Iech deelen</string>
<string name="updateBarcodeQuestionTitle">Aktualiséiert barcode-Wäert\?</string>
<string name="intent_import_card_from_url_share_text">Ech wëll eng Kaart mat dir deelen</string>
<string name="importSuccessfulTitle">Anere sproochen</string>
<string name="unsupportedBarcodeType">Dee barcode-Typ kann net ugewise ginn. Et kann zu enger spéiderer Versioun vun der App ënnerstëtzt ginn.</string>
<string name="yes">Jo</string>
<string name="importFailedTitle">Import fehlgeschlagen</string>
<string name="importFailed">Kaarten konnten net anere sproochen ginn</string>
<string name="exporting">Ausführende…</string>
<string name="exportOptionExplanation">D \' Donnéeë ginn op eng Plaz vun Hirer Wal geschriwwen.</string>
<string name="importOptionApplicationExplanation">Benotzen Se eng beliebige App oder Hire bevorzugten Dateimanager, fir eng Datei ze opmaachen.</string>
<string name="accept">Averstane</string>
<string name="settings_display_barcode_max_brightness">Erhellen barcode-Usiicht</string>
<string name="enterBarcodeInstructions">Gitt d \' Kaarten-ID en an wielen Se entweder den Barcode-Typ ënnen oder \"Dës Kaart huet kee Barcode\".</string>
<string name="importStocard">Importéieren vun Stocard</string>
<string name="importLoyaltyCardKeychain">Import vun Loyalty Card Keychain</string>
<string name="setBarcodeId">Leeë Si barcode-Wäert</string>
<string name="wrongValueForBarcodeType">De Wäert ass fir de ausgewielt Barcode-Typ net gëllt</string>
<string name="copy_to_clipboard_multiple_toast">Kaarten-IDs an d \' Tëschentablag inspiréiere</string>
<string name="updateBarcodeQuestionText">Si hunn d \' Kaarten-ID geännert. Wëllt Dir och de Barcode aktualiséieren, fir deselwechte Wäert ze benotzen\?</string>
<string name="settings_dark_theme">Donkel</string>
<string name="settings_lock_barcode_orientation">Barcode-Ausriichtung spären</string>
<string name="settings_disable_lockscreen_while_viewing_card">Bildschierm spären verhënneren</string>
<string name="settings_light_theme">Liicht</string>
<string name="settings_max_font_size_scale">Max. Schrëftgréisst</string>
<string name="settings_keep_screen_on">Hale Si op Bildschierm</string>
<string name="importSuccessful">Kartendaten anere sproochen</string>
<string name="exportSuccessful">Exportierte Kartendaten</string>
<string name="enter_group_name">Gruppenname aginn</string>
<string name="noGroupCards">Dës Grupp ass keng Kaarten</string>
<plurals name="groupCardCount">
<item quantity="one"><xliff:g>%d</xliff:g> Kaart</item>
<item quantity="other"><xliff:g>%d</xliff:g> Netzwerkkarten</item>
</plurals>
</resources>

View File

@@ -212,4 +212,6 @@
<string name="on_google_play">Google Play</string>
<string name="help_translate_this_app">Padėkite išversti šią programėlę</string>
<string name="report_error">Pranešti apie klaidą</string>
<string name="exportPasswordHint">Įveskite slaptažodį</string>
<string name="exportPassword">Nustatykite slaptažodį, kad apsaugotumėte eksportavimą (neprivaloma)</string>
</resources>

View File

@@ -208,4 +208,6 @@
<string name="on_google_play">på Google Play</string>
<string name="report_error">Rapporter feil</string>
<string name="credits">Bidragsytere</string>
<string name="exportPassword">Sett et passord for å beskytte eksporten din (valgfritt)</string>
<string name="exportPasswordHint">Skriv inn passord</string>
</resources>

View File

@@ -208,4 +208,6 @@
<string name="help_translate_this_app">Help deze app te vertalen</string>
<string name="credits">Met dank aan</string>
<string name="version_history">Versiegeschiedenis</string>
<string name="exportPasswordHint">Voer een wachtwoord in</string>
<string name="exportPassword">Stel een wachtwoord in om je exportbestand te beveiligen (optioneel)</string>
</resources>

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_add">Acrescentar</string>
<string name="importOptionFilesystemExplanation">Escolha um ficheiro específico a partir do sistema de ficheiros.</string>
<string name="action_search">Pesquisa</string>
<string name="star">Adicionar aos favoritos</string>
<string name="noMatchingGiftCards">Não encontrei nada. Tente alterar a sua pesquisa.</string>
<string name="storeName">Nome</string>
<string name="note">Nota</string>
<string name="barcodeType">Tipo de código de barras</string>
<string name="barcodeNoBarcode">Este cartão não tem código de barras</string>
<string name="cancel">Cancelar</string>
<string name="save">Guardar</string>
<string name="edit">Edição</string>
<string name="noGiftCards">Clique no botão + + para adicionar um cartão, ou importe algum do menu ⋮ primeiro.</string>
<string name="noBarcode">Não há código de barras</string>
<string name="unstar">Retirar dos favoritos</string>
<string name="importOptionFilesystemButton">Do sistema de arquivo</string>
<string name="importOptionApplicationTitle">Use outro aplicativo</string>
<string name="importOptionApplicationExplanation">Utilize qualquer aplicação ou o seu gestor de ficheiros favorito para abrir um ficheiro.</string>
<string name="importOptionApplicationButton">Utilize outro aplicativo</string>
<string name="about">Sobre</string>
<string name="app_license">Copylefted software livre, licenciado GPLv3+</string>
<string name="addCardTitle">Adicionar Cartão</string>
<string name="lockScreen">Rotação de blocos</string>
<string name="editCardTitle">Editar Cartão</string>
<string name="unlockScreen">Desbloquear a rotação</string>
<string name="deleteTitle">Apagar cartão</string>
<string name="copy_to_clipboard">Copiar ID para prancheta</string>
<string name="sendLabel">Enviar…</string>
<plurals name="selectedCardCount">
<item quantity="one"><xliff:g>%d</xliff:g> cartão escolhido</item>
<item quantity="other"><xliff:g>%d</xliff:g> cartões seleccionados</item>
</plurals>
<string name="deleteConfirmation">Eliminar este cartão permanentemente\?</string>
<string name="share">Partilhar</string>
<string name="scanCardBarcode">Código de barras do cartão de leitura</string>
<string name="confirm">Confirme</string>
<string name="delete">Eliminar</string>
<string name="cardId">Cartão de identificação</string>
<string name="cardShortcut">Atalho do cartão</string>
<string name="noCardsMessage">Adicione primeiro um cartão</string>
<string name="noStoreError">Nenhum nome inserido</string>
<string name="noCardExistsError">Não foi encontrado cartão</string>
<string name="failedParsingImportUriError">Não foi possível analisar o URI de importação</string>
<string name="importExport">Importação/Exportação</string>
<string name="exportName">Exportação</string>
</resources>

View File

@@ -24,4 +24,79 @@
<string name="star">Adaugă la favorite</string>
<string name="noBarcode">Fără cod de bare</string>
<string name="barcodeNoBarcode">Acest card nu are cod de bare</string>
<string name="moveDown">Mutarea în jos</string>
<string name="card">Cardul</string>
<string name="settings_theme">Tema</string>
<string name="all">Toate</string>
<string name="noCardsMessage">Adăugați mai întâi o carte</string>
<string name="noCardExistsError">Nu a putut găsi cardul</string>
<string name="failedParsingImportUriError">Nu s-a putut analiza URI-ul de import</string>
<string name="importExport">Importație/Export</string>
<string name="exportName">Exportați</string>
<string name="importSuccessfulTitle">Importat</string>
<string name="importFailedTitle">Importul a eșuat</string>
<string name="importFailed">Nu s-a putut importa carduri</string>
<string name="noCardIdError">Nu s-a introdus niciun ID de card</string>
<string name="exportFailed">Nu s-a putut exporta carduri</string>
<string name="importing">Importul…</string>
<string name="exporting">Exportul…</string>
<string name="noExternalStoragePermissionError">Acordați mai întâi permisiunea de stocare externă pentru a importa sau exporta carduri</string>
<string name="exportOptionExplanation">Datele vor fi scrise într-o locație aleasă de dumneavoastră.</string>
<string name="importOptionFilesystemTitle">Import din sistemul de fișiere</string>
<string name="importOptionApplicationTitle">Utilizați o altă aplicație</string>
<string name="starImage">Steaua preferată</string>
<string name="settings">Setări</string>
<string name="settings_category_title_ui">Interfață utilizator</string>
<string name="intent_import_card_from_url_share_text">Vreau să împărtășesc o carte cu tine</string>
<string name="moveUp">Mutarea în sus</string>
<string name="editCardTitle">Editare card</string>
<string name="addCardTitle">Adaugă card</string>
<string name="importOptionFilesystemButton">Din sistemul de fișiere</string>
<string name="importOptionApplicationExplanation">Utilizați orice aplicație sau managerul de fișiere preferat pentru a deschide un fișier.</string>
<string name="about">Despre</string>
<string name="app_license">Software liber cu copyleft, licențiat GPLv3+</string>
<string name="enterBarcodeInstructions">Introduceți ID-ul cardului și alegeți fie tipul de cod de bare de mai jos, fie \"Acest card nu are cod de bare\".</string>
<string name="settings_system_theme">Sistemul</string>
<string name="settings_light_theme">Lumină</string>
<string name="settings_dark_theme">Întuneric</string>
<string name="noBarcodeFound">Nu a fost găsit niciun cod de bare</string>
<string name="settings_max_font_size_scale">Mărimea maximă a fontului</string>
<string name="settings_display_barcode_max_brightness">Luminați vizualizarea codurilor de bare</string>
<string name="settings_lock_barcode_orientation">Blocare orientare cod de bare</string>
<string name="settings_keep_screen_on">Păstrați ecranul pornit</string>
<string name="settings_disable_lockscreen_while_viewing_card">Evitați ecranul de blocare</string>
<string name="balance">Balanță</string>
<string name="importSuccessful">Date de card importate</string>
<string name="exportSuccessful">Datele cardului exportate</string>
<string name="noGroups">Faceți clic pe butonul + plus pentru a adăuga mai întâi grupuri pentru clasificare.</string>
<string name="deleteConfirmationGroup">Ștergeți grupul\?</string>
<string name="failedOpeningFileManager">Instalați mai întâi un manager de fișiere.</string>
<string name="leaveWithoutSaveTitle">Ieșire</string>
<string name="addManually">Introduceți manual ID-ul cardului</string>
<string name="barcode">Cod de bare</string>
<string name="currency">Monedă</string>
<string name="editBarcode">Editarea codului de bare</string>
<string name="chooseExpiryDate">Alegeți data de expirare</string>
<string name="moveBarcodeToCenterOfScreen">Centrați codul de bare pe ecran</string>
<string name="copy_to_clipboard_toast">ID-ul cardului copiat în clipboard</string>
<string name="noStoreError">Nici un nume introdus</string>
<string name="selectBarcodeTitle">Selectare cod de bare</string>
<string name="noGroupCards">Acest grup nu conține nicio carte</string>
<string name="addFromImage">Selectați imaginea din galerie</string>
<string name="never">Niciodată</string>
<string name="groups">Grupuri</string>
<string name="leaveWithoutSaveConfirmation">Să pleci fără să salvezi\?</string>
<string name="expiryDate">Data expirării</string>
<string name="moveBarcodeToTopOfScreen">Mutați codul de bare în partea de sus a ecranului</string>
<string name="errorReadingImage">Nu s-a putut citi imaginea</string>
<string name="points">Puncte</string>
<string name="cardShortcut">Scurtătură de card</string>
<string name="scanCardBarcode">Scanarea codului de bare al cardului</string>
<string name="importExportHelp">Copierea de rezervă a cardurilor vă permite să le mutați pe un alt dispozitiv.</string>
<string name="exportSuccessfulTitle">Exportată</string>
<string name="exportFailedTitle">Export eșuat</string>
<string name="importOptionFilesystemExplanation">Alegeți un anumit fișier din sistemul de fișiere.</string>
<string name="importOptionApplicationButton">Utilizați o altă aplicație</string>
<string name="thumbnailDescription">Miniatură pentru card</string>
<string name="enter_group_name">Introduceți numele grupului</string>
</resources>

View File

@@ -54,7 +54,7 @@
<string name="debug_version_fmt">Версия: <xliff:g id="version">%s</xliff:g></string>
<string name="app_revision_fmt">Информация о версиях: <xliff:g id="app_revision_url">%s</xliff:g></string>
<string name="selectBarcodeTitle">Выбор штрих-кода</string>
<string name="enterBarcodeInstructions">Введите номер карты и выберите тип штрих-кода. Или выберите \"Эта карта без штрих-кода\".</string>
<string name="enterBarcodeInstructions">Введите номер карты и выберите тип штрих-кодали выберите \"Эта карта без штрих-кода\").</string>
<string name="copy_to_clipboard_toast">Номер карты скопирован в буфер обмена</string>
<string name="thumbnailDescription">Логотип карты</string>
<string name="settings">Настройки</string>
@@ -216,4 +216,6 @@
<string name="source_repository">Исходный код</string>
<string name="license">Лицензия</string>
<string name="help_translate_this_app">Помощь в переводе приложения</string>
<string name="exportPassword">Защитить файл экспорта паролем (необязательно)</string>
<string name="exportPasswordHint">Введите пароль</string>
</resources>

View File

@@ -25,7 +25,7 @@
<string name="noCardExistsError">Te kartice zvestobe ni bilo moč najti</string>
<string name="importExport">Uvozi/izvozi</string>
<string name="exportName">Izvozi</string>
<string name="importExportHelp">Varnostna kopija omogoča varen prenos kartic na druge telefonske naprave.</string>
<string name="importExportHelp">Varnostna kopija omogoča varen prenos kartic na druge naprave.</string>
<string name="importSuccessfulTitle">Uvoz je bil uspešen</string>
<string name="importFailedTitle">Uvoz ni uspel</string>
<string name="importFailed">Napaka pri uvozu</string>
@@ -39,7 +39,7 @@
<string name="importOptionFilesystemExplanation">Izberite specifično datoteko iz datotečnega sistema.</string>
<string name="importOptionFilesystemButton">Iz datotečnega sistema</string>
<string name="importOptionApplicationTitle">Uporabi zunanjo aplikacijo</string>
<string name="importOptionApplicationExplanation">Uporabi zunanjo aplikacijo, kot npr. Dropbox, Google Drive ali ostale upravljalnike datotek, za odpiranje datoteko.</string>
<string name="importOptionApplicationExplanation">Uporabi zunanjo aplikacijo, kot npr. Dropbox, Google Drive ali ostale upravljalnike datotek, za odpiranje datoteke.</string>
<string name="importOptionApplicationButton">Uporabi zunanjo aplikacijo</string>
<string name="about">Več o aplikaciji</string>
<string name="app_license">Licencirano s skladu z GPLv3.</string>
@@ -57,7 +57,7 @@
<string name="deleteConfirmation">Prosim potrdite, če želite izbrisati to kartico\?</string>
<string name="card">Kartica</string>
<string name="addFromImage">Izberite sliko iz galerije</string>
<string name="addManually">Ročno vnesite ID kartice</string>
<string name="addManually">Ročno vnesite št. kartice</string>
<string name="leaveWithoutSaveConfirmation">Zapustite brez shranjevanja\?</string>
<string name="leaveWithoutSaveTitle">Izhod</string>
<string name="moveDown">Premikanje navzdol</string>
@@ -71,18 +71,17 @@
<string name="enter_group_name">Vnesite ime skupine</string>
<string name="exportSuccessful">Izvoženi podatki o karticah</string>
<string name="importSuccessful">Uvoženi podatki o karticah</string>
<string name="intent_import_card_from_url_share_text">Želim z vami deliti kartico</string>
<string name="intent_import_card_from_url_share_text">Z vami želim deliti kartico</string>
<string name="settings_disable_lockscreen_while_viewing_card">Preprečitev zaklepanja zaslona</string>
<string name="settings_keep_screen_on">Ohranite zaslon vklopljen</string>
<string name="enterBarcodeInstructions">Vnesite ID kartice in spodaj izberite vrsto črtne kode ali \"Ta kartica nima črtne kode\".</string>
<string name="settings_max_font_size_scale">Največja velikost pisave</string>
<string name="settings_dark_theme">Temno</string>
<string name="settings_light_theme">Luč</string>
<string name="settings_light_theme">Svetlo</string>
<string name="settings_system_theme">Sistem</string>
<string name="settings_theme">Tema</string>
<string name="starImage">Najljubša zvezda</string>
<string name="app_copyright_old">Na podlagi kartice zvestobe obesek za ključe
\ncopyright © 2016-2020 Branden Archer.</string>
<string name="starImage">Zvezdica za priljubljene</string>
<string name="app_copyright_old">Na podlagi aplikacije Loyalty Card Keychain copyright © 2016-2020 Branden Archer.</string>
<string name="exportOptionExplanation">Podatki bodo zapisani na izbrano mesto.</string>
<string name="failedParsingImportUriError">Ni bilo mogoče razčleniti URI uvoza</string>
<string name="card_ids_copied">Kopirana kartica ID(s)</string>
@@ -94,4 +93,72 @@
<string name="barcodeType">Vrsta črtne kode</string>
<string name="noMatchingGiftCards">Ničesar nisem našel. Poskusite spremeniti iskanje.</string>
<string name="action_search">Iskanje</string>
<string name="exportPasswordHint">Vnesite geslo</string>
<string name="exportPassword">Izberite geslo za zaščito izvoza (neobvezno)</string>
<string name="help_translate_this_app">Pomagajte pri prevajanju aplikacije</string>
<string name="version_history">Zgodovina različic</string>
<string name="settings_brown_theme">Rjava</string>
<string name="settings_grey_theme">Siva</string>
<string name="settings_green_theme">Zelena</string>
<string name="settings_sky_blue_theme">Sinje modra</string>
<string name="settings_blue_theme">Modra</string>
<string name="settings_violet_theme">Vijolična</string>
<string name="settings_magenta_theme">Magenta</string>
<string name="settings_pink_theme">Roza</string>
<string name="settings_theme_color">Barva teme</string>
<string name="settings_system_locale">Sistem</string>
<string name="settings_locale">Jezik</string>
<string name="barcodeImageDescriptionWithType">Slika črtne kode tipa <xliff:g>%s</xliff:g></string>
<string name="swipeToSwitchImages">Povlecite ali dolgo pritisnite da zamenjate slike</string>
<string name="sort_by">Razvrsti po</string>
<string name="reverse">Obratno</string>
<string name="sort_by_balance">Stanje</string>
<string name="sort_by_expiry">Potek</string>
<string name="sort_by_most_recently_used">Nazadnje uporabljene</string>
<string name="sort_by_name">Ime</string>
<string name="sort">Razvrsti</string>
<string name="license">Licence</string>
<string name="on_github">na GitHubu</string>
<string name="rate_this_app">Ocenite aplikacijo</string>
<string name="report_error">Prijavite napako</string>
<string name="on_google_play">na Trgovini Google Play</string>
<string name="and_data_usage">in uporaba podatkov</string>
<string name="source_repository">Izvorna koda</string>
<string name="points">Točke</string>
<string name="currency">Valuta</string>
<string name="balance">Stanje na računu</string>
<string name="errorReadingImage">Slike ni bilo mogoče prebrati</string>
<string name="noBarcodeFound">Črtna koda ni bila najdena</string>
<string name="balancePoints"><xliff:g>%s</xliff:g> točk</string>
<string name="balanceSentence">Stanje: <xliff:g>%s</xliff:g></string>
<string name="chooseImportType">Uvoz iz?</string>
<string name="importCatima">Izvoz iz aplikacije Catima</string>
<string name="importStocard">Izvoz iz aplikacije Stocard</string>
<string name="importVoucherVault">Izvoz iz aplikacije Voucher Vault</string>
<string name="privacy_policy">Politika zasebnosti</string>
<string name="turn_flashlight_off">Izklop svetilke</string>
<string name="turn_flashlight_on">Vklop svetilke</string>
<string name="passwordRequired">Vnesite geslo</string>
<string name="accept">Sprejmi</string>
<string name="importLoyaltyCardKeychain">Uvoz iz aplikacije Loyalty Card Keychain</string>
<string name="barcodeId">Vsebina črtne kode</string>
<string name="sameAsCardId">Enaka kot številka kartice</string>
<string name="setBarcodeId">Nastavi vsebino črtne kode</string>
<string name="wrongValueForBarcodeType">Ta vrednost ni veljavna pri izbranem tipu čtne kode</string>
<string name="takePhoto">Naredi fotografijo</string>
<string name="intent_import_card_from_url_share_multiple_text">Z vami želim deliti kartice zvestobe</string>
<string name="copy_to_clipboard_multiple_toast">Številke kartic kopirane v odložišče</string>
<string name="importFidme">Uvoz iz aplikacije FidMe</string>
<string name="no">Ne</string>
<string name="yes">Da</string>
<string name="frontImageDescription">Slika sprednje strani</string>
<string name="backImageDescription">Slika zadnje strani</string>
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> ni veljavno stanje.</string>
<string name="setBackImage">Nastavi sliko sprednje strani</string>
<string name="setFrontImage">Nastavi sliko sprednje strani</string>
<string name="photos">Fotografije</string>
<string name="updateBarcodeQuestionText">Spremenili ste številko kartice. Želite posodobiti tudi črtno kodo na enako vrednost?</string>
<string name="updateBarcodeQuestionTitle">Posodobi črtno kodo?</string>
<string name="removeImage">Odstrani sliko</string>
<string name="unsupportedBarcodeType">Te vrste črtne kode aplikacija ne more prikazati. Morda bo to možno v prihodnosti.</string>
</resources>

View File

@@ -5,8 +5,8 @@
<string name="settings_max_font_size_scale">Max. teckenstorlek</string>
<string name="settings_keep_screen_on">Håll skärmen påslagen</string>
<string name="enterBarcodeInstructions">Ange kortets ID och välj antingen streckkodstyp nedan, eller \"Detta kort har ingen streckkod\".</string>
<string name="importFidmeMessage">Välj den exporterade <i>fidme-export-request-xxxxxx.zip</i> från FidMe som du vill importera och välj streckkodstyper manuellt efteråt,
\neller skapa en från din FidMe-profil först genom att välja \"Data Protection\" och sen trycka på \"Extract my data\".</string>
<string name="importFidmeMessage">Välj den exporterade <i>fidme-export-request-xxxxxx.zip</i> från FidMe som du vill importera och välj streckkodstyper manuellt efteråt.
\nSkapa den från din FidMe-profil först genom att välja \"Data Protection\" och sen trycka på \"Extract my data\".</string>
<string name="importOptionApplicationExplanation">Använd vilken app som helst eller den filhanterare du föredrar för att öppna en fil.</string>
<string name="importOptionApplicationButton">Använd en annan app</string>
<string name="intent_import_card_from_url_share_text">Jag vill dela ett kort med dig</string>
@@ -21,12 +21,12 @@
<item quantity="other"><xliff:g>%d</xliff:g> kort valda</item>
</plurals>
<string name="app_loyalty_card_keychain">Loyalty Card Keychain</string>
<string name="importLoyaltyCardKeychainMessage">Välj den exporterade <i>LoyaltyCardKeychain.csv</i> från Loyalty Card Keychain som du vill importera,
\neller skapa en från Import/Export-menyn i Loyalty Card Keychain först genom att trycka på Exportera.</string>
<string name="importVoucherVaultMessage">Välj den exporterade <i>vouchervault.json</i> från Voucher Vault som du vill importera,
\neller skapa en först genom att trycka på Exportera i Voucher Vault.</string>
<string name="importStocardMessage">Välj den exporterade <i>***-sync.zip</i> från Stocard som du vill importera,
\neller skaffa en först genom att skicka e-post till support@stocardapp.com och be om att få dina data exporterade.</string>
<string name="importLoyaltyCardKeychainMessage">Välj den exporterade <i>LoyaltyCardKeychain.csv</i> från Loyalty Card Keychain som du vill importera.
\nSkapa den från Import/Export-menyn i Loyalty Card Keychain först genom att trycka på Exportera.</string>
<string name="importVoucherVaultMessage">Välj den exporterade <i>vouchervault.json</i> från Voucher Vault som du vill importera.
\nSkapa den först genom att trycka på Exportera i Voucher Vault.</string>
<string name="importStocardMessage">Välj den exporterade <i>***-sync.zip</i> från Stocard som du vill importera.
\nSkaffa den först genom att skicka e-post till support@stocardapp.com och be om att få dina data exporterade.</string>
<string name="enter_group_name">Ange gruppnamn</string>
<string name="groups">Grupper</string>
<plurals name="groupCardCount">
@@ -90,8 +90,8 @@
<string name="debug_version_fmt">Version: <xliff:g id="version">%s</xliff:g></string>
<string name="about_title_fmt">Om <xliff:g id="app_name">%s</xliff:g></string>
<string name="app_copyright_old">Baserad på Loyalty Card Keychain
\ncopyright © 20162020 Branden Archer.</string>
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019<xliff:g>%d</xliff:g> Sylvia van Os.</string>
\ncopyright © 20162020 Branden Archer</string>
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019<xliff:g>%d</xliff:g> Sylvia van Os</string>
<string name="about">Om</string>
<string name="importOptionApplicationTitle">Använd en annan app</string>
<string name="importOptionFilesystemButton">Från filsystemet</string>
@@ -158,7 +158,7 @@
<string name="chooseExpiryDate">Välj förfallodatum</string>
<string name="expiryDate">Förfallodatum</string>
<string name="starImage">Favoritstjärna</string>
<string name="app_license">Copyleftad fri programvara, under GPLv3+-licens.</string>
<string name="app_license">Copyleftad fri programvara, under GPLv3+-licens</string>
<string name="app_resources">Fria tredjepartsresurser: <xliff:g id="app_resources_list">%s</xliff:g></string>
<string name="app_libraries">Fria tredjepartsbibliotek: <xliff:g id="app_libraries_list">%s</xliff:g></string>
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> verkar inte vara ett giltigt saldo.</string>
@@ -166,8 +166,8 @@
<string name="balanceSentence">Saldo: <xliff:g>%s</xliff:g></string>
<string name="settings_disable_lockscreen_while_viewing_card">Förhindra skärmlåsning</string>
<string name="lockScreen">Förhindra rotation</string>
<string name="importCatimaMessage">Välj den exporterade <i>catima.zip</i> från Catima som du vill importera,
\neller skapa en från Import/Export-menyn i en annan Catima-app genom att trycka på Exportera där först.</string>
<string name="importCatimaMessage">Välj den exporterade <i>catima.zip</i> från Catima som du vill importera.
\nSkapa den från Import/Export-menyn i en annan Catima-app genom att trycka på Exportera där först.</string>
<string name="expiryStateSentence">Giltigt till: <xliff:g>%s</xliff:g></string>
<string name="exportSuccessful">Kortdata exporterad</string>
<string name="importSuccessful">Kortdata importerad</string>
@@ -198,4 +198,12 @@
<string name="sort_by_most_recently_used">Senast använda</string>
<string name="sort_by_name">Namn</string>
<string name="sort">Sortera</string>
<string name="license">Licens</string>
<string name="and_data_usage">och dataanvändning</string>
<string name="rate_this_app">Betygsätt den här appen</string>
<string name="on_google_play">på Google Play</string>
<string name="report_error">Rapportera ett fel</string>
<string name="version_history">Versionshistorik</string>
<string name="help_translate_this_app">Hjälp till med översättningen av appen</string>
<string name="on_github">på GitHub</string>
</resources>

View File

@@ -208,4 +208,6 @@
<string name="help_translate_this_app">Bu uygulamayı çevirmeye yardımcı olun</string>
<string name="credits">Emeği Geçenler</string>
<string name="version_history">Sürüm Geçmişi</string>
<string name="exportPassword">Dışa aktarmanızı korumak için bir parola belirleyin (isteğe bağlı)</string>
<string name="exportPasswordHint">Parola girin</string>
</resources>

View File

@@ -50,7 +50,7 @@
<string name="noBarcodeFound">Жодного штрих-коду не знайдено</string>
<string name="moveBarcodeToCenterOfScreen">Відцентрувати штрих-код на екрані</string>
<string name="moveBarcodeToTopOfScreen">Посунути штрих-код наверх екрану</string>
<string name="chooseExpiryDate">Оберіть дату закінчення терміну дії</string>
<string name="chooseExpiryDate">Оберіть дату</string>
<string name="never">Ніколи</string>
<string name="expiryDate">Дата закінчення терміну дії</string>
<string name="editBarcode">Редагувати штрих-код</string>
@@ -101,7 +101,7 @@
\nавторські права © 20162020 Branden Archer</string>
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Авторські права © 2019<xliff:g>%d</xliff:g> Sylvia van Os</string>
<string name="about">Про програму</string>
<string name="importOptionApplicationButton">Використайте іншу програму</string>
<string name="importOptionApplicationButton">Вибір програми</string>
<string name="importOptionApplicationExplanation">Використайте іншу програму чи ваш улюблений файл-менеджер для відкриття файлу.</string>
<string name="importOptionApplicationTitle">З іншої програми</string>
<string name="importOptionFilesystemButton">Обрати файл</string>
@@ -216,4 +216,6 @@
<string name="rate_this_app">Оцінити програму</string>
<string name="on_google_play">у Google Play</string>
<string name="report_error">Повідомити про помилку</string>
<string name="exportPassword">Встановіть пароль для захисту експорту (необов\'язково)</string>
<string name="exportPasswordHint">Введіть пароль</string>
</resources>

View File

@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" xmlns:tools="http://schemas.android.com/tools">
<string name="app_revision_url">https://github.com/TheLastProject/Catima/releases</string>
<string name="action_search">搜尋</string>
<string name="action_add">新增</string>
<string name="noGiftCards">點選 + 按鈕以新增卡片\n或從 ⋮ 選單中匯入卡片</string>
<string name="noMatchingGiftCards">沒有找到任何東西。試試其他關鍵字。</string>
<string name="storeName">名稱</string>
<string name="note">註記</string>
<string name="cardId">卡片 ID</string>
<string name="barcodeType">條碼種類</string>
<string name="barcodeNoBarcode">此卡片沒有可用的條碼</string>
<string name="noBarcode">無條碼</string>
<string name="privacy_policy_popup_text">隱私權政策(某些應用程式商店需要此條目): 我們並不會收集任何資料!任何人都可以檢視我們的原始碼並驗證這點。</string>
<string name="star">新增至收藏</string>
<string name="app_license">公共版權 (Copylefted) 的自由軟體,許可 GPLv3+</string>
<string name="unstar">從收藏中移除</string>
<string name="cancel">取消</string>
<string name="save">儲存</string>
<string name="edit">編輯</string>
<string name="delete">刪除</string>
<string name="confirm">確認</string>
<string name="about">關於</string>
<string name="about_title_fmt">關於 <xliff:g id="app_name">%s</xliff:g></string>
<string name="accept">接受</string>
<string name="addCardTitle">新增卡片</string>
<string name="addFromImage">從圖庫中選擇圖片</string>
<string name="addManually">手動輸入卡片 ID</string>
<string name="all">全部</string>
<string name="balance">餘額</string>
<string name="balanceSentence">餘額: <xliff:g>%s</xliff:g></string>
<string name="balancePoints"><xliff:g>%s</xliff:g></string>
<string name="app_copyright_old">基於 Loyalty Card Keychain\n著作權所有 © 20162020 Branden Archer</string>
<string name="barcode">條碼</string>
<string name="barcodeId">條碼內容</string>
<string name="barcodeImageDescriptionWithType">條碼種類 <xliff:g>%s</xliff:g> 的圖片</string>
<string name="card">卡片</string>
<string name="card_ids_copied">已複製卡片 ID(s)</string>
<string name="cardShortcut">卡片捷徑</string>
<string name="chooseExpiryDate">選擇逾期日期</string>
<string name="chooseImportType">從哪裡匯入資料?</string>
<string name="copy_to_clipboard">已複製 ID 至剪貼簿中</string>
<string name="copy_to_clipboard_multiple_toast">已複製多個卡片 ID 至剪貼簿中</string>
<string name="copy_to_clipboard_toast">已複製卡片 ID 至剪貼簿中</string>
<string name="credits">貢獻者</string>
<string name="currency">幣別</string>
<string name="debug_version_fmt">版本:<xliff:g id="version">%s</xliff:g></string>
<string name="deleteConfirmation">永久刪除此卡片?</string>
<string name="deleteConfirmationGroup">刪除此群組?</string>
<string name="deleteTitle">刪除卡片</string>
<string name="editBarcode">編輯條碼</string>
<string name="editCardTitle">編輯圖片</string>
<string name="enter_group_name">輸入群組名稱</string>
<string name="enterBarcodeInstructions">輸入卡片 ID、選擇條碼種類、或選擇「此卡片沒有可用的條碼」。</string>
<string name="errorReadingImage">無法讀取此圖片</string>
<string name="expiryDate">逾期日期</string>
<string name="expiryStateSentence">逾期於:<xliff:g>%s</xliff:g></string>
<string name="expiryStateSentenceExpired">已逾期:<xliff:g>%s</xliff:g></string>
<string name="exportFailed">無法匯出卡片</string>
<string name="exportFailedTitle">匯出失敗</string>
<string name="exporting">匯出中…</string>
<string name="exportName">匯出</string>
<string name="exportOptionExplanation">資料將寫至您所選的位置。</string>
<string name="exportPassword">透過密碼保護您的匯出檔 (選用)</string>
<string name="exportPasswordHint">輸入密碼</string>
<string name="exportSuccessful">已匯出卡片資訊</string>
<string name="exportSuccessfulTitle">已匯出</string>
<string name="failedOpeningFileManager">請先安裝檔案管理員。</string>
<string name="failedParsingImportUriError">無法讀取匯入 URI</string>
<string name="frontImageDescription">卡片 (正面)</string>
<string name="groups">群組</string>
<string name="groupsList">群組:<xliff:g>%s</xliff:g></string>
<string name="help_translate_this_app">幫助翻譯本程式</string>
<string name="importExport">匯入/匯出</string>
<string name="importFailedTitle">匯入失敗</string>
<string name="importFailed">無法匯入卡片</string>
<string name="importing">匯入中…</string>
<string name="importSuccessfulTitle">已匯入</string>
<string name="intent_import_card_from_url_share_multiple_text">我想要分享些卡片給你</string>
<string name="intent_import_card_from_url_share_text">我想要分享張卡片給你</string>
<string name="leaveWithoutSaveConfirmation">不保存就離開?</string>
<string name="leaveWithoutSaveTitle">離開</string>
<string name="license">許可</string>
<string name="never">永不</string>
<string name="no"></string>
<string name="noBarcodeFound">找不到可用的條碼</string>
<string name="noCardExistsError">無法找到卡片</string>
<string name="noCardIdError">尚未輸入卡片 ID</string>
<string name="noCardsMessage">請先新增卡片</string>
<string name="sort">排列</string>
<string name="settings_catima_theme">Catima</string>
<string name="settings_pink_theme">粉紅</string>
<string name="settings_magenta_theme">品紅</string>
<string name="settings_violet_theme">紫色</string>
<string name="settings_blue_theme">藍色</string>
<string name="settings_sky_blue_theme">天空藍</string>
<string name="settings_green_theme">綠色</string>
<string name="settings_grey_theme">灰色</string>
<string name="settings_brown_theme">棕色</string>
<string name="sort_by_name">名稱</string>
<string name="sort_by_most_recently_used">最近使用</string>
<string name="sort_by_expiry">逾期日期</string>
<string name="sort_by_balance">餘額</string>
<string name="reverse">反序</string>
<string name="sort_by">排列方式</string>
<string name="version_history">版本歷史</string>
<string name="source_repository">原始碼版本庫</string>
<string name="on_github">於 GitHub</string>
<string name="and_data_usage">及資料使用</string>
<string name="rate_this_app">替本 App 評分</string>
<string name="on_google_play">於 Google Play</string>
<string name="report_error">回報錯誤</string>
<string name="setBarcodeId">設定條碼內容</string>
<string name="sameAsCardId">與卡片 ID 相同</string>
<string name="photos">圖片</string>
<string name="setFrontImage">設定正面圖片</string>
<string name="setBackImage">設定背面圖片</string>
<string name="removeImage">移除圖片</string>
<string name="takePhoto">拍照</string>
<string name="updateBarcodeQuestionTitle">更新條碼內容?</string>
<string name="yes"></string>
<string name="passwordRequired">請輸入密碼</string>
<string name="turn_flashlight_on">開啟手電筒</string>
<string name="turn_flashlight_off">關閉手電筒</string>
<string name="settings_locale">語言</string>
<string name="settings_system_locale">系統語言</string>
<string name="settings_theme_color">主題顏色</string>
<string name="app_contributors">感謝以下貢獻者: <xliff:g id="app_contributors">%s</xliff:g></string>
<string name="privacy_policy">隱私權政策</string>
<plurals name="selectedCardCount">
<item quantity="other">已選取 <xliff:g>%d</xliff:g> 張卡片</item>
</plurals>
<plurals name="deleteCardsTitle">
<item quantity="other">刪除 <xliff:g>%d</xliff:g> 張卡片</item>
</plurals>
<plurals name="deleteCardsConfirmation">
<item quantity="other">永久刪除 <xliff:g>%d</xliff:g> 張卡片?</item>
</plurals>
<plurals name="groupCardCount">
<item quantity="other"><xliff:g>%d</xliff:g> 張卡片</item>
</plurals>
<string name="settings">設定</string>
<string name="share">分享</string>
<string name="settings_system_theme">系統主題</string>
<string name="settings_theme">主題</string>
<string name="thumbnailDescription">卡片縮圖</string>
<string name="noGroupCards">此群組中無任何卡片</string>
<string name="settings_category_title_ui">用戶界面</string>
<string name="settings_max_font_size_scale">最大字體大小</string>
<string name="settings_light_theme">淺色</string>
<string name="settings_dark_theme">深色</string>
<string name="settings_display_barcode_max_brightness">調高條碼介面螢幕亮度</string>
<string name="settings_lock_barcode_orientation">鎖定條碼螢幕方向</string>
<string name="settings_keep_screen_on">螢幕恆亮</string>
<string name="settings_disable_lockscreen_while_viewing_card">防止螢幕鎖定</string>
<string name="importSuccessful">已匯入卡片資訊</string>
<string name="moveUp">往上移動</string>
<string name="moveDown">往下移動</string>
<string name="lockScreen">禁止旋轉</string>
<string name="unlockScreen">允許旋轉</string>
<string name="ok">OK</string>
<string name="sendLabel">送出…</string>
<string name="scanCardBarcode">掃描卡片條碼</string>
<string name="noStoreError">尚未輸入卡片名稱</string>
<string name="importExportHelp">備份您的卡片以將這些卡片移至其他裝置中。</string>
<string name="noExternalStoragePermissionError">在匯入及匯出卡片前,請先允許外部儲存裝置存取權限</string>
<string name="importOptionFilesystemTitle">自檔案系統中匯入</string>
<string name="importOptionFilesystemExplanation">自檔案系統中選取檔案。</string>
<string name="importOptionFilesystemButton">自檔案系統</string>
<string name="importOptionApplicationTitle">使用其他應用程式</string>
<string name="importOptionApplicationButton">使用其他應用程式</string>
<string name="importOptionApplicationExplanation">使用任何應用程式選擇您所想要匯入的檔案。</string>
<string name="app_copyright_fmt">著作權所有 © 2019<xliff:g>%d</xliff:g> Sylvia van Os</string>
<string name="importVoucherVault">自 Voucher Vault 中匯入</string>
<string name="importVoucherVaultMessage">選取您自 Voucher Vault 匯出的 <i>vouchervault.json</i> 檔案以進行匯入。
\n請您先透過 Voucher Vault 進行匯出。</string>
<string name="importStocard">自 Stocard 中匯入</string>
<string name="importStocardMessage">>選取您自 Stocard 匯出的 <i>***-sync.zip</i> 檔案以進行匯入。
\n請您寫封 Email 至 support@stocardapp.com 索取您的資料。</string>
<string name="importLoyaltyCardKeychain">自 Loyalty Card Keychain 中匯入</string>
<string name="importLoyaltyCardKeychainMessage">選取您自 Loyalty Card Keychain <i>LoyaltyCardKeychain.csv</i> 檔案以進行匯入。
\n請您先透過 Loyalty Card Keychain 的匯入/匯出選單進行匯出。</string>
<string name="importFidme">自 FidMe 匯入</string>
<string name="importFidmeMessage">選取您自 FidMe 匯出的<i>fidme-export-request-xxxxxx.zip</i> 檔案以進行匯入,並手動選擇條碼種類。
\n請您先透過您的 FidMe 個人檔案選取『Data Protection』並選擇『Extract my data』。</string>
<string name="importCatima">自 Catima 匯入</string>
<string name="importCatimaMessage">選取您自 Catima 匯出的 <i>catima.zip</i> 檔案以進行匯入。
\n您可透過其他裝置的 Catima 程式中的匯入/匯出選單進行匯出。</string>
<string name="points"></string>
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> 似乎不是個可用的餘額數值。</string>
<string name="app_revision_fmt">修訂版本資訊:<xliff:g id="app_revision_url">%s</xliff:g></string>
<string name="app_libraries">第三方自由函示庫:<xliff:g id="app_libraries_list">%s</xliff:g></string>
<string name="app_resources">第三方自由資源:<xliff:g id="app_resources_list">%s</xliff:g></string>
<string name="selectBarcodeTitle">選擇條碼</string>
<string name="noGroups">請先點選 + 加號按鈕新增群組。</string>
<string name="moveBarcodeToTopOfScreen">將條碼移至螢幕上方</string>
<string name="moveBarcodeToCenterOfScreen">將條碼移至螢幕中央</string>
<string name="app_loyalty_card_keychain">Loyalty Card Keychain</string>
<string name="unsupportedBarcodeType">尚支援此條碼種類,但未來版本的應用程式可能會支援此條碼種類。</string>
<string name="wrongValueForBarcodeType">條碼內容不適用於此條碼種類</string>
<string name="backImageDescription">卡片 (背面)</string>
<string name="updateBarcodeQuestionText">您已更新了條碼 ID是否要更新條碼內容以匹配此 ID</string>
<string name="failedGeneratingShareURL">無法建立可分享的 URL請回報此錯誤。</string>
<string name="toggleMoreInfo">切換顯示更多內容</string>
<string name="swipeToSwitchImages">滑動或長按以切換圖片</string>
<string name="starImage">收藏標示</string>
</resources>

View File

@@ -40,15 +40,20 @@
<string-array name="locale_values">
<item />
<item>bg</item>
<item>bn-rIN</item>
<item>bs</item>
<item>cs</item>
<item>da</item>
<item>de</item>
<item>el-rGR</item>
<item>eo</item>
<item>es-rAR</item>
<item>es</item>
<item>es-rAR</item>
<item>fi</item>
<item>fr</item>
<item>he-rIL</item>
<item>hr</item>
<item>in-rID</item>
<item>it</item>
<item>ja</item>
<item>ko</item>
@@ -57,11 +62,15 @@
<item>nl</item>
<item>oc</item>
<item>pl</item>
<item>pt</item>
<item>ro-rRO</item>
<item>ru</item>
<item>sk</item>
<item>sl</item>
<item>sv</item>
<item>tr</item>
<item>uk</item>
<item>zh-TW</item>
<item>zh-rCN</item>
</string-array>
@@ -82,4 +91,4 @@
<!-- Constraints -->
<integer name="settings_max_font_size_scale_pct_min">50</integer>
<integer name="settings_max_font_size_scale_pct_max">200</integer>
</resources>
</resources>

View File

@@ -196,6 +196,8 @@
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="passwordRequired">Please enter the password</string>
<string name="exportPassword">Set a password to protect your export (optional)</string>
<string name="exportPasswordHint">Enter password</string>
<string name="failedGeneratingShareURL">Could not generate sharable URL. Please report this.</string>
<string name="turn_flashlight_on">Turn flashlight on</string>
<string name="turn_flashlight_off">Turn flashlight off</string>
@@ -243,4 +245,4 @@
<string name="rate_this_app">Rate this app</string>
<string name="on_google_play">on Google Play</string>
<string name="report_error">Report Error</string>
</resources>
</resources>

View File

@@ -2,7 +2,6 @@ package protect.card_locker;
import android.app.Activity;
import android.content.Intent;
import android.os.Looper;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
@@ -13,16 +12,19 @@ import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLooper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class BarcodeSelectorActivityTest {
@Test
public void emptyStateTest()
{
public void emptyStateTest() {
ActivityController activityController = Robolectric.buildActivity(BarcodeSelectorActivity.class).create();
activityController.start();
activityController.resume();
@@ -41,8 +43,7 @@ public class BarcodeSelectorActivityTest {
}
@Test
public void nonEmptyStateTest() throws InterruptedException
{
public void nonEmptyStateTest() throws InterruptedException {
ActivityController activityController = Robolectric.buildActivity(BarcodeSelectorActivity.class).create();
activityController.start();
activityController.resume();
@@ -54,11 +55,12 @@ public class BarcodeSelectorActivityTest {
cardId.setText("abcdefg");
shadowOf(Looper.getMainLooper()).idle();
// Run the delayed Handler
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
// Button should be visible and enabled
assertEquals(View.VISIBLE, noBarcodeButton.getVisibility());
assertEquals(true, noBarcodeButton.isEnabled());
assertTrue(noBarcodeButton.isEnabled());
// Clicking button should create "empty" barcode
activity.findViewById(R.id.noBarcode).performClick();
@@ -70,8 +72,7 @@ public class BarcodeSelectorActivityTest {
}
@Test
public void nonEmptyToEmptyStateTest() throws InterruptedException
{
public void nonEmptyToEmptyStateTest() throws InterruptedException {
ActivityController activityController = Robolectric.buildActivity(BarcodeSelectorActivity.class).create();
activityController.start();
activityController.resume();
@@ -83,18 +84,20 @@ public class BarcodeSelectorActivityTest {
cardId.setText("abcdefg");
shadowOf(Looper.getMainLooper()).idle();
// Run the delayed Handler
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
// Button should be visible and enabled
assertEquals(View.VISIBLE, noBarcodeButton.getVisibility());
assertEquals(true, noBarcodeButton.isEnabled());
assertTrue(noBarcodeButton.isEnabled());
cardId.setText("");
shadowOf(Looper.getMainLooper()).idle();
// Run the delayed Handler
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
// Button should be visible but disabled
assertEquals(View.VISIBLE, noBarcodeButton.getVisibility());
assertEquals(false, noBarcodeButton.isEnabled());
assertFalse(noBarcodeButton.isEnabled());
}
}

View File

@@ -503,6 +503,8 @@ public class DatabaseTest
assertEquals(BarcodeFormat.UPC_A, card.barcodeType.format());
assertEquals(null, card.headerColor);
assertEquals(0, card.starStatus);
assertEquals(0,card.lastUsed);
assertEquals(100,card.zoomLevel);
// Determine that the entries are queryable and the fields are correct
LoyaltyCard card2 = db.getLoyaltyCard(newCardId2);
@@ -516,6 +518,8 @@ public class DatabaseTest
assertEquals(null, card2.barcodeType); // Empty string should've become null
assertEquals(null, card2.headerColor);
assertEquals(0, card2.starStatus);
assertEquals(0,card2.lastUsed);
assertEquals(100,card2.zoomLevel);
database.close();
}

View File

@@ -7,6 +7,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.os.Environment;
import android.os.Looper;
import android.util.DisplayMetrics;
import com.google.zxing.BarcodeFormat;
@@ -20,6 +21,7 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
import org.robolectric.shadows.ShadowLog;
import org.robolectric.shadows.ShadowLooper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -33,6 +35,7 @@ import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -42,6 +45,8 @@ import java.util.HashMap;
import java.util.List;
import androidx.core.content.res.ResourcesCompat;
import protect.card_locker.async.TaskHandler;
import protect.card_locker.importexport.DataFormat;
import protect.card_locker.importexport.ImportExportResult;
import protect.card_locker.importexport.MultiFormatExporter;
@@ -51,11 +56,11 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class ImportExportTest
{
public class ImportExportTest {
private Activity activity;
private DBHelper db;
private long nowMs;
@@ -66,8 +71,7 @@ public class ImportExportTest
private final CatimaBarcode BARCODE_TYPE = CatimaBarcode.fromBarcode(BarcodeFormat.UPC_A);
@Before
public void setUp()
{
public void setUp() {
ShadowLog.stream = System.out;
activity = Robolectric.setupActivity(MainActivity.class);
@@ -75,20 +79,19 @@ public class ImportExportTest
nowMs = System.currentTimeMillis();
Calendar lastYear = Calendar.getInstance();
lastYear.set(Calendar.YEAR, lastYear.get(Calendar.YEAR)-1);
lastYear.set(Calendar.YEAR, lastYear.get(Calendar.YEAR) - 1);
lastYearMs = lastYear.getTimeInMillis();
}
/**
* Add the given number of cards, each with
* an index in the store name.
*
* @param cardsToAdd
*/
private void addLoyaltyCards(int cardsToAdd)
{
private void addLoyaltyCards(int cardsToAdd) {
// Add in reverse order to test sorting
for(int index = cardsToAdd; index > 0; index--)
{
for (int index = cardsToAdd; index > 0; index--) {
String storeName = String.format("store, \"%4d", index);
String note = String.format("note, \"%4d", index);
long id = db.insertLoyaltyCard(storeName, note, null, new BigDecimal(String.valueOf(index)), null, BARCODE_DATA, null, BARCODE_TYPE, index, 0, null);
@@ -99,20 +102,17 @@ public class ImportExportTest
assertEquals(cardsToAdd, db.getLoyaltyCardCount());
}
private void addLoyaltyCardsFiveStarred()
{
private void addLoyaltyCardsFiveStarred() {
int cardsToAdd = 9;
// Add in reverse order to test sorting
for(int index = cardsToAdd; index > 4; index--)
{
for (int index = cardsToAdd; index > 4; index--) {
String storeName = String.format("store, \"%4d", index);
String note = String.format("note, \"%4d", index);
long id = db.insertLoyaltyCard(storeName, note, null, new BigDecimal(String.valueOf(index)), null, BARCODE_DATA, null, BARCODE_TYPE, index, 1, null);
boolean result = (id != -1);
assertTrue(result);
}
for(int index = cardsToAdd-5; index > 0; index--)
{
for (int index = cardsToAdd - 5; index > 0; index--) {
String storeName = String.format("store, \"%4d", index);
String note = String.format("note, \"%4d", index);
//if index is even
@@ -124,8 +124,7 @@ public class ImportExportTest
}
@Test
public void addLoyaltyCardsWithExpiryNeverPastTodayFuture()
{
public void addLoyaltyCardsWithExpiryNeverPastTodayFuture() {
long id = db.insertLoyaltyCard("No Expiry", "", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, 0, 0, null);
boolean result = (id != -1);
assertTrue(result);
@@ -165,8 +164,8 @@ public class ImportExportTest
card = db.getLoyaltyCard((int) id);
assertEquals("Today", card.store);
assertEquals("", card.note);
assertTrue(card.expiry.before(new Date(new Date().getTime()+86400)));
assertTrue(card.expiry.after(new Date(new Date().getTime()-86400)));
assertTrue(card.expiry.before(new Date(new Date().getTime() + 86400)));
assertTrue(card.expiry.after(new Date(new Date().getTime() - 86400)));
assertEquals(new BigDecimal("0"), card.balance);
assertEquals(null, card.balanceType);
assertEquals(BARCODE_DATA, card.cardId);
@@ -184,7 +183,7 @@ public class ImportExportTest
card = db.getLoyaltyCard((int) id);
assertEquals("Future", card.store);
assertEquals("", card.note);
assertTrue(card.expiry.after(new Date(new Date().getTime()+86400)));
assertTrue(card.expiry.after(new Date(new Date().getTime() + 86400)));
assertEquals(new BigDecimal("0"), card.balance);
assertEquals(null, card.balanceType);
assertEquals(BARCODE_DATA, card.cardId);
@@ -196,11 +195,9 @@ public class ImportExportTest
assertEquals(4, db.getLoyaltyCardCount());
}
private void addGroups(int groupsToAdd)
{
private void addGroups(int groupsToAdd) {
// Add in reverse order to test sorting
for(int index = groupsToAdd; index > 0; index--)
{
for (int index = groupsToAdd; index > 0; index--) {
String groupName = String.format("group, \"%4d", index);
long id = db.insertGroup(groupName);
boolean result = (id != -1);
@@ -215,13 +212,11 @@ public class ImportExportTest
* specified in addLoyaltyCards(), and are in sequential order
* where the smallest card's index is 1
*/
private void checkLoyaltyCards()
{
private void checkLoyaltyCards() {
Cursor cursor = db.getLoyaltyCardCursor();
int index = 1;
while(cursor.moveToNext())
{
while (cursor.moveToNext()) {
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cursor);
String expectedStore = String.format("store, \"%4d", index);
@@ -248,13 +243,11 @@ public class ImportExportTest
* specified in addLoyaltyCardsSomeStarred(), and are in sequential order
* with starred ones first
*/
private void checkLoyaltyCardsFiveStarred()
{
Cursor cursor = db.getLoyaltyCardCursor();
int index = 5;
private void checkLoyaltyCardsFiveStarred() {
Cursor cursor = db.getLoyaltyCardCursor();
int index = 5;
while(index<10)
{
while (index < 10) {
cursor.moveToNext();
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cursor);
@@ -276,26 +269,25 @@ public class ImportExportTest
}
index = 1;
while(cursor.moveToNext() && index<5)
{
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cursor);
while (cursor.moveToNext() && index < 5) {
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cursor);
String expectedStore = String.format("store, \"%4d", index);
String expectedNote = String.format("note, \"%4d", index);
String expectedStore = String.format("store, \"%4d", index);
String expectedNote = String.format("note, \"%4d", index);
assertEquals(expectedStore, card.store);
assertEquals(expectedNote, card.note);
assertEquals(null, card.expiry);
assertEquals(new BigDecimal(String.valueOf(index)), card.balance);
assertEquals(null, card.balanceType);
assertEquals(BARCODE_DATA, card.cardId);
assertEquals(null, card.barcodeId);
assertEquals(BARCODE_TYPE.format(), card.barcodeType.format());
assertEquals(Integer.valueOf(index), card.headerColor);
assertEquals(0, card.starStatus);
assertEquals(expectedStore, card.store);
assertEquals(expectedNote, card.note);
assertEquals(null, card.expiry);
assertEquals(new BigDecimal(String.valueOf(index)), card.balance);
assertEquals(null, card.balanceType);
assertEquals(BARCODE_DATA, card.cardId);
assertEquals(null, card.barcodeId);
assertEquals(BARCODE_TYPE.format(), card.barcodeType.format());
assertEquals(Integer.valueOf(index), card.headerColor);
assertEquals(0, card.starStatus);
index++;
}
index++;
}
cursor.close();
}
@@ -305,13 +297,11 @@ public class ImportExportTest
* specified in addGroups(), and are in sequential order
* where the smallest group's index is 1
*/
private void checkGroups()
{
private void checkGroups() {
Cursor cursor = db.getGroupCursor();
int index = db.getGroupCount();
while(cursor.moveToNext())
{
while (cursor.moveToNext()) {
Group group = Group.toGroup(cursor);
String expectedGroupName = String.format("group, \"%4d", index);
@@ -324,8 +314,7 @@ public class ImportExportTest
}
@Test
public void multipleCardsExportImport() throws IOException
{
public void multipleCardsExportImport() throws IOException {
final int NUM_CARDS = 10;
addLoyaltyCards(NUM_CARDS);
@@ -334,7 +323,7 @@ public class ImportExportTest
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export data to CSV format
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima);
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, null);
assertEquals(ImportExportResult.Success, result);
outStream.close();
@@ -354,9 +343,40 @@ public class ImportExportTest
TestHelpers.getEmptyDb(activity);
}
public void multipleCardsExportImportPasswordProtected() throws IOException {
final int NUM_CARDS = 10;
List<char[]> passwords = Arrays.asList(null, "123456789".toCharArray());
for (char[] password : passwords) {
addLoyaltyCards(NUM_CARDS);
ByteArrayOutputStream outData = new ByteArrayOutputStream();
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export data to CSV format
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, password);
assertEquals(ImportExportResult.Success, result);
outStream.close();
TestHelpers.getEmptyDb(activity);
ByteArrayInputStream inData = new ByteArrayInputStream(outData.toByteArray());
// Import the CSV data
result = MultiFormatImporter.importData(activity.getApplicationContext(), db, inData, DataFormat.Catima, password);
assertEquals(ImportExportResult.Success, result);
assertEquals(NUM_CARDS, db.getLoyaltyCardCount());
checkLoyaltyCards();
// Clear the database for the next format under test
TestHelpers.getEmptyDb(activity);
}
}
@Test
public void multipleCardsExportImportSomeStarred() throws IOException
{
public void multipleCardsExportImportSomeStarred() throws IOException {
final int NUM_CARDS = 9;
addLoyaltyCardsFiveStarred();
@@ -365,7 +385,7 @@ public class ImportExportTest
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export data to CSV format
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima);
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, null);
assertEquals(ImportExportResult.Success, result);
outStream.close();
@@ -385,8 +405,7 @@ public class ImportExportTest
TestHelpers.getEmptyDb(activity);
}
private List<String> groupsToGroupNames(List<Group> groups)
{
private List<String> groupsToGroupNames(List<Group> groups) {
List<String> groupNames = new ArrayList<>();
for (Group group : groups) {
@@ -397,8 +416,7 @@ public class ImportExportTest
}
@Test
public void multipleCardsExportImportWithGroups() throws IOException
{
public void multipleCardsExportImportWithGroups() throws IOException {
final int NUM_CARDS = 10;
final int NUM_GROUPS = 3;
@@ -438,7 +456,7 @@ public class ImportExportTest
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export data to CSV format
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima);
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, null);
assertEquals(ImportExportResult.Success, result);
outStream.close();
@@ -472,8 +490,7 @@ public class ImportExportTest
}
@Test
public void importExistingCardsNotReplace() throws IOException
{
public void importExistingCardsNotReplace() throws IOException {
final int NUM_CARDS = 10;
addLoyaltyCards(NUM_CARDS);
@@ -482,7 +499,7 @@ public class ImportExportTest
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export into CSV data
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima);
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, null);
assertEquals(ImportExportResult.Success, result);
outStream.close();
@@ -501,19 +518,17 @@ public class ImportExportTest
}
@Test
public void corruptedImportNothingSaved() throws IOException
{
public void corruptedImportNothingSaved() throws IOException {
final int NUM_CARDS = 10;
for(DataFormat format : DataFormat.values())
{
for (DataFormat format : DataFormat.values()) {
addLoyaltyCards(NUM_CARDS);
ByteArrayOutputStream outData = new ByteArrayOutputStream();
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export data to CSV format
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima);
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, null);
assertEquals(ImportExportResult.Success, result);
TestHelpers.getEmptyDb(activity);
@@ -536,20 +551,17 @@ public class ImportExportTest
}
}
class TestTaskCompleteListener implements ImportExportTask.TaskCompleteListener
{
class TestTaskCompleteListener implements ImportExportTask.TaskCompleteListener {
ImportExportResult result;
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat)
{
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat) {
this.result = result;
}
}
@Test
@LooperMode(LooperMode.Mode.LEGACY)
public void useImportExportTask() throws FileNotFoundException
{
@LooperMode(LooperMode.Mode.PAUSED)
public void useImportExportTask() throws FileNotFoundException {
final int NUM_CARDS = 10;
final File sdcardDir = Environment.getExternalStorageDirectory();
@@ -560,12 +572,17 @@ public class ImportExportTest
TestTaskCompleteListener listener = new TestTaskCompleteListener();
// Export to the file
final String password = "123456789";
FileOutputStream fileOutputStream = new FileOutputStream(exportFile);
ImportExportTask task = new ImportExportTask(activity, DataFormat.Catima, fileOutputStream, listener);
task.execute();
ImportExportTask task = new ImportExportTask(activity, DataFormat.Catima, fileOutputStream, password.toCharArray(), listener);
TaskHandler mTasks = new TaskHandler();
mTasks.executeTask(TaskHandler.TYPE.EXPORT, task);
// Actually run the task to completion
Robolectric.flushBackgroundThreadScheduler();
mTasks.flushTaskList(TaskHandler.TYPE.EXPORT, false, false, true);
shadowOf(Looper.getMainLooper()).idleFor(Duration.ofMillis(5000));
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
// Check that the listener was executed
assertNotNull(listener.result);
@@ -579,11 +596,14 @@ public class ImportExportTest
FileInputStream fileStream = new FileInputStream(exportFile);
task = new ImportExportTask(activity, DataFormat.Catima, fileStream, null, listener);
task.execute();
task = new ImportExportTask(activity, DataFormat.Catima, fileStream, password.toCharArray(), listener);
mTasks.executeTask(TaskHandler.TYPE.IMPORT, task);
// Actually run the task to completion
Robolectric.flushBackgroundThreadScheduler();
// I am CONVINCED there must be a better way than to wait on this Queue with a flush.
mTasks.flushTaskList(TaskHandler.TYPE.IMPORT, false, false, true);
shadowOf(Looper.getMainLooper()).idleFor(Duration.ofMillis(5000));
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
// Check that the listener was executed
assertNotNull(listener.result);
@@ -598,8 +618,7 @@ public class ImportExportTest
}
@Test
public void importWithoutColorsV1() throws IOException
{
public void importWithoutColorsV1() throws IOException {
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
@@ -634,8 +653,7 @@ public class ImportExportTest
}
@Test
public void importWithoutNullColorsV1() throws IOException
{
public void importWithoutNullColorsV1() throws IOException {
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
@@ -672,8 +690,7 @@ public class ImportExportTest
}
@Test
public void importWithoutInvalidColorsV1() throws IOException
{
public void importWithoutInvalidColorsV1() throws IOException {
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
@@ -697,8 +714,7 @@ public class ImportExportTest
}
@Test
public void importWithNoBarcodeTypeV1() throws IOException
{
public void importWithNoBarcodeTypeV1() throws IOException {
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
@@ -735,8 +751,7 @@ public class ImportExportTest
}
@Test
public void importWithStarredFieldV1() throws IOException
{
public void importWithStarredFieldV1() throws IOException {
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
@@ -773,8 +788,7 @@ public class ImportExportTest
}
@Test
public void importWithNoStarredFieldV1() throws IOException
{
public void importWithNoStarredFieldV1() throws IOException {
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
@@ -811,8 +825,7 @@ public class ImportExportTest
}
@Test
public void importWithInvalidStarFieldV1() throws IOException
{
public void importWithInvalidStarFieldV1() throws IOException {
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
@@ -868,8 +881,7 @@ public class ImportExportTest
}
@Test
public void exportImportV2Zip() throws FileNotFoundException
{
public void exportImportV2Zip() throws FileNotFoundException {
// Prepare images
BitmapDrawable launcher = (BitmapDrawable) ResourcesCompat.getDrawableForDensity(activity.getResources(), R.mipmap.ic_launcher, DisplayMetrics.DENSITY_XXXHIGH, activity.getTheme());
BitmapDrawable roundLauncher = (BitmapDrawable) ResourcesCompat.getDrawableForDensity(activity.getResources(), R.mipmap.ic_launcher_round, DisplayMetrics.DENSITY_XXXHIGH, activity.getTheme());
@@ -901,7 +913,7 @@ public class ImportExportTest
// Export everything
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
MultiFormatExporter.exportData(activity.getApplicationContext(), db, outputStream, DataFormat.Catima);
MultiFormatExporter.exportData(activity.getApplicationContext(), db, outputStream, DataFormat.Catima, null);
// Wipe database
TestHelpers.getEmptyDb(activity);
@@ -925,25 +937,25 @@ public class ImportExportTest
assertEquals(loyaltyCard.cardId, dbLoyaltyCard.cardId);
assertEquals(loyaltyCard.barcodeId, dbLoyaltyCard.barcodeId);
assertEquals(loyaltyCard.starStatus, dbLoyaltyCard.starStatus);
assertEquals(loyaltyCard.barcodeType != null ? loyaltyCard.barcodeType.format() : null, dbLoyaltyCard.barcodeType != null? dbLoyaltyCard.barcodeType.format() : null);
assertEquals(loyaltyCard.barcodeType != null ? loyaltyCard.barcodeType.format() : null, dbLoyaltyCard.barcodeType != null ? dbLoyaltyCard.barcodeType.format() : null);
assertEquals(loyaltyCard.balanceType, dbLoyaltyCard.balanceType);
assertEquals(loyaltyCard.headerColor, dbLoyaltyCard.headerColor);
List<Group> emptyGroup = new ArrayList<>();
assertEquals(
groupsToGroupNames(
(List<Group>) Utils.mapGetOrDefault(
loyaltyCardGroups,
loyaltyCardID,
emptyGroup
groupsToGroupNames(
(List<Group>) Utils.mapGetOrDefault(
loyaltyCardGroups,
loyaltyCardID,
emptyGroup
)
),
groupsToGroupNames(
db.getLoyaltyCardGroups(
loyaltyCardID
)
)
),
groupsToGroupNames(
db.getLoyaltyCardGroups(
loyaltyCardID
)
)
);
Bitmap expectedFrontImage = loyaltyCardFrontImages.get(loyaltyCardID);
@@ -966,8 +978,7 @@ public class ImportExportTest
}
@Test
public void importV2CSV()
{
public void importV2CSV() {
String csvText = "2\n" +
"\n" +
"_id\n" +

2
bors.toml Normal file
View File

@@ -0,0 +1,2 @@
status = [ 'build' ]
delete_merged_branches = true

View File

@@ -9,8 +9,8 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.2'
classpath 'gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.7.0'
classpath 'com.android.tools.build:gradle:7.0.3'
classpath 'gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.7.5'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View File

@@ -4,6 +4,7 @@ Copylefted libre software (GPLv3+) card management app.
[![GitHub Version](https://img.shields.io/github/v/release/TheLastProject/Catima.svg?logo=github&label=GitHub)](https://github.com/TheLastProject/Catima/releases)
[![F-Droid Version](https://img.shields.io/f-droid/v/me.hackerchick.catima.svg?logo=f-droid&label=F-Droid)](https://f-droid.org/packages/me.hackerchick.catima/)
[![IzzyOnDroid Version](https://img.shields.io/endpoint?url=https://apt.izzysoft.de/fdroid/api/v1/shield/me.hackerchick.catima)](https://apt.izzysoft.de/fdroid/index/apk/me.hackerchick.catima)
[![Google Play Store Version](https://img.shields.io/endpoint?color=blue&logo=google-play&url=https%3A%2F%2Fplayshields.herokuapp.com%2Fplay%3Fi%3Dme.hackerchick.catima%26l%3DGoogle%2520Play%26m%3D%24version)](https://play.google.com/store/apps/details?id=me.hackerchick.catima)
![Android CI](https://github.com/TheLastProject/Catima/workflows/Android%20CI/badge.svg)

View File

@@ -11,4 +11,4 @@
- QR_CODE
- UPC_A
- Vygenerované čárové kódy jsou větší, snadněji se skenují ze skenovacího zařízení.
- Vygenerované čárové kódy jsou větší, snadněji se skenují ze skenovacího zařízení

View File

@@ -1,4 +1,4 @@
- Překlad do nizozemštiny
- Umožnit editaci pole se jménem po přidání věrnostní karty
- Přidat nepovinné pole pro poznámku
- Vyřešit všechny problémy identifikované nástrojem FindBugs a vyžadovat vyřešení všech problémů FindBugs před přijetím požadavku na stažení.
- Vyřešit všechny problémy identifikované nástrojem FindBugs a vyžadovat vyřešení všech problémů FindBugs před přijetím požadavku na stažení

View File

@@ -1,4 +1,5 @@
Počínaje touto verzí již není systém Android 4.4 podporován. Pokud chcete používat Catimu v systému Android 4.4, použijte verzi 2.6.1.
- Vylepšená podpora systému Android 12
- Vylepšená obrazovka o aplikaci
- Vylepšená obrazovka s informacemi
- Vyhledávání nyní ignoruje diakritiku

View File

@@ -0,0 +1 @@
- Zlepšení vyhledávání obsahující mezery

View File

@@ -0,0 +1 @@
- Oprava regrese narušující import/export

View File

@@ -0,0 +1 @@
- Oprava nesprávné migrace, která způsobila, že první karta se stala neviditelnou

View File

@@ -0,0 +1,3 @@
- Oprava nefunkčního přecházení mezi skupinami v prázdné skupině
- Povolení exportu chráněného heslem
- Zlepšení využití prostoru pro kódy QR

View File

@@ -0,0 +1 @@
- Fix regression breaking import/export

View File

@@ -0,0 +1 @@
- Fix incorrect migration making first card become invisible

View File

@@ -0,0 +1,5 @@
- Fix swiping between groups not working on an empty group
- Allow password-protecting exports
- Improve usage of space for QR codes
- Save the last used zoom level per card
- Fix a crash when swiping right after a tap

View File

@@ -0,0 +1,4 @@
- Fix dots in card view having the wrong colour when changing theme manually
- Fix crash in card view on rotation/theme change
- Fix flashing of cards list
- Fix text overlaying star icon

View File

@@ -1 +1 @@
Catima — Den Open Source kortlommen
Catima — for kundekort, billetter og kuponger 🎴

View File

@@ -20,4 +20,3 @@ Med detta essentiella verktyg kan du ersätta värdelös plast med kontanter.
Förenkla ditt liv och din shopping, och förlora aldrig ett papperskvitto, presentkort eller flygbiljett igen.
Ta alla dina belöningar och bonusar med dig, och spara nya efter hand.

View File

@@ -1 +1 @@
Catima — Den Open Source kortplånboken
Catima — Kortplånboken med öppen källkod

View File

@@ -0,0 +1 @@
- İçe/dışa aktarmayı bozan sorun düzeltildi

View File

@@ -0,0 +1 @@
- İlk kartın görünmez hale gelmesine neden olan yanlış taşıma düzeltildi

View File

@@ -0,0 +1,5 @@
- Gruplar arasında kaydırmanın boş bir grup üzerinde çalışmaması düzeltildi
- Parola korumalı dışa aktarmalara izin ver
- QR kodları için boşluk kullanımını iyileştir
- Kart başına en son kullanılan yakınlaştırma seviyesini kaydet
- Dokunduktan sonra sağa kaydırmada çökmeyi düzelt

View File

@@ -20,4 +20,3 @@
Спростіть своє життя та покупки, і ніколи більше не втрачайте паперову квитанцію, подарункову картку магазину або квиток на літак.
Візьміть із собою всі свої нагороди та бонуси та економте на ходу.