Compare commits

...

84 Commits

Author SHA1 Message Date
Sylvia van Os
44711043b9 Release Catima 2.2.1 2021-08-07 13:28:02 +02:00
Sylvia van Os
80ee8aa860 Merge branch 'master' of github.com:TheLastProject/loyalty-card-locker 2021-08-07 13:16:35 +02:00
Sylvia van Os
cd6685b974 Fix flashing in ManageGroupsActivity 2021-08-07 13:16:21 +02:00
Sylvia van Os
b5f464000b Merge pull request #318 from weblate/weblate-catima-catima
Translations update from Weblate
2021-08-07 05:54:03 +02:00
J. Lavoie
27159323d5 Translated using Weblate (Italian)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2021-08-07 02:41:29 +02:00
J. Lavoie
9551ce8a8b Translated using Weblate (French)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2021-08-07 02:41:29 +02:00
J. Lavoie
525471f749 Translated using Weblate (German)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2021-08-07 02:41:28 +02:00
Sylvia van Os
57bedd0300 Actually fix properly 2021-08-05 20:51:29 +02:00
Sylvia van Os
c3345a1a15 Fix last commit 2021-08-05 20:35:44 +02:00
Sylvia van Os
15f6bd86a1 Change card title size within range 2021-08-05 20:21:18 +02:00
Sylvia van Os
e2ad1c9da2 Add animations to card list 2021-08-05 19:38:37 +02:00
Sylvia van Os
7082669612 Fix importing Catima export with multiline note 2021-08-05 18:28:14 +02:00
Sylvia van Os
d595d24769 Merge pull request #313 from weblate/weblate-catima-catima
Translations update from Weblate
2021-08-04 23:26:51 +02:00
Gediminas Murauskas
4287d66f6f Translated using Weblate (Lithuanian)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2021-08-04 23:24:45 +02:00
Sylvia van Os
311361d105 Merge pull request #312 from weblate/weblate-catima-catima
Translations update from Weblate
2021-08-04 23:24:41 +02:00
Sylvia van Os
4a88e39deb Fix syntax 2021-08-04 22:38:13 +02:00
mondstern
4511590263 Translated using Weblate (Danish)
Currently translated at 66.6% (2 of 3 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/da/
2021-08-04 22:32:46 +02:00
mondstern
d0c30ffa1c Translated using Weblate (Danish)
Currently translated at 27.3% (47 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/da/
2021-08-04 22:32:46 +02:00
Allan Nordhøy
813c2bff85 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (3 of 3 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/nb_NO/
2021-08-04 22:32:45 +02:00
solokot
0c3cf43841 Translated using Weblate (Russian)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2021-08-04 22:32:45 +02:00
Heimen Stoffels
6c651f7e3e Translated using Weblate (Dutch)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2021-08-04 22:32:45 +02:00
Allan Nordhøy
ef7fc92920 Translated using Weblate (Norwegian Bokmål)
Currently translated at 90.1% (155 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2021-08-04 22:32:44 +02:00
Sylvia van Os
ccaf70c749 Merge pull request #311 from weblate/weblate-catima-catima
Translations update from Weblate
2021-08-03 20:59:42 +02:00
mondstern
2299bf9d86 Added translation using Weblate (Danish) 2021-08-03 20:58:37 +02:00
Sylvia van Os
b65f8f32ca Merge pull request #310 from weblate/weblate-catima-catima
Translations update from Weblate
2021-08-03 20:48:23 +02:00
mondstern
47695d3a72 Translated using Weblate (Czech)
Currently translated at 66.6% (2 of 3 strings)

Translation: Catima/Fastlane
Translate-URL: https://hosted.weblate.org/projects/catima/fastlane/cs/
2021-08-03 20:43:07 +02:00
solokot
439c660b2e Translated using Weblate (Russian)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2021-08-03 20:43:07 +02:00
Gediminas Murauskas
4293d7d4b2 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/lt/
2021-08-03 20:43:07 +02:00
J. Lavoie
e368e66b8a Translated using Weblate (Italian)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2021-08-03 20:43:07 +02:00
Mattia
992a7f9e84 Translated using Weblate (Italian)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2021-08-03 20:43:07 +02:00
J. Lavoie
ecf0faf00a Translated using Weblate (French)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2021-08-03 20:43:07 +02:00
J. Lavoie
64178f3fd1 Translated using Weblate (Spanish)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2021-08-03 20:43:07 +02:00
J. Lavoie
dab6588800 Translated using Weblate (German)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2021-08-03 20:43:07 +02:00
mondstern
f71bb32592 Translated using Weblate (Czech)
Currently translated at 51.1% (88 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/cs/
2021-08-03 20:43:07 +02:00
Sylvia van Os
0c44212d92 Make SpotBugs happy 2021-08-03 20:42:57 +02:00
Sylvia van Os
ce149c91e9 Improve Stocard importer 2021-08-03 20:34:44 +02:00
Sylvia van Os
05dfd48f57 Release Catima 2.2.0 2021-08-02 23:42:32 +02:00
Sylvia van Os
ef955b866d Remove unused imports 2021-08-02 23:09:49 +02:00
Sylvia van Os
a843b5a1b9 Make lint happier 2021-08-02 22:58:06 +02:00
Sylvia van Os
8305d58ccc Fix maximize button appearing on no barcode 2021-08-02 22:57:55 +02:00
Sylvia van Os
6af79d5f41 General cleanups 2021-08-02 20:47:48 +02:00
Sylvia van Os
3b326d6f9c Also remove from AboutActivity 2021-08-02 20:37:13 +02:00
Sylvia van Os
1456e5073e Get rid of barely used dependency 2021-08-02 20:36:20 +02:00
Sylvia van Os
6a13dbf66a Comma-separate group names in loyalty card view 2021-08-01 23:03:56 +02:00
Sylvia van Os
c5b1718e8e Pre-select active group on creating new card 2021-08-01 22:33:44 +02:00
Sylvia van Os
e2bcc24867 Make links in notes clickable 2021-08-01 21:39:48 +02:00
Sylvia van Os
c86cc22a93 Release v2.1.0 2021-08-01 21:00:12 +02:00
Sylvia van Os
765577ae9e Merge pull request #306 from weblate/weblate-catima-catima
Translations update from Weblate
2021-08-01 20:50:42 +02:00
Heimen Stoffels
d1d15644b5 Translated using Weblate (Dutch)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2021-08-01 20:36:29 +02:00
Sylvia van Os
5d41b213db Remove translations to break lint 2021-08-01 20:36:17 +02:00
Sylvia van Os
aa515b1192 Be more explicit in quantity
Translators still keep triggering the linter with errors such as the
following:
Error: The quantity 'one' matches more than one specific number in this locale (1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …), but the message did not include a formatting argument (such as %d). This is usually an internationalization error. See full issue explanation for more. [ImpliedQuantity]
2021-08-01 12:50:56 +02:00
Sylvia van Os
068660fe3f Merge pull request #305 from weblate/weblate-catima-catima
Translations update from Weblate
2021-08-01 12:42:14 +02:00
solokot
99ffaf97d1 Translated using Weblate (Russian)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2021-08-01 12:32:51 +02:00
Heimen Stoffels
b53999c1cf Translated using Weblate (Dutch)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2021-08-01 12:32:51 +02:00
Allan Nordhøy
57f87d7dc0 Translated using Weblate (Norwegian Bokmål)
Currently translated at 90.6% (156 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2021-08-01 12:32:50 +02:00
J. Lavoie
760f6a873d Translated using Weblate (Italian)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/it/
2021-08-01 12:32:50 +02:00
J. Lavoie
675bd43ff8 Translated using Weblate (French)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/fr/
2021-08-01 12:32:50 +02:00
J. Lavoie
07532ce001 Translated using Weblate (Spanish)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/es/
2021-08-01 12:32:50 +02:00
J. Lavoie
908a7055c7 Translated using Weblate (German)
Currently translated at 100.0% (172 of 172 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/de/
2021-08-01 12:32:49 +02:00
Sylvia van Os
2be371caed Forgot number 2021-07-30 19:46:10 +02:00
Sylvia van Os
f4f3f2e307 Increase i18n flexibility
The following may seem weird, but it is necessary to give translators enough flexibility. For example, in Russian, Android's plural quantity "one" actually refers to "any number ending on 1 but not ending in 11". So while in English the extra non-plural form seems unnecessary duplication, it is necessary to give translators enough flexibility. Therefore, we use the plain string when meaning exactly 1, and otherwise use the plural forms.
2021-07-30 19:40:43 +02:00
Sylvia van Os
edbf76c7dc Merge pull request #303 from weblate/weblate-catima-catima
Translations update from Weblate
2021-07-30 19:02:48 +02:00
109247019824
f8615f45f0 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (170 of 170 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/bg/
2021-07-30 18:18:55 +02:00
IllusiveMan196
c3bc3e9911 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (170 of 170 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/uk/
2021-07-30 18:18:55 +02:00
solokot
8adcca1df2 Translated using Weblate (Russian)
Currently translated at 100.0% (170 of 170 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2021-07-30 18:18:55 +02:00
Heimen Stoffels
bdde8669ac Translated using Weblate (Dutch)
Currently translated at 100.0% (170 of 170 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2021-07-30 18:18:55 +02:00
solokot
59db2df525 Translated using Weblate (Russian)
Currently translated at 100.0% (170 of 170 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/ru/
2021-07-30 18:18:55 +02:00
Sylvia van Os
3b83ff5b0e Fix syntax 2021-07-30 18:18:32 +02:00
Heimen Stoffels
19fb290a51 Translated using Weblate (Dutch)
Currently translated at 100.0% (170 of 170 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nl/
2021-07-30 18:15:39 +02:00
Allan Nordhøy
e1e823d9e0 Translated using Weblate (Norwegian Bokmål)
Currently translated at 90.0% (153 of 170 strings)

Translation: Catima/Catima
Translate-URL: https://hosted.weblate.org/projects/catima/catima/nb_NO/
2021-07-30 18:15:30 +02:00
Sylvia van Os
7ed477b670 Merge branch 'master' of github.com:TheLastProject/loyalty-card-locker 2021-07-29 22:16:47 +02:00
Sylvia van Os
1960fb0b6a Fix fullscreen loss on rotation 2021-07-29 22:16:36 +02:00
Sylvia van Os
e913482790 Merge pull request #299 from comradekingu/patch-7
New strings reworked
2021-07-29 21:54:43 +02:00
Allan Nordhøy
2e5bd76d31 New strings reworked 2021-07-29 19:47:10 +00:00
Sylvia van Os
876ae979da Simplify updateTempState
Hopefully fixes the few weird crashes on Google Play
2021-07-29 21:42:21 +02:00
Sylvia van Os
d918c15ad6 Prevent ArithmeticException 2021-07-29 21:18:21 +02:00
Sylvia van Os
d57cb307c3 Support multi-deleting cards 2021-07-29 20:38:37 +02:00
Sylvia van Os
cbcf1bcd99 Use desugaring to upgrade zxing without having to increase minSdk
As documented by the zxing team on https://github.com/zxing/zxing/wiki/Frequently-Asked-Questions#it-doesnt-work-with-java-7--no-interface-method-sortljavautilcomparator
2021-07-28 23:05:27 +02:00
Sylvia van Os
96bc10583f Fix colour dialog selected colour 2021-07-27 22:04:09 +02:00
Sylvia van Os
5ca4d29a36 Release Catima 2.0.4 2021-07-27 21:42:04 +02:00
Sylvia van Os
2efb666fae Fix loyalty card colour changing 2021-07-27 21:38:54 +02:00
Sylvia van Os
89dce1068f Shortcut fixes 2021-07-27 21:26:24 +02:00
Sylvia van Os
9854125af9 Make lint happy 2021-07-26 23:37:17 +02:00
Sylvia van Os
6e307ab1f0 Update dependencies 2021-07-26 23:10:51 +02:00
67 changed files with 5164 additions and 620 deletions

View File

@@ -14,10 +14,11 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
- name: set up JDK 1.8
uses: actions/setup-java@v1
- name: set up JDK 11
uses: actions/setup-java@v2
with:
java-version: 1.8
distribution: 'adopt'
java-version: '11'
- name: Build
run: ./gradlew assembleRelease
- name: Check lint

View File

@@ -1,5 +1,40 @@
# Changelog
## v2.2.1 (2021-08-07)
Changes:
- Improve Stocard importer
- Fix importing Catima export with multiline note
- Scale card title in acceptable range
- Animation improvements
## v2.2.0 (2021-08-02)
Changes:
- Make links in notes clickable
- Pre-select group the user is currently in when creating a new card
- Comma-separate group names in loyalty card view
- Fix maximize button appearing on no barcode
## v2.1.0 (2021-08-01)
Changes:
- Fix selected colour in colour changing dialog
- Support for deleting multiple cards at once
- Fix possible ArithmeticException when resizing image
- Fix fullscreen is closed when rotating device
## v2.0.4 (2021-07-27)
Changes:
- Fix shortcut creation
- Generate card-specific shortcut icon
- Fix ability to change loyalty card colour
## v2.0.3 (2021-07-25)
Changes:

View File

@@ -18,10 +18,11 @@ android {
applicationId "me.hackerchick.catima"
minSdkVersion 19
targetSdkVersion 30
versionCode 73
versionName "2.0.3"
versionCode 77
versionName "2.2.1"
vectorDrawables.useSupportLibrary true
multiDexEnabled true
}
buildTypes {
@@ -38,6 +39,10 @@ android {
compileOptions {
encoding "UTF-8"
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
@@ -69,20 +74,18 @@ android {
dependencies {
// AndroidX
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'com.google.android.material:material:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
// Third-party
implementation 'com.journeyapps:zxing-android-embedded:4.1.0@aar'
// Do not upgrade past 3.3.3! Causes a crash on versions before Android Nougat
//noinspection GradleDependency
implementation 'com.google.zxing:core:3.3.3'
implementation 'com.google.zxing:core:3.4.1'
implementation 'org.apache.commons:commons-csv:1.8'
implementation 'com.jaredrummler:colorpicker:1.1.0'
implementation 'com.google.guava:guava:30.1.1-jre'
implementation 'com.github.invissvenska:NumberPickerPreference:1.0.2'
implementation 'net.lingala.zip4j:zip4j:2.8.0'
@@ -90,9 +93,9 @@ dependencies {
implementation 'io.wcm.tooling.spotbugs:io.wcm.tooling.spotbugs.annotations:1.0.0'
// Testing
testImplementation 'androidx.test:core:1.3.0'
testImplementation 'androidx.test:core:1.4.0'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.4'
testImplementation 'org.robolectric:robolectric:4.6.1'
}
tasks.withType(SpotBugsTask) {

View File

@@ -37,7 +37,6 @@ public class AboutActivity extends AppCompatActivity
final List<ThirdPartyInfo> USED_LIBRARIES = new ArrayList<>();
USED_LIBRARIES.add(new ThirdPartyInfo("Color Picker", "https://github.com/jaredrummler/ColorPicker", "Apache 2.0"));
USED_LIBRARIES.add(new ThirdPartyInfo("Commons CSV", "https://commons.apache.org/proper/commons-csv/", "Apache 2.0"));
USED_LIBRARIES.add(new ThirdPartyInfo("Guava", "https://github.com/google/guava", "Apache 2.0"));
USED_LIBRARIES.add(new ThirdPartyInfo("NumberPickerPreference", "https://github.com/invissvenska/NumberPickerPreference", "GNU LGPL 3.0"));
USED_LIBRARIES.add(new ThirdPartyInfo("Zip4j", "https://github.com/srikanth-lingala/zip4j", "Apache 2.0"));
USED_LIBRARIES.add(new ThirdPartyInfo("ZXing", "https://github.com/zxing/zxing", "Apache 2.0"));

View File

@@ -16,12 +16,12 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.common.collect.ImmutableMap;
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;
@@ -79,20 +79,19 @@ public class BarcodeSelectorActivity extends AppCompatActivity
actionBar.setDisplayHomeAsUpEnabled(true);
}
barcodeViewMap = ImmutableMap.<String, Pair<Integer, Integer>>builder()
.put(BarcodeFormat.AZTEC.name(), new Pair<>(R.id.aztecBarcode, R.id.aztecBarcodeText))
.put(BarcodeFormat.CODE_39.name(), new Pair<>(R.id.code39Barcode, R.id.code39BarcodeText))
.put(BarcodeFormat.CODE_128.name(), new Pair<>(R.id.code128Barcode, R.id.code128BarcodeText))
.put(BarcodeFormat.CODABAR.name(), new Pair<>(R.id.codabarBarcode, R.id.codabarBarcodeText))
.put(BarcodeFormat.DATA_MATRIX.name(), new Pair<>(R.id.datamatrixBarcode, R.id.datamatrixBarcodeText))
.put(BarcodeFormat.EAN_8.name(), new Pair<>(R.id.ean8Barcode, R.id.ean8BarcodeText))
.put(BarcodeFormat.EAN_13.name(), new Pair<>(R.id.ean13Barcode, R.id.ean13BarcodeText))
.put(BarcodeFormat.ITF.name(), new Pair<>(R.id.itfBarcode, R.id.itfBarcodeText))
.put(BarcodeFormat.PDF_417.name(), new Pair<>(R.id.pdf417Barcode, R.id.pdf417BarcodeText))
.put(BarcodeFormat.QR_CODE.name(), new Pair<>(R.id.qrcodeBarcode, R.id.qrcodeBarcodeText))
.put(BarcodeFormat.UPC_A.name(), new Pair<>(R.id.upcaBarcode, R.id.upcaBarcodeText))
.put(BarcodeFormat.UPC_E.name(), new Pair<>(R.id.upceBarcode, R.id.upceBarcodeText))
.build();
barcodeViewMap = new HashMap<>();
barcodeViewMap.put(BarcodeFormat.AZTEC.name(), new Pair<>(R.id.aztecBarcode, R.id.aztecBarcodeText));
barcodeViewMap.put(BarcodeFormat.CODE_39.name(), new Pair<>(R.id.code39Barcode, R.id.code39BarcodeText));
barcodeViewMap.put(BarcodeFormat.CODE_128.name(), new Pair<>(R.id.code128Barcode, R.id.code128BarcodeText));
barcodeViewMap.put(BarcodeFormat.CODABAR.name(), new Pair<>(R.id.codabarBarcode, R.id.codabarBarcodeText));
barcodeViewMap.put(BarcodeFormat.DATA_MATRIX.name(), new Pair<>(R.id.datamatrixBarcode, R.id.datamatrixBarcodeText));
barcodeViewMap.put(BarcodeFormat.EAN_8.name(), new Pair<>(R.id.ean8Barcode, R.id.ean8BarcodeText));
barcodeViewMap.put(BarcodeFormat.EAN_13.name(), new Pair<>(R.id.ean13Barcode, R.id.ean13BarcodeText));
barcodeViewMap.put(BarcodeFormat.ITF.name(), new Pair<>(R.id.itfBarcode, R.id.itfBarcodeText));
barcodeViewMap.put(BarcodeFormat.PDF_417.name(), new Pair<>(R.id.pdf417Barcode, R.id.pdf417BarcodeText));
barcodeViewMap.put(BarcodeFormat.QR_CODE.name(), new Pair<>(R.id.qrcodeBarcode, R.id.qrcodeBarcodeText));
barcodeViewMap.put(BarcodeFormat.UPC_A.name(), new Pair<>(R.id.upcaBarcode, R.id.upcaBarcodeText));
barcodeViewMap.put(BarcodeFormat.UPC_E.name(), new Pair<>(R.id.upceBarcode, R.id.upceBarcodeText));
EditText cardId = findViewById(R.id.cardId);
cardId.addTextChangedListener(new TextWatcher()

View File

@@ -2,8 +2,8 @@ package protect.card_locker;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
@@ -12,6 +12,8 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
@@ -47,6 +49,11 @@ public class CardShortcutConfigure extends AppCompatActivity implements LoyaltyC
}
final RecyclerView cardList = findViewById(R.id.list);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
cardList.setLayoutManager(mLayoutManager);
cardList.setItemAnimator(new DefaultItemAnimator());
cardList.setVisibility(View.VISIBLE);
Cursor cardCursor = db.getLoyaltyCardCursor();
@@ -72,11 +79,12 @@ public class CardShortcutConfigure extends AppCompatActivity implements LoyaltyC
bundle.putBoolean("view", true);
shortcutIntent.putExtras(bundle);
Parcelable icon = Intent.ShortcutIconResource.fromContext(CardShortcutConfigure.this, R.mipmap.ic_launcher);
Bitmap iconBitmap = Utils.generateIcon(CardShortcutConfigure.this, loyaltyCard, true).getLetterTile();
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, loyaltyCard.store);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, iconBitmap);
setResult(RESULT_OK, intent);
finish();

View File

@@ -754,6 +754,9 @@ public class DBHelper extends SQLiteOpenHelper
db.endTransaction();
}
// Reorder after delete to ensure no bad order IDs
reorderGroups(getGroups());
return success;
}

View File

@@ -5,16 +5,18 @@ import android.database.Cursor;
public class Group
{
public final String _id;
public final int order;
public Group(final String _id)
{
public Group(final String _id, final int order) {
this._id = _id;
this.order = order;
}
public static Group toGroup(Cursor cursor)
{
String _id = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.ID));
int order = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.ORDER));
return new Group(_id);
return new Group(_id, order);
}
}

View File

@@ -5,52 +5,94 @@ import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageButton;
import androidx.recyclerview.widget.RecyclerView;
import protect.card_locker.preferences.Settings;
class GroupCursorAdapter extends CursorAdapter
class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.GroupListItemViewHolder>
{
Settings settings;
DBHelper db;
Settings mSettings;
private Cursor mCursor;
private final Context mContext;
private final GroupCursorAdapter.GroupAdapterListener mListener;
DBHelper mDb;
public GroupCursorAdapter(Context context, Cursor cursor)
{
super(context, cursor, 0);
settings = new Settings(context);
public GroupCursorAdapter(Context inputContext, Cursor inputCursor, GroupCursorAdapter.GroupAdapterListener inputListener) {
super(inputCursor);
setHasStableIds(true);
mSettings = new Settings(inputContext);
mContext = inputContext;
mListener = inputListener;
mDb = new DBHelper(inputContext);
db = new DBHelper(context);
swapCursor(mCursor);
}
// The newView method is used to inflate a new view and return it,
// you don't bind any data to the view at this point.
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent)
{
return LayoutInflater.from(context).inflate(R.layout.group_layout, parent, false);
public void swapCursor(Cursor inputCursor) {
super.swapCursor(inputCursor);
mCursor = inputCursor;
}
// The bindView method is used to bind all data to a given view
// such as setting the text on a TextView.
@NonNull
@Override
public void bindView(View view, Context context, Cursor cursor)
public GroupCursorAdapter.GroupListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType)
{
// Find fields to populate in inflated template
TextView nameField = view.findViewById(R.id.name);
TextView countField = view.findViewById(R.id.cardCount);
View itemView = LayoutInflater.from(inputParent.getContext()).inflate(R.layout.group_layout, inputParent, false);
return new GroupCursorAdapter.GroupListItemViewHolder(itemView);
}
// Extract properties from cursor
Group group = Group.toGroup(cursor);
public Cursor getCursor()
{
return mCursor;
}
Integer groupCardCount = db.getGroupCardCount(group._id);
public void onBindViewHolder(GroupCursorAdapter.GroupListItemViewHolder inputHolder, Cursor inputCursor) {
Group group = Group.toGroup(inputCursor);
// Populate fields with extracted properties
nameField.setText(group._id);
inputHolder.mName.setText(group._id);
countField.setText(context.getResources().getQuantityString(R.plurals.groupCardCount, groupCardCount, groupCardCount));
int groupCardCount = mDb.getGroupCardCount(group._id);
inputHolder.mCardCount.setText(mContext.getResources().getQuantityString(R.plurals.groupCardCount, groupCardCount, groupCardCount));
nameField.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
countField.setTextSize(settings.getFontSizeMax(settings.getSmallFont()));
inputHolder.mName.setTextSize(mSettings.getFontSizeMax(mSettings.getMediumFont()));
inputHolder.mCardCount.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
applyClickEvents(inputHolder);
}
private void applyClickEvents(GroupListItemViewHolder inputHolder)
{
inputHolder.mMoveDown.setOnClickListener(view -> mListener.onMoveDownButtonClicked(inputHolder.itemView));
inputHolder.mMoveUp.setOnClickListener(view -> mListener.onMoveUpButtonClicked(inputHolder.itemView));
inputHolder.mEdit.setOnClickListener(view -> mListener.onEditButtonClicked(inputHolder.itemView));
inputHolder.mDelete.setOnClickListener(view -> mListener.onDeleteButtonClicked(inputHolder.itemView));
}
public interface GroupAdapterListener
{
void onMoveDownButtonClicked(View view);
void onMoveUpButtonClicked(View view);
void onEditButtonClicked(View view);
void onDeleteButtonClicked(View view);
}
public class GroupListItemViewHolder extends RecyclerView.ViewHolder
{
public TextView mName, mCardCount;
public AppCompatImageButton mMoveUp, mMoveDown, mEdit, mDelete;
public GroupListItemViewHolder(View inputView) {
super(inputView);
mName = inputView.findViewById(R.id.name);
mCardCount = inputView.findViewById(R.id.cardCount);
mMoveUp = inputView.findViewById(R.id.moveUp);
mMoveDown = inputView.findViewById(R.id.moveDown);
mEdit = inputView.findViewById(R.id.edit);
mDelete = inputView.findViewById(R.id.delete);
}
}
}

View File

@@ -220,23 +220,20 @@ public class ImportExportActivity extends AppCompatActivity
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
{
if(requestCode == PERMISSIONS_EXTERNAL_STORAGE)
{
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSIONS_EXTERNAL_STORAGE) {
// If request is cancelled, the result arrays are empty.
boolean success = grantResults.length > 0;
for(int grant : grantResults)
{
if(grant != PackageManager.PERMISSION_GRANTED)
{
for (int grant : grantResults) {
if (grant != PackageManager.PERMISSION_GRANTED) {
success = false;
}
}
if(!success)
{
if (!success) {
// External storage permission rejected, inform user that
// import/export is prevented
Toast.makeText(getApplicationContext(), R.string.noExternalStoragePermissionError,

View File

@@ -11,7 +11,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import protect.card_locker.importexport.DataFormat;

View File

@@ -7,8 +7,6 @@ import com.google.zxing.BarcodeFormat;
import java.math.BigDecimal;
import java.util.Currency;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import androidx.annotation.Nullable;

View File

@@ -39,14 +39,22 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener)
{
super(inputCursor);
setHasStableIds(true);
mSettings = new Settings(inputContext);
mCursor = inputCursor;
mContext = inputContext;
mListener = inputListener;
mSelectedItems = new SparseBooleanArray();
mAnimationItemsIndex = new SparseBooleanArray();
mDarkModeEnabled = MainActivity.isDarkModeEnabled(inputContext);
swapCursor(mCursor);
}
@Override
public void swapCursor(Cursor inputCursor) {
super.swapCursor(inputCursor);
mCursor = inputCursor;
}
@Override
@@ -111,53 +119,20 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
private void applyClickEvents(LoyaltyCardListItemViewHolder inputHolder, final int inputPosition)
{
inputHolder.mThumbnailContainer.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View inputView)
{
mListener.onIconClicked(inputPosition);
}
inputHolder.mThumbnailContainer.setOnClickListener(inputView -> mListener.onIconClicked(inputPosition));
inputHolder.mRow.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition));
inputHolder.mInformationContainer.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition));
inputHolder.mRow.setOnLongClickListener(inputView -> {
mListener.onRowLongClicked(inputPosition);
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
});
inputHolder.mRow.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View inputView)
{
mListener.onRowClicked(inputPosition);
}
});
inputHolder.mInformationContainer.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View inputView)
{
mListener.onRowClicked(inputPosition);
}
});
inputHolder.mRow.setOnLongClickListener(new View.OnLongClickListener()
{
@Override
public boolean onLongClick(View inputView)
{
mListener.onRowLongClicked(inputPosition);
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
}
});
inputHolder.mInformationContainer.setOnLongClickListener(new View.OnLongClickListener()
{
@Override
public boolean onLongClick(View inputView)
{
mListener.onRowLongClicked(inputPosition);
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
}
inputHolder.mInformationContainer.setOnLongClickListener(inputView -> {
mListener.onRowLongClicked(inputPosition);
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
});
}

View File

@@ -50,7 +50,6 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.ArrayList;
@@ -63,7 +62,6 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
@@ -87,6 +85,13 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
private static final int PERMISSION_REQUEST_CAMERA_IMAGE_FRONT = 100;
private static final int PERMISSION_REQUEST_CAMERA_IMAGE_BACK = 101;
public static final String BUNDLE_ID = "id";
public static final String BUNDLE_UPDATE = "update";
public static final String BUNDLE_CARDID = "cardId";
public static final String BUNDLE_BARCODEID = "barcodeId";
public static final String BUNDLE_BARCODETYPE = "barcodeType";
public static final String BUNDLE_ADDGROUP = "addGroup";
TabLayout tabs;
ImageView thumbnail;
@@ -114,9 +119,9 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
String cardId;
String barcodeId;
String barcodeType;
String addGroup;
Uri importLoyaltyCardUri = null;
Integer headingColorValue = null;
DBHelper db;
ImportURIHelper importUriHelper;
@@ -137,31 +142,18 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
LoyaltyCard tempLoyaltyCard;
private static LoyaltyCard updateTempState(LoyaltyCard loyaltyCard, LoyaltyCardField fieldName, Object value) {
Map<LoyaltyCardField, Object> cardData = new HashMap<>();
for (LoyaltyCardField existingFieldName : LoyaltyCardField.values()) {
try {
Field field = LoyaltyCard.class.getField(existingFieldName.name());
cardData.put(existingFieldName, field.get(loyaltyCard));
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
cardData.put(fieldName, value);
return new LoyaltyCard(
(int) cardData.get(LoyaltyCardField.id),
(String) cardData.get(LoyaltyCardField.store),
(String) cardData.get(LoyaltyCardField.note),
(Date) cardData.get(LoyaltyCardField.expiry),
(BigDecimal) cardData.get(LoyaltyCardField.balance),
(Currency) cardData.get(LoyaltyCardField.balanceType),
(String) cardData.get(LoyaltyCardField.cardId),
(String) cardData.get(LoyaltyCardField.barcodeId),
(BarcodeFormat) cardData.get(LoyaltyCardField.barcodeType),
(Integer) cardData.get(LoyaltyCardField.headerColor),
(int) cardData.get(LoyaltyCardField.starStatus)
(int) (fieldName == LoyaltyCardField.id ? value : loyaltyCard.id),
(String) (fieldName == LoyaltyCardField.store ? value : loyaltyCard.store),
(String) (fieldName == LoyaltyCardField.note ? value : loyaltyCard.note),
(Date) (fieldName == LoyaltyCardField.expiry ? value : loyaltyCard.expiry),
(BigDecimal) (fieldName == LoyaltyCardField.balance ? value : loyaltyCard.balance),
(Currency) (fieldName == LoyaltyCardField.balanceType ? value : loyaltyCard.balanceType),
(String) (fieldName == LoyaltyCardField.cardId ? value : loyaltyCard.cardId),
(String) (fieldName == LoyaltyCardField.barcodeId ? value : loyaltyCard.barcodeId),
(BarcodeFormat) (fieldName == LoyaltyCardField.barcodeType ? value : loyaltyCard.barcodeType),
(Integer) (fieldName == LoyaltyCardField.headerColor ? value : loyaltyCard.headerColor),
(int) (fieldName == LoyaltyCardField.starStatus ? value : loyaltyCard.starStatus)
);
}
@@ -174,12 +166,13 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
private void extractIntentFields(Intent intent)
{
final Bundle b = intent.getExtras();
loyaltyCardId = b != null ? b.getInt("id") : 0;
updateLoyaltyCard = b != null && b.getBoolean("update", false);
loyaltyCardId = b != null ? b.getInt(BUNDLE_ID) : 0;
updateLoyaltyCard = b != null && b.getBoolean(BUNDLE_UPDATE, false);
cardId = b != null ? b.getString("cardId") : null;
barcodeId = b != null ? b.getString("barcodeId") : null;
barcodeType = b != null ? b.getString("barcodeType") : null;
cardId = b != null ? b.getString(BUNDLE_CARDID) : null;
barcodeId = b != null ? b.getString(BUNDLE_BARCODEID) : null;
barcodeType = b != null ? b.getString(BUNDLE_BARCODETYPE) : null;
addGroup = b != null ? b.getString(BUNDLE_ADDGROUP) : null;
importLoyaltyCardUri = intent.getData();
@@ -610,13 +603,18 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
chip.setText(group._id);
chip.setTag(group);
chip.setChecked(false);
for (Group loyaltyCardGroup : loyaltyCardGroups) {
if (loyaltyCardGroup._id.equals(group._id)) {
chip.setChecked(true);
break;
if (group._id.equals(addGroup)) {
chip.setChecked(true);
} else {
chip.setChecked(false);
for (Group loyaltyCardGroup : loyaltyCardGroups) {
if (loyaltyCardGroup._id.equals(group._id)) {
chip.setChecked(true);
break;
}
}
}
chip.setOnTouchListener((v, event) -> {
hasChanged = true;
@@ -640,7 +638,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
// 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) {
thumbnail.setOnClickListener(new ColorSelectListener(tempLoyaltyCard.headerColor));
thumbnail.setOnClickListener(new ColorSelectListener());
}
// Update from intent
@@ -837,7 +835,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
{
Intent i = new Intent(getApplicationContext(), ScanActivity.class);
final Bundle b = new Bundle();
b.putString("cardId", cardIdFieldView.getText().toString());
b.putString(LoyaltyCardEditActivity.BUNDLE_CARDID, cardIdFieldView.getText().toString());
i.putExtras(b);
startActivityForResult(i, Utils.BARCODE_SCAN);
}
@@ -896,25 +894,22 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
class ColorSelectListener implements View.OnClickListener
{
final int defaultColor;
ColorSelectListener(int defaultColor)
{
this.defaultColor = defaultColor;
}
@Override
public void onClick(View v)
{
ColorPickerDialog dialog = ColorPickerDialog.newBuilder().setColor(defaultColor).create();
ColorPickerDialog.Builder dialogBuilder = ColorPickerDialog.newBuilder();
if (tempLoyaltyCard.headerColor != null) {
dialogBuilder.setColor(tempLoyaltyCard.headerColor);
}
ColorPickerDialog dialog = dialogBuilder.create();
dialog.setColorPickerDialogListener(new ColorPickerDialogListener()
{
@Override
public void onColorSelected(int dialogId, int color)
{
hasChanged = true;
headingColorValue = color;
updateTempState(LoyaltyCardField.headerColor, color);
generateIcon(storeFieldEdit.getText().toString());
}
@@ -1064,30 +1059,18 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.deleteTitle);
builder.setMessage(R.string.deleteConfirmation);
builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
Log.e(TAG, "Deleting card: " + loyaltyCardId);
builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
Log.e(TAG, "Deleting card: " + loyaltyCardId);
DBHelper db = new DBHelper(LoyaltyCardEditActivity.this);
db.deleteLoyaltyCard(loyaltyCardId);
DBHelper db = new DBHelper(LoyaltyCardEditActivity.this);
db.deleteLoyaltyCard(loyaltyCardId);
ShortcutHelper.removeShortcut(LoyaltyCardEditActivity.this, loyaltyCardId);
ShortcutHelper.removeShortcut(LoyaltyCardEditActivity.this, loyaltyCardId);
finish();
dialog.dismiss();
}
});
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
}
finish();
dialog.dismiss();
});
builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
AlertDialog dialog = builder.create();
dialog.show();

View File

@@ -1,11 +1,10 @@
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 Application {
public class LoyaltyCardLockerApplication extends MultiDexApplication {
public void onCreate() {
super.onCreate();

View File

@@ -8,6 +8,7 @@ import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
@@ -32,6 +33,7 @@ import com.google.zxing.BarcodeFormat;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -39,6 +41,7 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.Guideline;
import androidx.core.graphics.drawable.DrawableCompat;
@@ -62,7 +65,7 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
TextView groupsView;
TextView balanceView;
TextView expiryView;
TextView storeName;
AppCompatTextView storeName;
ImageButton maximizeButton;
ImageView barcodeImage;
ImageButton minimizeButton;
@@ -92,6 +95,8 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
FullscreenType fullscreenType = FullscreenType.NONE;
boolean isBarcodeSupported = true;
static final String STATE_FULLSCREENTYPE = "fullscreenType";
enum FullscreenType {
NONE,
BARCODE,
@@ -128,6 +133,10 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
{
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
fullscreenType = FullscreenType.valueOf(savedInstanceState.getString(STATE_FULLSCREENTYPE));
}
settings = new Settings(this);
extractIntentFields(getIntent());
@@ -285,6 +294,13 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
extractIntentFields(intent);
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString(STATE_FULLSCREENTYPE, String.valueOf(fullscreenType));
super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onResume()
{
@@ -367,14 +383,13 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
List<Group> loyaltyCardGroups = db.getLoyaltyCardGroups(loyaltyCardId);
if(loyaltyCardGroups.size() > 0) {
StringBuilder groupsString = new StringBuilder();
List<String> groupNames = new ArrayList<>();
for (Group group : loyaltyCardGroups) {
groupsString.append(group._id);
groupsString.append(" ");
groupNames.add(group._id);
}
groupsView.setVisibility(View.VISIBLE);
groupsView.setText(getString(R.string.groupsList, groupsString.toString()));
groupsView.setText(getString(R.string.groupsList, TextUtils.join(", ", groupNames)));
groupsView.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
}
else
@@ -415,6 +430,12 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
storeName.setText(loyaltyCard.store);
storeName.setTextSize(settings.getFontSizeMax(settings.getLargeFont()));
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(
storeName,
settings.getFontSizeMin(settings.getLargeFont()),
settings.getFontSizeMax(settings.getLargeFont()),
1,
TypedValue.COMPLEX_UNIT_DIP);
int backgroundHeaderColor;
if(loyaltyCard.headerColor != null)
@@ -468,40 +489,7 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
Toast.makeText(this, getString(R.string.unsupportedBarcodeType), Toast.LENGTH_LONG).show();
}
if(format != null && isBarcodeSupported)
{
if (fullscreenType == FullscreenType.NONE) {
maximizeButton.setVisibility(View.VISIBLE);
}
barcodeImage.setVisibility(View.VISIBLE);
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
// yet been drawn. Wait for it to be drawn so the size is available.
redrawBarcodeAfterResize();
}
else
{
Log.d(TAG, "ImageView size known known, creating barcode");
new BarcodeImageWriterTask(
barcodeImage,
barcodeIdString != null ? barcodeIdString : cardIdString,
format,
null,
false,
null)
.execute();
}
// Force redraw fullscreen state
setFullscreen(fullscreenType);
}
else
{
maximizeButton.setVisibility(View.GONE);
barcodeImage.setVisibility(View.GONE);
}
setFullscreen(fullscreenType);
}
@Override

View File

@@ -16,7 +16,6 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
@@ -25,6 +24,7 @@ import com.google.android.material.tabs.TabLayout;
import java.io.UnsupportedEncodingException;
import java.util.List;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.SearchView;
@@ -46,12 +46,13 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
protected String mFilter = "";
protected int selectedTab = 0;
private RecyclerView mCardList;
private View mHelpText;
private View mNoMatchingCardsText;
private ActionMode.Callback mCurrentActionModeCallback = new ActionMode.Callback()
{
@Override
public boolean onCreateActionMode(ActionMode inputMode, Menu inputMenu)
{
public boolean onCreateActionMode(ActionMode inputMode, Menu inputMenu) {
inputMode.getMenuInflater().inflate(R.menu.card_longclick_menu, inputMenu);
return true;
}
@@ -63,10 +64,8 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
}
@Override
public boolean onActionItemClicked(ActionMode inputMode, MenuItem inputItem)
{
if (inputItem.getItemId() == R.id.action_copy_to_clipboard)
{
public boolean onActionItemClicked(ActionMode inputMode, MenuItem inputItem) {
if (inputItem.getItemId() == R.id.action_copy_to_clipboard) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
String clipboardData;
@@ -94,9 +93,7 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
Toast.makeText(MainActivity.this, cardCount > 1 ? R.string.copy_to_clipboard_multiple_toast : R.string.copy_to_clipboard_toast, Toast.LENGTH_LONG).show();
inputMode.finish();
return true;
}
else if (inputItem.getItemId() == R.id.action_share)
{
} else if (inputItem.getItemId() == R.id.action_share) {
final ImportURIHelper importURIHelper = new ImportURIHelper(MainActivity.this);
try {
importURIHelper.startShareIntent(mAdapter.getSelectedItems());
@@ -106,20 +103,54 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
}
inputMode.finish();
return true;
}
else if(inputItem.getItemId() == R.id.action_edit)
{
} else if(inputItem.getItemId() == R.id.action_edit) {
if (mAdapter.getSelectedItemCount() != 1) {
throw new IllegalArgumentException("Cannot edit more than 1 card at a time");
}
Intent intent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("id", mAdapter.getSelectedItems().get(0).id);
bundle.putBoolean("update", true);
bundle.putInt(LoyaltyCardEditActivity.BUNDLE_ID, mAdapter.getSelectedItems().get(0).id);
bundle.putBoolean(LoyaltyCardEditActivity.BUNDLE_UPDATE, true);
intent.putExtras(bundle);
startActivity(intent);
inputMode.finish();
return true;
} else if(inputItem.getItemId() == R.id.action_delete) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
// The following may seem weird, but it is necessary to give translators enough flexibility.
// For example, in Russian, Android's plural quantity "one" actually refers to "any number ending on 1 but not ending in 11".
// So while in English the extra non-plural form seems unnecessary duplication, it is necessary to give translators enough flexibility.
// In here, we use the plain string when meaning exactly 1, and otherwise use the plural forms
if (mAdapter.getSelectedItemCount() == 1) {
builder.setTitle(R.string.deleteTitle);
builder.setMessage(R.string.deleteConfirmation);
} else {
builder.setTitle(getResources().getQuantityString(R.plurals.deleteCardsTitle, mAdapter.getSelectedItemCount(), mAdapter.getSelectedItemCount()));
builder.setMessage(getResources().getQuantityString(R.plurals.deleteCardsConfirmation, mAdapter.getSelectedItemCount(), mAdapter.getSelectedItemCount()));
}
builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
DBHelper db = new DBHelper(MainActivity.this);
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
Log.e(TAG, "Deleting card: " + loyaltyCard.id);
db.deleteLoyaltyCard(loyaltyCard.id);
ShortcutHelper.removeShortcut(MainActivity.this, loyaltyCard.id);
}
TabLayout.Tab tab = ((TabLayout) findViewById(R.id.groups)).getTabAt(selectedTab);
updateLoyaltyCardList(mFilter, tab != null ? tab.getTag() : null);
dialog.dismiss();
});
builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
AlertDialog dialog = builder.create();
dialog.show();
return true;
}
@@ -150,8 +181,6 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
updateLoyaltyCardList(mFilter, null);
TabLayout groupsTabLayout = findViewById(R.id.groups);
groupsTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
@@ -188,13 +217,24 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
}
};
final View helpText = findViewById(R.id.helpText);
final View noMatchingCardsText = findViewById(R.id.noMatchingCardsText);
final View list = findViewById(R.id.list);
mHelpText = findViewById(R.id.helpText);
mNoMatchingCardsText = findViewById(R.id.noMatchingCardsText);
mCardList = findViewById(R.id.list);
helpText.setOnTouchListener(gestureTouchListener);
noMatchingCardsText.setOnTouchListener(gestureTouchListener);
list.setOnTouchListener(gestureTouchListener);
mHelpText.setOnTouchListener(gestureTouchListener);
mNoMatchingCardsText.setOnTouchListener(gestureTouchListener);
mCardList.setOnTouchListener(gestureTouchListener);
// Init card list
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
mCardList.setLayoutManager(mLayoutManager);
mCardList.setItemAnimator(new DefaultItemAnimator());
mAdapter = new LoyaltyCardCursorAdapter(this, null, this);
mCardList.setAdapter(mAdapter);
registerForContextMenu(mCardList);
updateLoyaltyCardList(mFilter, null);
/*
* This was added for Huawei, but Huawei is just too much of a fucking pain.
@@ -276,8 +316,13 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
FloatingActionButton addButton = findViewById(R.id.fabAdd);
addButton.setOnClickListener(v -> {
Intent i = new Intent(getApplicationContext(), ScanActivity.class);
startActivityForResult(i, Utils.BARCODE_SCAN);
Intent intent = new Intent(getApplicationContext(), ScanActivity.class);
Bundle bundle = new Bundle();
if (selectedTab != 0) {
bundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, groupsTabLayout.getTabAt(selectedTab).getText().toString());
}
intent.putExtras(bundle);
startActivityForResult(intent, Utils.BARCODE_SCAN);
});
addButton.bringToFront();
}
@@ -305,8 +350,12 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
if(!barcodeValues.isEmpty()) {
Intent newIntent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle newBundle = new Bundle();
newBundle.putString("barcodeType", barcodeValues.format());
newBundle.putString("cardId", barcodeValues.content());
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_BARCODETYPE, barcodeValues.format());
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_CARDID, barcodeValues.content());
Bundle inputBundle = intent.getExtras();
if (inputBundle != null && inputBundle.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP) != null) {
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, inputBundle.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP));
}
newIntent.putExtras(newBundle);
startActivity(newIntent);
}
@@ -345,20 +394,7 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
group = (Group) tag;
}
mCardList = findViewById(R.id.list);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
mCardList.setLayoutManager(mLayoutManager);
mCardList.setItemAnimator(new DefaultItemAnimator());
final TextView helpText = findViewById(R.id.helpText);
final TextView noMatchingCardsText = findViewById(R.id.noMatchingCardsText);
Cursor cardCursor = mDB.getLoyaltyCardCursor(filterText, group);
mAdapter = new LoyaltyCardCursorAdapter(this, cardCursor, this);
mCardList.setAdapter(mAdapter);
registerForContextMenu(mCardList);
mAdapter.swapCursor(mDB.getLoyaltyCardCursor(filterText, group));
if(mDB.getLoyaltyCardCount() > 0)
{
@@ -366,21 +402,21 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
// to ensure that the noMatchingCardsText doesn't end up being shown below
// the keyboard
mCardList.setVisibility(View.VISIBLE);
helpText.setVisibility(View.GONE);
mHelpText.setVisibility(View.GONE);
if(mAdapter.getItemCount() > 0)
{
noMatchingCardsText.setVisibility(View.GONE);
mNoMatchingCardsText.setVisibility(View.GONE);
}
else
{
noMatchingCardsText.setVisibility(View.VISIBLE);
mNoMatchingCardsText.setVisibility(View.VISIBLE);
}
}
else
{
mCardList.setVisibility(View.GONE);
helpText.setVisibility(View.VISIBLE);
noMatchingCardsText.setVisibility(View.GONE);
mHelpText.setVisibility(View.VISIBLE);
mNoMatchingCardsText.setVisibility(View.GONE);
}
if (mCurrentActionMode != null) {
@@ -643,7 +679,6 @@ public class MainActivity extends AppCompatActivity implements LoyaltyCardCursor
@Override
public void onRowClicked(int inputPosition)
{
if (mAdapter.getSelectedItemCount() > 0)
{
enableActionMode(inputPosition);

View File

@@ -1,7 +1,6 @@
package protect.card_locker;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
@@ -10,8 +9,6 @@ import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
@@ -22,12 +19,18 @@ import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class ManageGroupsActivity extends AppCompatActivity
public class ManageGroupsActivity extends AppCompatActivity implements GroupCursorAdapter.GroupAdapterListener
{
private static final String TAG = "Catima";
private final DBHelper db = new DBHelper(this);
private final DBHelper mDb = new DBHelper(this);
private TextView mHelpText;
private RecyclerView mGroupList;
GroupCursorAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState)
@@ -41,19 +44,28 @@ public class ManageGroupsActivity extends AppCompatActivity
{
actionBar.setDisplayHomeAsUpEnabled(true);
}
updateGroupList();
}
@Override
protected void onResume() {
super.onResume();
updateGroupList();
FloatingActionButton addButton = findViewById(R.id.fabAdd);
addButton.setOnClickListener(v -> createGroup());
addButton.bringToFront();
mGroupList = findViewById(R.id.list);
mHelpText = findViewById(R.id.helpText);
// Init group list
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
mGroupList.setLayoutManager(mLayoutManager);
mGroupList.setItemAnimator(new DefaultItemAnimator());
mAdapter = new GroupCursorAdapter(this, null, this);
mGroupList.setAdapter(mAdapter);
updateGroupList();
}
@Override
@@ -63,27 +75,17 @@ public class ManageGroupsActivity extends AppCompatActivity
private void updateGroupList()
{
final ListView groupList = findViewById(R.id.list);
final TextView helpText = findViewById(R.id.helpText);
final DBHelper db = new DBHelper(this);
mAdapter.swapCursor(mDb.getGroupCursor());
if(db.getGroupCount() > 0)
{
groupList.setVisibility(View.VISIBLE);
helpText.setVisibility(View.GONE);
}
else
{
groupList.setVisibility(View.GONE);
helpText.setVisibility(View.VISIBLE);
if (mDb.getGroupCount() == 0) {
mGroupList.setVisibility(View.GONE);
mHelpText.setVisibility(View.VISIBLE);
return;
}
Cursor groupCursor = db.getGroupCursor();
final GroupCursorAdapter adapter = new GroupCursorAdapter(this, groupCursor);
groupList.setAdapter(adapter);
registerForContextMenu(groupList);
mGroupList.setVisibility(View.VISIBLE);
mHelpText.setVisibility(View.GONE);
}
private void invalidateHomescreenActiveTab()
@@ -108,69 +110,6 @@ public class ManageGroupsActivity extends AppCompatActivity
return super.onOptionsItemSelected(item);
}
public void moveGroupUp(View view) {
moveGroup(view, true);
}
public void moveGroupDown(View view) {
moveGroup(view, false);
}
public void editGroup(View view) {
final String groupName = getGroupname(view);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.enter_group_name);
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setText(groupName);
builder.setView(input);
builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
db.updateGroup(groupName, input.getText().toString());
updateGroupList();
}
});
builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog dialog = builder.create();
dialog.show();
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
input.requestFocus();
}
public void deleteGroup(View view) {
final String groupName = getGroupname(view);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.deleteConfirmationGroup);
builder.setMessage(groupName);
builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
db.deleteGroup(groupName);
updateGroupList();
// Delete may change ordering, so invalidate
invalidateHomescreenActiveTab();
}
});
builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
private void createGroup() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.enter_group_name);
@@ -178,51 +117,28 @@ public class ManageGroupsActivity extends AppCompatActivity
input.setInputType(InputType.TYPE_CLASS_TEXT);
builder.setView(input);
builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
db.insertGroup(input.getText().toString());
updateGroupList();
}
});
builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
mDb.insertGroup(input.getText().toString());
updateGroupList();
});
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
AlertDialog dialog = builder.create();
dialog.show();
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
input.requestFocus();
}
private String getGroupname(View view) {
LinearLayout parentRow = (LinearLayout) view.getParent().getParent();
TextView groupNameTextView = parentRow.findViewById(R.id.name);
private String getGroupName(View view) {
TextView groupNameTextView = view.findViewById(R.id.name);
return (String) groupNameTextView.getText();
}
private void moveGroup(View view, boolean up) {
final String groupName = getGroupname(view);
List<Group> groups = mDb.getGroups();
final String groupName = getGroupName(view);
List<Group> groups = db.getGroups();
int currentIndex = -1;
Integer newIndex;
// Get current index in group list
for (int i = 0; i < groups.size(); i++) {
if (groups.get(i)._id.equals(groupName)) {
currentIndex = i;
break;
}
}
if (currentIndex == -1) {
throw new IndexOutOfBoundsException();
}
int currentIndex = mDb.getGroup(groupName).order;
int newIndex;
// Reinsert group in correct position
if (up) {
@@ -240,7 +156,7 @@ public class ManageGroupsActivity extends AppCompatActivity
groups.add(newIndex, group);
// Update database
db.reorderGroups(groups);
mDb.reorderGroups(groups);
// Update UI
updateGroupList();
@@ -248,4 +164,56 @@ public class ManageGroupsActivity extends AppCompatActivity
// Ordering may have changed, so invalidate
invalidateHomescreenActiveTab();
}
@Override
public void onMoveDownButtonClicked(View view) {
moveGroup(view, false);
}
@Override
public void onMoveUpButtonClicked(View view) {
moveGroup(view, true);
}
@Override
public void onEditButtonClicked(View view) {
final String groupName = getGroupName(view);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.enter_group_name);
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setText(groupName);
builder.setView(input);
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
String newGroupName = input.getText().toString();
mDb.updateGroup(groupName, newGroupName);
updateGroupList();
});
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
AlertDialog dialog = builder.create();
dialog.show();
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
input.requestFocus();
}
@Override
public void onDeleteButtonClicked(View view) {
final String groupName = getGroupName(view);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.deleteConfirmationGroup);
builder.setMessage(groupName);
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
mDb.deleteGroup(groupName);
updateGroupList();
// Delete may change ordering, so invalidate
invalidateHomescreenActiveTab();
});
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
AlertDialog dialog = builder.create();
dialog.show();
}
}

View File

@@ -36,11 +36,13 @@ public class ScanActivity extends AppCompatActivity {
private DecoratedBarcodeView barcodeScannerView;
private String cardId;
private String addGroup;
private boolean torch = false;
private void extractIntentFields(Intent intent) {
final Bundle b = intent.getExtras();
cardId = b != null ? b.getString("cardId") : null;
cardId = b != null ? b.getString(LoyaltyCardEditActivity.BUNDLE_CARDID) : null;
addGroup = b != null ? b.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP) : null;
Log.d(TAG, "Scan activity: id=" + cardId);
}
@@ -58,6 +60,9 @@ public class ScanActivity extends AppCompatActivity {
extractIntentFields(getIntent());
findViewById(R.id.add_from_image).setOnClickListener(this::addFromImage);
findViewById(R.id.add_manually).setOnClickListener(this::addManually);
barcodeScannerView = findViewById(R.id.zxing_barcode_scanner);
// Even though we do the actual decoding with the barcodeScannerView
@@ -76,6 +81,9 @@ public class ScanActivity extends AppCompatActivity {
Bundle scanResultBundle = new Bundle();
scanResultBundle.putString(BarcodeSelectorActivity.BARCODE_CONTENTS, result.getText());
scanResultBundle.putString(BarcodeSelectorActivity.BARCODE_FORMAT, result.getBarcodeFormat().toString());
if (addGroup != null) {
scanResultBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, addGroup);
}
scanResult.putExtras(scanResultBundle);
ScanActivity.this.setResult(RESULT_OK, scanResult);
finish();
@@ -167,6 +175,9 @@ public class ScanActivity extends AppCompatActivity {
Bundle manualResultBundle = new Bundle();
manualResultBundle.putString(BarcodeSelectorActivity.BARCODE_CONTENTS, barcodeValues.content());
manualResultBundle.putString(BarcodeSelectorActivity.BARCODE_FORMAT, barcodeValues.format());
if (addGroup != null) {
manualResultBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, addGroup);
}
manualResult.putExtras(manualResultBundle);
ScanActivity.this.setResult(RESULT_OK, manualResult);
finish();

View File

@@ -5,6 +5,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.os.Build;
@@ -37,6 +38,8 @@ class ShortcutHelper
ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class);
LinkedList<ShortcutInfo> list = new LinkedList<>(shortcutManager.getDynamicShortcuts());
DBHelper dbHelper = new DBHelper(context);
String shortcutId = Integer.toString(card.id);
// Sort the shortcuts by rank, so working with the relative order will be easier.
@@ -105,6 +108,14 @@ class ShortcutHelper
Intent shortcutIntent = prevShortcut.getIntent();
Bitmap iconBitmap = Utils.generateIcon(context, dbHelper.getLoyaltyCard(Integer.parseInt(prevShortcut.getId())), true).getLetterTile();
Icon icon;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
icon = Icon.createWithAdaptiveBitmap(iconBitmap);
} else {
icon = Icon.createWithBitmap(iconBitmap);
}
// Prevent instances of the view activity from piling up; if one exists let this
// one replace it.
shortcutIntent.setFlags(shortcutIntent.getFlags() | Intent.FLAG_ACTIVITY_SINGLE_TOP);
@@ -113,7 +124,7 @@ class ShortcutHelper
.setShortLabel(prevShortcut.getShortLabel())
.setLongLabel(prevShortcut.getLongLabel())
.setIntent(shortcutIntent)
.setIcon(Icon.createWithResource(context, R.drawable.circle))
.setIcon(icon)
.setRank(index)
.build();

View File

@@ -9,7 +9,6 @@ import android.graphics.Color;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.Log;
import android.widget.Toast;
@@ -33,7 +32,6 @@ import java.util.Currency;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import androidx.core.graphics.ColorUtils;
@@ -54,6 +52,10 @@ public class Utils {
static final int BITMAP_SIZE_BIG = 512;
static public LetterBitmap generateIcon(Context context, LoyaltyCard loyaltyCard, boolean forShortcut) {
return generateIcon(context, loyaltyCard.store, loyaltyCard.headerColor, forShortcut);
}
static public LetterBitmap generateIcon(Context context, String store, Integer backgroundColor) {
return generateIcon(context, store, backgroundColor, false);
}
@@ -240,17 +242,17 @@ public class Utils {
return null;
}
Integer maxSize = BITMAP_SIZE_BIG;
double maxSize = BITMAP_SIZE_BIG;
Integer width = bitmap.getWidth();
Integer height = bitmap.getHeight();
double width = bitmap.getWidth();
double height = bitmap.getHeight();
if (height > width) {
Integer scale = height / maxSize;
double scale = height / maxSize;
height = maxSize;
width = width / scale;
} else if (width > height) {
Integer scale = width / maxSize;
double scale = width / maxSize;
width = maxSize;
height = height / scale;
} else {
@@ -258,7 +260,7 @@ public class Utils {
width = maxSize;
}
return Bitmap.createScaledBitmap(bitmap, width, height, true);
return Bitmap.createScaledBitmap(bitmap, (int) Math.round(width), (int) Math.round(height), true);
}
static public Bitmap rotateBitmap(Bitmap bitmap, ExifInterface exifInterface) {

View File

@@ -12,7 +12,6 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class ZipUtils {

View File

@@ -4,7 +4,6 @@ import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.InternalZipConstants;
@@ -12,16 +11,13 @@ import net.lingala.zip4j.util.InternalZipConstants;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import protect.card_locker.DBHelper;
import protect.card_locker.Group;

View File

@@ -21,6 +21,7 @@ import java.io.InputStreamReader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Currency;
import java.util.Date;
import java.util.List;
@@ -142,18 +143,36 @@ public class CatimaImporter implements Importer
String tmp = input.readLine();
if (tmp == null || tmp.isEmpty()) {
boolean sectionParsed = false;
switch (part) {
case 0:
// This is the version info, ignore
sectionParsed = true;
break;
case 1:
parseV2Groups(db, database, stringPart);
try {
parseV2Groups(db, database, stringPart);
sectionParsed = true;
} catch (FormatException e) {
// We may have a multiline field, try again
}
break;
case 2:
parseV2Cards(context, db, database, stringPart);
try {
parseV2Cards(context, db, database, stringPart);
sectionParsed = true;
} catch (FormatException e) {
// We may have a multiline field, try again
}
break;
case 3:
parseV2CardGroups(db, database, stringPart);
try {
parseV2CardGroups(db, database, stringPart);
sectionParsed = true;
} catch (FormatException e) {
// We may have a multiline field, try again
}
break;
default:
throw new FormatException("Issue parsing CSV data, too many parts for v2 parsing");
@@ -163,8 +182,12 @@ public class CatimaImporter implements Importer
break;
}
part += 1;
stringPart = "";
if (sectionParsed) {
part += 1;
stringPart = "";
} else {
stringPart += tmp + "\n";
}
} else {
stringPart += tmp + "\n";
}
@@ -183,9 +206,11 @@ public class CatimaImporter implements Importer
// Parse groups
final CSVParser groupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
List<CSVRecord> records = new ArrayList<>();
try {
for (CSVRecord record : groupParser) {
importGroup(database, db, record);
records.add(record);
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
@@ -196,6 +221,10 @@ public class CatimaImporter implements Importer
} finally {
groupParser.close();
}
for (CSVRecord record : records) {
importGroup(database, db, record);
}
}
public void parseV2Cards(Context context, DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
@@ -203,9 +232,11 @@ public class CatimaImporter implements Importer
// Parse cards
final CSVParser cardParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
List<CSVRecord> records = new ArrayList<>();
try {
for (CSVRecord record : cardParser) {
importLoyaltyCard(context, database, db, record);
records.add(record);
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
@@ -216,6 +247,10 @@ public class CatimaImporter implements Importer
} finally {
cardParser.close();
}
for (CSVRecord record : records) {
importLoyaltyCard(context, database, db, record);
}
}
public void parseV2CardGroups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
@@ -223,9 +258,11 @@ public class CatimaImporter implements Importer
// Parse card group mappings
final CSVParser cardGroupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
List<CSVRecord> records = new ArrayList<>();
try {
for (CSVRecord record : cardGroupParser) {
importCardGroupMapping(database, db, record);
records.add(record);
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
@@ -236,6 +273,10 @@ public class CatimaImporter implements Importer
} finally {
cardGroupParser.close();
}
for (CSVRecord record : records) {
importCardGroupMapping(database, db, record);
}
}
/**

View File

@@ -4,7 +4,6 @@ import android.content.Context;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import protect.card_locker.DBHelper;

View File

@@ -5,7 +5,6 @@ import android.util.Log;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import protect.card_locker.DBHelper;

View File

@@ -3,32 +3,29 @@ package protect.card_locker.importexport;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.google.zxing.BarcodeFormat;
import net.lingala.zip4j.io.inputstream.ZipInputStream;
import net.lingala.zip4j.model.LocalFileHeader;
import org.json.JSONArray;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import protect.card_locker.DBHelper;
import protect.card_locker.FormatException;
import protect.card_locker.R;
import protect.card_locker.Utils;
import protect.card_locker.ZipUtils;
@@ -43,7 +40,25 @@ public class StocardImporter implements Importer
{
public void importData(Context context, DBHelper db, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
HashMap<String, HashMap<String, Object>> loyaltyCardHashMap = new HashMap<>();
HashMap<String, String> providers = 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());
try
{
for (CSVRecord record : parser)
{
HashMap<String, String> recordData = new HashMap<>();
recordData.put("name", record.get("name"));
recordData.put("barcodeFormat", record.get("barcodeFormat"));
providers.put(record.get("_id"), recordData);
}
parser.close();
} catch(IllegalArgumentException|IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e);
}
ZipInputStream zipInputStream = new ZipInputStream(input, password);
@@ -74,9 +89,7 @@ public class StocardImporter implements Importer
};
}
if (startsWith(nameParts, providersFileName, 0) && !localFileHeader.isDirectory()) {
providers = parseProviders(zipInputStream);
} else if (startsWith(nameParts, cardBaseName, 1)) {
if (startsWith(nameParts, cardBaseName, 1)) {
// Extract cardName
cardName = nameParts[cardBaseName.length].split("\\.", 2)[0];
@@ -145,10 +158,13 @@ public class StocardImporter implements Importer
database.beginTransaction();
for (HashMap<String, Object> loyaltyCardData : loyaltyCardHashMap.values()) {
String store = providers.get(loyaltyCardData.get("_providerId").toString());
String providerId = (String) loyaltyCardData.get("_providerId");
HashMap<String, String> providerData = providers.get(providerId);
String store = providerData != null ? providerData.get("name") : providerId;
String note = (String) Utils.hashmapGetOrDefault(loyaltyCardData, "note", "");
String cardId = (String) loyaltyCardData.get("cardId");
String barcodeTypeString = (String) Utils.hashmapGetOrDefault(loyaltyCardData, "barcodeType", null);
String barcodeTypeString = (String) Utils.hashmapGetOrDefault(loyaltyCardData, "barcodeType", providerData != null ? providerData.get("barcodeFormat") : null);
BarcodeFormat barcodeType = null;
if (barcodeTypeString != null) {
if (barcodeTypeString.equals("RSS_DATABAR_EXPANDED")) {
@@ -200,33 +216,4 @@ public class StocardImporter implements Importer
return loyaltyCardHashMap;
}
private HashMap<String, String> parseProviders(ZipInputStream zipInputStream) throws IOException, JSONException {
// FIXME: This is probably completely wrong, but it works for the one and only test file I have
JSONObject jsonObject = ZipUtils.readJSON(zipInputStream);
JSONArray providerIdList = jsonObject.getJSONArray("provider_id_list");
JSONArray providerList = jsonObject.getJSONArray("provider_list");
// Resort, put IDs with - in them after IDs without any -
List<String> providerIds = new ArrayList<>();
List<String> customProviderIds = new ArrayList<>();
for (int i = 0; i < providerIdList.length(); i++) {
String providerId = providerIdList.get(i).toString();
if (providerId.contains("-")) {
customProviderIds.add(providerId);
} else {
providerIds.add(providerId);
}
}
providerIds.addAll(customProviderIds);
HashMap<String, String> providers = new HashMap<>();
for (int i = 0; i < jsonObject.getInt("number_of_cards"); i++) {
providers.put(providerIds.get(i), providerList.get(i).toString());
}
return providers;
}
}

View File

@@ -30,14 +30,12 @@
android:id="@+id/add_from_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="addFromImage"
android:text="@string/addFromImage" />
<Button
android:id="@+id/add_manually"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="addManually"
android:text="@string/addManually" />
</LinearLayout>
</merge>

View File

@@ -4,7 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:baselineAligned="false"
android:padding="@dimen/activity_margin">
@@ -44,8 +44,7 @@
android:layout_weight="1"
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24"
android:contentDescription="@string/moveUp"
app:tint="@color/iconColor"
android:onClick="moveGroupUp"/>
app:tint="@color/iconColor"/>
<ImageButton
android:id="@+id/moveDown"
@@ -54,8 +53,7 @@
android:layout_weight="1"
app:srcCompat="@drawable/ic_baseline_arrow_drop_down_24"
android:contentDescription="@string/moveDown"
app:tint="@color/iconColor"
android:onClick="moveGroupDown"/>
app:tint="@color/iconColor"/>
<ImageButton
android:id="@+id/edit"
@@ -64,8 +62,7 @@
android:layout_weight="1"
app:srcCompat="@drawable/ic_mode_edit_white_24dp"
android:contentDescription="@string/edit"
app:tint="@color/iconColor"
android:onClick="editGroup" />
app:tint="@color/iconColor"/>
<ImageButton
android:id="@+id/delete"
@@ -74,8 +71,7 @@
android:layout_weight="1"
app:srcCompat="@drawable/ic_delete_white_24dp"
android:contentDescription="@string/delete"
app:tint="@color/iconColor"
android:onClick="deleteGroup"/>
app:tint="@color/iconColor"/>
</LinearLayout>

View File

@@ -17,9 +17,10 @@
android:text="@string/noGroups"
android:visibility="gone"/>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:visibility="gone"/>
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:visibility="gone" />
</RelativeLayout>

View File

@@ -113,6 +113,6 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@android:color/black" />
app:tint="#000000" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -45,6 +45,7 @@
<ImageButton
android:id="@+id/maximizeButton"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginStart="15.0dip"
@@ -53,7 +54,7 @@
android:padding="0dp"
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24"
android:contentDescription="@string/moveBarcodeToTopOfScreen"
android:tint="@android:color/white"
app:tint="#ffffff"
android:background="@color/colorPrimary"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/barcode"
@@ -84,7 +85,7 @@
android:padding="0dp"
app:srcCompat="@drawable/ic_baseline_arrow_drop_down_24"
android:contentDescription="@string/moveBarcodeToCenterOfScreen"
android:tint="@android:color/white"
app:tint="#ffffff"
android:background="@color/colorPrimary"
app:layout_constraintTop_toBottomOf="@+id/barcode"
app:layout_constraintEnd_toEndOf="parent"
@@ -150,7 +151,7 @@
android:layout_gravity="top|start"
android:background="@color/colorPrimary"
android:scaleType="fitCenter"
android:tint="@android:color/white"
app:tint="#ffffff"
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24" />
<androidx.core.widget.NestedScrollView
@@ -219,6 +220,7 @@
<TextView
android:id="@+id/noteView"
android:autoLink="all"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
@@ -273,7 +275,7 @@
app:expandedTitleMarginEnd="64dp"
app:contentScrim="?colorPrimary"
app:expandedTitleGravity="top">
<TextView
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/storeName"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@@ -7,20 +7,27 @@
android:title="@string/copy_to_clipboard"
android:icon="@drawable/ic_copy"
android:titleCondensed="@string/copy_to_clipboard"
app:showAsAction="always"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_share"
android:title="@string/share"
android:icon="@drawable/ic_share"
android:titleCondensed="@string/share"
app:showAsAction="always"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_edit"
android:icon="@drawable/ic_edit"
android:title="@string/editCardTitle"
android:titleCondensed="@string/editCardTitle"
app:showAsAction="always"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_delete"
android:icon="@drawable/ic_delete_white_24dp"
android:title="@string/delete"
android:titleCondensed="@string/delete"
app:showAsAction="ifRoom"/>
</menu>

View File

@@ -0,0 +1,7 @@
# stocard_stores.csv
stocard_stores.csv was created by extracting /data/data/de.stocard/de.stocard.stocard/databases/stores on a rooted devices and running the following command over it:
sqlite3 -header -csv stores "select _id,name,barcodeFormat from stores" > stocard_stores.csv
Only used for data portability reasons (ensuring importing works). Do NOT copy this anywhere else or use it for any purpose other than ensuring we can import a GDPR-provided export. We want to make sure this stays under fair use.

View File

File diff suppressed because it is too large Load Diff

View File

@@ -122,8 +122,6 @@
<string name="share">Споделя</string>
<string name="copy_to_clipboard">Копира идентификатора в междинната памет</string>
<string name="ok">Добре</string>
<string name="deleteConfirmation">Потвърдете премахване на карта</string>
<string name="deleteTitle">Премахване на карта</string>
<string name="importSuccessful">Картите са внесени успешно</string>
<string name="chooseImportType">От къде ще внесете\?</string>
<string name="importCatimaMessage">Изберете файла <i>catima.zip</i>, предварително изнесен от Catima.
@@ -146,8 +144,8 @@
<string name="unlockScreen">Разрешава автоматичното завъртане</string>
<string name="lockScreen">Спира автоматичното завъртане</string>
<plurals name="selectedCardCount">
<item quantity="one">Избрана <xliff:g>%d</xliff:g> карта</item>
<item quantity="other">Избрани <xliff:g>%d</xliff:g> карти</item>
<item quantity="one"><xliff:g>%d</xliff:g> избрана карта</item>
<item quantity="other"><xliff:g>%d</xliff:g> избрани карти</item>
</plurals>
<string name="deleteConfirmationGroup">Изтриване на група\?</string>
<string name="moveDown">Преместване надолу</string>
@@ -166,5 +164,15 @@
\nИли създайте такъв файл от меню Внасяне/изнасяне от друго устройство със Loyalty Card Keychain като изберете Изнасяне.</string>
<string name="failedParsingImportUriError">Препратката не може да бъде анализирана за внасяне</string>
<string name="card_ids_copied">[не превеждай този низ, https://github.com/TheLastProject/Catima/issues/278]</string>
<string name="failedGeneratingShareURL">Неуспешно генериране на адрес за споделяне. Докладвайте за тази грешка!</string>
<string name="failedGeneratingShareURL">Грешка при създаване на адрес за споделяне. Изпратете доклад за дефект.</string>
<string name="deleteTitle">Премахване на карта</string>
<plurals name="deleteCardsTitle">
<item quantity="one">Премахване на карта</item>
<item quantity="other">Премахване на карти</item>
</plurals>
<string name="deleteConfirmation">Потвърдете премахване на карта</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">Желаете ли картата да бъде премахната\?</item>
<item quantity="other">Желаете ли <xliff:g>%d</xliff:g> картати да бъдат премахнати\?</item>
</plurals>
</resources>

View File

@@ -1,10 +1,8 @@
<resources
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_add">Přidat</string>
<string name="noGiftCards">ZAtím némáte žádné věrnostní karty. Klikněte na tlačítko "+" (plus) nahoře a začněte.\n\nLoyalty Card Locker umožňuje nosit své věrnostní karty v telefonu, takže jsou vždy na dosah.</string>
<string name="storeName">Obchod</string>
<string name="noGiftCards">Klepnutím na tlačítko + plus přidáte kartu nebo ji nejprve importujete z nabídky⋮.</string>
<string name="storeName">Název</string>
<string name="note">Poznámka</string>
<string name="cardId">ID karty</string>
<string name="cancel">Zrušit</string>
@@ -12,43 +10,66 @@
<string name="edit">Editovat</string>
<string name="delete">Smazat</string>
<string name="confirm">Potvrdit</string>
<string name="deleteTitle">Odstzranit věrnostní kartu</string>
<string name="deleteConfirmation">Opravdu chcete smazat tuto věrnostní kartu?</string>
<string name="ok">Ano</string>
<string name="copy_to_clipboard">Kopírovat ID do schránky</string>
<string name="sendLabel">Odeslat&#8230;</string>
<string name="sendLabel">Odeslat</string>
<string name="editCardTitle">Editovat věrnostní kartu</string>
<string name="addCardTitle">Přidat věrnostní kartu</string>
<string name="scanCardBarcode">Oskenujte kód karty</string>
<string name="barcodeImageDescription">Obrázek kódu karty</string>
<string name="noStoreError">Nebyl zadán Obchod</string>
<string name="noCardIdError">Nebylo zadáno ID karty</string>
<string name="scanCardBarcode">Skenování Čárový Kód Karty</string>
<string name="barcodeImageDescription">Obrázek čárového kódu karty</string>
<string name="noStoreError">Zadáno žádné jméno</string>
<string name="noCardIdError">Žádné ID karty zadáno</string>
<string name="importExport">Import/Export</string>
<string name="exportName">Export</string>
<string name="importExportHelp">Zálohování dat vám umožní přesunout vaše uložené karty na jiné zařízení.</string>
<string name="importSuccessfulTitle">Import proběhl úspěšně</string>
<string name="importExportHelp">Zálohování karet vám umožní přesunout je do jiného zařízení.</string>
<string name="importSuccessfulTitle">Dovážit</string>
<string name="importFailedTitle">Import selhal</string>
<string name="importFailed">Import selhal</string>
<string name="exportSuccessfulTitle">Export proběhl úspěšně</string>
<string name="importFailed">Nelze importovat karty</string>
<string name="exportSuccessfulTitle">Exportovat</string>
<string name="exportFailedTitle">Export selhal</string>
<string name="exportFailed">Export selhal</string>
<string name="importing">Importuji&#8230;</string>
<string name="exporting">Exportuji&#8230;</string>
<string name="noExternalStoragePermissionError">Nelze importovat nebo exportovat karty bez přístupu k externímu uložišti</string>
<string name="exportFailed">Nelze exportovat karty</string>
<string name="importing">Importuji</string>
<string name="exporting">Exportuji</string>
<string name="noExternalStoragePermissionError">Udělit povolení externího úložiště pro import nebo export karet jako první</string>
<string name="importOptionFilesystemTitle">Import ze souborového systému</string>
<string name="importOptionFilesystemExplanation">Vyberte konkrétní soubor v uložišti.</string>
<string name="importOptionFilesystemButton">Ze souborového systému</string>
<string name="importOptionApplicationTitle">Použít externí aplikaci</string>
<string name="importOptionApplicationExplanation">K otevření souboru použije externí aplikaci jako Dropbox, Google Drive, nebo vámi preferovaný prohlížeč souborů.</string>
<string name="importOptionApplicationButton">Použít externí aplikaci</string>
<string name="importOptionApplicationTitle">Použijte jinou aplikaci</string>
<string name="importOptionApplicationExplanation">K otevření souboru použijte libovolnou aplikaci nebo svého oblíbeného správce souborů.</string>
<string name="importOptionApplicationButton">Použijte jinou aplikaci</string>
<string name="about">O aplikaci</string>
<string name="app_license">Licensed under the GPLv3.</string>
<string name="app_license">Copylefted libre software, licencovaný GPLv3+.</string>
<string name="about_title_fmt">O aplikaci <xliff:g id="app_name">%s</xliff:g></string>
<string name="debug_version_fmt">Verze: <xliff:g id="version">%s</xliff:g></string>
<string name="app_revision_fmt">Revizní informace: <xliff:g id="app_revision_url">%s</xliff:g></string>
<string name="app_revision_fmt">Informace o revizi: <xliff:g id="app_revision_url">%s</xliff:g></string>
<string name="selectBarcodeTitle">Vyberte čárový kód</string>
<string name="copy_to_clipboard_toast">ID karty zkopírováno do schránky</string>
</resources>
<string name="copy_to_clipboard_toast">ID karty zkopírované do schránky</string>
<string name="deleteTitle">Smazat kartu</string>
<string name="deleteConfirmation">Opravdu chcete smazat tuto věrnostní kartu?</string>
<string name="moveBarcodeToCenterOfScreen">Střed čárového kódu na obrazovce</string>
<string name="moveBarcodeToTopOfScreen">Přesuňte čárový kód do horní části obrazovky</string>
<string name="chooseExpiryDate">Zvolte datum vypršení platnosti</string>
<string name="never">Nikdy</string>
<string name="expiryDate">Platnost</string>
<string name="editBarcode">Upravit čárový kód</string>
<string name="barcode">Kód</string>
<string name="app_resources">Zdroje třetích stran Libre: <xliff:g id="app_resources_list">%s</xliff:g></string>
<string name="app_libraries">Libre knihovny třetích stran: <xliff:g id="app_libraries_list">%s</xliff:g></string>
<string name="app_copyright_old">Na základě Loyalty Card Keychain
\ncopyright © 20162020 Branden Archer.</string>
<string name="exportOptionExplanation">Data budou zapsána na místo podle vašeho výběru.</string>
<string name="failedParsingImportUriError">Nelze analyzovat import URI</string>
<string name="noCardExistsError">Nelze najít kartu</string>
<string name="noCardsMessage">Nejprve přidejte kartu</string>
<string name="cardShortcut">Zástupce Karty</string>
<string name="share">Podíl</string>
<string name="unlockScreen">Odblokovat Rotaci</string>
<string name="lockScreen">Otáčení Bloku</string>
<string name="unstar">Odebrat z oblíbených</string>
<string name="star">Přidat do oblíbených</string>
<string name="noBarcode">Žádný čárový kód</string>
<string name="barcodeNoBarcode">Tato karta nemá čárový kód</string>
<string name="barcodeType">Typ čárového kódu</string>
<string name="noMatchingGiftCards">Nic jsem nenašel. Zkuste změnit vyhledávání.</string>
<string name="action_search">Vyhledávání</string>
</resources>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="scanCardBarcode">Scanne kortets stregkode</string>
<string name="addCardTitle">Tilføj kort</string>
<string name="editCardTitle">Rediger kort</string>
<string name="sendLabel">Afsend…</string>
<string name="share">Aktie</string>
<string name="copy_to_clipboard">Kopier ID til udklipsholder</string>
<string name="ok">OK</string>
<string name="deleteConfirmation">Slete dette kort permanent\?</string>
<plurals name="deleteCardsTitle">
<item quantity="one">Streichen <xliff:g>%d</xliff:g> kort</item>
<item quantity="other">Streichen <xliff:g>%d</xliff:g> korts</item>
</plurals>
<string name="deleteTitle">Karte streichen</string>
<string name="unlockScreen">Afbloker rotation</string>
<string name="lockScreen">Blokrotation</string>
<string name="confirm">Bekræft</string>
<string name="delete">Slet</string>
<string name="edit">Rediger</string>
<string name="save">Gem</string>
<string name="cancel">Annuller</string>
<string name="unstar">Fjern fra favoritter</string>
<string name="star">Føj til favoritter</string>
<string name="noBarcode">Ingen stregkode</string>
<string name="barcodeNoBarcode">Dette kort har ingen stregkode</string>
<string name="barcodeType">Stregkode type</string>
<string name="cardId">Kort ID</string>
<string name="note">Bemærk</string>
<string name="storeName">Navn</string>
<string name="noMatchingGiftCards">Jeg fandt ikke noget. Prøv at ændre din søgning.</string>
<string name="noGiftCards">Klik på + plus-knappen for at tilføje et kort, eller importer først nogle kort fra ⋮-menuen.</string>
<plurals name="selectedCardCount">
<item quantity="one"><xliff:g>%d</xliff:g> valgt kort</item>
<item quantity="other"><xliff:g>%d</xliff:g> valgte kort</item>
</plurals>
<string name="action_add">Tilføj</string>
<string name="action_search">Søg</string>
</resources>

View File

@@ -16,8 +16,6 @@
<string name="unlockScreen">Rotation zulassen</string>
<string name="star">Zu den Favoriten hinzufügen</string>
<string name="unstar">Aus der Favoritenliste entfernen</string>
<string name="deleteTitle">Karte entfernen</string>
<string name="deleteConfirmation">Diese Karte löschen\?</string>
<string name="ok">OK</string>
<string name="copy_to_clipboard">Nummer in die Zwischenablage kopieren</string>
<string name="sendLabel">Senden </string>
@@ -157,14 +155,24 @@
<string name="frontImageDescription">Bild der Kartenvorderseite</string>
<string name="backImageDescription">Bild der Kartenrückseite</string>
<string name="passwordRequired">Bitte geben Sie das Passwort ein</string>
<string name="importStocardMessage">Wählen Sie Ihren <i>***-sync.zip</i>-Export aus Stocard zum Importieren aus, und wählen Sie anschließend die Strichcodetypen manuell aus.
<string name="importStocardMessage">Wählen Sie Ihren <i>***-sync.zip</i>-Export aus Stocard zum Importieren aus.
\nOder Sie erhalten ihn, indem Sie eine E-Mail an support@stocardapp.com senden und um einen Export Ihrer Daten bitten.</string>
<string name="importStocard">Von Stocard importieren</string>
<string name="turn_flashlight_off">Taschenlampe ausschalten</string>
<string name="turn_flashlight_on">Taschenlampe einschalten</string>
<string name="failedGeneratingShareURL">Fehler beim Generieren der Freigabe-URL. Bitte melden Sie diesen Fehler!</string>
<string name="failedGeneratingShareURL">Keine teilbare URL konnte generiert werden. Bitte melden Sie dies.</string>
<plurals name="selectedCardCount">
<item quantity="one">Ausgewählt: <xliff:g>%d</xliff:g> Karte</item>
<item quantity="other">Ausgewählt: <xliff:g>%d</xliff:g> Karten</item>
<item quantity="one"><xliff:g>%d</xliff:g> Karte ausgewählt</item>
<item quantity="other"><xliff:g>%d</xliff:g> Karten ausgewählt</item>
</plurals>
<string name="deleteTitle">Karte entfernen</string>
<string name="deleteConfirmation">Diese Karte löschen\?</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">Diese <xliff:g>%d</xliff:g> Karte endgültig löschen\?</item>
<item quantity="other">Diese <xliff:g>%d</xliff:g> Karten endgültig löschen\?</item>
</plurals>
<plurals name="deleteCardsTitle">
<item quantity="one"><xliff:g>%d</xliff:g> Karte löschen</item>
<item quantity="other"><xliff:g>%d</xliff:g> Karten löschen</item>
</plurals>
</resources>

View File

@@ -12,8 +12,6 @@
<string name="confirm">Επιβεβαίωση</string>
<string name="lockScreen">Αποκλεισμός Περιστροφής</string>
<string name="unlockScreen">Περιστροφή</string>
<string name="deleteTitle">Αφαίρεση Κάρτας</string>
<string name="deleteConfirmation">Παρακαλώ επιβεβαιώστε ότι θέλετε να διαγράψετε αυτή την κάρτα.</string>
<string name="ok">Εντάξει</string>
<string name="copy_to_clipboard">Αντιγραφή κωδικού στο πρόχειρο</string>
<string name="sendLabel">Αποστολή…</string>
@@ -58,4 +56,6 @@
<string name="settings_light_theme">Φωτεινό</string>
<string name="settings_system_theme">Σύστημα</string>
<string name="barcode">Γραμμικός κώδικας</string>
<string name="deleteTitle">Αφαίρεση Κάρτας</string>
<string name="deleteConfirmation">Παρακαλώ επιβεβαιώστε ότι θέλετε να διαγράψετε αυτή την κάρτα.</string>
</resources>

View File

@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" xmlns:tools="http://schemas.android.com/tools">
<string name="deleteConfirmation">Ĉu forigi ĉi tiun karton\?</string>
<string name="deleteTitle">Forigi karton</string>
<string name="barcodeNoBarcode">Strekokodo mankas al karto</string>
<string name="delete">Forigi</string>
<string name="noBarcode">Sen strekokodo</string>
@@ -52,4 +50,6 @@
<string name="cancel">Nuligi</string>
<string name="action_add">Aldoni</string>
<string name="action_search">Serĉi</string>
<string name="deleteConfirmation">Ĉu forigi ĉi tiun karton\?</string>
<string name="deleteTitle">Forigi karton</string>
</resources>

View File

@@ -12,8 +12,6 @@
<string name="confirm">Confirmar</string>
<string name="lockScreen">Bloquear giro</string>
<string name="unlockScreen">Desbloquear giro</string>
<string name="deleteTitle">Eliminar tarjeta</string>
<string name="deleteConfirmation">¿Quiere eliminar esta tarjeta\?</string>
<string name="ok">Aceptar</string>
<string name="copy_to_clipboard">Copiar id. en portapapeles</string>
<string name="sendLabel">Enviar…</string>
@@ -119,7 +117,7 @@
\nO consígalo enviando un correo electrónico a support@stocardapp.com solicitando una exportación de sus datos.</string>
<string name="importVoucherVaultMessage">Seleccione su <i>vouchervault.json</i> exportado desde Voucher Vault para importarlo.
\nO créalo pulsando primero Exportar en Voucher Vault.</string>
<string name="failedGeneratingShareURL">Error al generar la URL compartida. Por favor, ¡reporte este error!</string>
<string name="failedGeneratingShareURL">No se ha podido generar una URL compartible. Por favor, informe de ello.</string>
<string name="passwordRequired">Por favor, introduzca la contraseña</string>
<string name="updateBarcodeQuestionText">Ha cambiado la Id. de la tarjeta. ¿Desea actualizar también el código de barras para usar el mismo valor\?</string>
<string name="intent_import_card_from_url_share_multiple_text">Quiero compartirte algunas tarjetas</string>
@@ -164,7 +162,17 @@
<string name="settings_disable_lockscreen_while_viewing_card">Evitar bloqueo de pantalla</string>
<string name="settings_keep_screen_on">Mantener pantalla encendida</string>
<plurals name="selectedCardCount">
<item quantity="one">Seleccionadas: <xliff:g>%d</xliff:g> tarjeta</item>
<item quantity="other">Seleccionadas: <xliff:g>%d</xliff:g> tarjetas</item>
<item quantity="one"><xliff:g>%d</xliff:g> tarjeta seleccionada</item>
<item quantity="other"><xliff:g>%d</xliff:g> tarjetas seleccionadas</item>
</plurals>
<string name="deleteTitle">Eliminar la tarjeta</string>
<string name="deleteConfirmation">¿Quiere eliminar esta tarjeta\?</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">¿Borrar esta tarjeta <xliff:g>%d</xliff:g> permanentemente\?</item>
<item quantity="other">¿Borrar estas tarjetas <xliff:g>%d</xliff:g> permanentemente\?</item>
</plurals>
<plurals name="deleteCardsTitle">
<item quantity="one">Borrar <xliff:g>%d</xliff:g> tarjeta</item>
<item quantity="other">Borrar <xliff:g>%d</xliff:g> tarjetas</item>
</plurals>
</resources>

View File

@@ -128,8 +128,6 @@
<string name="share">Jaa</string>
<string name="copy_to_clipboard">Kopioi ID-tunnus leikepöydälle</string>
<string name="ok">OK</string>
<string name="deleteConfirmation">Poista tämä kortti\?</string>
<string name="deleteTitle">Poista kortti</string>
<string name="unlockScreen">Poista kierron esto</string>
<string name="lockScreen">Estä kierto</string>
<string name="confirm">Vahvista</string>
@@ -156,4 +154,6 @@
<string name="photos">Valokuvat</string>
<string name="backImageDescription">Kortin takakuva</string>
<string name="frontImageDescription">Kortin etukuva</string>
<string name="deleteConfirmation">Poista tämä kortti\?</string>
<string name="deleteTitle">Poista kortti</string>
</resources>

View File

@@ -12,8 +12,6 @@
<string name="confirm">Confirmer</string>
<string name="lockScreen">Désactiver la rotation</string>
<string name="unlockScreen">Activer la rotation</string>
<string name="deleteTitle">Supprimer la carte de fidélité</string>
<string name="deleteConfirmation">Supprimer cette carte \?</string>
<string name="ok">OK</string>
<string name="copy_to_clipboard">Copier le numéro dans le presse-papier</string>
<string name="sendLabel">Envoyer…</string>
@@ -157,14 +155,24 @@
<string name="backImageDescription">Image verso de la carte</string>
<string name="frontImageDescription">Image recto de la carte</string>
<string name="passwordRequired">Veuillez entrer le mot de passe</string>
<string name="importStocardMessage">Sélectionnez votre exportation <i>***-sync.zip</i> de Stocard pour limporter, et sélectionnez les types de codes-barres manuellement par la suite.
<string name="importStocardMessage">Sélectionnez votre exportation <i>***-sync.zip</i> de Stocard pour limporter.
\nVous pouvez aussi lobtenir en envoyant un courriel à support@stocardapp.com pour demander une exportation de vos données.</string>
<string name="importStocard">Importer depuis Stocard</string>
<string name="turn_flashlight_off">Éteindre la lampe de poche</string>
<string name="turn_flashlight_on">Allumer la lampe de poche</string>
<string name="failedGeneratingShareURL">Échec de la génération de lURL de partage. Veuillez signaler ce problème !</string>
<string name="failedGeneratingShareURL">Impossible de générer une URL partageable. Veuillez signaler ceci.</string>
<plurals name="selectedCardCount">
<item quantity="one">Sélectionnée : <xliff:g>%d</xliff:g> carte</item>
<item quantity="other">Sélectionnées : <xliff:g>%d</xliff:g> cartes</item>
<item quantity="one"><xliff:g>%d</xliff:g> carte sélectionnée</item>
<item quantity="other"><xliff:g>%d</xliff:g> cartes sélectionnées</item>
</plurals>
<string name="deleteTitle">Supprimer la carte</string>
<string name="deleteConfirmation">Supprimer cette carte \?</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">Supprimer cette <xliff:g>%d</xliff:g> carte définitivement \?</item>
<item quantity="other">Supprimer ces <xliff:g>%d</xliff:g> cartes définitivement \?</item>
</plurals>
<plurals name="deleteCardsTitle">
<item quantity="one">Supprimer <xliff:g>%d</xliff:g> carte</item>
<item quantity="other">Supprimer <xliff:g>%d</xliff:g> cartes</item>
</plurals>
</resources>

View File

@@ -15,8 +15,6 @@
<string name="confirm">Conferma</string>
<string name="lockScreen">Blocca rotazione</string>
<string name="unlockScreen">Sblocca rotazione</string>
<string name="deleteTitle">Rimuovi carta fedeltà</string>
<string name="deleteConfirmation">Eliminare questa carta\?</string>
<string name="ok">OK</string>
<string name="copy_to_clipboard">Copia ID negli appunti</string>
<string name="share">Condividi</string>
@@ -43,9 +41,9 @@
<string name="importing">Importazione in corso…</string>
<string name="exporting">Esportazione in corso…</string>
<string name="noExternalStoragePermissionError">Concedi l\'autorizzazione all\'archiviazione esterna per importare o esportare prima le carte</string>
<string name="importOptionFilesystemTitle">Importa dal file system</string>
<string name="importOptionFilesystemExplanation">Scegli un file dal file system.</string>
<string name="importOptionFilesystemButton">Dal file system</string>
<string name="importOptionFilesystemTitle">Importa dall\'archivio</string>
<string name="importOptionFilesystemExplanation">Scegli un file dall\'archivio.</string>
<string name="importOptionFilesystemButton">Dall\'archivio</string>
<string name="importOptionApplicationTitle">Usa unaltra app</string>
<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>
@@ -157,14 +155,24 @@
<string name="backImageDescription">Immagine posteriore della carta</string>
<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, e seleziona i tipi di codice a barre manualmente dopo.
<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>
<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>
<string name="failedGeneratingShareURL">Impossibile generare l\'URL di condivisione. Si prega di segnalare questo errore!</string>
<string name="failedGeneratingShareURL">Impossibile generare un URL condivisibile. Si prega di segnalarlo.</string>
<plurals name="selectedCardCount">
<item quantity="one">Selezionata: <xliff:g>%d</xliff:g> carta</item>
<item quantity="other">Selezionate: <xliff:g>%d</xliff:g> carte</item>
<item quantity="one"><xliff:g>%d</xliff:g> carta selezionata</item>
<item quantity="other"><xliff:g>%d</xliff:g> carte selezionate</item>
</plurals>
<string name="deleteTitle">Rimuovi la carta</string>
<string name="deleteConfirmation">Eliminare questa carta\?</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">Eliminare definitivamente questa scheda <xliff:g>%d</xliff:g>\?</item>
<item quantity="other">Eliminare definitivamente queste schede <xliff:g>%d</xliff:g>\?</item>
</plurals>
<plurals name="deleteCardsTitle">
<item quantity="one">Elimina <xliff:g>%d</xliff:g> carta</item>
<item quantity="other">Elimina <xliff:g>%d</xliff:g> carte</item>
</plurals>
</resources>

View File

@@ -120,8 +120,6 @@
<string name="share">共有</string>
<string name="copy_to_clipboard">カード番号をクリップボードにコピーする</string>
<string name="ok">確定</string>
<string name="deleteConfirmation">このカードを削除しますか?</string>
<string name="deleteTitle">カードの削除</string>
<string name="unlockScreen">自動回転を無効にしない</string>
<string name="lockScreen">自動回転を無効にする</string>
<string name="confirm">確認</string>
@@ -165,4 +163,6 @@
<plurals name="selectedCardCount">
<item quantity="other">選択済み: <xliff:g>%d</xliff:g></item>
</plurals>
<string name="deleteConfirmation">このカードを削除しますか?</string>
<string name="deleteTitle">カードの削除</string>
</resources>

View File

@@ -31,8 +31,6 @@
<string name="share">공유</string>
<string name="copy_to_clipboard">ID를 클립보드에 복사</string>
<string name="ok">확인</string>
<string name="deleteConfirmation">정말 이 카드를 삭제하시겠습니까\?</string>
<string name="deleteTitle">카드 제거</string>
<string name="unlockScreen">회전 잠금 해제</string>
<string name="lockScreen">회전 잠금</string>
<string name="confirm">확인</string>
@@ -78,4 +76,6 @@
<string name="starImage">즐겨찾기 별</string>
<string name="settings_display_barcode_max_brightness">바코드를 표시할 때 화면 밝기 높이기</string>
<string name="barcode">바코드</string>
<string name="deleteConfirmation">정말 이 카드를 삭제하시겠습니까\?</string>
<string name="deleteTitle">카드 제거</string>
</resources>

View File

@@ -10,8 +10,6 @@
<string name="edit">Redaguoti</string>
<string name="delete">Ištrinti</string>
<string name="confirm">Patvirtinti</string>
<string name="deleteTitle">Panaikinti lojalumo kortelę</string>
<string name="deleteConfirmation">Ištrinti šią kortelę\?</string>
<string name="ok">Gerai</string>
<string name="copy_to_clipboard">Nukopijuoti ID į iškarpinę</string>
<string name="editCardTitle">Redaguoti lojalumo kortelę</string>
@@ -61,7 +59,7 @@
<string name="failedParsingImportUriError">Nepavyko iššifruoti importo URI</string>
<string name="turn_flashlight_off">Išjunkti žibintuvėlį</string>
<string name="turn_flashlight_on">Įjunkti žibintuvėlį</string>
<string name="failedGeneratingShareURL">Nepavyko sugeneruoti bendrinamo URL. Praneškite apie šią klaidą!</string>
<string name="failedGeneratingShareURL">Nepavyko sugeneruoti bendrinamo URL. Praneškite apie tai.</string>
<string name="passwordRequired">Įveskite slaptažodį</string>
<string name="no">Ne</string>
<string name="yes">Taip</string>
@@ -81,7 +79,7 @@
<string name="setBarcodeId">Nustatyti brūkšninio kodo reikšmę</string>
<string name="sameAsCardId">Tokia pat kaip kortelės ID</string>
<string name="barcodeId">Brūkšninio kodo reikšmė</string>
<string name="importStocardMessage">Pasirinkite <i>***-sync.zip</i> eksportą iš Stocard, kad galėtumėte importuoti, o vėliau brūkšninių kodų tipus pasirinkite rankiniu būdu.
<string name="importStocardMessage">Pasirinkite <i>***-sync.zip</i> eksportą iš Stocard, kad galėtumėte importuoti.
\nArba gaukite susisiekę el. paštu support@stocardapp.com, prašydami eksportuoti jūsų duomenis.</string>
<string name="importStocard">Importuoti iš Stocard</string>
<string name="importFidmeMessage">Pasirinkite <i>fidme-export-request-xxxxxx.zip</i> eksportą iš FidMe, kurį norite importuoti, ir po to brūkšninių kodų tipus pasirinkite rankiniu būdu.
@@ -169,4 +167,16 @@
<item quantity="few">Pasirinktos: <xliff:g>%d</xliff:g> kortelės</item>
<item quantity="other">Pasirinkta: <xliff:g>%d</xliff:g> kortelių</item>
</plurals>
<string name="deleteTitle">Panaikinti lojalumo kortelę</string>
<string name="deleteConfirmation">Ištrinti šią kortelę\?</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">Ištrinti šią <xliff:g>%d</xliff:g> kortelę visam laikui\?</item>
<item quantity="few">Ištrinti šias <xliff:g>%d</xliff:g> korteles visam laikui\?</item>
<item quantity="other">Ištrinti šias <xliff:g>%d</xliff:g> kortelių visam laikui\?</item>
</plurals>
<plurals name="deleteCardsTitle">
<item quantity="one">Ištrinti <xliff:g>%d</xliff:g> kortelę</item>
<item quantity="few">Ištrinti <xliff:g>%d</xliff:g> korteles</item>
<item quantity="other">Ištrinti <xliff:g>%d</xliff:g> kortelių</item>
</plurals>
</resources>

View File

@@ -13,8 +13,6 @@
<string name="confirm">Bekreft</string>
<string name="lockScreen">Ingen rotering</string>
<string name="unlockScreen">Skru på rotering</string>
<string name="deleteTitle">Fjern kundekort</string>
<string name="deleteConfirmation">Slett dette kortet\?</string>
<string name="ok">OK</string>
<string name="copy_to_clipboard">Kopier ID til utklippstavle</string>
<string name="sendLabel">Send…</string>
@@ -156,9 +154,25 @@
<string name="photos">Bilder</string>
<string name="backImageDescription">Kortets bakside</string>
<string name="frontImageDescription">Kortets forside</string>
<string name="importStocardMessage">Finn din Stocard.zip-fil å importere, og velg strekkodetypene manuelt etterpå.
<string name="importStocardMessage">Velg din <i>***-sync.zip</i>-eksport fra Stocard å importere.
\nEller få den ved å sende e-post til support@stocardapp.com der du etterspør eksport av dataen din.</string>
<string name="passwordRequired">Skriv inn passordet</string>
<string name="importStocard">Importer fra Stocard</string>
<string name="failedGeneratingShareURL">Klarte ikke å lage delingsnettadresse. Rapporter denne feilen.</string>
</resources>
<string name="failedGeneratingShareURL">Klarte ikke å lage delbar nettadresse. Rapporter denne feilen.</string>
<plurals name="selectedCardCount">
<item quantity="one"><xliff:g>%d</xliff:g> kort valgt</item>
<item quantity="other"><xliff:g>%d</xliff:g> kort valgt</item>
</plurals>
<string name="deleteConfirmation">Slett dette kortet\?</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">Slett dette kortet for godt\?</item>
<item quantity="other">Slett disse <xliff:g xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">%d</xliff:g> kortene for godt\?</item>
</plurals>
<string name="turn_flashlight_on">Skru på lommelykten</string>
<string name="turn_flashlight_off">Skru av lommelykten</string>
<string name="deleteTitle">Fjern kundekort</string>
<plurals name="deleteCardsTitle">
<item quantity="one">Slett <xliff:g xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">%d</xliff:g> kort</item>
<item quantity="other">Slett <xliff:g xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">%d</xliff:g> kort</item>
</plurals>
</resources>

View File

@@ -16,8 +16,6 @@
<string name="confirm">Bevestigen</string>
<string name="lockScreen">Draaien niet toestaan</string>
<string name="unlockScreen">Draaien toestaan</string>
<string name="deleteTitle">Kaart verwijderen</string>
<string name="deleteConfirmation">Kaart verwijderen\?</string>
<string name="ok">Oké</string>
<string name="copy_to_clipboard">Kaartnummer kopiëren naar klembord</string>
<string name="share">Delen</string>
@@ -157,14 +155,24 @@
<string name="backImageDescription">Achterzijde van de kaart</string>
<string name="frontImageDescription">Voorzijde van de kaart</string>
<string name="passwordRequired">Voer het wachtwoord in</string>
<string name="importStocardMessage">Kies het te importeren Stocard-exportbestand genaamd <i>***-sync.zip</i> en kies nadien de juiste barcodes.
<string name="importStocardMessage">Kies het te importeren Stocard-exportbestand genaamd <i>***-sync.zip</i>.
\nOf stuur een e-mail naar support@stocardapp.com waarin je vraagt om een exportbestand.</string>
<string name="importStocard">Importeren uit Stocard</string>
<string name="failedGeneratingShareURL">De te delen link kan niet worden gegenereerd. Meld deze bug!</string>
<string name="failedGeneratingShareURL">De te delen link kan niet worden gegenereerd. Meld deze fout.</string>
<string name="turn_flashlight_off">Zaklamp uitzetten</string>
<string name="turn_flashlight_on">Zaklamp aanzetten</string>
<plurals name="selectedCardCount">
<item quantity="one"><xliff:g>%d</xliff:g> kaart geselecteerd</item>
<item quantity="other"><xliff:g>%d</xliff:g> kaarten geselecteerd</item>
</plurals>
<string name="deleteTitle">Kaart verwijderen</string>
<plurals name="deleteCardsTitle">
<item quantity="one"><xliff:g>%d</xliff:g> kaart verwijderen</item>
<item quantity="other"><xliff:g>%d</xliff:g> kaarten verwijderen</item>
</plurals>
<string name="deleteConfirmation">Kaart verwijderen\?</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">Weet je zeker dat je deze <xliff:g>%d</xliff:g> kaart wilt verwijderen\?</item>
<item quantity="other">Weet je zeker dat je deze <xliff:g>%d</xliff:g> kaarten wilt verwijderen\?</item>
</plurals>
</resources>

View File

@@ -15,8 +15,6 @@
<string name="confirm">Potwierdź</string>
<string name="lockScreen">Zablokuj autoobracanie ekranu</string>
<string name="unlockScreen">Odblokuj autoobracanie ekranu</string>
<string name="deleteTitle">Usuń kartę lojalnościową</string>
<string name="deleteConfirmation">Potwierdź, że chcesz usunąć tę kartę.</string>
<string name="ok">OK</string>
<string name="copy_to_clipboard">Skopiuj identyfikator do schowka</string>
<string name="share">Udostępnij</string>
@@ -83,4 +81,6 @@
<string name="star">Dodaj do ulubionych</string>
<string name="noBarcode">Brak kodu kreskowego</string>
<string name="barcodeType">Typ kodu kreskowego</string>
<string name="deleteTitle">Usuń kartę lojalnościową</string>
<string name="deleteConfirmation">Potwierdź, że chcesz usunąć tę kartę.</string>
</resources>

View File

@@ -16,8 +16,6 @@
<string name="confirm">Подтвердить</string>
<string name="lockScreen">Блокировать поворот экрана</string>
<string name="unlockScreen">Автоповорот экрана</string>
<string name="deleteTitle">Удаление карты</string>
<string name="deleteConfirmation">Удалить карту\?</string>
<string name="ok">ОК</string>
<string name="copy_to_clipboard">Копировать номер карты</string>
<string name="share">Переслать</string>
@@ -158,11 +156,11 @@
<string name="backImageDescription">Задняя сторона карты</string>
<string name="frontImageDescription">Лицевая сторона карты</string>
<string name="photos">Фотографии</string>
<string name="importStocardMessage">Выберите файл <i>***-sync.zip</i> для импортирования, а затем вручную укажите типы штрих-кодов.
<string name="importStocardMessage">Выберите файл <i>***-sync.zip</i> для импортирования.
\nЭтот файл можно получить по электронной почте от support@stocardapp.com, предварительно запросив экспорт ваших данных.</string>
<string name="passwordRequired">Введите пароль</string>
<string name="importStocard">Импорт из Stocard</string>
<string name="failedGeneratingShareURL">Невозможно создать URL для обмена. Пожалуйста, сообщите об ошибке!</string>
<string name="failedGeneratingShareURL">Невозможно создать URL для обмена. Пожалуйста, сообщите об этом.</string>
<string name="turn_flashlight_off">Отключить вспышку</string>
<string name="turn_flashlight_on">Включить вспышку</string>
<plurals name="selectedCardCount">
@@ -171,4 +169,18 @@
<item quantity="many">Выбрано: <xliff:g>%d</xliff:g> карт</item>
<item quantity="other">Выбрано: <xliff:g>%d</xliff:g> карт</item>
</plurals>
<string name="deleteTitle">Удаление карты</string>
<string name="deleteConfirmation">Удалить карту\?</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">Удалить эту <xliff:g>%d</xliff:g> карту безвозвратно\?</item>
<item quantity="few">Удалить эти <xliff:g>%d</xliff:g> карты безвозвратно\?</item>
<item quantity="many">Удалить эти <xliff:g>%d</xliff:g> карт безвозвратно\?</item>
<item quantity="other">Удалить эти <xliff:g>%d</xliff:g> карт безвозвратно\?</item>
</plurals>
<plurals name="deleteCardsTitle">
<item quantity="one">Удаление <xliff:g>%d</xliff:g> карты</item>
<item quantity="few">Удаление <xliff:g>%d</xliff:g> карт</item>
<item quantity="many">Удаление <xliff:g>%d</xliff:g> карт</item>
<item quantity="other">Удаление <xliff:g>%d</xliff:g> карт</item>
</plurals>
</resources>

View File

@@ -14,8 +14,6 @@
<string name="confirm">Potvrdiť</string>
<string name="lockScreen">Zakázať rotáciu</string>
<string name="unlockScreen">Povoliť rotáciu</string>
<string name="deleteTitle">Odstrániť kartu</string>
<string name="deleteConfirmation">Naozaj chcete túto kartu odstrániť?</string>
<string name="ok">Áno</string>
<string name="copy_to_clipboard">Kopírovať ID do schránky</string>
<string name="sendLabel">Odoslať&#8230;</string>
@@ -64,4 +62,6 @@
<string name="settings_category_title_ui">Používateľské prostredie</string>
<string name="settings_display_barcode_max_brightness">Zvýšiť jas pri zobrazení čiarového kódu </string>
<string name="settings_lock_barcode_orientation">Uzamkni orientáciu čiarového kódu</string>
</resources>
<string name="deleteTitle">Odstrániť kartu</string>
<string name="deleteConfirmation">Naozaj chcete túto kartu odstrániť?</string>
</resources>

View File

@@ -12,8 +12,6 @@
<string name="confirm">Potrdi</string>
<string name="lockScreen">Onemogoči obračanje zaslona</string>
<string name="unlockScreen">Omogoči obračanje zaslona</string>
<string name="deleteTitle">Odstrani kartico zvestobe</string>
<string name="deleteConfirmation">Prosim potrdite, če želite izbrisati to kartico.</string>
<string name="ok">Vredu</string>
<string name="copy_to_clipboard">Kopirajte številko kartice</string>
<string name="sendLabel">Pošlji…</string>
@@ -56,4 +54,6 @@
<string name="settings_category_title_ui">Uporabniški vmesnik</string>
<string name="settings_display_barcode_max_brightness">Povečaj osvetljenost prikaza črtne kode</string>
<string name="settings_lock_barcode_orientation">Zakleni orientacijo črtne kode</string>
<string name="deleteTitle">Odstrani kartico zvestobe</string>
<string name="deleteConfirmation">Prosim potrdite, če želite izbrisati to kartico.</string>
</resources>

View File

@@ -134,8 +134,6 @@
<string name="share">Поділитися</string>
<string name="copy_to_clipboard">Копіювати ID до буферу обміну</string>
<string name="ok">ОК</string>
<string name="deleteConfirmation">Бажаєте видалити карту\?</string>
<string name="deleteTitle">Видалити карту</string>
<string name="unlockScreen">Розблокувати обертання</string>
<string name="lockScreen">Блокувати обертання</string>
<string name="confirm">Підтвердити</string>
@@ -153,7 +151,7 @@
<string name="action_search">Пошук</string>
<string name="turn_flashlight_off">Вимкнути спалах</string>
<string name="turn_flashlight_on">Увімкнути спалах</string>
<string name="failedGeneratingShareURL">Збій створення URL обміну. Будь ласка повідомте про цю помилку!</string>
<string name="failedGeneratingShareURL">Збій створення URL обміну. Будь ласка повідомте про цю помилку.</string>
<string name="passwordRequired">Будь ласка введіть пароль</string>
<string name="takePhoto">Зробити фото</string>
<string name="removeImage">Видалити зображення</string>
@@ -171,4 +169,6 @@
<item quantity="many">Обрано: <xliff:g>%d</xliff:g> карт</item>
<item quantity="other">Обрано: <xliff:g>%d</xliff:g> карт</item>
</plurals>
</resources>
<string name="deleteTitle">Видалити карту</string>
<string name="deleteConfirmation">Бажаєте видалити карту\?</string>
</resources>

View File

@@ -123,8 +123,6 @@
<string name="share">分享</string>
<string name="copy_to_clipboard">复制卡号到剪贴板</string>
<string name="ok">确定</string>
<string name="deleteConfirmation">删除此卡?</string>
<string name="deleteTitle">移除卡片</string>
<string name="unlockScreen">解除旋转锁定</string>
<string name="lockScreen">锁定旋转</string>
<string name="confirm">确认</string>
@@ -143,4 +141,6 @@
<string name="noGiftCards">点击 \"+\"加号按钮来添加卡片,或者先从⋮菜单中导入一些。</string>
<string name="action_add">添加</string>
<string name="action_search">搜索</string>
<string name="deleteConfirmation">删除此卡?</string>
<string name="deleteTitle">移除卡片</string>
</resources>

View File

@@ -5,8 +5,8 @@
<string name="action_search">Search</string>
<string name="action_add">Add</string>
<plurals name="selectedCardCount">
<item quantity="one">Selected: <xliff:g>%d</xliff:g> card</item>
<item quantity="other">Selected: <xliff:g>%d</xliff:g> cards</item>
<item quantity="one"><xliff:g>%d</xliff:g> card selected</item>
<item quantity="other"><xliff:g>%d</xliff:g> cards selected</item>
</plurals>
<string name="noGiftCards">Click the + plus button to add a card, or import some from the ⋮ menu first.</string>
@@ -29,8 +29,22 @@
<string name="confirm">Confirm</string>
<string name="lockScreen">Block Rotation</string>
<string name="unlockScreen">Unblock Rotation</string>
<string name="deleteTitle">Remove Card</string>
<string name="deleteConfirmation">Delete this card?</string>
<!-- START NOTE: i18n oddness -->
<!-- The following may seem weird, but it is necessary to give translators enough flexibility.
For example, in Russian, Android's plural quantity "one" actually refers to "any number ending on 1 but not ending in 11".
So while in English the extra non-plural form seems unnecessary duplication, it is necessary to give translators enough flexibility.
In Catima, we use the plain string when meaning exactly 1, and otherwise use the plural forms -->
<string name="deleteTitle">Delete card</string>
<plurals name="deleteCardsTitle">
<item quantity="one">Delete <xliff:g>%d</xliff:g> card</item>
<item quantity="other">Delete <xliff:g>%d</xliff:g> cards</item>
</plurals>
<string name="deleteConfirmation">Delete this card permanently?</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">Delete this <xliff:g>%d</xliff:g> card permanently?</item>
<item quantity="other">Delete these <xliff:g>%d</xliff:g> cards permanently?</item>
</plurals>
<!-- END NOTE: i18n oddness -->
<string name="ok">OK</string>
<string name="copy_to_clipboard">Copy ID to clipboard</string>
<string name="share">Share</string>
@@ -174,7 +188,7 @@
<string name="importLoyaltyCardKeychain">Import from Loyalty Card Keychain</string>
<string name="importLoyaltyCardKeychainMessage">Select your <i>LoyaltyCardKeychain.csv</i> export from Loyalty Card Keychain to import.\nOr create it from the "Import/Export" menu in Loyalty Card Keychain by pressing "Export" there first.</string>
<string name="importStocard">Import from Stocard</string>
<string name="importStocardMessage">Select your <i>***-sync.zip</i> export from Stocard to import, and select the barcode types manually afterwards.\nOr get it by e-mailing support@stocardapp.com asking for an export of your data.</string>
<string name="importStocardMessage">Select your <i>***-sync.zip</i> export from Stocard to import.\nOr get it by e-mailing support@stocardapp.com asking for an export of your data.</string>
<string name="importVoucherVault">Import from Voucher Vault</string>
<string name="importVoucherVaultMessage">Select your <i>vouchervault.json</i> export from Voucher Vault to import.\nOr create it by pressing "Export" in Voucher Vault first.</string>
<string name="barcodeId">Barcode value</string>
@@ -196,7 +210,7 @@
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="passwordRequired">Please enter the password</string>
<string name="failedGeneratingShareURL">Failed generating share URL. Please report this bug!</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>
</resources>

View File

@@ -29,7 +29,6 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
@@ -981,7 +980,9 @@ public class ImportExportTest
"1,Card 1,Note 1,1618053234,100,USD,1234,5432,1,QR_CODE,0,\r\n" +
"8,Clothes Store,Note about store,,0,,a,,-5317,,0,\n" +
"2,Department Store,,1618041729,0,,A,,-9977996,,0,\n" +
"3,Grocery Store,,,150,,dhd,,-9977996,,0,\n" +
"3,Grocery Store,\"Multiline note about grocery store\n" +
"\n" +
"with blank line\",,150,,dhd,,-9977996,,0,\n" +
"4,Pharmacy,,,0,,dhshsvshs,,-10902850,,1,\n" +
"5,Restaurant,Note about restaurant here,,0,,98765432,23456,-10902850,CODE_128,0,\n" +
"6,Shoe Store,,,12.50,EUR,a,-5317,,AZTEC,0,\n" +
@@ -1066,7 +1067,7 @@ public class ImportExportTest
LoyaltyCard card3 = db.getLoyaltyCard(3);
assertEquals("Grocery Store", card3.store);
assertEquals("", card3.note);
assertEquals("Multiline note about grocery store\n\nwith blank line", card3.note);
assertEquals(null, card3.expiry);
assertEquals(new BigDecimal("150"), card3.balance);
assertEquals(null, card3.balanceType);
@@ -1198,7 +1199,7 @@ public class ImportExportTest
assertEquals(null, card.balanceType);
assertEquals("55555", card.cardId);
assertEquals(null, card.barcodeId);
assertEquals(null, card.barcodeType);
assertEquals(BarcodeFormat.EAN_13, card.barcodeType);
assertEquals(0, card.starStatus);
assertNull(Utils.retrieveCardImage(activity.getApplicationContext(), 1, true));
@@ -1213,7 +1214,7 @@ public class ImportExportTest
assertEquals(null, card.balanceType);
assertEquals("7649484", card.cardId);
assertEquals(null, card.barcodeId);
assertEquals(null, card.barcodeType);
assertEquals(BarcodeFormat.EAN_13, card.barcodeType);
assertEquals(0, card.starStatus);
assertTrue(BitmapFactory.decodeStream(getClass().getResourceAsStream("stocard-front.jpg")).sameAs(Utils.retrieveCardImage(activity.getApplicationContext(), 2, true)));
@@ -1221,7 +1222,8 @@ public class ImportExportTest
card = db.getLoyaltyCard(3);
assertEquals("", card.store);
// I don't think we can know this one, but falling back to an unique store name is at least something
assertEquals("63536738-d64b-48ae-aeb8-82761523fa67", card.store);
assertEquals("", card.note);
assertEquals(null, card.expiry);
assertEquals(new BigDecimal("0"), card.balance);

View File

@@ -25,6 +25,8 @@ import java.util.Currency;
import java.util.Date;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import protect.card_locker.preferences.Settings;
@@ -61,8 +63,8 @@ public class LoyaltyCardCursorAdapterTest
{
LoyaltyCardCursorAdapter adapter = new LoyaltyCardCursorAdapter(activity.getApplicationContext(), cursor, (MainActivity) activity);
RecyclerView.ViewHolder viewHolder = adapter.createViewHolder(activity.findViewById(R.id.list), 0);
adapter.bindViewHolder((LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder) viewHolder, cursor.getPosition());
LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder viewHolder = adapter.createViewHolder(activity.findViewById(R.id.list), 0);
adapter.bindViewHolder(viewHolder, cursor.getPosition());
return viewHolder.itemView;
}

View File

@@ -1,7 +1,6 @@
package protect.card_locker;
import android.app.Activity;
import androidx.appcompat.app.AlertDialog;
import android.app.DatePickerDialog;
import android.content.Context;
import android.content.Intent;
@@ -43,7 +42,6 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowActivity;
import org.robolectric.shadows.ShadowAlertDialog;
import org.robolectric.shadows.ShadowDialog;
import org.robolectric.shadows.ShadowLog;
@@ -54,6 +52,7 @@ import java.text.ParseException;
import java.util.Currency;
import java.util.Date;
import androidx.appcompat.app.AlertDialog;
import androidx.core.widget.TextViewCompat;
import androidx.preference.PreferenceManager;
@@ -1158,7 +1157,6 @@ public class LoyaltyCardViewActivityTest
TextViewCompat.getAutoSizeMaxTextSize(storeName);
TextViewCompat.getAutoSizeMaxTextSize(storeName);
assertEquals(LARGE_FONT_SIZE, (int)storeName.getTextSize());
assertEquals(LARGE_FONT_SIZE, TextViewCompat.getAutoSizeMaxTextSize(cardIdFieldView));
shadowOf(activity).clickMenuItem(android.R.id.home);
@@ -1341,6 +1339,50 @@ public class LoyaltyCardViewActivityTest
db.close();
}
@Test
public void checkNoBarcodeFullscreenWorkflow()
{
ActivityController activityController = createActivityWithLoyaltyCard(false);
Activity activity = (Activity)activityController.get();
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, null, Color.BLACK, 0);
activityController.start();
activityController.visible();
activityController.resume();
assertEquals(false, activity.isFinishing());
ImageView barcodeImage = activity.findViewById(R.id.barcode);
View collapsingToolbarLayout = activity.findViewById(R.id.collapsingToolbarLayout);
View bottomSheet = activity.findViewById(R.id.bottom_sheet);
ImageButton maximizeButton = activity.findViewById(R.id.maximizeButton);
ImageButton minimizeButton = activity.findViewById(R.id.minimizeButton);
FloatingActionButton editButton = activity.findViewById(R.id.fabEdit);
SeekBar barcodeScaler = activity.findViewById(R.id.barcodeScaler);
// Android should not be in fullscreen mode
int uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions);
assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions);
// Elements should be visible (except minimize/maximize buttons and barcode and scaler)
assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility());
assertEquals(View.VISIBLE, bottomSheet.getVisibility());
assertEquals(View.GONE, maximizeButton.getVisibility());
assertEquals(View.GONE, minimizeButton.getVisibility());
assertEquals(View.VISIBLE, editButton.getVisibility());
assertEquals(View.GONE, barcodeScaler.getVisibility());
// Pressing back when not in full screen should finish activity
activity.onBackPressed();
shadowOf(getMainLooper()).idle();
assertEquals(true, activity.isFinishing());
db.close();
}
@Test
public void importCard()
{

View File

@@ -5,8 +5,6 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
public class TestHelpers {
static public DBHelper getEmptyDb(Activity activity) {

View File

@@ -9,7 +9,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.2'
classpath 'com.android.tools.build:gradle:7.0.0'
classpath 'gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.7.0'
// NOTE: Do not place your application dependencies here; they belong
@@ -20,7 +20,6 @@ buildscript {
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
gradlePluginPortal()
}

View File

@@ -0,0 +1 @@
Pro čárové kódy, členství, věrnostní programy, kupony a vstupenky.

View File

@@ -0,0 +1 @@
Catima - Peněženka Libre Card

View File

@@ -0,0 +1 @@
Til dine stregkoder, medlemskaber, loyalitetsprogrammer, kuponer og billetter.

View File

@@ -0,0 +1 @@
Catima - Den frie kortpung

View File

@@ -8,7 +8,7 @@ Med dette essensielle verktøyet kan du erstatte unyttig plast med kontanter.
- Unngå spionasje med veldig få tilganger. Ingen tilgang til Internett, og ingen reklame.
- Legg til kort eller koder med navn og egne farger.
- Manuell kodeinnskriving hvis det ikke er noen strekkode å lagre, eller den ikke kan brukes.
- Importer kort og koder fra filer, Catima, Loyalty Card Keychain, Voucher Vault, og FidMe.
- Importer kort og koder fra filer ,Catima, FidMe, Kundekortknippe, Stocard og Voucher Vault.
- Lag en sikkerhetskopi av alle kortene dine og overfør dem til en ny enhet hvis du ønsker det.
- Del kupponger, eksklusive tilbud, promokoder eller kort og koder ved bruk av ethvert program.
- Mørk drakt og tilgjengelighetsvalg for synshemmede brukere.