Compare commits

..

1 Commits

Author SHA1 Message Date
Sylvia van Os
70cdb18c51 WIP 2023-03-17 17:18:43 +01:00
96 changed files with 4139 additions and 7271 deletions

View File

@@ -20,11 +20,11 @@ jobs:
- name: Fail on bad translations - name: Fail on bad translations
run: if grep -ri "<xliff" app/src/main/res/values*/strings.xml; then echo "Invalidly escaped translations found"; exit 1; fi run: if grep -ri "<xliff" app/src/main/res/values*/strings.xml; then echo "Invalidly escaped translations found"; exit 1; fi
- uses: gradle/wrapper-validation-action@v1 - uses: gradle/wrapper-validation-action@v1
- name: set up JDK 17 - name: set up JDK 11
uses: actions/setup-java@v2 uses: actions/setup-java@v2
with: with:
distribution: 'temurin' distribution: 'adopt'
java-version: '17' java-version: '11'
- name: Build - name: Build
run: ./gradlew assembleRelease run: ./gradlew assembleRelease
- name: Check lint - name: Check lint

View File

@@ -1,13 +1,8 @@
# Changelog # Changelog
## v2.22.1 - 119 ## Unreleased - 118
- Use Material You colours on more devices (Google library update)
## v2.22.0 - 118
- Support setting start of card validity - Support setting start of card validity
- Fix Stocard import (Stocard's export format changed)
## v2.21.2 - 117 ## v2.21.2 - 117

View File

@@ -19,8 +19,8 @@ android {
applicationId "me.hackerchick.catima" applicationId "me.hackerchick.catima"
minSdk 21 minSdk 21
targetSdk 33 targetSdk 33
versionCode 119 versionCode 117
versionName "2.22.1" versionName "2.21.2"
vectorDrawables.useSupportLibrary true vectorDrawables.useSupportLibrary true
multiDexEnabled true multiDexEnabled true
@@ -58,6 +58,9 @@ android {
targetCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11
} }
lintOptions {
lintConfig file("lint.xml")
}
sourceSets { sourceSets {
test { test {
@@ -77,22 +80,18 @@ android {
includeAndroidResources true includeAndroidResources true
} }
} }
lint {
lintConfig file('lint.xml')
}
namespace 'protect.card_locker'
} }
dependencies { dependencies {
// AndroidX // AndroidX
implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.exifinterface:exifinterface:1.3.6' implementation 'androidx.exifinterface:exifinterface:1.3.5'
implementation 'androidx.palette:palette:1.0.0' implementation 'androidx.palette:palette:1.0.0'
implementation 'androidx.preference:preference:1.2.0' implementation 'androidx.preference:preference:1.2.0'
implementation 'com.google.android.material:material:1.8.0' implementation 'com.google.android.material:material:1.6.1'
implementation 'com.github.yalantis:ucrop:2.2.8' implementation 'com.github.yalantis:ucrop:2.2.8'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6'
// Splash Screen // Splash Screen
implementation 'androidx.core:core-splashscreen:1.0.0' implementation 'androidx.core:core-splashscreen:1.0.0'
@@ -100,7 +99,7 @@ dependencies {
// Third-party // Third-party
implementation 'com.journeyapps:zxing-android-embedded:4.3.0@aar' implementation 'com.journeyapps:zxing-android-embedded:4.3.0@aar'
implementation 'com.google.zxing:core:3.5.1' implementation 'com.google.zxing:core:3.5.1'
implementation 'org.apache.commons:commons-csv:1.10.0' implementation 'org.apache.commons:commons-csv:1.9.0'
implementation 'com.jaredrummler:colorpicker:1.1.0' implementation 'com.jaredrummler:colorpicker:1.1.0'
implementation 'com.github.invissvenska:NumberPickerPreference:1.0.4' implementation 'com.github.invissvenska:NumberPickerPreference:1.0.4'
implementation 'net.lingala.zip4j:zip4j:2.11.5' implementation 'net.lingala.zip4j:zip4j:2.11.5'
@@ -111,7 +110,7 @@ dependencies {
// Testing // Testing
testImplementation 'androidx.test:core:1.5.0' testImplementation 'androidx.test:core:1.5.0'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.10' testImplementation 'org.robolectric:robolectric:4.9.2'
} }
tasks.withType(SpotBugsTask) { tasks.withType(SpotBugsTask) {

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools"
package="protect.card_locker">
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" /> <uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />

View File

@@ -1,5 +1,6 @@
package protect.card_locker; package protect.card_locker;
import android.annotation.SuppressLint;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -68,9 +69,10 @@ public class CardsOnPowerScreenService extends ControlsProviderService {
subscriber.onSubscribe(new NoOpSubscription()); subscriber.onSubscribe(new NoOpSubscription());
for (String controlId : controlIds) { for (String controlId : controlIds) {
Control control; Control control;
Integer cardId = this.controlIdToCardId(controlId);
LoyaltyCard card = DBHelper.getLoyaltyCard(mDatabase, cardId); try {
if (card != null) { Integer cardId = this.controlIdToCardId(controlId);
LoyaltyCard card = DBHelper.getLoyaltyCard(mDatabase, cardId);
Intent openIntent = new Intent(this, LoyaltyCardViewActivity.class) Intent openIntent = new Intent(this, LoyaltyCardViewActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra("id", card.id); .putExtra("id", card.id);
@@ -83,7 +85,7 @@ public class CardsOnPowerScreenService extends ControlsProviderService {
.setControlTemplate(new StatelessTemplate(controlId)) .setControlTemplate(new StatelessTemplate(controlId))
.setCustomIcon(Icon.createWithBitmap(getIcon(this, card))) .setCustomIcon(Icon.createWithBitmap(getIcon(this, card)))
.build(); .build();
} else { } catch (NullPointerException ignored) {
Intent mainScreenIntent = new Intent(this, MainActivity.class) Intent mainScreenIntent = new Intent(this, MainActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(getBaseContext(), -1, mainScreenIntent, PendingIntent.FLAG_IMMUTABLE); PendingIntent pendingIntent = PendingIntent.getActivity(getBaseContext(), -1, mainScreenIntent, PendingIntent.FLAG_IMMUTABLE);

View File

@@ -21,11 +21,12 @@ import java.util.List;
public class DBHelper extends SQLiteOpenHelper { public class DBHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "Catima.db"; public static final String DATABASE_NAME = "Catima.db";
public static final int ORIGINAL_DATABASE_VERSION = 1; public static final int ORIGINAL_DATABASE_VERSION = 1;
public static final int DATABASE_VERSION = 16; public static final int DATABASE_VERSION = 17;
public static class LoyaltyCardDbGroups { public static class LoyaltyCardDbGroups {
public static final String TABLE = "groups"; public static final String TABLE = "groups";
public static final String ID = "_id"; public static final String ID = "_id";
public static final String NAME = "name";
public static final String ORDER = "orderId"; public static final String ORDER = "orderId";
} }
@@ -87,7 +88,8 @@ public class DBHelper extends SQLiteOpenHelper {
public void onCreate(SQLiteDatabase db) { public void onCreate(SQLiteDatabase db) {
// create table for card groups // create table for card groups
db.execSQL("CREATE TABLE " + LoyaltyCardDbGroups.TABLE + "(" + db.execSQL("CREATE TABLE " + LoyaltyCardDbGroups.TABLE + "(" +
LoyaltyCardDbGroups.ID + " TEXT primary key not null," + LoyaltyCardDbGroups.ID + " INTEGER primary key autoincrement," +
LoyaltyCardDbGroups.NAME + " TEXT not null," +
LoyaltyCardDbGroups.ORDER + " INTEGER DEFAULT '0')"); LoyaltyCardDbGroups.ORDER + " INTEGER DEFAULT '0')");
// create table for cards // create table for cards
@@ -112,7 +114,7 @@ public class DBHelper extends SQLiteOpenHelper {
// create associative table for cards in groups // create associative table for cards in groups
db.execSQL("CREATE TABLE " + LoyaltyCardDbIdsGroups.TABLE + "(" + db.execSQL("CREATE TABLE " + LoyaltyCardDbIdsGroups.TABLE + "(" +
LoyaltyCardDbIdsGroups.cardID + " INTEGER," + LoyaltyCardDbIdsGroups.cardID + " INTEGER," +
LoyaltyCardDbIdsGroups.groupID + " TEXT," + LoyaltyCardDbIdsGroups.groupID + " INTEGER," +
"primary key (" + LoyaltyCardDbIdsGroups.cardID + "," + LoyaltyCardDbIdsGroups.groupID + "))"); "primary key (" + LoyaltyCardDbIdsGroups.cardID + "," + LoyaltyCardDbIdsGroups.groupID + "))");
// create FTS search table // create FTS search table
@@ -321,6 +323,70 @@ public class DBHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
+ " ADD COLUMN " + LoyaltyCardDbIds.VALID_FROM + " INTEGER"); + " ADD COLUMN " + LoyaltyCardDbIds.VALID_FROM + " INTEGER");
} }
if (oldVersion < 17 && newVersion >= 17) {
// SQLite doesn't support modify column
// So we need to create a temp column to change the key of the group table
// https://www.sqlite.org/faq.html#q11
db.beginTransaction();
// Step 1: Migrate LoyaltyCardDbGroups to contain integer ID
db.execSQL("CREATE TEMPORARY TABLE tmp (" +
LoyaltyCardDbGroups.ID + " INTEGER primary key autoincrement," +
LoyaltyCardDbGroups.NAME + " TEXT not null," +
LoyaltyCardDbGroups.ORDER + " INTEGER DEFAULT '0')");
db.execSQL("INSERT INTO tmp (" +
LoyaltyCardDbGroups.NAME + " ," +
LoyaltyCardDbGroups.ORDER + ")" +
" SELECT " +
LoyaltyCardDbGroups.NAME + " ," +
LoyaltyCardDbGroups.ORDER +
" FROM " + LoyaltyCardDbGroups.TABLE);
db.execSQL("DROP TABLE " + LoyaltyCardDbGroups.TABLE);
db.execSQL("CREATE TABLE " + LoyaltyCardDbGroups.TABLE + "(" +
LoyaltyCardDbGroups.ID + " INTEGER primary key autoincrement," +
LoyaltyCardDbGroups.NAME + " TEXT not null," +
LoyaltyCardDbGroups.ORDER + " INTEGER DEFAULT '0')");
db.execSQL("INSERT INTO " + LoyaltyCardDbGroups.TABLE + "(" +
LoyaltyCardDbGroups.ID + " ," +
LoyaltyCardDbGroups.NAME + " ," +
LoyaltyCardDbGroups.ORDER + ")" +
" SELECT " +
LoyaltyCardDbGroups.ID + " ," +
LoyaltyCardDbGroups.NAME + " ," +
LoyaltyCardDbGroups.ORDER +
" FROM tmp");
db.execSQL("DROP TABLE tmp");
// Step 2: Migrate LoyaltyCardDbIdsGroups to link to ID
db.execSQL("CREATE TEMPORARY TABLE tmp (" +
LoyaltyCardDbIdsGroups.cardID + " INTEGER," +
LoyaltyCardDbIdsGroups.groupID + " INTEGER," +
"primary key (" + LoyaltyCardDbIdsGroups.cardID + "," + LoyaltyCardDbIdsGroups.groupID + "))");
db.execSQL("INSERT INTO tmp (" +
LoyaltyCardDbIdsGroups.cardID + " ," +
LoyaltyCardDbIdsGroups.groupID + ")" +
" SELECT " +
LoyaltyCardDbGroups.NAME + " ," +
LoyaltyCardDbGroups.ORDER +
" FROM " + LoyaltyCardDbGroups.TABLE);
//////////
db.execSQL("CREATE TABLE " + LoyaltyCardDbIdsGroups.TABLE + "(" +
LoyaltyCardDbIdsGroups.cardID + " INTEGER," +
LoyaltyCardDbIdsGroups.groupID + " INTEGER," +
"primary key (" + LoyaltyCardDbIdsGroups.cardID + "," + LoyaltyCardDbIdsGroups.groupID + "))");
db.setTransactionSuccessful();
db.endTransaction();
}
} }
private static ContentValues generateFTSContentValues(final int id, final String store, final String note) { private static ContentValues generateFTSContentValues(final int id, final String store, final String note) {

View File

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

View File

@@ -141,7 +141,7 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, loyaltyCard.store, loyaltyCard.headerColor).getLetterTile()); inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, loyaltyCard.store, loyaltyCard.headerColor).getLetterTile());
inputHolder.mCardIcon.setScaleType(ImageView.ScaleType.FIT_CENTER); inputHolder.mCardIcon.setScaleType(ImageView.ScaleType.FIT_CENTER);
} }
inputHolder.setIconBackgroundColor(loyaltyCard.headerColor != null ? loyaltyCard.headerColor : androidx.appcompat.R.attr.colorPrimary); inputHolder.setIconBackgroundColor(loyaltyCard.headerColor != null ? loyaltyCard.headerColor : R.attr.colorPrimary);
inputHolder.toggleCardStateIcon(loyaltyCard.starStatus != 0, loyaltyCard.archiveStatus != 0, itemSelected(inputCursor.getPosition())); inputHolder.toggleCardStateIcon(loyaltyCard.starStatus != 0, loyaltyCard.archiveStatus != 0, itemSelected(inputCursor.getPosition()));
@@ -290,7 +290,7 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
field.setVisibility(View.VISIBLE); field.setVisibility(View.VISIBLE);
field.setText(text); field.setText(text);
field.setTextSize(size); field.setTextSize(size);
field.setTextColor(color != null ? color : MaterialColors.getColor(mContext, com.google.android.material.R.attr.colorSecondary, ContextCompat.getColor(mContext, mDarkModeEnabled ? R.color.md_theme_dark_secondary : R.color.md_theme_light_secondary))); field.setTextColor(color != null ? color : MaterialColors.getColor(mContext, R.attr.colorSecondary, ContextCompat.getColor(mContext, mDarkModeEnabled ? R.color.md_theme_dark_secondary : R.color.md_theme_light_secondary)));
int drawableSize = dpToPx((size * 24) / 14, mContext); int drawableSize = dpToPx((size * 24) / 14, mContext);
mDivider.setVisibility(View.VISIBLE); mDivider.setVisibility(View.VISIBLE);

View File

@@ -1,5 +1,6 @@
package protect.card_locker; package protect.card_locker;
import android.Manifest;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.app.DatePickerDialog; import android.app.DatePickerDialog;
@@ -72,6 +73,7 @@ import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.AppCompatTextView; import androidx.appcompat.widget.AppCompatTextView;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
@@ -670,16 +672,16 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
} }
mCropperOptions.setAspectRatioOptions(selectedByDefault, mCropperOptions.setAspectRatioOptions(selectedByDefault,
new AspectRatio(null, 1, 1), new AspectRatio(null, 1, 1),
new AspectRatio(getResources().getString(com.yalantis.ucrop.R.string.ucrop_label_original).toUpperCase(), sourceWidth, sourceHeight), new AspectRatio(getResources().getString(R.string.ucrop_label_original).toUpperCase(), sourceWidth, sourceHeight),
new AspectRatio(getResources().getString(R.string.card).toUpperCase(), 85.6f, 53.98f) new AspectRatio(getResources().getString(R.string.card).toUpperCase(), 85.6f, 53.98f)
); );
// Fix theming // Fix theming
int colorPrimary = MaterialColors.getColor(this, androidx.appcompat.R.attr.colorPrimary, ContextCompat.getColor(this, R.color.md_theme_light_primary)); int colorPrimary = MaterialColors.getColor(this, R.attr.colorPrimary, ContextCompat.getColor(this, R.color.md_theme_light_primary));
int colorOnPrimary = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnPrimary, ContextCompat.getColor(this, R.color.md_theme_light_onPrimary)); int colorOnPrimary = MaterialColors.getColor(this, R.attr.colorOnPrimary, ContextCompat.getColor(this, R.color.md_theme_light_onPrimary));
int colorSurface = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurface, ContextCompat.getColor(this, R.color.md_theme_light_surface)); int colorSurface = MaterialColors.getColor(this, R.attr.colorSurface, ContextCompat.getColor(this, R.color.md_theme_light_surface));
int colorOnSurface = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurface, ContextCompat.getColor(this, R.color.md_theme_light_onSurface)); int colorOnSurface = MaterialColors.getColor(this, R.attr.colorOnSurface, ContextCompat.getColor(this, R.color.md_theme_light_onSurface));
int colorBackground = MaterialColors.getColor(this, android.R.attr.colorBackground, ContextCompat.getColor(this, R.color.md_theme_light_onSurface)); int colorBackground = MaterialColors.getColor(this, android.R.attr.colorBackground, ContextCompat.getColor(this, R.color.md_theme_light_onSurface));
mCropperOptions.setToolbarColor(colorSurface); mCropperOptions.setToolbarColor(colorSurface);
mCropperOptions.setStatusBarColor(colorSurface); mCropperOptions.setStatusBarColor(colorSurface);
@@ -911,7 +913,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
protected void setColorFromIcon() { protected void setColorFromIcon() {
Object icon = thumbnail.getTag(); Object icon = thumbnail.getTag();
if (icon != null && (icon instanceof Bitmap)) { if (icon != null && (icon instanceof Bitmap)) {
int headerColor = Utils.getHeaderColorFromImage((Bitmap) icon, tempLoyaltyCard.headerColor != null ? tempLoyaltyCard.headerColor : androidx.appcompat.R.attr.colorPrimary); int headerColor = Utils.getHeaderColorFromImage((Bitmap) icon, tempLoyaltyCard.headerColor != null ? tempLoyaltyCard.headerColor : R.attr.colorPrimary);
updateTempState(LoyaltyCardField.headerColor, headerColor); updateTempState(LoyaltyCardField.headerColor, headerColor);

View File

@@ -1209,7 +1209,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
getWindow().setDecorFitsSystemWindows(true); getWindow().setDecorFitsSystemWindows(true);
if (getWindow().getInsetsController() != null) { if (getWindow().getInsetsController() != null) {
getWindow().getInsetsController().show(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars()); getWindow().getInsetsController().show(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars());
getWindow().getInsetsController().setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT);
} }
} else { } else {
unsetFullscreenModeSdkLessThan30(); unsetFullscreenModeSdkLessThan30();

View File

@@ -375,28 +375,18 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
// Start of active tab logic // Start of active tab logic
updateTabGroups(groupsTabLayout); updateTabGroups(groupsTabLayout);
// Restore selected tab from Shared Preference // Restore settings from Shared Preference
SharedPreferences activeTabPref = getApplicationContext().getSharedPreferences( SharedPreferences activeTabPref = getApplicationContext().getSharedPreferences(
getString(R.string.sharedpreference_active_tab), getString(R.string.sharedpreference_active_tab),
Context.MODE_PRIVATE); Context.MODE_PRIVATE);
selectedTab = activeTabPref.getInt(getString(R.string.sharedpreference_active_tab), 0); selectedTab = activeTabPref.getInt(getString(R.string.sharedpreference_active_tab), 0);
// Restore sort preferences from Shared Preferences
// If one of the sorting prefererences has never been set or is set to an invalid value,
// stick to the defaults.
SharedPreferences sortPref = getApplicationContext().getSharedPreferences( SharedPreferences sortPref = getApplicationContext().getSharedPreferences(
getString(R.string.sharedpreference_sort), getString(R.string.sharedpreference_sort),
Context.MODE_PRIVATE); Context.MODE_PRIVATE);
try {
String orderString = sortPref.getString(getString(R.string.sharedpreference_sort_order), null); mOrder = DBHelper.LoyaltyCardOrder.valueOf(sortPref.getString(getString(R.string.sharedpreference_sort_order), null));
String orderDirectionString = sortPref.getString(getString(R.string.sharedpreference_sort_direction), null); mOrderDirection = DBHelper.LoyaltyCardOrderDirection.valueOf(sortPref.getString(getString(R.string.sharedpreference_sort_direction), null));
} catch (IllegalArgumentException | NullPointerException ignored) {
if (orderString != null && orderDirectionString != null) {
try {
mOrder = DBHelper.LoyaltyCardOrder.valueOf(orderString);
mOrderDirection = DBHelper.LoyaltyCardOrderDirection.valueOf(orderDirectionString);
} catch (IllegalArgumentException ignored) {
}
} }
mGroup = null; mGroup = null;
@@ -530,41 +520,38 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
// Check if an image was shared to us // Check if an image was shared to us
if (Intent.ACTION_SEND.equals(receivedAction)) { if (Intent.ACTION_SEND.equals(receivedAction)) {
if (!receivedType.startsWith("image/")) { if (receivedType.startsWith("image/")) {
BarcodeValues barcodeValues;
try {
Bitmap bitmap;
try {
Uri data = intent.getParcelableExtra(Intent.EXTRA_STREAM);
bitmap = Utils.retrieveImageFromUri(this, data);
} catch (IOException e) {
Log.e(TAG, "Error getting data from image file");
e.printStackTrace();
Toast.makeText(this, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
finish();
return;
}
barcodeValues = Utils.getBarcodeFromBitmap(bitmap);
if (barcodeValues.isEmpty()) {
Log.i(TAG, "No barcode found in image file");
Toast.makeText(this, R.string.noBarcodeFound, Toast.LENGTH_LONG).show();
finish();
return;
}
} catch (NullPointerException e) {
Toast.makeText(this, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
finish();
return;
}
processBarcodeValues(barcodeValues, null);
} else {
Log.e(TAG, "Wrong mime-type"); Log.e(TAG, "Wrong mime-type");
return;
} }
BarcodeValues barcodeValues;
Bitmap bitmap;
Uri data = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (data == null) {
Toast.makeText(this, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
finish();
return;
}
try {
bitmap = Utils.retrieveImageFromUri(this, data);
} catch (IOException e) {
Log.e(TAG, "Error getting data from image file");
e.printStackTrace();
Toast.makeText(this, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
finish();
return;
}
barcodeValues = Utils.getBarcodeFromBitmap(bitmap);
if (barcodeValues.isEmpty()) {
Log.i(TAG, "No barcode found in image file");
Toast.makeText(this, R.string.noBarcodeFound, Toast.LENGTH_LONG).show();
finish();
return;
}
processBarcodeValues(barcodeValues, null);
} }
} }

View File

@@ -21,6 +21,7 @@ import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts; import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
@@ -193,22 +194,27 @@ public class ScanActivity extends CatimaAppCompatActivity {
private void handleActivityResult(int requestCode, int resultCode, Intent intent) { private void handleActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent); super.onActivityResult(requestCode, resultCode, intent);
BarcodeValues barcodeValues = Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this); BarcodeValues barcodeValues;
if (barcodeValues.isEmpty()) { try {
barcodeValues = Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this);
} catch (NullPointerException e) {
Toast.makeText(this, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
return; return;
} }
Intent manualResult = new Intent(); if (!barcodeValues.isEmpty()) {
Bundle manualResultBundle = new Bundle(); Intent manualResult = new Intent();
manualResultBundle.putString(BarcodeSelectorActivity.BARCODE_CONTENTS, barcodeValues.content()); Bundle manualResultBundle = new Bundle();
manualResultBundle.putString(BarcodeSelectorActivity.BARCODE_FORMAT, barcodeValues.format()); manualResultBundle.putString(BarcodeSelectorActivity.BARCODE_CONTENTS, barcodeValues.content());
if (addGroup != null) { manualResultBundle.putString(BarcodeSelectorActivity.BARCODE_FORMAT, barcodeValues.format());
manualResultBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, addGroup); if (addGroup != null) {
manualResultBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, addGroup);
}
manualResult.putExtras(manualResultBundle);
ScanActivity.this.setResult(RESULT_OK, manualResult);
finish();
} }
manualResult.putExtras(manualResultBundle);
ScanActivity.this.setResult(RESULT_OK, manualResult);
finish();
} }
public void addManually(View view) { public void addManually(View view) {
@@ -245,7 +251,7 @@ public class ScanActivity extends CatimaAppCompatActivity {
customBarcodeScannerBinding.cameraPermissionDeniedLayout.cameraPermissionDeniedClickableArea.setOnClickListener(show ? v -> { customBarcodeScannerBinding.cameraPermissionDeniedLayout.cameraPermissionDeniedClickableArea.setOnClickListener(show ? v -> {
navigateToSystemPermissionSetting(); navigateToSystemPermissionSetting();
} : null); } : null);
customBarcodeScannerBinding.cardInputContainer.setBackgroundColor(show ? obtainThemeAttribute(com.google.android.material.R.attr.colorSurface) : Color.TRANSPARENT); customBarcodeScannerBinding.cardInputContainer.setBackgroundColor(show ? obtainThemeAttribute(R.attr.colorSurface) : Color.TRANSPARENT);
customBarcodeScannerBinding.cameraPermissionDeniedLayout.getRoot().setVisibility(show ? View.VISIBLE : View.GONE); customBarcodeScannerBinding.cameraPermissionDeniedLayout.getRoot().setVisibility(show ? View.VISIBLE : View.GONE);
} }

View File

@@ -53,8 +53,8 @@ public class UCropWrapper extends UCropActivity {
AppCompatImageView controlsBackgroundImage = (AppCompatImageView) check; AppCompatImageView controlsBackgroundImage = (AppCompatImageView) check;
// everything gathered and are as expected, now perform color patching // everything gathered and are as expected, now perform color patching
Utils.patchColors(this); Utils.patchColors(this);
int colorSurface = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurface, ContextCompat.getColor(this, R.color.md_theme_light_surface)); int colorSurface = MaterialColors.getColor(this, R.attr.colorSurface, ContextCompat.getColor(this, R.color.md_theme_light_surface));
int colorOnSurface = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSurface, ContextCompat.getColor(this, R.color.md_theme_light_onSurface)); int colorOnSurface = MaterialColors.getColor(this, R.attr.colorOnSurface, ContextCompat.getColor(this, R.color.md_theme_light_onSurface));
Drawable controlsBackgroundImageDrawable = controlsBackgroundImage.getBackground(); Drawable controlsBackgroundImageDrawable = controlsBackgroundImage.getBackground();
controlsBackgroundImageDrawable.mutate(); controlsBackgroundImageDrawable.mutate();

View File

@@ -15,6 +15,7 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.LocaleList; import android.os.LocaleList;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.text.format.DateUtils;
import android.util.Log; import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.MenuItem; import android.view.MenuItem;
@@ -45,6 +46,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.StringWriter;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.NumberFormat; import java.text.NumberFormat;
@@ -112,17 +114,6 @@ public class Utils {
return ColorUtils.calculateLuminance(backgroundColor) > LUMINANCE_MIDPOINT; return ColorUtils.calculateLuminance(backgroundColor) > LUMINANCE_MIDPOINT;
} }
/**
* Returns the Barcode format and content based on the result of an activity.
* It shows toasts to notify the end-user as needed itself and will return an empty
* BarcodeValues object if the activity was cancelled or nothing could be found.
*
* @param requestCode
* @param resultCode
* @param intent
* @param context
* @return BarcodeValues
*/
static public BarcodeValues parseSetBarcodeActivityResult(int requestCode, int resultCode, Intent intent, Context context) { static public BarcodeValues parseSetBarcodeActivityResult(int requestCode, int resultCode, Intent intent, Context context) {
String contents; String contents;
String format; String format;
@@ -134,15 +125,9 @@ public class Utils {
if (requestCode == Utils.BARCODE_IMPORT_FROM_IMAGE_FILE) { if (requestCode == Utils.BARCODE_IMPORT_FROM_IMAGE_FILE) {
Log.i(TAG, "Received image file with possible barcode"); Log.i(TAG, "Received image file with possible barcode");
Uri data = intent.getData();
if (data == null) {
Log.e(TAG, "Intent did not contain any data");
Toast.makeText(context, R.string.errorReadingImage, Toast.LENGTH_LONG).show();
return new BarcodeValues(null, null);
}
Bitmap bitmap; Bitmap bitmap;
try { try {
Uri data = intent.getData();
bitmap = retrieveImageFromUri(context, data); bitmap = retrieveImageFromUri(context, data);
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Error getting data from image file"); Log.e(TAG, "Error getting data from image file");
@@ -572,7 +557,7 @@ public class Utils {
return fallback; return fallback;
} }
return new Palette.Builder(image).generate().getDominantColor(androidx.appcompat.R.attr.colorPrimary); return new Palette.Builder(image).generate().getDominantColor(R.attr.colorPrimary);
} }
public static int getRandomHeaderColor(Context context) { public static int getRandomHeaderColor(Context context) {

View File

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

View File

@@ -17,7 +17,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.StringReader; import java.io.StringReader;
import java.io.UncheckedIOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
@@ -78,7 +77,7 @@ public class CatimaImporter implements Importer {
int version = parseVersion(bufferedReader); int version = parseVersion(bufferedReader);
switch (version) { switch (version) {
case 1: case 1:
parseV1(database, bufferedReader); parseV1(context, database, bufferedReader);
break; break;
case 2: case 2:
parseV2(context, database, bufferedReader); parseV2(context, database, bufferedReader);
@@ -88,12 +87,12 @@ public class CatimaImporter implements Importer {
} }
} }
public void parseV1(SQLiteDatabase database, BufferedReader input) throws IOException, FormatException, InterruptedException { public void parseV1(Context context, SQLiteDatabase database, BufferedReader input) throws IOException, FormatException, InterruptedException {
final CSVParser parser = new CSVParser(input, CSVFormat.RFC4180.builder().setHeader().build()); final CSVParser parser = new CSVParser(input, CSVFormat.RFC4180.builder().setHeader().build());
try { try {
for (CSVRecord record : parser) { for (CSVRecord record : parser) {
importLoyaltyCard(database, record); importLoyaltyCard(context, database, record);
if (Thread.currentThread().isInterrupted()) { if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException(); throw new InterruptedException();
@@ -101,7 +100,7 @@ public class CatimaImporter implements Importer {
} }
parser.close(); parser.close();
} catch (UncheckedIOException e) { } catch (IllegalArgumentException | IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e); throw new FormatException("Issue parsing CSV data", e);
} }
} }
@@ -183,7 +182,7 @@ public class CatimaImporter implements Importer {
throw new InterruptedException(); throw new InterruptedException();
} }
} }
} catch (UncheckedIOException e) { } catch (IllegalArgumentException | IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e); throw new FormatException("Issue parsing CSV data", e);
} finally { } finally {
groupParser.close(); groupParser.close();
@@ -208,14 +207,14 @@ public class CatimaImporter implements Importer {
throw new InterruptedException(); throw new InterruptedException();
} }
} }
} catch (UncheckedIOException e) { } catch (IllegalArgumentException | IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e); throw new FormatException("Issue parsing CSV data", e);
} finally { } finally {
cardParser.close(); cardParser.close();
} }
for (CSVRecord record : records) { for (CSVRecord record : records) {
importLoyaltyCard(database, record); importLoyaltyCard(context, database, record);
} }
} }
@@ -233,7 +232,7 @@ public class CatimaImporter implements Importer {
throw new InterruptedException(); throw new InterruptedException();
} }
} }
} catch (UncheckedIOException e) { } catch (IllegalArgumentException | IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e); throw new FormatException("Issue parsing CSV data", e);
} finally { } finally {
cardGroupParser.close(); cardGroupParser.close();
@@ -277,9 +276,9 @@ public class CatimaImporter implements Importer {
* Import a single loyalty card into the database using the given * Import a single loyalty card into the database using the given
* session. * session.
*/ */
private void importLoyaltyCard(SQLiteDatabase database, CSVRecord record) private void importLoyaltyCard(Context context, SQLiteDatabase database, CSVRecord record)
throws FormatException { throws IOException, FormatException {
int id = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ID, record); int id = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ID, record, false);
String store = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.STORE, record, ""); String store = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.STORE, record, "");
if (store.isEmpty()) { if (store.isEmpty()) {
@@ -287,38 +286,25 @@ public class CatimaImporter implements Importer {
} }
String note = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.NOTE, record, ""); String note = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.NOTE, record, "");
Date validFrom = null; Date validFrom = null;
Long validFromLong;
try { try {
validFromLong = CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.VALID_FROM, record); validFrom = new Date(CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.VALID_FROM, record, true));
} catch (FormatException ignored) { } catch (NullPointerException | FormatException e) {
validFromLong = null;
}
if (validFromLong != null) {
validFrom = new Date(validFromLong);
} }
Date expiry = null; Date expiry = null;
Long expiryLong;
try { try {
expiryLong = CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.EXPIRY, record); expiry = new Date(CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.EXPIRY, record, true));
} catch (FormatException ignored) { } catch (NullPointerException | FormatException e) {
expiryLong = null;
}
if (expiryLong != null) {
expiry = new Date(expiryLong);
} }
// These fields did not exist in versions 1.8.1 and before BigDecimal balance;
// We default to 0 so we can still import old backups try {
BigDecimal balance = new BigDecimal("0"); balance = new BigDecimal(CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BALANCE, record, null));
String balanceString = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BALANCE, record, null); } catch (FormatException _e) {
if (balanceString != null) { // These fields did not exist in versions 1.8.1 and before
try { // We catch this exception so we can still import old backups
balance = new BigDecimal(CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BALANCE, record, null)); balance = new BigDecimal("0");
} catch (NumberFormatException ignored) {
}
} }
Currency balanceType = null; Currency balanceType = null;
@@ -344,14 +330,14 @@ public class CatimaImporter implements Importer {
} }
Integer headerColor = null; Integer headerColor = null;
try {
headerColor = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.HEADER_COLOR, record); if (record.isMapped(DBHelper.LoyaltyCardDbIds.HEADER_COLOR)) {
} catch (FormatException ignored) { headerColor = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.HEADER_COLOR, record, true);
} }
int starStatus = 0; int starStatus = 0;
try { try {
starStatus = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.STAR_STATUS, record); starStatus = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.STAR_STATUS, record, false);
} catch (FormatException _e) { } catch (FormatException _e) {
// This field did not exist in versions 0.28 and before // This field did not exist in versions 0.28 and before
// We catch this exception so we can still import old backups // We catch this exception so we can still import old backups
@@ -360,7 +346,7 @@ public class CatimaImporter implements Importer {
int archiveStatus = 0; int archiveStatus = 0;
try { try {
archiveStatus = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ARCHIVE_STATUS, record); archiveStatus = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ARCHIVE_STATUS, record, false);
} catch (FormatException _e) { } catch (FormatException _e) {
// This field did not exist in versions 2.16.3 and before // This field did not exist in versions 2.16.3 and before
// We catch this exception so we can still import old backups // We catch this exception so we can still import old backups
@@ -369,7 +355,7 @@ public class CatimaImporter implements Importer {
Long lastUsed = 0L; Long lastUsed = 0L;
try { try {
lastUsed = CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.LAST_USED, record); lastUsed = CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.LAST_USED, record, false);
} catch (FormatException _e) { } catch (FormatException _e) {
// This field did not exist in versions 2.5.0 and before // This field did not exist in versions 2.5.0 and before
// We catch this exception so we can still import old backups // We catch this exception so we can still import old backups
@@ -385,10 +371,6 @@ public class CatimaImporter implements Importer {
private void importGroup(SQLiteDatabase database, CSVRecord record) throws FormatException { private void importGroup(SQLiteDatabase database, CSVRecord record) throws FormatException {
String id = CSVHelpers.extractString(DBHelper.LoyaltyCardDbGroups.ID, record, null); String id = CSVHelpers.extractString(DBHelper.LoyaltyCardDbGroups.ID, record, null);
if (id == null) {
throw new FormatException("Group has no ID: " + record);
}
DBHelper.insertGroup(database, id); DBHelper.insertGroup(database, id);
} }
@@ -397,13 +379,9 @@ public class CatimaImporter implements Importer {
* session. * session.
*/ */
private void importCardGroupMapping(SQLiteDatabase database, CSVRecord record) throws FormatException { private void importCardGroupMapping(SQLiteDatabase database, CSVRecord record) throws FormatException {
int cardId = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIdsGroups.cardID, record); Integer cardId = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIdsGroups.cardID, record, false);
String groupId = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIdsGroups.groupID, record, null); String groupId = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIdsGroups.groupID, record, null);
if (groupId == null) {
throw new FormatException("Group has no ID: " + record);
}
List<Group> cardGroups = DBHelper.getLoyaltyCardGroups(database, cardId); List<Group> cardGroups = DBHelper.getLoyaltyCardGroups(database, cardId);
cardGroups.add(DBHelper.getGroup(database, groupId)); cardGroups.add(DBHelper.getGroup(database, groupId));
DBHelper.setLoyaltyCardGroups(database, cardId, cardGroups); DBHelper.setLoyaltyCardGroups(database, cardId, cardGroups);

View File

@@ -74,31 +74,29 @@ public class StocardImporter implements Importer {
String fileName = localFileHeader.getFileName(); String fileName = localFileHeader.getFileName();
String[] nameParts = fileName.split("/"); String[] nameParts = fileName.split("/");
if (nameParts.length < 2) {
continue;
}
if (providersFileName == null) { if (providersFileName == null) {
providersFileName = new String[]{ providersFileName = new String[]{
"extracts", nameParts[0],
nameParts[1], "sync",
"data",
"users", "users",
nameParts[1], nameParts[0],
"analytics-properties", "analytics-properties.json"
"content.json"
}; };
customProvidersBaseName = new String[]{ customProvidersBaseName = new String[]{
"extracts", nameParts[0],
nameParts[1], "sync",
"data",
"users", "users",
nameParts[1], nameParts[0],
"loyalty-card-custom-providers" "loyalty-card-custom-providers"
}; };
cardBaseName = new String[]{ cardBaseName = new String[]{
"extracts", nameParts[0],
nameParts[1], "sync",
"data",
"users", "users",
nameParts[1], nameParts[0],
"loyalty-cards" "loyalty-cards"
}; };
} }
@@ -108,15 +106,18 @@ public class StocardImporter implements Importer {
customProviderId = nameParts[customProvidersBaseName.length].split("\\.", 2)[0]; customProviderId = nameParts[customProvidersBaseName.length].split("\\.", 2)[0];
// Name file // Name file
if (fileName.endsWith(customProviderId + "/content.json")) { if (nameParts.length == customProvidersBaseName.length + 1) {
JSONObject jsonObject = ZipUtils.readJSON(zipInputStream); // Ignore the .txt file
if (fileName.endsWith(".json")) {
JSONObject jsonObject = ZipUtils.readJSON(zipInputStream);
providers = appendToHashMap( providers = appendToHashMap(
providers, providers,
customProviderId, customProviderId,
"name", "name",
jsonObject.getString("name") jsonObject.getString("name")
); );
}
} else if (fileName.endsWith("logo.png")) { } else if (fileName.endsWith("logo.png")) {
providers = appendToHashMap( providers = appendToHashMap(
providers, providers,
@@ -132,43 +133,46 @@ public class StocardImporter implements Importer {
cardName = nameParts[cardBaseName.length].split("\\.", 2)[0]; cardName = nameParts[cardBaseName.length].split("\\.", 2)[0];
// This is the card itself // This is the card itself
if (fileName.endsWith(cardName + "/content.json")) { if (nameParts.length == cardBaseName.length + 1) {
JSONObject jsonObject = ZipUtils.readJSON(zipInputStream); // Ignore the .txt file
if (fileName.endsWith(".json")) {
JSONObject jsonObject = ZipUtils.readJSON(zipInputStream);
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap,
cardName,
"cardId",
jsonObject.getString("input_id")
);
// Provider ID can be either custom or not, extract whatever version is relevant
String customProviderPrefix = "/users/" + nameParts[1] + "/loyalty-card-custom-providers/";
String providerId = jsonObject
.getJSONObject("input_provider_reference")
.getString("identifier");
if (providerId.startsWith(customProviderPrefix)) {
providerId = providerId.substring(customProviderPrefix.length());
} else {
providerId = providerId.substring("/loyalty-card-providers/".length());
}
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap,
cardName,
"_providerId",
providerId
);
if (jsonObject.has("input_barcode_format")) {
loyaltyCardHashMap = appendToHashMap( loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap, loyaltyCardHashMap,
cardName, cardName,
"barcodeType", "cardId",
jsonObject.getString("input_barcode_format") jsonObject.getString("input_id")
); );
// Provider ID can be either custom or not, extract whatever version is relevant
String customProviderPrefix = "/users/" + nameParts[0] + "/loyalty-card-custom-providers/";
String providerId = jsonObject
.getJSONObject("input_provider_reference")
.getString("identifier");
if (providerId.startsWith(customProviderPrefix)) {
providerId = providerId.substring(customProviderPrefix.length());
} else {
providerId = providerId.substring("/loyalty-card-providers/".length());
}
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap,
cardName,
"_providerId",
providerId
);
if (jsonObject.has("input_barcode_format")) {
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap,
cardName,
"barcodeType",
jsonObject.getString("input_barcode_format")
);
}
} }
} else if (fileName.endsWith("notes/default/content.json")) { } else if (fileName.endsWith("notes/default.json")) {
loyaltyCardHashMap = appendToHashMap( loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap, loyaltyCardHashMap,
cardName, cardName,

View File

@@ -16,8 +16,8 @@ Gediminas Murauskas
Petr Novák Petr Novák
Joel A Joel A
Taco Taco
laralem
pfaffenrodt pfaffenrodt
laralem
Nyatsuki Nyatsuki
gallegonovato gallegonovato
HudobniVolk HudobniVolk
@@ -30,11 +30,10 @@ huuhaa
Quentin PAGÈS Quentin PAGÈS
Alexander Ivanov Alexander Ivanov
arshbeerSingh arshbeerSingh
Denis Shilin
Freddo espresso Freddo espresso
Silvério Santos Silvério Santos
Miha Frangež Miha Frangež
Arnis Jaundžeikars Arnis Jaundzeikars
Kefir2105 Kefir2105
sr093906 sr093906
Giovanni Donisi Giovanni Donisi
@@ -43,7 +42,6 @@ Katarzyna
echo r"0xX4H" | rev echo r"0xX4H" | rev
Magnitudee Magnitudee
Olivia (Zoe) Olivia (Zoe)
Projjal Moitra
betsythefc betsythefc
waffshappen waffshappen
Robin Robin
@@ -109,7 +107,6 @@ BmBKun
Aditya Das Aditya Das
Kevin Sicong Jiang Kevin Sicong Jiang
Tomer Ben-Rachel Tomer Ben-Rachel
Tom Sawyer
tfuxu tfuxu
Ahmed Saleh Ahmed Saleh
Airat Airat
@@ -142,7 +139,7 @@ Jacopo Gennaro Esposito
Jasielprogramador Jasielprogramador
Jean Mareilles Jean Mareilles
Jean-Baptiste Jean-Baptiste
Kung-chih 人工知能
Karvjorm Karvjorm
krkk krkk
Laura Ferraz Laura Ferraz
@@ -154,12 +151,10 @@ Mattia
Md. Al-Amin Md. Al-Amin
Michael Gangolf Michael Gangolf
3DN1M 3DN1M
Mobashir Raihan
Moi Toi Moi Toi
DivideEtImpera DivideEtImpera
Nicolas Nicolas
Nosnahc Nosnahc
pa4k
pbeckmann pbeckmann
Peer Beckmann Peer Beckmann
Piotr Strebski Piotr Strebski
@@ -176,16 +171,15 @@ Samarth Asthan
Shailendra Maurya Shailendra Maurya
Simone Dotto Simone Dotto
Subhashish Anand Subhashish Anand
SziaTomi TenTraicion
Mehedi Hasan
Titas Pažereckas Titas Pažereckas
Tom Sawyer
atakujonc atakujonc
Tony C Tony C
Tymofii Lytvynenko Tymofii Lytvynenko
Vancha March Vancha March
Yevgeny M Yevgeny M
Yusril A Yusril A
ahmed-awad26
Avik Kundu Avik Kundu
diksha-2911 diksha-2911
gbonaspetti gbonaspetti
@@ -205,7 +199,6 @@ Truestorybaby
tygyh tygyh
unstartdev unstartdev
wmilan 17 wmilan 17
يوسف لطفي
luoyang3 luoyang3
JaeBeom An JaeBeom An
JungHee Lee JungHee Lee

View File

@@ -2,18 +2,6 @@
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: 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
sqlite3 -header -csv sync_db "select id,content from synced_resources where collection = '/loyalty-card-providers/'" > stocard_providers.csv
while IFS= read -r line; do
if [ "$line" = "id,content" ]; then
echo "_id,name,barcodeFormat" > stocard_stores.csv
else
id="$(echo "$line" | cut -d ',' -f1)"
name="$(echo "$line" | cut -d ',' -f2- | sed 's/""/"/g' | sed 's/^"//g' | sed 's/"$//g' | jq -r .name)"
barcodeFormat="$(echo "$line" | cut -d ',' -f2- | sed 's/""/"/g' | sed 's/^"//g' | sed 's/"$//g' | jq -r .default_barcode_format)"
echo "$id,\"$name\",$barcodeFormat" >> stocard_stores.csv
fi
done < stocard_providers.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. 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

@@ -93,7 +93,7 @@
<string name="importFidme">الاستيراد من FidMe</string> <string name="importFidme">الاستيراد من FidMe</string>
<string name="importFidmeMessage">حدد ملفك <i>fidme-export-request-xxxxxx.zip</i> تصدير من FidMe للاستيراد ، ثم حدد أنواع الباركود يدويًا بعد ذلك. <string name="importFidmeMessage">حدد ملفك <i>fidme-export-request-xxxxxx.zip</i> تصدير من FidMe للاستيراد ، ثم حدد أنواع الباركود يدويًا بعد ذلك.
\nقم بإنشائه من ملف تعريف FidMe الخاص بك عن طريق اختيار حماية البيانات ثم الضغط على استخراج بياناتي أولاً.</string> \nقم بإنشائه من ملف تعريف FidMe الخاص بك عن طريق اختيار حماية البيانات ثم الضغط على استخراج بياناتي أولاً.</string>
<string name="importStocardMessage">حدد ملفك <i>***.zip</i> تصدير من Stocard للاستيراد. <string name="importStocardMessage">حدد ملفك <i>***-sync.zip</i> تصدير من Stocard للاستيراد.
\nاحصل عليه عن طريق إرسال بريد إلكتروني إلى support@stocardapp.com لطلب تصدير بياناتك.</string> \nاحصل عليه عن طريق إرسال بريد إلكتروني إلى support@stocardapp.com لطلب تصدير بياناتك.</string>
<string name="importVoucherVault">الاستيراد من Voucher Vault</string> <string name="importVoucherVault">الاستيراد من Voucher Vault</string>
<string name="importVoucherVaultMessage">حدد ملفك <i>vouchervault.json</i> تصدير من Voucher Vault للاستيراد. <string name="importVoucherVaultMessage">حدد ملفك <i>vouchervault.json</i> تصدير من Voucher Vault للاستيراد.
@@ -290,6 +290,4 @@
<string name="noCameraPermissionDirectToSystemSetting">لمسح الباركود، ستحتاج Catima إلى الوصول إلى الكاميرا. اضغط هنا لتغيير إعدادات الأذونات.</string> <string name="noCameraPermissionDirectToSystemSetting">لمسح الباركود، ستحتاج Catima إلى الوصول إلى الكاميرا. اضغط هنا لتغيير إعدادات الأذونات.</string>
<string name="updateBalance">تحديث الرصيد</string> <string name="updateBalance">تحديث الرصيد</string>
<string name="updateBalanceHint">أدخل المبلغ</string> <string name="updateBalanceHint">أدخل المبلغ</string>
<string name="storageReadPermissionRequired">الصلاحيه للوصل للتخزين مطلوبة لهذا الاجراء</string>
<string name="validFromDate">عربيه</string>
</resources> </resources>

View File

@@ -71,13 +71,13 @@
<string name="moveBarcodeToCenterOfScreen">Премества щрихкода в центъра на екрана</string> <string name="moveBarcodeToCenterOfScreen">Премества щрихкода в центъра на екрана</string>
<string name="moveBarcodeToTopOfScreen">Премества щрихкода най-горе на екрана</string> <string name="moveBarcodeToTopOfScreen">Премества щрихкода най-горе на екрана</string>
<string name="never">Не изтича</string> <string name="never">Не изтича</string>
<string name="chooseExpiryDate">Определена дата</string> <string name="chooseExpiryDate">Дата на изтичане</string>
<string name="expiryDate">Валидна до</string> <string name="expiryDate">Валидност</string>
<string name="editBarcode">Редактиране на щрихкод</string> <string name="editBarcode">Редактиране на щрихкод</string>
<string name="barcode">Щрихкод</string> <string name="barcode">Щрихкод</string>
<string name="card">Карта</string> <string name="card">Карта</string>
<string name="groupsList">Списъци: <xliff:g>%s</xliff:g></string> <string name="groupsList">Списъци: <xliff:g>%s</xliff:g></string>
<string name="expiryStateSentence">Валидна до: <xliff:g>%s</xliff:g></string> <string name="expiryStateSentence">Валидност: <xliff:g>%s</xliff:g></string>
<string name="expiryStateSentenceExpired">Изтекла: <xliff:g>%s</xliff:g></string> <string name="expiryStateSentenceExpired">Изтекла: <xliff:g>%s</xliff:g></string>
<string name="balanceSentence">Наличност: <xliff:g>%s</xliff:g></string> <string name="balanceSentence">Наличност: <xliff:g>%s</xliff:g></string>
<string name="noGroups">Докоснете бутона +, за да добавите списък.</string> <string name="noGroups">Докоснете бутона +, за да добавите списък.</string>
@@ -152,7 +152,7 @@
<string name="importVoucherVault">Внасяне от Voucher Vault</string> <string name="importVoucherVault">Внасяне от Voucher Vault</string>
<string name="importVoucherVaultMessage">Изберете файла <i>vouchervault.json</i>, предварително изнесен от Voucher Vault. <string name="importVoucherVaultMessage">Изберете файла <i>vouchervault.json</i>, предварително изнесен от Voucher Vault.
\nСъздайте такъв файл от меню „Export“ във Voucher Vault.</string> \nСъздайте такъв файл от меню „Export“ във Voucher Vault.</string>
<string name="importStocardMessage">Изберете файла <i>***.zip</i>, предварително изнесен от Stocard. <string name="importStocardMessage">Изберете файла <i>***-sync.zip</i>, предварително изнесен от Stocard.
\nПолучете го като изпратите писмо на support@stocardapp.com с искане за изнасяне вашите данни.</string> \nПолучете го като изпратите писмо на support@stocardapp.com с искане за изнасяне вашите данни.</string>
<string name="importLoyaltyCardKeychainMessage">Изберете файла <i>LoyaltyCardKeychain.csv</i>, предварително изнесен от Loyalty Card Keychain. <string name="importLoyaltyCardKeychainMessage">Изберете файла <i>LoyaltyCardKeychain.csv</i>, предварително изнесен от Loyalty Card Keychain.
\nСъздайте такъв файл от меню Внасяне/изнасяне от друго устройство с Loyalty Card Keychain като изберете Изнасяне.</string> \nСъздайте такъв файл от меню Внасяне/изнасяне от друго устройство с Loyalty Card Keychain като изберете Изнасяне.</string>
@@ -267,5 +267,5 @@
<string name="validFromDate">Валидна от</string> <string name="validFromDate">Валидна от</string>
<string name="anyDate">Без значение от датата</string> <string name="anyDate">Без значение от датата</string>
<string name="validFromSentence">Валидна от: <xliff:g>%s</xliff:g></string> <string name="validFromSentence">Валидна от: <xliff:g>%s</xliff:g></string>
<string name="chooseValidFromDate">Определена дата</string> <string name="chooseValidFromDate">Изберете датата, от която е валидна</string>
</resources> </resources>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="save">সংরক্ষণ</string> <string name="save">সংরক্ষণ</string>
<string name="cancel">বাতিল</string> <string name="cancel">বাতিল</string>
<string name="unstar">তারা মুক্ত</string> <string name="unstar">তারা মুক্ত</string>
@@ -8,18 +8,18 @@
<string name="barcodeType">বারকোড ধরন</string> <string name="barcodeType">বারকোড ধরন</string>
<string name="note">বিঃদ্রঃ</string> <string name="note">বিঃদ্রঃ</string>
<string name="storeName">দোকানের নাম</string> <string name="storeName">দোকানের নাম</string>
<string name="noMatchingGiftCards">কোনো ফলাফল পাওয়া যায়নি। অনুসন্ধানের বাক্যটি বদলে দেখুন।</string> <string name="noMatchingGiftCards">কোন ম্যাচিং উপহার কার্ড নেই</string>
<string name="noGiftCards">প্লাস বোতামটি টিপে একটি কার্ড যোগ করুন বা ⋮ মেনু থেকে কিছু নিয়ে আসুন।</string> <string name="noGiftCards">উপহার কার্ড নেই</string>
<string name="action_add">কর্ম যোগ</string> <string name="action_add">কর্ম যোগ</string>
<string name="all">সব</string> <string name="all">সব</string>
<string name="noGroupCards">এই গ্রুপটি খালি</string> <string name="noGroupCards">গোষ্ঠী কার্ড নেই</string>
<string name="noGroups">+ যোগ বোতামটি টিপে গ্রুপ যোগ করুন যাতে তাদের শ্রেণীকরণ করা যায়।</string> <string name="noGroups">গোষ্ঠীগুলি নেই</string>
<string name="groups">গোষ্ঠীগুলি</string> <string name="groups">গোষ্ঠীগুলি</string>
<string name="enter_group_name">গোষ্ঠী নাম লিখুন </string> <string name="enter_group_name">গোষ্ঠী নাম লিখুন </string>
<string name="exportSuccessful">তথ্য রপ্তানি করা শেষ</string> <string name="exportSuccessful">রপ্তানি সফল</string>
<string name="importSuccessful">তথ্য আনা শেষ</string> <string name="importSuccessful">আগম সফল</string>
<string name="intent_import_card_from_url_share_text">url শেয়ার টেক্সট থেকে ইন্টেন্ট ইম্পোর্ট কার্ড</string> <string name="intent_import_card_from_url_share_text">url শেয়ার টেক্সট থেকে ইন্টেন্ট ইম্পোর্ট কার্ড</string>
<string name="settings_disable_lockscreen_while_viewing_card">স্ক্রীন লক হতে দেবেন না</string> <string name="settings_disable_lockscreen_while_viewing_card"> কার্ড দেখা কালিন লকস্ক্রিন নিষ্ক্রিয়</string>
<string name="settings_keep_screen_on">সেটিংস পর্দা খোলা রাখুন</string> <string name="settings_keep_screen_on">সেটিংস পর্দা খোলা রাখুন</string>
<string name="settings_max_font_size_scale">সর্বোচ্চ হরফ আকার</string> <string name="settings_max_font_size_scale">সর্বোচ্চ হরফ আকার</string>
<string name="settings_light_theme">সাদাটে থিম</string> <string name="settings_light_theme">সাদাটে থিম</string>
@@ -32,11 +32,11 @@
<string name="importStocard">স্টো কার্ড আমদানি করুন</string> <string name="importStocard">স্টো কার্ড আমদানি করুন</string>
<string name="importVoucherVault">আমদানি ভাউচার ভল্ট</string> <string name="importVoucherVault">আমদানি ভাউচার ভল্ট</string>
<string name="barcodeId">বারকোড আইডি</string> <string name="barcodeId">বারকোড আইডি</string>
<string name="sameAsCardId">আইডি আর এটা এক</string> <string name="sameAsCardId">কার্ড আইডির মতো</string>
<string name="setBarcodeId">বারকোড আইডি সেট করুন</string> <string name="setBarcodeId">বারকোড আইডি সেট করুন</string>
<string name="unsupportedBarcodeType">এই বারকোডের টাইপটি এখন দেখানো যাচ্ছে না। অ্যাপের পরের সংস্করণে হয়ত এটি সমর্থন করা যেতে পারে।</string> <string name="unsupportedBarcodeType">অসমর্থিত বারকোড টাইপ</string>
<string name="wrongValueForBarcodeType">বারকোড টাইপের জন্য ভুল মান</string> <string name="wrongValueForBarcodeType">বারকোড টাইপের জন্য ভুল মান</string>
<string name="copy_to_clipboard_multiple_toast">আইডিগুলি ক্লিপবোর্ডে কপি হল</string> <string name="copy_to_clipboard_multiple_toast">ক্লিপবোর্ড একাধিক টোস্টে অনুলিপি করুন</string>
<string name="intent_import_card_from_url_share_multiple_text">url থেকে ইন্টেন্ট ইম্পোর্ট কার্ড একাধিক টেক্সট শেয়ার করে</string> <string name="intent_import_card_from_url_share_multiple_text">url থেকে ইন্টেন্ট ইম্পোর্ট কার্ড একাধিক টেক্সট শেয়ার করে</string>
<string name="frontImageDescription">সামনের চিত্র</string> <string name="frontImageDescription">সামনের চিত্র</string>
<string name="backImageDescription">পিছনের চিত্র</string> <string name="backImageDescription">পিছনের চিত্র</string>
@@ -45,12 +45,12 @@
<string name="setBackImage">পিছনের ছবি স্থাপন</string> <string name="setBackImage">পিছনের ছবি স্থাপন</string>
<string name="removeImage">ছবি অপসারণ</string> <string name="removeImage">ছবি অপসারণ</string>
<string name="takePhoto">ছবি নেত্তয়া</string> <string name="takePhoto">ছবি নেত্তয়া</string>
<string name="updateBarcodeQuestionTitle">বারকোডের মানটি আপডেট করবেন\?</string> <string name="updateBarcodeQuestionTitle">হালনাগাদ বারকোড প্রশ্ন শিরোনাম</string>
<string name="updateBarcodeQuestionText">আপনি আইডিটি পাল্টেছেন, এটির কোনো বারকোড দিয়ে কি এখনের বারকোডটি আপডেট করে দেবেন\?</string> <string name="updateBarcodeQuestionText">হালনাগাদ বারকোড প্রশ্ন টেক্সট </string>
<string name="yes">হাঁ</string> <string name="yes">হাঁ</string>
<string name="no">না</string> <string name="no">না</string>
<string name="passwordRequired">পাসওয়ার্ড প্রয়োজন</string> <string name="passwordRequired">পাসওয়ার্ড প্রয়োজন</string>
<string name="failedGeneratingShareURL">শেয়ার করার ইউআরএল তৈরি করা গেল না। অনুগ্রহ করে এটিকে রিপোর্ট করে দিন।</string> <string name="failedGeneratingShareURL">শেয়ার ইউআরএল তৈরি করতে ব্যর্থ হয়েছে</string>
<string name="turn_flashlight_on">টর্চলাইট চালু করুন</string> <string name="turn_flashlight_on">টর্চলাইট চালু করুন</string>
<string name="turn_flashlight_off">টর্চলাইট বন্ধ করুন</string> <string name="turn_flashlight_off">টর্চলাইট বন্ধ করুন</string>
<string name="settings_locale">লোকেল</string> <string name="settings_locale">লোকেল</string>
@@ -65,11 +65,11 @@
<string name="settings_green_theme">সবুজ থিম</string> <string name="settings_green_theme">সবুজ থিম</string>
<string name="settings_brown_theme">বাদামী থিম</string> <string name="settings_brown_theme">বাদামী থিম</string>
<string name="sort">সাজান</string> <string name="sort">সাজান</string>
<string name="swipeToSwitchImages">ছবি পাল্টানোর জন্য সোয়াইপ করুন, ছবিটি গ্যালারি অ্যাপে খোলার জন্য টিপে ধড়ে থাকুন</string> <string name="swipeToSwitchImages">ছবি পরিবর্তন করতে সোয়াইপ করুন</string>
<string name="sort_by_name">নামের দ্বারা সাজান</string> <string name="sort_by_name">নামের দ্বারা সাজান</string>
<string name="sort_by_most_recently_used">সর্বাধিক সম্প্রতি ব্যবহৃত দ্বারা সাজান</string> <string name="sort_by_most_recently_used">সর্বাধিক সম্প্রতি ব্যবহৃত দ্বারা সাজান</string>
<string name="sort_by_expiry">মেয়াদ শেষ করে সাজান</string> <string name="sort_by_expiry">মেয়াদ শেষ করে সাজান</string>
<string name="reverse">...উল্টো ক্রমে</string> <string name="reverse">বিপরীত</string>
<string name="sort_by">ক্রমানুসার</string> <string name="sort_by">ক্রমানুসার</string>
<string name="noCardExistsError">কার্ডটি পাওয়া যায়নি</string> <string name="noCardExistsError">কার্ডটি পাওয়া যায়নি</string>
<string name="noStoreError">স্টোরেজ ত্রুটি নেই</string> <string name="noStoreError">স্টোরেজ ত্রুটি নেই</string>
@@ -80,7 +80,7 @@
<string name="sendLabel">পাঠান…</string> <string name="sendLabel">পাঠান…</string>
<string name="share">ভাগ</string> <string name="share">ভাগ</string>
<string name="copy_to_clipboard">নকল করুন ক্লিপবোর্ড এ</string> <string name="copy_to_clipboard">নকল করুন ক্লিপবোর্ড এ</string>
<string name="deleteConfirmation">এই কার্ডটি চিরকালের জন্য মুছে দেবো\?</string> <string name="deleteConfirmation">নিশ্চিতকরণ মুছে দিন</string>
<string name="confirm">নিশ্চিত করুন</string> <string name="confirm">নিশ্চিত করুন</string>
<string name="delete">মুছে ফেলুন</string> <string name="delete">মুছে ফেলুন</string>
<string name="edit">সম্পাদনা</string> <string name="edit">সম্পাদনা</string>
@@ -92,109 +92,13 @@
<string name="deleteTitle">কার্ড ডিলিট করুন</string> <string name="deleteTitle">কার্ড ডিলিট করুন</string>
<string name="ok">ঠিক আছে</string> <string name="ok">ঠিক আছে</string>
<string name="about">সম্পর্কিত</string> <string name="about">সম্পর্কিত</string>
<string name="debug_version_fmt">সংস্করণ: <xliff:g id="version">%s</xliff:g></string> <string name="debug_version_fmt">সংস্করণ:
\n<xliff:g id="version">
\n%s</xliff:g></string>
<string name="importOptionApplicationButton">অন্য অ্যাপ ব্যাবহার করুন</string> <string name="importOptionApplicationButton">অন্য অ্যাপ ব্যাবহার করুন</string>
<string name="moveUp">উপরে উঠান</string> <string name="moveUp">উপরে উঠান</string>
<string name="moveDown">নিচে নামান</string> <string name="moveDown">নিচে নামান</string>
<string name="barcode">বারকোড</string> <string name="barcode">বারকোড</string>
<string name="expiryDate">মেয়াদোত্তীর্ণ তারিখ</string> <string name="expiryDate">মেয়াদোত্তীর্ণ তারিখ</string>
<string name="noBarcodeFound">কোনো বারকোড পাওয়া যায়নি</string> <string name="noBarcodeFound">কোনো বারকোড পাওয়া যায়নি</string>
<string name="cameraPermissionRequired">এই কাজটির জন্য ক্যামেরা ব্যবহার করার অনুমতি লাগবে…</string>
<string name="noCameraPermissionDirectToSystemSetting">বারকোড স্ক্যান করার জন্য, কাটিমাকে ফোনের ক্যামেরা ব্যবহার করার অনুমতি দিতে হবে। এইখানে টাচ করে আপনার অনুমতি সেটিংস পালটে নিন।</string>
<string name="importOptionApplicationExplanation">আপনার প্রিয় ফাইল ম্যানেজার বা আর যেকোনো অ্যাপ দিয়ে একটি ফাইল খুলুন।</string>
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">মেধাস্বত্ব © ২০১৯-<xliff:g>%d</xliff:g> সিলভিয়া ভান অস</string>
<string name="app_license">কপিলেফ্ট করা মুক্ত সফটওয়্যার, জিপিএলের ৩য় এবং তার অধিক সংস্করণে লাইসেন্স করা</string>
<string name="enterBarcodeInstructions">আইডিটি লিখুন আর নয় নিচ থেকে একটি বারকোডের প্রকার বা \"কোনো বারকোড নেই\", নির্বাচন করুন।</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">এই <xliff:g>%d</xliff:g>টি কার্ড কি চিরকালের জন্য মুছে দেবো\?</item>
<item quantity="other">এই <xliff:g>%d</xliff:g>টি কার্ড কি চিরকালের জন্য মুছে দেবো\?</item>
</plurals>
<plurals name="selectedCardCount">
<item quantity="one"><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="other"><xliff:g>%d</xliff:g>টি কার্ড মুছে ফেলুন</item>
</plurals>
<string name="cameraPermissionDeniedTitle">ফোনের ক্যামেরা ব্যবহার করা যাচ্ছে না</string>
<string name="importOptionFilesystemExplanation">ফোনের স্টোরেজ থেকে নির্দিষ্ট একটি ফাইল আনুন।</string>
<string name="app_libraries">মুক্ত লাইব্রেরি যেগুলি আমার নয়: <xliff:g id="app_libraries_list">%s</xliff:g></string>
<string name="about_title_fmt"><xliff:g id="app_name">%s</xliff:g>টির ব্যাপারে</string>
<string name="app_revision_fmt">সংশোধন তথ্য: <xliff:g id="app_revision_url">%s</xliff:g></string>
<string name="app_resources">মুক্ত সম্পদ যেগুলি আমার নয়: <xliff:g id="app_resources_list">%s</xliff:g></string>
<string name="thumbnailDescription">থাম্বনেইল</string>
<string name="settings_card_orientation">বারকোড অভিমুখ</string>
<string name="settings_follow_system_orientation">সিস্টেমের অনুসারে</string>
<string name="settings_portrait_orientation">প্রতিকৃতি</string>
<string name="barcodeImageDescriptionWithType">ছবি <xliff:g>%s</xliff:g> বারকোড</string>
<string name="exportName">রপ্তানি</string>
<string name="failedParsingImportUriError">আমদানির ইউআরআই বোঝা যাচ্ছে না</string>
<string name="importExport">আমদানি/রপ্তানি</string>
<string name="cardShortcut">কার্ড শর্টকাট</string>
<string name="exportFailed">বার করা যাচ্ছে না</string>
<string name="copy_to_clipboard_toast">আইডি ক্লিপবোর্ডে নকল করা হল</string>
<string name="noCardIdError">কোনো আইডি দওয়া হয়নি</string>
<string name="importExportHelp">নিজের তথ্য অন্য কোথাও সংরক্ষণ করে রাখলে পরে সেটা অন্য ফোনে আবার নিয়ে নাওয়া যাই।</string>
<string name="importFailed">আনা যাচ্ছে না</string>
<string name="noGiftCardsGroup">কিছু কার্ড বানান আর এই গ্রুপে স্থির করুন।</string>
<string name="scanCardBarcode">বারকোড স্ক্যান করুন</string>
<string name="importSuccessfulTitle">আনা শেষ</string>
<string name="importFailedTitle">আনা ব্যর্থ</string>
<string name="exportSuccessfulTitle">বার করা শেষ</string>
<string name="exportFailedTitle">বার করা ব্যর্থ</string>
<string name="importing">আনা হচ্ছে…</string>
<string name="exporting">বার করা হচ্ছে…</string>
<string name="storageReadPermissionRequired">এই কাজটির জন্য ফোনের স্টোরেজ দেখার অনুমতি লাগবে…</string>
<string name="exportOptionExplanation">তথ্যটি আপনার পছন্দের জায়গায় রাখা হবে।</string>
<string name="importOptionFilesystemTitle">ফোনের স্টোরেজ থেকে আনুন</string>
<string name="importOptionFilesystemButton">ফোনের স্টোরেজ থেকে</string>
<string name="importOptionApplicationTitle">অন্য অ্যাপ ব্যবহার করুন</string>
<string name="app_copyright_old">লয়ালটি কার্ড কিচ্যেনের উপর ভিত্তি করে
\nমেধাস্বত্ব © ২০১৬-২০২০ ব্রানডেন আর্চার</string>
<string name="selectBarcodeTitle">বারকোড নির্বাচন করুন</string>
<string name="settings">সেটিংস</string>
<string name="settings_dark_theme">অন্ধকার</string>
<string name="settings_landscape_orientation">অনুভূমিক</string>
<string name="settings_lock_on_opening_orientation">কার্ড খোলার সময় যে অভিমুখ থাকে সেটিতে লক করে দেবেন</string>
<string name="group_name_already_in_use">গ্রুপটির নাম আগে একবার ব্যবহার করে ফেলেছেন</string>
<string name="group_edit">গ্রুপ সম্পাদনা করুন</string>
<string name="group_updated">গ্রুপটি আপডেট করা হল</string>
<string name="group_name_is_empty">গ্রুপের একটি নাম থাকতে হবে</string>
<string name="deleteConfirmationGroup">গ্রুপটি মুছে দেবেন\?</string>
<string name="failedOpeningFileManager">প্রথমে একটি ফাইল ম্যানেজার ইনস্টল করুন।</string>
<string name="leaveWithoutSaveConfirmation">সংরক্ষণ না করেই চলে যাবেন\?</string>
<string name="addManually">নিজে হাতে আইডি লিখুন</string>
<plurals name="groupCardCount">
<item quantity="one"><xliff:g>%d</xliff:g>টি কার্ড</item>
<item quantity="other"><xliff:g>%d</xliff:g>টি কার্ড</item>
</plurals>
<string name="leaveWithoutSaveTitle">প্রস্থান</string>
<string name="settings_display_barcode_max_brightness">বারকোড উজ্জ্বল করুন</string>
<string name="editGroup">যেই গ্রুপ সম্পাদনা করা হচ্ছে: <xliff:g>%s</xliff:g></string>
<string name="expiryStateSentenceExpired">মেয়াদ শেষ হয়ে গিয়েছে: <xliff:g>%s</xliff:g></string>
<string name="editBarcode">বারকোড সম্পাদন করুন</string>
<string name="never">কখনই না</string>
<string name="addFromImage">গ্যালারি থেকে ছবি বাছুন</string>
<string name="groupsList">গ্রুপগুলি: <xliff:g>%s</xliff:g></string>
<plurals name="balancePoints">
<item quantity="one"><xliff:g>%s</xliff:g> পয়েন্ট</item>
<item quantity="other"><xliff:g>%s</xliff:g> পয়েন্ট</item>
</plurals>
<string name="expiryStateSentence">মেয়াদ শেষ হবে: <xliff:g>%s</xliff:g></string>
<string name="balanceSentence">ব্যালেন্স: <xliff:g>%s</xliff:g></string>
<string name="chooseExpiryDate">মেয়াদ শেষ হওয়ার তারিখ মনোনীত করুন</string>
<string name="moveBarcodeToTopOfScreen">বারকোডটি স্ক্রিনের উপরে উঠিয়ে দিন</string>
<string name="moveBarcodeToCenterOfScreen">বারকোডটি স্ক্রিনের কেন্দ্রে সরিয়ে দিন</string>
<string name="errorReadingImage">ছবিটি স্ক্যান করা যাচ্ছে না</string>
<string name="privacy_policy_popup_text">ব্যক্তিগত তথ্যের গোপনীয়তা নীতি নোটিশ (কিছু অ্যাপ স্টোরের এটি লাগে):
\n
\nকোন তথ্য একেবারেই সংগ্রহ করা হয় না, যা যে কেউ নিশ্চিত করতে পারবেন কারন আমাদের অ্যাপ মুক্ত সফটওয়্যার।</string>
<string name="balance">ব্যালান্স</string>
<string name="points">পয়েন্ট</string>
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> কোনো বৈধ ব্যালান্স মনে হচ্ছে না।</string>
<string name="chooseImportType">এখান থেকে তথ্য আমদানি করুন</string>
<string name="app_loyalty_card_keychain">আনুগত্য কার্ড কীচেন</string>
<string name="privacy_policy">ব্যক্তিগত তথ্যের গোপনীয়তা নীতি</string>
<string name="accept">গ্রহণ</string>
</resources> </resources>

View File

@@ -52,5 +52,4 @@
<item quantity="other"><xliff:g>%d</xliff:g> কার্ডগুলো মুছুন</item> <item quantity="other"><xliff:g>%d</xliff:g> কার্ডগুলো মুছুন</item>
</plurals> </plurals>
<string name="deleteTitle">কার্ড মুছুন</string> <string name="deleteTitle">কার্ড মুছুন</string>
<string name="noGiftCards">একটি কার্ড যোগ করতে + প্লাস বোতামে ক্লিক করুন বা ⋮ মেনু থেকে আমদানি করুন।</string> </resources>
</resources>

View File

@@ -135,7 +135,7 @@
<string name="importVoucherVaultMessage">Vyberte k importu svůj <i>vouchervault.json</i> exportovaný z Voucher Vault. <string name="importVoucherVaultMessage">Vyberte k importu svůj <i>vouchervault.json</i> exportovaný z Voucher Vault.
\nVytvoříte jej tak, že nejprve stisknete tlačítko Exportovat v aplikaci Voucher Vault.</string> \nVytvoříte jej tak, že nejprve stisknete tlačítko Exportovat v aplikaci Voucher Vault.</string>
<string name="importVoucherVault">Import z Voucher Vault</string> <string name="importVoucherVault">Import z Voucher Vault</string>
<string name="importStocardMessage">Vyberte k importu svůj <i>***.zip</i> exportovaný z aplikace Stocard. <string name="importStocardMessage">Vyberte k importu svůj <i>***-sync.zip</i> exportovaný z aplikace Stocard.
\nZískejte ji zasláním e-mailu na adresu support@stocardapp.com s žádostí o export vašich dat.</string> \nZískejte ji zasláním e-mailu na adresu support@stocardapp.com s žádostí o export vašich dat.</string>
<string name="importStocard">Import ze Stocard</string> <string name="importStocard">Import ze Stocard</string>
<string name="importLoyaltyCardKeychainMessage">Vyberte k importu <i>LoyaltyCardKeychain.csv</i> exportovaný z Loyalty Card Keychain. <string name="importLoyaltyCardKeychainMessage">Vyberte k importu <i>LoyaltyCardKeychain.csv</i> exportovaný z Loyalty Card Keychain.

View File

@@ -150,7 +150,7 @@
<string name="frontImageDescription">Bild auf der Vorseite</string> <string name="frontImageDescription">Bild auf der Vorseite</string>
<string name="backImageDescription">Bild auf der Rückseite</string> <string name="backImageDescription">Bild auf der Rückseite</string>
<string name="passwordRequired">Bitte gib das Passwort ein</string> <string name="passwordRequired">Bitte gib das Passwort ein</string>
<string name="importStocardMessage">Wähle deinen <i>***.zip</i>-Export aus Stocard zum Importieren aus. <string name="importStocardMessage">Wähle deinen <i>***-sync.zip</i>-Export aus Stocard zum Importieren aus.
\nSie erhalten ihn, indem du eine E-Mail an support@stocardapp.com sendest und um einen Export deiner Daten bitten.</string> \nSie erhalten ihn, indem du eine E-Mail an support@stocardapp.com sendest und um einen Export deiner Daten bitten.</string>
<string name="importStocard">Von Stocard importieren</string> <string name="importStocard">Von Stocard importieren</string>
<string name="turn_flashlight_off">Licht ausschalten</string> <string name="turn_flashlight_off">Licht ausschalten</string>

View File

@@ -140,7 +140,7 @@
</plurals> </plurals>
<string name="importCatimaMessage">Επιλέξτε την <i>catima.zip</i> εξαγωγή από το Catima για εισαγωγή <string name="importCatimaMessage">Επιλέξτε την <i>catima.zip</i> εξαγωγή από το Catima για εισαγωγή
\nΔημιουργήστε το από το μενού Εισαγωγής/Εξαγωγής μιας άλλης εφαρμογής Catima κάνοντας εξαγωγή εκεί πρώτα.</string> \nΔημιουργήστε το από το μενού Εισαγωγής/Εξαγωγής μιας άλλης εφαρμογής Catima κάνοντας εξαγωγή εκεί πρώτα.</string>
<string name="importStocardMessage">Επιλέξτε την <i>***.zip</i> εξαγωγή από το Stocard για εισαγωγή. <string name="importStocardMessage">Επιλέξτε την <i>***-sync.zip</i> εξαγωγή από το Stocard για εισαγωγή.
\nΠάρτε το στέλνοντας email στο: support@stocardapp.com ζητώντας μια εξαγωγή αρχείων των δεδομένων σας.</string> \nΠάρτε το στέλνοντας email στο: support@stocardapp.com ζητώντας μια εξαγωγή αρχείων των δεδομένων σας.</string>
<string name="intent_import_card_from_url_share_multiple_text">Θέλω να μοιραστώ μερικές κάρτες μαζί σου</string> <string name="intent_import_card_from_url_share_multiple_text">Θέλω να μοιραστώ μερικές κάρτες μαζί σου</string>
<string name="editGroup">Επεξεργασία Ομάδας: <xliff:g>%s</xliff:g></string> <string name="editGroup">Επεξεργασία Ομάδας: <xliff:g>%s</xliff:g></string>

View File

@@ -108,7 +108,7 @@
\nCréalo primero desde tu perfil de FidMe eligiendo Protección de datos y pulsa Extraer mis datos.</string> \nCréalo primero desde tu perfil de FidMe eligiendo Protección de datos y pulsa Extraer mis datos.</string>
<string name="importLoyaltyCardKeychainMessage">Seleccione su <i>LoyaltyCardKeychain.csv</i> exportado desde Loyalty Card Keychain para importarlo. <string name="importLoyaltyCardKeychainMessage">Seleccione su <i>LoyaltyCardKeychain.csv</i> exportado desde Loyalty Card Keychain para importarlo.
\nCréalo primero desde el menú Importar/Exportar en Loyalty Card Keychain pulsando Exportar desde allí.</string> \nCréalo primero desde el menú Importar/Exportar en Loyalty Card Keychain pulsando Exportar desde allí.</string>
<string name="importStocardMessage">Seleccione su exportación <i>*.zip</i> de Stocard para importarla. <string name="importStocardMessage">Seleccione su exportación <i>*-sync.zip</i> de Stocard para importarla.
\nConsígalo enviando un correo electrónico a support@stocardapp.com solicitando una exportación de sus datos.</string> \nConsí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. <string name="importVoucherVaultMessage">Seleccione su <i>vouchervault.json</i> exportado desde Voucher Vault para importarlo.
\nCréalo pulsando primero Exportar en Voucher Vault.</string> \nCréalo pulsando primero Exportar en Voucher Vault.</string>

View File

@@ -163,7 +163,7 @@
<item quantity="other"><xliff:g>%d</xliff:g> valittu</item> <item quantity="other"><xliff:g>%d</xliff:g> valittu</item>
</plurals> </plurals>
<string name="importStocard">Tuo Stocardista</string> <string name="importStocard">Tuo Stocardista</string>
<string name="importStocardMessage">Valitse tuotava <i>***.zip</i>-vienti Stocardista. <string name="importStocardMessage">Valitse tuotava <i>***-sync.zip</i>-vienti Stocardista.
\nHanki se lähettämällä sähköpostia osoitteeseen support@stocardapp.com ja pyytämällä tietojesi vientiä.</string> \nHanki se lähettämällä sähköpostia osoitteeseen support@stocardapp.com ja pyytämällä tietojesi vientiä.</string>
<string name="passwordRequired">Ole hyvä ja syötä salasana</string> <string name="passwordRequired">Ole hyvä ja syötä salasana</string>
<string name="failedGeneratingShareURL">Jaettavaa URL-osoitetta ei voitu luoda. Ilmoita tästä.</string> <string name="failedGeneratingShareURL">Jaettavaa URL-osoitetta ei voitu luoda. Ilmoita tästä.</string>

View File

@@ -150,7 +150,7 @@
<string name="backImageDescription">Image du verso</string> <string name="backImageDescription">Image du verso</string>
<string name="frontImageDescription">Image du recto</string> <string name="frontImageDescription">Image du recto</string>
<string name="passwordRequired">Veuillez entrer le mot de passe</string> <string name="passwordRequired">Veuillez entrer le mot de passe</string>
<string name="importStocardMessage">Sélectionnez votre exportation <i>***.zip</i> de Stocard pour limporter. <string name="importStocardMessage">Sélectionnez votre exportation <i>***-sync.zip</i> de Stocard pour limporter.
\nVous pouvez lobtenir en envoyant un courriel à support@stocardapp.com pour demander une exportation de vos données.</string> \nVous pouvez 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="importStocard">Importer depuis Stocard</string>
<string name="turn_flashlight_off">Éteindre la lampe de poche</string> <string name="turn_flashlight_off">Éteindre la lampe de poche</string>

View File

@@ -22,7 +22,7 @@
<string name="save">Mentés</string> <string name="save">Mentés</string>
<string name="edit">Szerkesztés</string> <string name="edit">Szerkesztés</string>
<string name="delete">Törlés</string> <string name="delete">Törlés</string>
<string name="confirm">Jóváhagy</string> <string name="confirm">Alkalmaz</string>
<plurals name="deleteCardsTitle"> <plurals name="deleteCardsTitle">
<item quantity="one">Törölje az <xliff:g>%d</xliff:g> kártyát</item> <item quantity="one">Törölje az <xliff:g>%d</xliff:g> kártyát</item>
<item quantity="other">Törölje az <xliff:g>%d</xliff:g> kártyákat</item> <item quantity="other">Törölje az <xliff:g>%d</xliff:g> kártyákat</item>
@@ -55,7 +55,7 @@
<string name="barcodeImageDescriptionWithType"><xliff:g>%s</xliff:g> vonalkód képe</string> <string name="barcodeImageDescriptionWithType"><xliff:g>%s</xliff:g> vonalkód képe</string>
<string name="noCardIdError">Nincs azonosító megadva</string> <string name="noCardIdError">Nincs azonosító megadva</string>
<string name="noCardExistsError">Kártya nem található</string> <string name="noCardExistsError">Kártya nem található</string>
<string name="importStocardMessage">Válassza ki a <i>***.zip</i> Stocard exportot. <string name="importStocardMessage">Válassza ki a <i>***-sync.zip</i> Stocard exportot.
\nAdatinak exportját kérheti e-mailben a support@stocardapp.com címre írva.</string> \nAdatinak exportját kérheti e-mailben a support@stocardapp.com címre írva.</string>
<string name="importVoucherVault">Importálás Voucher Vault-ból</string> <string name="importVoucherVault">Importálás Voucher Vault-ból</string>
<string name="wrongValueForBarcodeType">Ez az érték meg megfelelő a vonalkód típushoz</string> <string name="wrongValueForBarcodeType">Ez az érték meg megfelelő a vonalkód típushoz</string>
@@ -262,10 +262,4 @@
</plurals> </plurals>
<string name="updateBalance">Egyenleg frissítése</string> <string name="updateBalance">Egyenleg frissítése</string>
<string name="noCameraPermissionDirectToSystemSetting">A vonalkódok beolvasásához a Catimának hozzá kell férnie a kamerához. Koppintson ide az engedélybeállítások módosításához.</string> <string name="noCameraPermissionDirectToSystemSetting">A vonalkódok beolvasásához a Catimának hozzá kell férnie a kamerához. Koppintson ide az engedélybeállítások módosításához.</string>
<string name="validFromDate">Érvényesség kezdete</string>
<string name="anyDate">Bármely dátum</string>
<string name="chooseValidFromDate">Válassza ki az érvényesség kezdeti dátumot</string>
<string name="validFromSentence">Érvényesség kezdete: <xliff:g>%s</xliff:g></string>
<string name="storageReadPermissionRequired">A művelethez tároló olvasási engedély szükséges…</string>
<string name="cameraPermissionRequired">A kamerához való hozzáférés engedélye szükséges ehhez a művelethez…</string>
</resources> </resources>

View File

@@ -161,7 +161,7 @@
<string name="importLoyaltyCardKeychainMessage">Pilih ekspor <i>LoyaltyCardKeychain.csv</i> Anda dari Loyalty Card Keychain untuk diimpor. <string name="importLoyaltyCardKeychainMessage">Pilih ekspor <i>LoyaltyCardKeychain.csv</i> Anda dari Loyalty Card Keychain untuk diimpor.
\nBuat dari menu Import/Export di Loyalty Card Keychain dengan menekan Export terlebih dahulu.</string> \nBuat dari menu Import/Export di Loyalty Card Keychain dengan menekan Export terlebih dahulu.</string>
<string name="importStocard">Impor dari Stocard</string> <string name="importStocard">Impor dari Stocard</string>
<string name="importStocardMessage">Pilih ekspor <i>***.zip</i> Anda dari Stocard untuk diimpor. <string name="importStocardMessage">Pilih ekspor <i>***-sync.zip</i> Anda dari Stocard untuk diimpor.
\nDapatkan dengan mengirim email ke support@stocardapp.com untuk meminta ekspor data Anda.</string> \nDapatkan dengan mengirim email ke support@stocardapp.com untuk meminta ekspor data Anda.</string>
<string name="importVoucherVault">Impor dari Voucher Vault</string> <string name="importVoucherVault">Impor dari Voucher Vault</string>
<string name="importVoucherVaultMessage">Pilih ekspor <i>vouchervault.json</i> Anda dari Vault Voucher untuk diimpor. <string name="importVoucherVaultMessage">Pilih ekspor <i>vouchervault.json</i> Anda dari Vault Voucher untuk diimpor.

View File

@@ -150,7 +150,7 @@
<string name="backImageDescription">Immagine posteriore</string> <string name="backImageDescription">Immagine posteriore</string>
<string name="frontImageDescription">Immagine frontale</string> <string name="frontImageDescription">Immagine frontale</string>
<string name="passwordRequired">Si prega di inserire la password</string> <string name="passwordRequired">Si prega di inserire la password</string>
<string name="importStocardMessage">Seleziona il tuo file di esportazione <i>***.zip</i> da Stocard per importarlo. <string name="importStocardMessage">Seleziona il tuo file di esportazione <i>***-sync.zip</i> da Stocard per importarlo.
\nOttienilo inviando un\'e-mail a support@stocardapp.com chiedendo un\'esportazione dei tuoi dati.</string> \nOttienilo inviando un\'e-mail a support@stocardapp.com chiedendo un\'esportazione dei tuoi dati.</string>
<string name="importStocard">Importa da Stocard</string> <string name="importStocard">Importa da Stocard</string>
<string name="turn_flashlight_off">Spegni la torcia</string> <string name="turn_flashlight_off">Spegni la torcia</string>

View File

@@ -151,7 +151,7 @@
<string name="photos">フォト</string> <string name="photos">フォト</string>
<string name="backImageDescription"></string> <string name="backImageDescription"></string>
<string name="frontImageDescription"></string> <string name="frontImageDescription"></string>
<string name="importStocardMessage">Stocardでエクスポートした<i>***.zip</i>ファイルを選択してください。 <string name="importStocardMessage">Stocardでエクスポートした<i>***-sync.zip</i>ファイルを選択してください。
\nファイルがない場合、e-mailing support@stocardapp.comにデータのエクスポートを要求してください。</string> \nファイルがない場合、e-mailing support@stocardapp.comにデータのエクスポートを要求してください。</string>
<string name="importStocard">Stocardからインポート</string> <string name="importStocard">Stocardからインポート</string>
<plurals name="selectedCardCount"> <plurals name="selectedCardCount">

View File

@@ -75,7 +75,7 @@
<string name="setBarcodeId">Nustatyti brūkšninio kodo reikšmę</string> <string name="setBarcodeId">Nustatyti brūkšninio kodo reikšmę</string>
<string name="sameAsCardId">Tokia pat kaip ID</string> <string name="sameAsCardId">Tokia pat kaip ID</string>
<string name="barcodeId">Brūkšninio kodo reikšmė</string> <string name="barcodeId">Brūkšninio kodo reikšmė</string>
<string name="importStocardMessage">Pasirinkite <i>***.zip</i> eksportą iš Stocard, kad galėtumėte importuoti. <string name="importStocardMessage">Pasirinkite <i>***-sync.zip</i> eksportą iš Stocard, kad galėtumėte importuoti.
\nGaukite susisiekę el. paštu support@stocardapp.com, prašydami eksportuoti jūsų duomenis.</string> \nGaukite susisiekę el. paštu support@stocardapp.com, prašydami eksportuoti jūsų duomenis.</string>
<string name="importStocard">Importuoti iš Stocard</string> <string name="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. <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.

View File

@@ -204,7 +204,7 @@
\nFailu var izveidot Jūsu FidMe profilā, ejot uz \"Data Protection\" un spiežot \"Extract my data\".</string> \nFailu var izveidot Jūsu FidMe profilā, ejot uz \"Data Protection\" un spiežot \"Extract my data\".</string>
<string name="importLoyaltyCardKeychain">Importēt no Loyalty Card Keychain</string> <string name="importLoyaltyCardKeychain">Importēt no Loyalty Card Keychain</string>
<string name="importStocard">Importēt no Stocard</string> <string name="importStocard">Importēt no Stocard</string>
<string name="importStocardMessage">Importam izvēlieties Jūsu <i>***.zip</i> eksporta failu no Stocard. <string name="importStocardMessage">Importam izvēlieties Jūsu <i>***-sync.zip</i> eksporta failu no Stocard.
\nFailu var iegūt sūtot e-pastu uz support@stocardapp.com ar pieprasījumu eksportēt Jūsu datus.</string> \nFailu var iegūt sūtot e-pastu uz support@stocardapp.com ar pieprasījumu eksportēt Jūsu datus.</string>
<string name="importVoucherVault">Importēt no Voucher Vault</string> <string name="importVoucherVault">Importēt no Voucher Vault</string>
<string name="importVoucherVaultMessage">Importam izvēlieties Jūsu <i>vouchervault.json</i> failu no Voucher Vault. <string name="importVoucherVaultMessage">Importam izvēlieties Jūsu <i>vouchervault.json</i> failu no Voucher Vault.

View File

@@ -146,7 +146,7 @@
<string name="photos">Bilder</string> <string name="photos">Bilder</string>
<string name="backImageDescription">Baksidebilde</string> <string name="backImageDescription">Baksidebilde</string>
<string name="frontImageDescription">Forsidebilde</string> <string name="frontImageDescription">Forsidebilde</string>
<string name="importStocardMessage">Velg din <i>***.zip</i>-eksport fra Stocard å importere. <string name="importStocardMessage">Velg din <i>***-sync.zip</i>-eksport fra Stocard å importere.
\nSkaff den ved å sende e-post til support@stocardapp.com der du etterspør eksport av dataen din.</string> \nSkaff den ved å sende e-post til support@stocardapp.com der du etterspør eksport av dataen din.</string>
<string name="passwordRequired">Skriv inn passordet</string> <string name="passwordRequired">Skriv inn passordet</string>
<string name="importStocard">Importer fra Stocard</string> <string name="importStocard">Importer fra Stocard</string>

View File

@@ -149,7 +149,7 @@
<string name="backImageDescription">Achterzijde van kaart</string> <string name="backImageDescription">Achterzijde van kaart</string>
<string name="frontImageDescription">Voorzijde van kaart</string> <string name="frontImageDescription">Voorzijde van kaart</string>
<string name="passwordRequired">Voer het wachtwoord in</string> <string name="passwordRequired">Voer het wachtwoord in</string>
<string name="importStocardMessage">Kies het te importeren Stocard-exportbestand genaamd <i>***.zip</i>. <string name="importStocardMessage">Kies het te importeren Stocard-exportbestand genaamd <i>***-sync.zip</i>.
\nStuur een e-mail naar support@stocardapp.com waarin je vraagt om een exportbestand.</string> \nStuur een e-mail naar support@stocardapp.com waarin je vraagt om een exportbestand.</string>
<string name="importStocard">Importeren uit Stocard</string> <string name="importStocard">Importeren uit Stocard</string>
<string name="failedGeneratingShareURL">De te delen link kan niet worden gegenereerd. Meld deze fout.</string> <string name="failedGeneratingShareURL">De te delen link kan niet worden gegenereerd. Meld deze fout.</string>

View File

@@ -115,7 +115,7 @@
<string name="importVoucherVaultMessage">Wybierz swój <i>vouchervault.json</i> z Voucher Vault, aby zaimportować. <string name="importVoucherVaultMessage">Wybierz swój <i>vouchervault.json</i> z Voucher Vault, aby zaimportować.
\nUtwórz go wpierw klikając Eksportuj w Voucher Vault.</string> \nUtwórz go wpierw klikając Eksportuj w Voucher Vault.</string>
<string name="importVoucherVault">Importuj z Voucher Vault</string> <string name="importVoucherVault">Importuj z Voucher Vault</string>
<string name="importStocardMessage">Wybierz swój <i>***.zip</i> z Stocard, aby zaimportować. <string name="importStocardMessage">Wybierz swój <i>***-sync.zip</i> z Stocard, aby zaimportować.
\nUzyskaj go, wysyłając email na adres support@stocardapp.com, z prośbą o eksport Twoich danych.</string> \nUzyskaj go, wysyłając email na adres support@stocardapp.com, z prośbą o eksport Twoich danych.</string>
<string name="importStocard">Importuj z Stocard</string> <string name="importStocard">Importuj z Stocard</string>
<string name="importLoyaltyCardKeychainMessage">Wybierz swój <i>LoyaltyCardKeychain.csv</i> z Loyalty Card Keychain, aby zaimportować. <string name="importLoyaltyCardKeychainMessage">Wybierz swój <i>LoyaltyCardKeychain.csv</i> z Loyalty Card Keychain, aby zaimportować.

View File

@@ -97,7 +97,7 @@
<string name="sameAsCardId">Igual ao identificador</string> <string name="sameAsCardId">Igual ao identificador</string>
<string name="importFidmeMessage">Selecione a exportação <i>fidme-export-request-xxxxxx.zip</i> do FidMe para importar e depois selecione os tipos de código de barras manualmente. <string name="importFidmeMessage">Selecione a exportação <i>fidme-export-request-xxxxxx.zip</i> do FidMe para importar e depois selecione os tipos de código de barras manualmente.
\nPrimeiro crie a exportação no seu perfil do FidMe escolhendo a opção \"Proteção de dados\" e em seguida pressionando \"Extrair os meus dados\".</string> \nPrimeiro crie a exportação no seu perfil do FidMe escolhendo a opção \"Proteção de dados\" e em seguida pressionando \"Extrair os meus dados\".</string>
<string name="importStocardMessage">Selecione a exportação <i>***.zip</i> do Stocard para importar. <string name="importStocardMessage">Selecione a exportação <i>***-sync.zip</i> do Stocard para importar.
\nObtenha-o através do e-mail support@stocardapp.com solicitando uma exportação dos seus dados.</string> \nObtenha-o através do e-mail support@stocardapp.com solicitando uma exportação dos seus dados.</string>
<string name="barcodeId">Valor do código de barras</string> <string name="barcodeId">Valor do código de barras</string>
<string name="wrongValueForBarcodeType">O valor não é válido para o tipo de código de barras selecionado</string> <string name="wrongValueForBarcodeType">O valor não é válido para o tipo de código de barras selecionado</string>

View File

@@ -94,9 +94,9 @@
<string name="moveBarcodeToTopOfScreen">Переместить штрих-код в верхнюю часть экрана</string> <string name="moveBarcodeToTopOfScreen">Переместить штрих-код в верхнюю часть экрана</string>
<string name="moveBarcodeToCenterOfScreen">Центрировать штрих-код на экране</string> <string name="moveBarcodeToCenterOfScreen">Центрировать штрих-код на экране</string>
<string name="currency">Валюта</string> <string name="currency">Валюта</string>
<string name="chooseExpiryDate">Выбор срока действия</string> <string name="chooseExpiryDate">Указать срок действия</string>
<string name="never">Никогда</string> <string name="never">Никогда</string>
<string name="expiryDate">Срок действия</string> <string name="expiryDate">Окончание срока действия</string>
<string name="editBarcode">Изменить штрих-код</string> <string name="editBarcode">Изменить штрих-код</string>
<string name="barcode">Штрих-код</string> <string name="barcode">Штрих-код</string>
<string name="card">Карта</string> <string name="card">Карта</string>
@@ -150,7 +150,7 @@
<string name="backImageDescription">Задняя сторона</string> <string name="backImageDescription">Задняя сторона</string>
<string name="frontImageDescription">Лицевая сторона</string> <string name="frontImageDescription">Лицевая сторона</string>
<string name="photos">Фото</string> <string name="photos">Фото</string>
<string name="importStocardMessage">Выберите для импортирования файл <i>***.zip</i>. <string name="importStocardMessage">Выберите для импортирования файл <i>***-sync.zip</i>.
\nЭтот файл можно получить по электронной почте от support@stocardapp.com, предварительно запросив экспорт ваших данных.</string> \nЭтот файл можно получить по электронной почте от support@stocardapp.com, предварительно запросив экспорт ваших данных.</string>
<string name="passwordRequired">Введите пароль</string> <string name="passwordRequired">Введите пароль</string>
<string name="importStocard">Импорт из Stocard</string> <string name="importStocard">Импорт из Stocard</string>
@@ -280,6 +280,6 @@
<string name="cameraPermissionRequired">Для этого действия необходимо разрешение на доступ к камере…</string> <string name="cameraPermissionRequired">Для этого действия необходимо разрешение на доступ к камере…</string>
<string name="validFromDate">Действует с</string> <string name="validFromDate">Действует с</string>
<string name="anyDate">Любая дата</string> <string name="anyDate">Любая дата</string>
<string name="chooseValidFromDate">Выбор даты действия</string> <string name="chooseValidFromDate">Выберите дату действия</string>
<string name="validFromSentence">Действует с: <xliff:g>%s</xliff:g></string> <string name="validFromSentence">Действует с: <xliff:g>%s</xliff:g></string>
</resources> </resources>

View File

@@ -265,7 +265,7 @@
<string name="settings_landscape_orientation">Na šírku</string> <string name="settings_landscape_orientation">Na šírku</string>
<string name="importFidmeMessage">Vyberte svoj <i>fidme-export-request-xxxxxx.zip</i> export zo služby FidMe pre import a potom vyberte typy čiarových kódov ručne. <string name="importFidmeMessage">Vyberte svoj <i>fidme-export-request-xxxxxx.zip</i> export zo služby FidMe pre import a potom vyberte typy čiarových kódov ručne.
\nVytvorte ho z profilu FidMe tak, že najprv vyberiete položku Ochrana údajov a potom stlačíte tlačidlo Extrahovať moje údaje.</string> \nVytvorte ho z profilu FidMe tak, že najprv vyberiete položku Ochrana údajov a potom stlačíte tlačidlo Extrahovať moje údaje.</string>
<string name="importStocardMessage">Vyberte svoj <i>***.zip</i> export zo Stocard pre import. <string name="importStocardMessage">Vyberte svoj <i>***-sync.zip</i> export zo Stocard pre import.
\nZískate ho zaslaním e-mailu na adresu support@stocardapp.com, v ktorom požiadate o export svojich údajov.</string> \nZískate ho zaslaním e-mailu na adresu support@stocardapp.com, v ktorom požiadate o export svojich údajov.</string>
<string name="currentBalanceSentence">Aktuálny zostatok: <xliff:g>%s</xliff:g></string> <string name="currentBalanceSentence">Aktuálny zostatok: <xliff:g>%s</xliff:g></string>
<string name="copy_to_clipboard_multiple_toast">ID skopírované do schránky</string> <string name="copy_to_clipboard_multiple_toast">ID skopírované do schránky</string>

View File

@@ -221,7 +221,7 @@
<string name="moveBarcodeToCenterOfScreen">Postavi črtno kodo na sredino zaslona</string> <string name="moveBarcodeToCenterOfScreen">Postavi črtno kodo na sredino zaslona</string>
<string name="importCatimaMessage">Izberi svoj obstoječ Catima <i>catima.zip</i> izvoz podatkov za uvoz v aplikacijo. <string name="importCatimaMessage">Izberi svoj obstoječ Catima <i>catima.zip</i> izvoz podatkov za uvoz v aplikacijo.
\nNajprej izvozi podatke v meniju \"Uvozi/Izvozi\" v drugi aplikaciji Catima s pritiskom na izbiro izvozi.</string> \nNajprej izvozi podatke v meniju \"Uvozi/Izvozi\" v drugi aplikaciji Catima s pritiskom na izbiro izvozi.</string>
<string name="importStocardMessage">Izberi svoj <i>***.zip</i> Stocard izvoz podatkov za uvoz. <string name="importStocardMessage">Izberi svoj <i>***-sync.zip</i> Stocard izvoz podatkov za uvoz.
\nIzvoz podatkov dobiš s pošiljanjem elektronske pošte na support@stocardapp.com, kjer povprašaš za izvoz svojih podatkov.</string> \nIzvoz podatkov dobiš s pošiljanjem elektronske pošte na support@stocardapp.com, kjer povprašaš za izvoz svojih podatkov.</string>
<string name="importVoucherVaultMessage">Izberi svoj <i>vouchervault.json</i> Voucher Vault izvoz podatkov za uvoz. <string name="importVoucherVaultMessage">Izberi svoj <i>vouchervault.json</i> Voucher Vault izvoz podatkov za uvoz.
\nIzvoz podatkov dobiš s pritiskom na gumb \"Export\" v Voucher Vault first.</string> \nIzvoz podatkov dobiš s pritiskom na gumb \"Export\" v Voucher Vault first.</string>

View File

@@ -24,7 +24,7 @@
\nSkapa den från Import/Export-menyn i Loyalty Card Keychain först genom att trycka på Exportera.</string> \nSkapa den från Import/Export-menyn i Loyalty Card Keychain först genom att trycka på Exportera.</string>
<string name="importVoucherVaultMessage">Välj den exporterade <i>vouchervault.json</i> från Voucher Vault som du vill importera. <string name="importVoucherVaultMessage">Välj den exporterade <i>vouchervault.json</i> från Voucher Vault som du vill importera.
\nSkapa den först genom att trycka på Exportera i Voucher Vault.</string> \nSkapa den först genom att trycka på Exportera i Voucher Vault.</string>
<string name="importStocardMessage">Välj den exporterade <i>***.zip</i> från Stocard som du vill importera. <string name="importStocardMessage">Välj den exporterade <i>***-sync.zip</i> från Stocard som du vill importera.
\nSkaffa den först genom att skicka e-post till support@stocardapp.com och be om att få dina data exporterade.</string> \nSkaffa den först genom att skicka e-post till support@stocardapp.com och be om att få dina data exporterade.</string>
<string name="enter_group_name">Ange gruppnamn</string> <string name="enter_group_name">Ange gruppnamn</string>
<string name="groups">Grupper</string> <string name="groups">Grupper</string>

View File

@@ -39,7 +39,7 @@
<string name="importVoucherVaultMessage">İçe aktarmak için Voucher Vault\'tan dışa aktardığınız <i>vouchervault.json</i> dosyasını seçin. <string name="importVoucherVaultMessage">İçe aktarmak için Voucher Vault\'tan dışa aktardığınız <i>vouchervault.json</i> dosyasını seçin.
\nÖnce Voucher Vault\'ta \"Dışa aktar\" düğmesine basarak bir tane oluşturun.</string> \nÖnce Voucher Vault\'ta \"Dışa aktar\" düğmesine basarak bir tane oluşturun.</string>
<string name="importVoucherVault">Voucher Vault\'tan içe aktar</string> <string name="importVoucherVault">Voucher Vault\'tan içe aktar</string>
<string name="importStocardMessage">İçe aktarmak için Stocard\'dan dışa aktardığınız <i>***.zip</i> dosyasını seçin. <string name="importStocardMessage">İçe aktarmak için Stocard\'dan dışa aktardığınız <i>***-sync.zip</i> dosyasını seçin.
\nsupport@stocardapp.com adresine e-posta göndererek verilerinizin dışa aktarılmasını isteyerek edinin.</string> \nsupport@stocardapp.com adresine e-posta göndererek verilerinizin dışa aktarılmasını isteyerek edinin.</string>
<string name="importStocard">Stocard\'dan içe aktar</string> <string name="importStocard">Stocard\'dan içe aktar</string>
<string name="importLoyaltyCardKeychainMessage">İçe aktarmak için Loyalty Card Keychain\'den dışa aktardığınız <i>LoyaltyCardKeychain.csv</i> dosyasını seçin. <string name="importLoyaltyCardKeychainMessage">İçe aktarmak için Loyalty Card Keychain\'den dışa aktardığınız <i>LoyaltyCardKeychain.csv</i> dosyasını seçin.

View File

@@ -154,7 +154,7 @@
<string name="photos">Світлини</string> <string name="photos">Світлини</string>
<string name="backImageDescription">Тильна сторона</string> <string name="backImageDescription">Тильна сторона</string>
<string name="frontImageDescription">Лицьова сторона</string> <string name="frontImageDescription">Лицьова сторона</string>
<string name="importStocardMessage">Виберіть експорт <i> ***.zip </i> зі Stocard для імпорту. <string name="importStocardMessage">Виберіть експорт <i> ***-sync.zip </i> зі Stocard для імпорту.
\nОтримайте його, надіславши електронного листа support@stocardapp.com з проханням експортувати ваші дані.</string> \nОтримайте його, надіславши електронного листа support@stocardapp.com з проханням експортувати ваші дані.</string>
<string name="importStocard">Імпорт із Stocard</string> <string name="importStocard">Імпорт із Stocard</string>
<plurals name="selectedCardCount"> <plurals name="selectedCardCount">

View File

@@ -140,7 +140,7 @@
<string name="deleteConfirmation">删除此卡?</string> <string name="deleteConfirmation">删除此卡?</string>
<string name="deleteTitle">移除卡片</string> <string name="deleteTitle">移除卡片</string>
<string name="starImage">最喜欢的星星</string> <string name="starImage">最喜欢的星星</string>
<string name="importStocardMessage">选择 Stocard 导出文件 <i>****.zip</i>来导入。 <string name="importStocardMessage">选择 Stocard 导出文件 <i>****-sync.zip</i>来导入。
\n发电子邮件给 support@stocardapp.com 请求获得数据导出文件。</string> \n发电子邮件给 support@stocardapp.com 请求获得数据导出文件。</string>
<plurals name="deleteCardsConfirmation"> <plurals name="deleteCardsConfirmation">
<item quantity="other">确定永久删除 <xliff:g>%d</xliff:g> 这些卡片?</item> <item quantity="other">确定永久删除 <xliff:g>%d</xliff:g> 这些卡片?</item>

View File

@@ -172,7 +172,7 @@
<string name="importVoucherVaultMessage">選取您自 Voucher Vault 匯出的 <i>vouchervault.json</i> 檔案以進行匯入。 <string name="importVoucherVaultMessage">選取您自 Voucher Vault 匯出的 <i>vouchervault.json</i> 檔案以進行匯入。
\n請您先透過 Voucher Vault 進行匯出。</string> \n請您先透過 Voucher Vault 進行匯出。</string>
<string name="importStocard">自 Stocard 中匯入</string> <string name="importStocard">自 Stocard 中匯入</string>
<string name="importStocardMessage">&gt;選取您自 Stocard 匯出的 <i>***.zip</i> 檔案以進行匯入。 <string name="importStocardMessage">&gt;選取您自 Stocard 匯出的 <i>***-sync.zip</i> 檔案以進行匯入。
\n請您寫封 Email 至 support@stocardapp.com 索取您的資料。</string> \n請您寫封 Email 至 support@stocardapp.com 索取您的資料。</string>
<string name="importLoyaltyCardKeychain">自 Loyalty Card Keychain 中匯入</string> <string name="importLoyaltyCardKeychain">自 Loyalty Card Keychain 中匯入</string>
<string name="importLoyaltyCardKeychainMessage">選取您自 Loyalty Card Keychain <i>LoyaltyCardKeychain.csv</i> 檔案以進行匯入。 <string name="importLoyaltyCardKeychainMessage">選取您自 Loyalty Card Keychain <i>LoyaltyCardKeychain.csv</i> 檔案以進行匯入。

View File

@@ -194,7 +194,7 @@
<string name="importLoyaltyCardKeychainMessage">Select your <i>LoyaltyCardKeychain.csv</i> export from Loyalty Card Keychain to import. <string name="importLoyaltyCardKeychainMessage">Select your <i>LoyaltyCardKeychain.csv</i> export from Loyalty Card Keychain to import.
\nCreate it from the Import/Export menu in Loyalty Card Keychain by pressing Export there first.</string> \nCreate 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="importStocard">Import from Stocard</string>
<string name="importStocardMessage">Select your <i>***.zip</i> export from Stocard to import. <string name="importStocardMessage">Select your <i>***-sync.zip</i> export from Stocard to import.
\nGet it by e-mailing support@stocardapp.com asking for an export of your data.</string> \nGet 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="importVoucherVault">Import from Voucher Vault</string>
<string name="importVoucherVaultMessage">Select your <i>vouchervault.json</i> export from Voucher Vault to import. <string name="importVoucherVaultMessage">Select your <i>vouchervault.json</i> export from Voucher Vault to import.

View File

@@ -11,6 +11,7 @@ import org.junit.runner.RunWith;
import org.robolectric.Robolectric; import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController; import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLooper; import org.robolectric.shadows.ShadowLooper;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -20,6 +21,7 @@ import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class BarcodeSelectorActivityTest { public class BarcodeSelectorActivityTest {
@Test @Test
public void emptyStateTest() { public void emptyStateTest() {

View File

@@ -27,6 +27,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class DatabaseTest { public class DatabaseTest {
private SQLiteDatabase mDatabase; private SQLiteDatabase mDatabase;
private Activity mActivity; private Activity mActivity;

View File

@@ -13,11 +13,13 @@ import org.junit.runner.RunWith;
import org.robolectric.Robolectric; import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.robolectric.Shadows.shadowOf; import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class ImportExportActivityTest { public class ImportExportActivityTest {
private void registerIntentHandler(String handler) { private void registerIntentHandler(String handler) {
// Add something that will 'handle' the given intent type // Add something that will 'handle' the given intent type

View File

@@ -6,16 +6,20 @@ import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.os.Environment; import android.os.Environment;
import android.os.Looper; import android.os.Looper;
import android.util.DisplayMetrics;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
import org.json.JSONException;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.Robolectric; import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.LooperMode;
import org.robolectric.shadows.ShadowLog; import org.robolectric.shadows.ShadowLog;
import org.robolectric.shadows.ShadowLooper; import org.robolectric.shadows.ShadowLooper;
@@ -30,6 +34,8 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -38,6 +44,7 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import androidx.core.content.res.ResourcesCompat;
import protect.card_locker.async.TaskHandler; import protect.card_locker.async.TaskHandler;
import protect.card_locker.importexport.DataFormat; import protect.card_locker.importexport.DataFormat;
import protect.card_locker.importexport.ImportExportResult; import protect.card_locker.importexport.ImportExportResult;
@@ -52,6 +59,7 @@ import static org.junit.Assert.assertTrue;
import static org.robolectric.Shadows.shadowOf; import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class ImportExportTest { public class ImportExportTest {
private Activity activity; private Activity activity;
private SQLiteDatabase mDatabase; private SQLiteDatabase mDatabase;
@@ -509,7 +517,7 @@ public class ImportExportTest {
} }
@Test @Test
public void corruptedImportNothingSaved() { public void corruptedImportNothingSaved() throws IOException {
final int NUM_CARDS = 10; final int NUM_CARDS = 10;
for (DataFormat format : DataFormat.values()) { for (DataFormat format : DataFormat.values()) {
@@ -530,7 +538,7 @@ public class ImportExportTest {
// ^ after the quote there should only be a , \n or EOF // ^ after the quote there should only be a , \n or EOF
String corruptEntry = "ThisStringIsLikelyNotPartOfAnyFormat,\"\"a"; String corruptEntry = "ThisStringIsLikelyNotPartOfAnyFormat,\"\"a";
ByteArrayInputStream inData = new ByteArrayInputStream((outData + corruptEntry).getBytes()); ByteArrayInputStream inData = new ByteArrayInputStream((outData.toString() + corruptEntry).getBytes());
// Attempt to import the data // Attempt to import the data
result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inData, format, null); result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inData, format, null);
@@ -609,8 +617,18 @@ public class ImportExportTest {
} }
@Test @Test
public void importWithoutColorsV1() { public void importWithoutColorsV1() throws IOException {
InputStream inputStream = getClass().getResourceAsStream("catima_v1_no_colors.csv"); String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
DBHelper.LoyaltyCardDbIds.NOTE + "," +
DBHelper.LoyaltyCardDbIds.CARD_ID + "," +
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE + "," +
DBHelper.LoyaltyCardDbIds.STAR_STATUS + "\n";
csvText += "1,store,note,12345,AZTEC,0";
ByteArrayInputStream inputStream = new ByteArrayInputStream(csvText.getBytes(StandardCharsets.UTF_8));
// Import the CSV data // Import the CSV data
ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null); ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null);
@@ -635,8 +653,20 @@ public class ImportExportTest {
} }
@Test @Test
public void importWithoutNullColorsV1() { public void importWithoutNullColorsV1() throws IOException {
InputStream inputStream = getClass().getResourceAsStream("catima_v1_empty_colors.csv"); String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
DBHelper.LoyaltyCardDbIds.NOTE + "," +
DBHelper.LoyaltyCardDbIds.CARD_ID + "," +
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE + "," +
DBHelper.LoyaltyCardDbIds.HEADER_COLOR + "," +
DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR + "," +
DBHelper.LoyaltyCardDbIds.STAR_STATUS + "\n";
csvText += "1,store,note,12345,AZTEC,,,0";
ByteArrayInputStream inputStream = new ByteArrayInputStream(csvText.getBytes(StandardCharsets.UTF_8));
// Import the CSV data // Import the CSV data
ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null); ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null);
@@ -661,8 +691,20 @@ public class ImportExportTest {
} }
@Test @Test
public void importWithoutInvalidColorsV1() { public void importWithoutInvalidColorsV1() throws IOException {
InputStream inputStream = getClass().getResourceAsStream("catima_v1_invalid_colors.csv"); String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
DBHelper.LoyaltyCardDbIds.NOTE + "," +
DBHelper.LoyaltyCardDbIds.CARD_ID + "," +
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE + "," +
DBHelper.LoyaltyCardDbIds.HEADER_COLOR + "," +
DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR + "," +
DBHelper.LoyaltyCardDbIds.STAR_STATUS + "\n";
csvText += "1,store,note,12345,type,not a number,invalid,0";
ByteArrayInputStream inputStream = new ByteArrayInputStream(csvText.getBytes(StandardCharsets.UTF_8));
// Import the CSV data // Import the CSV data
ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null); ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null);
@@ -673,8 +715,20 @@ public class ImportExportTest {
} }
@Test @Test
public void importWithNoBarcodeTypeV1() { public void importWithNoBarcodeTypeV1() throws IOException {
InputStream inputStream = getClass().getResourceAsStream("catima_v1_no_barcode_type.csv"); String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
DBHelper.LoyaltyCardDbIds.NOTE + "," +
DBHelper.LoyaltyCardDbIds.CARD_ID + "," +
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE + "," +
DBHelper.LoyaltyCardDbIds.HEADER_COLOR + "," +
DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR + "," +
DBHelper.LoyaltyCardDbIds.STAR_STATUS + "\n";
csvText += "1,store,note,12345,,1,1,0";
ByteArrayInputStream inputStream = new ByteArrayInputStream(csvText.getBytes(StandardCharsets.UTF_8));
// Import the CSV data // Import the CSV data
ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null); ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null);
@@ -699,8 +753,20 @@ public class ImportExportTest {
} }
@Test @Test
public void importWithStarredFieldV1() { public void importWithStarredFieldV1() throws IOException {
InputStream inputStream = getClass().getResourceAsStream("catima_v1_starred_field.csv"); String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
DBHelper.LoyaltyCardDbIds.NOTE + "," +
DBHelper.LoyaltyCardDbIds.CARD_ID + "," +
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE + "," +
DBHelper.LoyaltyCardDbIds.HEADER_COLOR + "," +
DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR + "," +
DBHelper.LoyaltyCardDbIds.STAR_STATUS + "\n";
csvText += "1,store,note,12345,AZTEC,1,1,1";
ByteArrayInputStream inputStream = new ByteArrayInputStream(csvText.getBytes(StandardCharsets.UTF_8));
// Import the CSV data // Import the CSV data
ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null); ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null);
@@ -725,8 +791,20 @@ public class ImportExportTest {
} }
@Test @Test
public void importWithNoStarredFieldV1() { public void importWithNoStarredFieldV1() throws IOException {
InputStream inputStream = getClass().getResourceAsStream("catima_v1_no_starred_field.csv"); String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
DBHelper.LoyaltyCardDbIds.NOTE + "," +
DBHelper.LoyaltyCardDbIds.CARD_ID + "," +
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE + "," +
DBHelper.LoyaltyCardDbIds.HEADER_COLOR + "," +
DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR + "," +
DBHelper.LoyaltyCardDbIds.STAR_STATUS + "\n";
csvText += "1,store,note,12345,AZTEC,1,1,";
ByteArrayInputStream inputStream = new ByteArrayInputStream(csvText.getBytes(StandardCharsets.UTF_8));
// Import the CSV data // Import the CSV data
ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null); ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null);
@@ -751,15 +829,39 @@ public class ImportExportTest {
} }
@Test @Test
public void importWithInvalidStarFieldV1() { public void importWithInvalidStarFieldV1() throws IOException {
InputStream inputStream = getClass().getResourceAsStream("catima_v1_invalid_starred_field.csv"); String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
DBHelper.LoyaltyCardDbIds.NOTE + "," +
DBHelper.LoyaltyCardDbIds.CARD_ID + "," +
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE + "," +
DBHelper.LoyaltyCardDbIds.HEADER_COLOR + "," +
DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR + "," +
DBHelper.LoyaltyCardDbIds.STAR_STATUS + "\n";
csvText += "1,store,note,12345,AZTEC,1,1,2";
ByteArrayInputStream inputStream = new ByteArrayInputStream(csvText.getBytes(StandardCharsets.UTF_8));
// Import the CSV data // Import the CSV data
ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null); ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null);
assertEquals(ImportExportResultType.Success, result.resultType()); assertEquals(ImportExportResultType.Success, result.resultType());
assertEquals(1, DBHelper.getLoyaltyCardCount(mDatabase)); assertEquals(1, DBHelper.getLoyaltyCardCount(mDatabase));
inputStream = getClass().getResourceAsStream("catima_v1_invalid_starred_field_2.csv"); csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
DBHelper.LoyaltyCardDbIds.STORE + "," +
DBHelper.LoyaltyCardDbIds.NOTE + "," +
DBHelper.LoyaltyCardDbIds.CARD_ID + "," +
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE + "," +
DBHelper.LoyaltyCardDbIds.HEADER_COLOR + "," +
DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR + "," +
DBHelper.LoyaltyCardDbIds.STAR_STATUS + "\n";
csvText += "1,store,note,12345,AZTEC,1,1,text";
inputStream = new ByteArrayInputStream(csvText.getBytes(StandardCharsets.UTF_8));
// Import the CSV data // Import the CSV data
result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null); result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null);
@@ -786,8 +888,11 @@ public class ImportExportTest {
@Test @Test
public void exportImportV2Zip() throws FileNotFoundException { public void exportImportV2Zip() throws FileNotFoundException {
// Prepare images // Prepare images
Bitmap bitmap1 = new LetterBitmap(activity.getApplicationContext(), "1", "1", 12, 64, 64, Color.BLACK, Color.YELLOW).getLetterTile(); BitmapDrawable launcher = (BitmapDrawable) ResourcesCompat.getDrawableForDensity(activity.getResources(), R.mipmap.ic_launcher, DisplayMetrics.DENSITY_XXXHIGH, activity.getTheme());
Bitmap bitmap2 = new LetterBitmap(activity.getApplicationContext(), "2", "2", 12, 64, 64, Color.GREEN, Color.WHITE).getLetterTile(); BitmapDrawable roundLauncher = (BitmapDrawable) ResourcesCompat.getDrawableForDensity(activity.getResources(), R.mipmap.ic_launcher_round, DisplayMetrics.DENSITY_XXXHIGH, activity.getTheme());
Bitmap launcherBitmap = launcher.getBitmap();
Bitmap roundLauncherBitmap = roundLauncher.getBitmap();
// Set up cards and groups // Set up cards and groups
HashMap<Integer, LoyaltyCard> loyaltyCardHashMap = new HashMap<>(); HashMap<Integer, LoyaltyCard> loyaltyCardHashMap = new HashMap<>();
@@ -803,12 +908,12 @@ public class ImportExportTest {
List<Group> groups = Arrays.asList(DBHelper.getGroup(mDatabase, "One")); List<Group> groups = Arrays.asList(DBHelper.getGroup(mDatabase, "One"));
DBHelper.setLoyaltyCardGroups(mDatabase, loyaltyCardId, groups); DBHelper.setLoyaltyCardGroups(mDatabase, loyaltyCardId, groups);
loyaltyCardGroups.put(loyaltyCardId, groups); loyaltyCardGroups.put(loyaltyCardId, groups);
Utils.saveCardImage(activity.getApplicationContext(), bitmap1, loyaltyCardId, ImageLocationType.front); Utils.saveCardImage(activity.getApplicationContext(), launcherBitmap, loyaltyCardId, ImageLocationType.front);
Utils.saveCardImage(activity.getApplicationContext(), bitmap2, loyaltyCardId, ImageLocationType.back); Utils.saveCardImage(activity.getApplicationContext(), roundLauncherBitmap, loyaltyCardId, ImageLocationType.back);
Utils.saveCardImage(activity.getApplicationContext(), bitmap1, loyaltyCardId, ImageLocationType.icon); Utils.saveCardImage(activity.getApplicationContext(), launcherBitmap, loyaltyCardId, ImageLocationType.icon);
loyaltyCardFrontImages.put(loyaltyCardId, bitmap1); loyaltyCardFrontImages.put(loyaltyCardId, launcherBitmap);
loyaltyCardBackImages.put(loyaltyCardId, bitmap2); loyaltyCardBackImages.put(loyaltyCardId, roundLauncherBitmap);
loyaltyCardIconImages.put(loyaltyCardId, bitmap1); loyaltyCardIconImages.put(loyaltyCardId, launcherBitmap);
// Create card 2 // Create card 2
loyaltyCardId = (int) DBHelper.insertLoyaltyCard(mDatabase, "Card 2", "", null, null, new BigDecimal(0), null, "123456", null, null, 2, 1, null,0); loyaltyCardId = (int) DBHelper.insertLoyaltyCard(mDatabase, "Card 2", "", null, null, new BigDecimal(0), null, "123456", null, null, 2, 1, null,0);
@@ -892,7 +997,32 @@ public class ImportExportTest {
@Test @Test
public void importV2CSV() { public void importV2CSV() {
InputStream inputStream = getClass().getResourceAsStream("catima_v2.csv"); String csvText = "2\n" +
"\n" +
"_id\n" +
"Health\n" +
"Food\n" +
"Fashion\n" +
"\n" +
"_id,store,note,validfrom,expiry,balance,balancetype,cardid,barcodeid,headercolor,barcodetype,starstatus\n" +
"1,Card 1,Note 1,1601510400,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,\"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" +
"\n" +
"cardId,groupId\n" +
"8,Fashion\n" +
"3,Food\n" +
"4,Health\n" +
"5,Food\n" +
"6,Fashion\n";
ByteArrayInputStream inputStream = new ByteArrayInputStream(csvText.getBytes(StandardCharsets.UTF_8));
// Import the CSV data // Import the CSV data
ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null); ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null);
@@ -1091,11 +1221,7 @@ public class ImportExportTest {
} }
@Test @Test
public void importStocard() { public void importStocard() throws IOException {
// FIXME: The provided stocard.zip is a very old export (8 July 2021) manually edited to
// look more like the Stocard files provided by users for #1242. It is not an up-to-date
// export and the test is possibly unreliable. This should be replaced by an up-to-date
// export.
InputStream inputStream = getClass().getResourceAsStream("stocard.zip"); InputStream inputStream = getClass().getResourceAsStream("stocard.zip");
// Import the Stocard data // Import the Stocard data
@@ -1145,7 +1271,8 @@ public class ImportExportTest {
card = DBHelper.getLoyaltyCard(mDatabase, 3); card = DBHelper.getLoyaltyCard(mDatabase, 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("", card.note);
assertEquals(null, card.validFrom); assertEquals(null, card.validFrom);
assertEquals(null, card.expiry); assertEquals(null, card.expiry);
@@ -1164,8 +1291,33 @@ public class ImportExportTest {
} }
@Test @Test
public void importVoucherVault() { public void importVoucherVault() throws IOException, FormatException, JSONException, ParseException {
InputStream inputStream = getClass().getResourceAsStream("vouchervault.json"); String jsonText = "[\n" +
" {\n" +
" \"uuid\": \"ae1ae525-3f27-481e-853a-8c30b7fa12d8\",\n" +
" \"description\": \"Clothes Store\",\n" +
" \"code\": \"123456\",\n" +
" \"codeType\": \"CODE128\",\n" +
" \"expires\": null,\n" +
" \"removeOnceExpired\": true,\n" +
" \"balance\": null,\n" +
" \"balanceMilliunits\": null,\n" +
" \"color\": \"GREY\"\n" +
" },\n" +
" {\n" +
" \"uuid\": \"29a5d3b3-eace-4311-a15c-4c7e6a010531\",\n" +
" \"description\": \"Department Store\",\n" +
" \"code\": \"26846363\",\n" +
" \"codeType\": \"CODE39\",\n" +
" \"expires\": \"2021-03-26T00:00:00.000\",\n" +
" \"removeOnceExpired\": true,\n" +
" \"balance\": null,\n" +
" \"balanceMilliunits\": 3500,\n" +
" \"color\": \"PURPLE\"\n" +
" }\n" +
"]";
ByteArrayInputStream inputStream = new ByteArrayInputStream(jsonText.getBytes(StandardCharsets.UTF_8));
// Import the Voucher Vault data // Import the Voucher Vault data
ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.VoucherVault, null); ImportExportResult result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.VoucherVault, null);

View File

@@ -12,6 +12,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.Robolectric; import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.io.InvalidObjectException; import java.io.InvalidObjectException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@@ -24,6 +25,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class ImportURITest { public class ImportURITest {
private ImportURIHelper importURIHelper; private ImportURIHelper importURIHelper;
private SQLiteDatabase mDatabase; private SQLiteDatabase mDatabase;
@@ -109,11 +111,10 @@ public class ImportURITest {
@Test @Test
public void failToParseBadData() { public void failToParseBadData() {
String[] urls = new String[4]; String[] urls = new String[3];
urls[0] = "https://brarcher.github.io/loyalty-card-locker/share?stare=store&note=note&cardid=12345&barcodetype=ITF&headercolor=-416706"; urls[0] = "https://brarcher.github.io/loyalty-card-locker/share?stare=store&note=note&cardid=12345&barcodetype=ITF&headercolor=-416706";
urls[1] = "https://thelastproject.github.io/Catima/share#stare%3Dstore%26note%3Dnote%26balance%3D0%26cardid%3D12345%26barcodetype%3DITF%26headercolor%3D-416706"; urls[1] = "https://thelastproject.github.io/Catima/share#stare%3Dstore%26note%3Dnote%26balance%3D0%26cardid%3D12345%26barcodetype%3DITF%26headercolor%3D-416706";
urls[2] = "https://catima.app/share#stare%3Dstore%26note%3Dnote%26balance%3D0%26cardid%3D12345%26barcodetype%3DITF%26headercolor%3D-416706"; urls[2] = "https://catima.app/share#stare%3Dstore%26note%3Dnote%26balance%3D0%26cardid%3D12345%26barcodetype%3DITF%26headercolor%3D-416706";
urls[3] = "https://catima.app/share#";
for (String url : urls) { for (String url : urls) {
try { try {

View File

@@ -15,6 +15,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.Robolectric; import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog; import org.robolectric.shadows.ShadowLog;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -31,6 +32,7 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class LoyaltyCardCursorAdapterTest { public class LoyaltyCardCursorAdapterTest {
private Activity activity; private Activity activity;
private SQLiteDatabase mDatabase; private SQLiteDatabase mDatabase;

View File

@@ -19,8 +19,6 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.View; import android.view.View;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageButton; import android.widget.ImageButton;
@@ -64,7 +62,6 @@ import androidx.preference.PreferenceManager;
import static android.os.Looper.getMainLooper; import static android.os.Looper.getMainLooper;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
@@ -72,6 +69,7 @@ import static org.junit.Assert.assertTrue;
import static org.robolectric.Shadows.shadowOf; import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class LoyaltyCardViewActivityTest { public class LoyaltyCardViewActivityTest {
private final String BARCODE_DATA = "428311627547"; private final String BARCODE_DATA = "428311627547";
private final CatimaBarcode BARCODE_TYPE = CatimaBarcode.fromBarcode(BarcodeFormat.UPC_A); private final CatimaBarcode BARCODE_TYPE = CatimaBarcode.fromBarcode(BarcodeFormat.UPC_A);
@@ -1211,7 +1209,7 @@ public class LoyaltyCardViewActivityTest {
activityController.visible(); activityController.visible();
activityController.resume(); activityController.resume();
assertFalse(activity.isFinishing()); assertEquals(false, activity.isFinishing());
View collapsingToolbarLayout = activity.findViewById(R.id.collapsingToolbarLayout); View collapsingToolbarLayout = activity.findViewById(R.id.collapsingToolbarLayout);
BottomAppBar bottomAppBar = activity.findViewById(R.id.bottom_app_bar); BottomAppBar bottomAppBar = activity.findViewById(R.id.bottom_app_bar);
@@ -1222,9 +1220,9 @@ public class LoyaltyCardViewActivityTest {
SeekBar barcodeScaler = activity.findViewById(R.id.barcodeScaler); SeekBar barcodeScaler = activity.findViewById(R.id.barcodeScaler);
// Android should not be in fullscreen mode // Android should not be in fullscreen mode
assertTrue(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.statusBars())); int uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
assertTrue(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.navigationBars())); assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions);
assertEquals(WindowInsetsController.BEHAVIOR_DEFAULT, activity.getWindow().getInsetsController().getSystemBarsBehavior()); assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions);
// Elements should be visible (except minimize button and scaler) // Elements should be visible (except minimize button and scaler)
assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility()); assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility());
@@ -1240,9 +1238,9 @@ public class LoyaltyCardViewActivityTest {
shadowOf(getMainLooper()).idle(); shadowOf(getMainLooper()).idle();
// Android should be in fullscreen mode // Android should be in fullscreen mode
assertFalse(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.statusBars())); uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
assertFalse(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.navigationBars())); assertEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions);
assertEquals(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE, activity.getWindow().getInsetsController().getSystemBarsBehavior()); assertEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions);
// Elements should not be visible (except minimize button and scaler) // Elements should not be visible (except minimize button and scaler)
assertEquals(View.GONE, collapsingToolbarLayout.getVisibility()); assertEquals(View.GONE, collapsingToolbarLayout.getVisibility());
@@ -1256,11 +1254,9 @@ public class LoyaltyCardViewActivityTest {
// Clicking minimize button should deactivate fullscreen mode // Clicking minimize button should deactivate fullscreen mode
minimizeButton.performClick(); minimizeButton.performClick();
shadowOf(getMainLooper()).idle(); shadowOf(getMainLooper()).idle();
uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
assertTrue(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.statusBars())); assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions);
assertTrue(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.navigationBars())); assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions);
assertEquals(WindowInsetsController.BEHAVIOR_DEFAULT, activity.getWindow().getInsetsController().getSystemBarsBehavior());
assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility()); assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility());
assertEquals(View.VISIBLE, bottomAppBar.getVisibility()); assertEquals(View.VISIBLE, bottomAppBar.getVisibility());
assertEquals(View.VISIBLE, maximizeButton.getVisibility()); assertEquals(View.VISIBLE, maximizeButton.getVisibility());
@@ -1272,11 +1268,9 @@ public class LoyaltyCardViewActivityTest {
// Another click back to fullscreen // Another click back to fullscreen
maximizeButton.performClick(); maximizeButton.performClick();
shadowOf(getMainLooper()).idle(); shadowOf(getMainLooper()).idle();
uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
assertFalse(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.statusBars())); assertEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions);
assertFalse(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.navigationBars())); assertEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions);
assertEquals(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE, activity.getWindow().getInsetsController().getSystemBarsBehavior());
assertEquals(View.GONE, collapsingToolbarLayout.getVisibility()); assertEquals(View.GONE, collapsingToolbarLayout.getVisibility());
assertEquals(View.GONE, bottomAppBar.getVisibility()); assertEquals(View.GONE, bottomAppBar.getVisibility());
assertEquals(View.GONE, maximizeButton.getVisibility()); assertEquals(View.GONE, maximizeButton.getVisibility());
@@ -1288,11 +1282,9 @@ public class LoyaltyCardViewActivityTest {
// In full screen mode, back button should disable fullscreen // In full screen mode, back button should disable fullscreen
activity.onBackPressed(); activity.onBackPressed();
shadowOf(getMainLooper()).idle(); shadowOf(getMainLooper()).idle();
uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
assertTrue(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.statusBars())); assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions);
assertTrue(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.navigationBars())); assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions);
assertEquals(WindowInsetsController.BEHAVIOR_DEFAULT, activity.getWindow().getInsetsController().getSystemBarsBehavior());
assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility()); assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility());
assertEquals(View.VISIBLE, bottomAppBar.getVisibility()); assertEquals(View.VISIBLE, bottomAppBar.getVisibility());
assertEquals(View.VISIBLE, maximizeButton.getVisibility()); assertEquals(View.VISIBLE, maximizeButton.getVisibility());
@@ -1304,7 +1296,7 @@ public class LoyaltyCardViewActivityTest {
// Pressing back when not in full screen should finish activity // Pressing back when not in full screen should finish activity
activity.onBackPressed(); activity.onBackPressed();
shadowOf(getMainLooper()).idle(); shadowOf(getMainLooper()).idle();
assertTrue(activity.isFinishing()); assertEquals(true, activity.isFinishing());
database.close(); database.close();
} }

View File

@@ -33,6 +33,7 @@ import static org.junit.Assert.assertNotNull;
import static org.robolectric.Shadows.shadowOf; import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class MainActivityTest { public class MainActivityTest {
private SharedPreferences prefs; private SharedPreferences prefs;

View File

@@ -1,2 +0,0 @@
_id,store,note,cardid,barcodetype,headercolor,headertextcolor,starstatus
1,store,note,12345,AZTEC,,,0
1 _id store note cardid barcodetype headercolor headertextcolor starstatus
2 1 store note 12345 AZTEC 0

View File

@@ -1,2 +0,0 @@
_id,store,note,cardid,barcodetype,headercolor,headertextcolor,starstatus
1,store,note,12345,type,not a number,invalid,0
1 _id store note cardid barcodetype headercolor headertextcolor starstatus
2 1 store note 12345 type not a number invalid 0

View File

@@ -1,2 +0,0 @@
_id,store,note,cardid,barcodetype,headercolor,headertextcolor,starstatus
1,store,note,12345,AZTEC,1,1,2
1 _id store note cardid barcodetype headercolor headertextcolor starstatus
2 1 store note 12345 AZTEC 1 1 2

View File

@@ -1,2 +0,0 @@
_id,store,note,cardid,barcodetype,headercolor,headertextcolor,starstatus
1,store,note,12345,AZTEC,1,1,text
1 _id store note cardid barcodetype headercolor headertextcolor starstatus
2 1 store note 12345 AZTEC 1 1 text

View File

@@ -1,2 +0,0 @@
_id,store,note,cardid,barcodetype,headercolor,headertextcolor,starstatus
1,store,note,12345,,1,1,0
1 _id store note cardid barcodetype headercolor headertextcolor starstatus
2 1 store note 12345 1 1 0

View File

@@ -1,2 +0,0 @@
_id,store,note,cardid,barcodetype,starstatus
1,store,note,12345,AZTEC,0
1 _id store note cardid barcodetype starstatus
2 1 store note 12345 AZTEC 0

View File

@@ -1,2 +0,0 @@
_id,store,note,cardid,barcodetype,headercolor,headertextcolor,starstatus
1,store,note,12345,AZTEC,1,1,
1 _id store note cardid barcodetype headercolor headertextcolor starstatus
2 1 store note 12345 AZTEC 1 1

View File

@@ -1,2 +0,0 @@
_id,store,note,cardid,barcodetype,headercolor,headertextcolor,starstatus
1,store,note,12345,AZTEC,1,1,1
1 _id store note cardid barcodetype headercolor headertextcolor starstatus
2 1 store note 12345 AZTEC 1 1 1

View File

@@ -1,24 +0,0 @@
2
_id
Health
Food
Fashion
_id,store,note,validfrom,expiry,balance,balancetype,cardid,barcodeid,headercolor,barcodetype,starstatus
1,Card 1,Note 1,1601510400,1618053234,100,USD,1234,5432,1,QR_CODE,0,
8,Clothes Store,Note about store,,,0,,a,,-5317,,0,
2,Department Store,,,1618041729,0,,A,,-9977996,,0,
3,Grocery Store,"Multiline note about grocery store
with blank line",,,150,,dhd,,-9977996,,0,
4,Pharmacy,,,,0,,dhshsvshs,,-10902850,,1,
5,Restaurant,Note about restaurant here,,,0,,98765432,23456,-10902850,CODE_128,0,
6,Shoe Store,,,,12.50,EUR,a,-5317,,AZTEC,0,
cardId,groupId
8,Fashion
3,Food
4,Health
5,Food
6,Fashion
1 2
2 _id
3 Health
4 Food
5 Fashion
6 _id store note validfrom expiry balance balancetype cardid barcodeid headercolor barcodetype starstatus
7 1 Card 1 Note 1 1601510400 1618053234 100 USD 1234 5432 1 QR_CODE 0
8 8 Clothes Store Note about store 0 a -5317 0
9 2 Department Store 1618041729 0 A -9977996 0
10 3 Grocery Store Multiline note about grocery store with blank line 150 dhd -9977996 0
11 4 Pharmacy 0 dhshsvshs -10902850 1
12 5 Restaurant Note about restaurant here 0 98765432 23456 -10902850 CODE_128 0
13 6 Shoe Store 12.50 EUR a -5317 AZTEC 0
14 cardId groupId
15 8 Fashion
16 3 Food
17 4 Health
18 5 Food
19 6 Fashion

View File

Binary file not shown.

View File

@@ -1,24 +0,0 @@
[
{
"uuid": "ae1ae525-3f27-481e-853a-8c30b7fa12d8",
"description": "Clothes Store",
"code": "123456",
"codeType": "CODE128",
"expires": null,
"removeOnceExpired": true,
"balance": null,
"balanceMilliunits": null,
"color": "GREY"
},
{
"uuid": "29a5d3b3-eace-4311-a15c-4c7e6a010531",
"description": "Department Store",
"code": "26846363",
"codeType": "CODE39",
"expires": "2021-03-26T00:00:00.000",
"removeOnceExpired": true,
"balance": null,
"balanceMilliunits": 3500,
"color": "PURPLE"
}
]

View File

@@ -1,8 +1,8 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
id 'com.android.application' version '8.0.0' apply false id 'com.android.application' version '7.0.4' apply false
id 'com.github.spotbugs' version "5.0.14" apply false id 'com.github.spotbugs' version "4.7.5" apply false
} }
allprojects { allprojects {

View File

@@ -11,13 +11,13 @@ if [ -z "${ANDROID_SDK_ROOT:-}" ]; then
fi fi
if [ -z "${JAVA_HOME:-}" ]; then if [ -z "${JAVA_HOME:-}" ]; then
echo "JAVA_HOME is not set, setting to Java 17" echo "JAVA_HOME is not set, setting to Java 11 (like F-Droid)"
if [ -f "/etc/debian_version" ]; then if [ -f "/etc/debian_version" ]; then
echo "Debian-based distro, Java 17 is /usr/lib/jvm/java-17-openjdk-amd64" echo "Debian-based distro, Java 11 is /usr/lib/jvm/java-11-openjdk-amd64"
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
else else
echo "Not Debian-based, assuming Fedora and setting Java 17 as /usr/lib/jvm/java-17-openjdk" echo "Not Debian-based, assuming Fedora and setting Java 11 as /usr/lib/jvm/java-11-openjdk"
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk export JAVA_HOME=/usr/lib/jvm/java-11-openjdk
fi fi
fi fi

View File

@@ -1,2 +1 @@
- Podpora nastavení začátku platnosti karty - Podpora nastavení začátku platnosti karty
- Oprava importu Stocard (změnil se formát exportu Stocard)

View File

@@ -1 +0,0 @@
- Použít barvy motivu Material You na více zařízeních (aktualizace knihovny Google)

View File

@@ -1,2 +1,2 @@
- Dlouhé kliknutí na kartu vyvolá možnost zkopírovat ID karty do schránky. (pull #49 (https://github.com/brarcher/loyalty-card-locker/issues/49)) - Dlouhé kliknutí na kartu vyvolá možnost zkopírovat ID karty do schránky. (pull #49 (https://github.com/brarcher/loyalty-card-locker/issues/49))
- Tlačítko Zpět v zobrazení Import/Export nyní funguje a přesune uživatele do hlavního zobrazení - Tlačítko Zpět v zobrazení Vstup/Export nyní funguje a přesune uživatele do hlavního zobrazení

View File

@@ -1,2 +1 @@
- Support setting start of card validity - Support setting start of card validity
- Fix Stocard import (Stocard's export format changed)

View File

@@ -1 +0,0 @@
- Use Material You colours on more devices (Google library update)

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -1,2 +0,0 @@
- Correction de la boîte de dialogue de dépense rapide qui ne permettait pas l'utilisation de la virgule comme séparateur
- Prise en charge du chargement d'images à partir du gestionnaire de fichiers

View File

@@ -1,2 +1 @@
- Prise en charge du début de la validité de la carte -Prise en charge du début de la validité de la carte
- Correction de l'importation Stocard (le format d'exportation de Stocard a changé)

View File

@@ -1,2 +1 @@
- Supporto alla validità della carta - Supporto alla validità della carta
- Sistemata l'importazione da Stocard (è cambiato il formato di esportazione di Stocard)

View File

@@ -1,2 +1 @@
- Suporte a configuração da data de início de validade - Suporte a configuração da data de início de validade
- Correção na importação Stocard (o formato de exportação Stocard foi alterado)

View File

@@ -1 +0,0 @@
- Usar cores Material You em mais dispositivos (atualização da biblioteca Google)

View File

@@ -1,2 +1,2 @@
- Clique longo num cartão faz com que apareça uma opção para copiar o ID do cartão para a área de transferência. (pull #49 (https://github.com/brarcher/loyalty-card-locker/issues/49)) - Clique longo em um cartão faz com que apareça uma opção para copiar o ID do card para a área de transferência. (pull #49 (https://github.com/brarcher/loyalty-card-locker/issues/49))
- O botão de voltar agora funciona no ecrã de importar/exportar, levando ao ecrã principal - O botão de voltar agora funciona quando na tela de importar/exportar, levando a usuária para a tela principal

View File

@@ -1,6 +1,5 @@
- При редактировании номера, поле предварительно заполняется текущим. (№94) - При редактировании номера карты, поле предварительно заполняется текущим номером. (запрос №94 (https://github.com/brarcher/loyalty-card-locker/pull/94))
- Ограничена ширина формируемых штрих-кодов для уменьшения потребления памяти. (№103) - Ширина формируемых штрихкодов ограничена для уменьшения потребления памяти и ошибок её нехватки. (запрос №103 (https://github.com/brarcher/loyalty-card-locker/pull/103))
- Кнопка «Ввести карту» меняется на «Изменить карту», если указанный номер уже используется. (№104) - При редактировании карты кнопка ввода карты меняется на кнопку редактирования, если указанный номер уже используется. (запрос №104 (https://github.com/brarcher/loyalty-card-locker/pull/104))
- Цветовая гамма смягчена и сочетается со значком приложения, упрощена страница просмотра карты. (№107) - Цветовая гамма изменена на более мягкую и сочетающуюся с значком приложения, упрощена страница просмотра карты. (запрос №107 (https://github.com/brarcher/loyalty-card-locker/pull/107))
- Сделан вводный мастер для первого запуска приложения. (№108) - Добавлен вводный мастер, включающийся при первом запуске приложения. (запрос №108 (https://github.com/brarcher/loyalty-card-locker/pull/108))
Все запросы см. в https://github.com/brarcher/loyalty-card-locker/pulls

View File

@@ -1,2 +1 @@
- Добавлена возможность указания даты начала действия карты - Добавлена возможность указания даты начала действия карты
- Исправлен импорт из Stocard (в Stocard изменился формат выгрузки)

View File

@@ -1 +0,0 @@
- На большинстве устройств используются цвета Material You (обновлена библиотека Google)

View File

@@ -1,4 +1,3 @@
- Добавлена возможность блокировки поворота экрана в меню показа карты. Если заблокирован, экран перейдёт в "обычную" ориентацию и дальше поворачиваться не будет. (запрос №128) - Добавлена возможность блокировки поворота экрана в меню показа карты. Если заблокирован, экран перейдёт в "обычную" ориентацию и дальше поворачиваться не будет. (запрос №128 (https://github.com/brarcher/loyalty-card-locker/pull/128))
- Устранён сбой при выборе на главном экране карты, которая не может быть открыта: приложение корректно сообщает об ошибке. (запрос №132) - Устранён сбой при выборе на главном экране карты, которая не может быть открыта: приложение корректно сообщает об ошибке. (запрос №132 (https://github.com/brarcher/loyalty-card-locker/pull/132))
- Исправлена проблема с нехваткой идентификаторов компоновки для вводного мастера. (запрос №128) - Исправлена проблема с нехваткой идентификаторов компоновки для вводного мастера. (запрос №128 (https://github.com/brarcher/loyalty-card-locker/pull/128))
Все запросы см. в https://github.com/brarcher/loyalty-card-locker/pulls

View File

@@ -1,6 +1,5 @@
- Добавлена возможность создания ярлыков на домашнем экране при создании или редактировании карты. (запрос №155) - Добавлена возможность создания ярлыков на домашнем экране при создании или редактировании карты. (запрос №155 (https://github.com/brarcher/loyalty-card-locker/pull/155))
- Виджет удалён, поскольку был плохой заменой ярлыкам. (запрос №155) - Виджет удалён, поскольку был плохой заменой ярлыкам. (запрос №155 (https://github.com/brarcher/loyalty-card-locker/pull/155))
- Исправлена выгрузка резервных копий для Android 7+. (запрос №153) - Исправлена выгрузка резервных копий для Android 7+. (запрос №153 (https://github.com/brarcher/loyalty-card-locker/pull/153))
- Уточнён MIME-тип при выгрузке резервных копий. (запрос №156) - Уточнён MIME-тип при выгрузке резервных копий. (запрос №156 (https://github.com/brarcher/loyalty-card-locker/pull/156))
- Исправлена ошибка, из-за которой карту нельзя было редактировать. (запрос №155) - Исправлена ошибка, из-за которой карту нельзя было редактировать. (запрос №155 (https://github.com/brarcher/loyalty-card-locker/pull/155))
Все запросы см. в https://github.com/brarcher/loyalty-card-locker/pulls

View File

@@ -1,9 +1,14 @@
- Возможность поиска карты (№320) - Добавлена возможость поиска карты (запрос №320 (https://github.com/brarcher/loyalty-card-locker/pull/320))
- Возможность отправки и получения карт (№321) - Добавлена возможность отправки и получения карт (запрос №321 (https://github.com/brarcher/loyalty-card-locker/pull/321))
- Поддержка тёмного режима (№322) - Добавлена поддержка тёмного режима (запрос №322 (https://github.com/brarcher/loyalty-card-locker/pull/322))
- Поддержка карт без штрих-кодов (№324) - Карты лояльности теперь могут быть без штрихкодов (запрос №324 (https://github.com/brarcher/loyalty-card-locker/pull/324))
- Примечания могут отображаться в несколько строк (№326) - Примечания могут отображаться в несколько строк (запрос №326 (https://github.com/brarcher/loyalty-card-locker/pull/326))
- Улучшено масштабирование примечаний (№319) - Улучшено масштабирование примечаний (запрос №319 (https://github.com/brarcher/loyalty-card-locker/pull/319))
- Улучшена видимость уведомлений и значка приложения (№330) - Улучшена видимость уведомлений и значка приложения (запрос №330 (https://github.com/brarcher/loyalty-card-locker/pull/330))
- Целевой SDK обновлён до Android 10 - Целевой SDK обновлён до Android 10
- Улучшены переводы: немецкий, итальянский, нидерландский, польский, русский. - Улучшены следующие переводы:
- немецкий
- итальянский
- нидерладский
- польский
- русский

View File

@@ -1,11 +1,11 @@
- ВАЖНО: Изменён формат резервирования (ссылка устарела) - СУЩЕСТВЕННОЕ ИЗМЕНЕНИЕ: Изменён формат резервного копирования, смотри https://github.com/TheLastProject/Catima/wiki/Export-format
- ВАЖНО: Изменён формат URL отправки карты (ссылка устарела) - СУЩЕСТВЕННОЕ ИЗМЕНЕНИЕ: Изменён формат URL отправки карты, смотри https://github.com/TheLastProject/Catima/wiki/Card-sharing-URL-format
- Возможность включения подсветки при сканировании - Добавлена возможность использования подсветки при сканировании
- Поддержка штрихкодов UPC-E - Добавлена поддержка штрихкодов формата UPC-E
- Хранение фото лицевой и тыльной стороны карты - Добавлена возможность сохранения фотографий лицевой и тыльной стороны карты
- Импорт из ZIP с паролем - Добавлена возможность загрузки из ZIP-архивов, защищённых паролем
- Импорт из Stocard (бета) - Добавлена возможность импорта из Stocard (бета)
- Устранены лишние пробелы в примечаниях из FidMe - Устранены бесполезные пробелы в загруженных из FidMe примечаниях
- Поддержка нового формата Voucher Vault - Добавлена поддержка нового формата выгрузки Voucher Vault
- Устранено перекрытие кнопок в Android 4 - Устранено перекртие плавающих кнопок действий другими элементами интерфейса на Android 4
- Исправлено верхнее поле панели при просмотре карты - Исправлено верхнее поле панели приложения при просмотре карты

View File

@@ -1,5 +1,4 @@
- Яркость экрана увеличена до максимальной при отображении карты, чтобы улучшить считывание штрих-кода сканерами (запрос №54). - Яркость экрана увеличена до максимальной при отображении карты, чтобы улучшить считывание штрихкода сканерами. (запрос №54 (https://github.com/brarcher/loyalty-card-locker/pull/54))
- Добавлен запрос подтверждения удаления карты (запрос №55). - Добавлен запрос подтверждения удаления карты. (запрос №55 (https://github.com/brarcher/loyalty-card-locker/pull/55))
- Добавлены переводы на немецкий (запрос №57) и чешский (запрос №58). - Добавлены переводы на немецкий (запрос №57 (https://github.com/brarcher/loyalty-card-locker/pull/57)) и чешский (запрос №58 (https://github.com/brarcher/loyalty-card-locker/pull/58)).
- Уточнён перевод на итальянский (запрос №66). - Уточнён перевод на итальянский. (запрос №66 (https://github.com/brarcher/loyalty-card-locker/pull/66))
Все запросы см. в https://github.com/brarcher/loyalty-card-locker/pulls

View File

@@ -1,6 +1,7 @@
«Шкафчик» в названии не был интуитивно понятным. Поэтому betsythefc создал новый значок приложения, который лучше отражает его назначение: хранить карты лояльности со штрих-кодами. Одновременно изменилось и название приложения на «Брелок для карт лояльности». «Шкафчик» в названии не был интуитивно понятным. Чтобы устранить это, betsythefc создал новый значок приложения, который лучше отражает назначение приложения: хранить использующие штрихкоды карты лояльности. Одовременно со значком и название приложения изменилось на «Брелок для карт лояльности».
Дополнительно (все запросы см. в https://github.com/brarcher/loyalty-card-locker/pulls): Дополнительные улучшения:
- Более гибкая загрузка и выгрузка карт (запрос №76).
- Добавлен литовский перевод (запрос №62). - Загрузка и выгрузка карт изменена для большей гибкости. (запрос №76 (https://github.com/brarcher/loyalty-card-locker/pull/76))
- Добавлен французский перевод (запрос №80). - Добавлен литовский перевод. (запрос №62 (https://github.com/brarcher/loyalty-card-locker/pull/62))
- Добавлен французский перевод. (запрос №80 (https://github.com/brarcher/loyalty-card-locker/pull/80))

View File

@@ -1,4 +1,2 @@
- Förbättrat stöd för skärmläsare - Förbättrat stöd för skärmläsare
- Kraschar inte vid försök att öppna en video från galleriet - Kraschar inte när den försöker öppna en video från galleriet
- Svepstöd på lojalitetskortets översiktssida
- Nollställ inte grupp vid klickning på tillbakaknappen

View File

@@ -16,7 +16,5 @@
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
android.defaults.buildfeatures.buildconfig=true android.enableJetifier=true
android.nonFinalResIds=true
android.nonTransitiveRClass=true
android.useAndroidX=true android.useAndroidX=true

View File

@@ -1,6 +1,6 @@
#Sun Jul 25 20:59:51 CEST 2021 #Sun Jul 25 20:59:51 CEST 2021
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- FIXME: Disable the MissingQuantity check until https://github.com/WeblateOrg/weblate/issues/7520 gets fixed -->
<issue id="MissingQuantity" severity="ignore" />
</lint>