mirror of
https://github.com/CatimaLoyalty/Android.git
synced 2026-04-04 23:53:51 -04:00
Merge branch 'master' of github.com:TheLastProject/loyalty-card-locker into feature/power_screen_widgets
This commit is contained in:
@@ -24,5 +24,10 @@ with open('CHANGELOG.md') as changelog:
|
||||
text.append(re.sub(r'\[(.*?)\]\((.*?)\)', r'\1 (\2)', line))
|
||||
|
||||
for version, description in changelogs.items():
|
||||
description = "".join(description).strip()
|
||||
|
||||
if not description:
|
||||
continue
|
||||
|
||||
with open(os.path.join("fastlane", "metadata", "android", "en-US", "changelogs", f"{version}.txt"), "w") as fastlane_file:
|
||||
fastlane_file.write("".join(description).strip())
|
||||
fastlane_file.write(description)
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
# Changelog
|
||||
|
||||
## Unreleased - 89
|
||||
## Unreleased - 90
|
||||
|
||||
## v2.8.0 - 89 (2021-10-25)
|
||||
|
||||
- Fix swiping between groups not working on an empty group
|
||||
- Allow password-protecting exports
|
||||
- Improve usage of space for QR codes
|
||||
- Save the last used zoom level per card
|
||||
- Fix a crash when swiping right after a tap
|
||||
|
||||
## v2.7.3 - 88 (2021-10-10)
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ android {
|
||||
applicationId "me.hackerchick.catima"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 31
|
||||
versionCode 88
|
||||
versionName "2.7.3"
|
||||
versionCode 89
|
||||
versionName "2.8.0"
|
||||
|
||||
vectorDrawables.useSupportLibrary true
|
||||
multiDexEnabled true
|
||||
@@ -91,7 +91,7 @@ dependencies {
|
||||
implementation 'androidx.core:core-splashscreen:1.0.0-alpha02'
|
||||
|
||||
// Third-party
|
||||
implementation 'com.journeyapps:zxing-android-embedded:4.2.0@aar'
|
||||
implementation 'com.journeyapps:zxing-android-embedded:4.3.0@aar'
|
||||
implementation 'com.google.zxing:core:3.4.1'
|
||||
implementation 'org.apache.commons:commons-csv:1.9.0'
|
||||
implementation 'com.jaredrummler:colorpicker:1.1.0'
|
||||
|
||||
@@ -4,30 +4,29 @@ import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import protect.card_locker.async.CompatCallable;
|
||||
|
||||
/**
|
||||
* This task will generate a barcode and load it into an ImageView.
|
||||
* Only a weak reference of the ImageView is kept, so this class will not
|
||||
* prevent the ImageView from being garbage collected.
|
||||
*/
|
||||
class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
{
|
||||
public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
private static final int IS_VALID = 999;
|
||||
private Context mContext;
|
||||
private final Context mContext;
|
||||
private boolean isSuccesful;
|
||||
|
||||
// When drawn in a smaller window 1D barcodes for some reason end up
|
||||
@@ -44,10 +43,11 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
private final boolean showFallback;
|
||||
private final Runnable callback;
|
||||
|
||||
BarcodeImageWriterTask(Context context, ImageView imageView, String cardIdString,
|
||||
CatimaBarcode barcodeFormat, TextView textView,
|
||||
boolean showFallback, Runnable callback)
|
||||
{
|
||||
BarcodeImageWriterTask(
|
||||
Context context, ImageView imageView, String cardIdString,
|
||||
CatimaBarcode barcodeFormat, TextView textView,
|
||||
boolean showFallback, Runnable callback
|
||||
) {
|
||||
mContext = context;
|
||||
|
||||
isSuccesful = true;
|
||||
@@ -62,26 +62,21 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
|
||||
final int MAX_WIDTH = getMaxWidth(format);
|
||||
|
||||
if(imageView.getWidth() < MAX_WIDTH)
|
||||
{
|
||||
if (imageView.getWidth() < MAX_WIDTH) {
|
||||
imageHeight = imageView.getHeight();
|
||||
imageWidth = imageView.getWidth();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Scale down the image to reduce the memory needed to produce it
|
||||
imageWidth = MAX_WIDTH;
|
||||
double ratio = (double)MAX_WIDTH / (double)imageView.getWidth();
|
||||
imageHeight = (int)(imageView.getHeight() * ratio);
|
||||
double ratio = (double) MAX_WIDTH / (double) imageView.getWidth();
|
||||
imageHeight = (int) (imageView.getHeight() * ratio);
|
||||
}
|
||||
|
||||
this.showFallback = showFallback;
|
||||
}
|
||||
|
||||
private int getMaxWidth(CatimaBarcode format)
|
||||
{
|
||||
switch(format.format())
|
||||
{
|
||||
private int getMaxWidth(CatimaBarcode format) {
|
||||
switch (format.format()) {
|
||||
// 2D barcodes
|
||||
case AZTEC:
|
||||
case DATA_MATRIX:
|
||||
@@ -108,10 +103,8 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
}
|
||||
}
|
||||
|
||||
private String getFallbackString(CatimaBarcode format)
|
||||
{
|
||||
switch(format.format())
|
||||
{
|
||||
private String getFallbackString(CatimaBarcode format) {
|
||||
switch (format.format()) {
|
||||
// 2D barcodes
|
||||
case AZTEC:
|
||||
return "AZTEC";
|
||||
@@ -144,23 +137,17 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap generate()
|
||||
{
|
||||
if (cardId.isEmpty())
|
||||
{
|
||||
private Bitmap generate() {
|
||||
if (cardId.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MultiFormatWriter writer = new MultiFormatWriter();
|
||||
BitMatrix bitMatrix;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
try {
|
||||
bitMatrix = writer.encode(cardId, format.format(), imageWidth, imageHeight, null);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
// Cast a wider net here and catch any exception, as there are some
|
||||
// cases where an encoder may fail if the data is invalid for the
|
||||
// barcode type. If this happens, we want to fail gracefully.
|
||||
@@ -175,11 +162,9 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
|
||||
int[] pixels = new int[bitMatrixWidth * bitMatrixHeight];
|
||||
|
||||
for (int y = 0; y < bitMatrixHeight; y++)
|
||||
{
|
||||
for (int y = 0; y < bitMatrixHeight; y++) {
|
||||
int offset = y * bitMatrixWidth;
|
||||
for (int x = 0; x < bitMatrixWidth; x++)
|
||||
{
|
||||
for (int x = 0; x < bitMatrixWidth; x++) {
|
||||
int color = bitMatrix.get(x, y) ? BLACK : WHITE;
|
||||
pixels[offset + x] = color;
|
||||
}
|
||||
@@ -199,19 +184,14 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
int widthScale = imageWidth / bitMatrixHeight;
|
||||
int scalingFactor = Math.min(heightScale, widthScale);
|
||||
|
||||
if(scalingFactor > 1)
|
||||
{
|
||||
if (scalingFactor > 1) {
|
||||
bitmap = Bitmap.createScaledBitmap(bitmap, bitMatrixWidth * scalingFactor, bitMatrixHeight * scalingFactor, false);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
catch (WriterException e)
|
||||
{
|
||||
} catch (WriterException e) {
|
||||
Log.e(TAG, "Failed to generate barcode of type " + format + ": " + cardId, e);
|
||||
}
|
||||
catch(OutOfMemoryError e)
|
||||
{
|
||||
} catch (OutOfMemoryError e) {
|
||||
Log.w(TAG, "Insufficient memory to render barcode, "
|
||||
+ imageWidth + "x" + imageHeight + ", " + format.name()
|
||||
+ ", length=" + cardId.length(), e);
|
||||
@@ -220,29 +200,36 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
return null;
|
||||
}
|
||||
|
||||
public Bitmap doInBackground(Void... params)
|
||||
{
|
||||
Bitmap bitmap = generate();
|
||||
public Bitmap doInBackground(Void... params) {
|
||||
// Only do the hard tasks if we've not already been cancelled
|
||||
if (!Thread.currentThread().isInterrupted()) {
|
||||
Bitmap bitmap = generate();
|
||||
|
||||
if (bitmap == null) {
|
||||
isSuccesful = false;
|
||||
if (bitmap == null) {
|
||||
isSuccesful = false;
|
||||
|
||||
if (showFallback) {
|
||||
Log.i(TAG, "Barcode generation failed, generating fallback...");
|
||||
cardId = getFallbackString(format);
|
||||
bitmap = generate();
|
||||
if (showFallback && !Thread.currentThread().isInterrupted()) {
|
||||
Log.i(TAG, "Barcode generation failed, generating fallback...");
|
||||
cardId = getFallbackString(format);
|
||||
bitmap = generate();
|
||||
return bitmap;
|
||||
}
|
||||
} else {
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
// We've been interrupted - create a empty fallback
|
||||
Bitmap.Config config = Bitmap.Config.ARGB_8888;
|
||||
return Bitmap.createBitmap(imageWidth, imageHeight, config);
|
||||
}
|
||||
|
||||
protected void onPostExecute(Bitmap result)
|
||||
{
|
||||
public void onPostExecute(Object castResult) {
|
||||
Bitmap result = (Bitmap) castResult;
|
||||
|
||||
Log.i(TAG, "Finished generating barcode image of type " + format + ": " + cardId);
|
||||
ImageView imageView = imageViewReference.get();
|
||||
if(imageView == null)
|
||||
{
|
||||
if (imageView == null) {
|
||||
// The ImageView no longer exists, nothing to do
|
||||
return;
|
||||
}
|
||||
@@ -255,8 +242,7 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
imageView.setContentDescription(mContext.getString(R.string.barcodeImageDescriptionWithType, formatPrettyName));
|
||||
TextView textView = textViewReference.get();
|
||||
|
||||
if(result != null)
|
||||
{
|
||||
if (result != null) {
|
||||
Log.i(TAG, "Displaying barcode");
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
|
||||
@@ -270,9 +256,7 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
textView.setVisibility(View.VISIBLE);
|
||||
textView.setText(formatPrettyName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Log.i(TAG, "Barcode generation failed, removing image from display");
|
||||
imageView.setVisibility(View.GONE);
|
||||
if (textView != null) {
|
||||
@@ -284,4 +268,19 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreExecute() {
|
||||
// No Action
|
||||
}
|
||||
|
||||
/**
|
||||
* Provided to comply with Callable while keeping the original Syntax of AsyncTask
|
||||
*
|
||||
* @return generated Bitmap
|
||||
*/
|
||||
@Override
|
||||
public Bitmap call() {
|
||||
return doInBackground();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ package protect.card_locker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.MenuItem;
|
||||
@@ -16,24 +17,21 @@ import android.widget.Toast;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import protect.card_locker.async.TaskHandler;
|
||||
|
||||
/**
|
||||
* This activity is callable and will allow a user to enter
|
||||
* barcode data and generate all barcodes possible for
|
||||
* the data. The user may then select any barcode, where its
|
||||
* data and type will be returned to the caller.
|
||||
*/
|
||||
public class BarcodeSelectorActivity extends CatimaAppCompatActivity
|
||||
{
|
||||
public class BarcodeSelectorActivity extends CatimaAppCompatActivity {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
// Result this activity will return
|
||||
@@ -41,19 +39,21 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity
|
||||
public static final String BARCODE_FORMAT = "format";
|
||||
|
||||
private Map<String, Pair<Integer, Integer>> barcodeViewMap;
|
||||
private LinkedList<AsyncTask> barcodeGeneratorTasks = new LinkedList<>();
|
||||
|
||||
final private TaskHandler mTasks = new TaskHandler();
|
||||
|
||||
private final Handler typingDelayHandler = new Handler(Looper.getMainLooper());
|
||||
public static final Integer INPUT_DELAY = 250;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(R.string.selectBarcodeTitle);
|
||||
setContentView(R.layout.barcode_selector_activity);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@@ -72,26 +72,31 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity
|
||||
barcodeViewMap.put(BarcodeFormat.UPC_E.name(), new Pair<>(R.id.upceBarcode, R.id.upceBarcodeText));
|
||||
|
||||
EditText cardId = findViewById(R.id.cardId);
|
||||
cardId.addTextChangedListener(new SimpleTextWatcher()
|
||||
{
|
||||
|
||||
cardId.addTextChangedListener(new SimpleTextWatcher() {
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count)
|
||||
{
|
||||
Log.d(TAG, "Entered text: " + s);
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Delay the input processing so we avoid overload
|
||||
typingDelayHandler.removeCallbacksAndMessages(null);
|
||||
|
||||
generateBarcodes(s.toString());
|
||||
typingDelayHandler.postDelayed(() -> {
|
||||
Log.d(TAG, "Entered text: " + s);
|
||||
|
||||
View noBarcodeButtonView = findViewById(R.id.noBarcode);
|
||||
setButtonListener(noBarcodeButtonView, s.toString());
|
||||
noBarcodeButtonView.setEnabled(s.length() > 0);
|
||||
runOnUiThread(() -> {
|
||||
generateBarcodes(s.toString());
|
||||
|
||||
View noBarcodeButtonView = findViewById(R.id.noBarcode);
|
||||
setButtonListener(noBarcodeButtonView, s.toString());
|
||||
noBarcodeButtonView.setEnabled(s.length() > 0);
|
||||
});
|
||||
}, INPUT_DELAY);
|
||||
}
|
||||
});
|
||||
|
||||
final Bundle b = getIntent().getExtras();
|
||||
final String initialCardId = b != null ? b.getString("initialCardId") : null;
|
||||
|
||||
if(initialCardId != null)
|
||||
{
|
||||
if (initialCardId != null) {
|
||||
cardId.setText(initialCardId);
|
||||
} else {
|
||||
generateBarcodes("");
|
||||
@@ -99,24 +104,19 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity
|
||||
}
|
||||
|
||||
private void generateBarcodes(String value) {
|
||||
// Stop any async tasks which may not have been started yet
|
||||
for(AsyncTask task : barcodeGeneratorTasks)
|
||||
{
|
||||
task.cancel(false);
|
||||
}
|
||||
barcodeGeneratorTasks.clear();
|
||||
// Attempt to stop any async tasks which may not have been started yet
|
||||
// TODO this can be very much optimized by only generating Barcodes visible to the User
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.BARCODE, true, false, false);
|
||||
|
||||
// Update barcodes
|
||||
for(Map.Entry<String, Pair<Integer, Integer>> entry : barcodeViewMap.entrySet())
|
||||
{
|
||||
for (Map.Entry<String, Pair<Integer, Integer>> entry : barcodeViewMap.entrySet()) {
|
||||
ImageView image = findViewById(entry.getValue().first);
|
||||
TextView text = findViewById(entry.getValue().second);
|
||||
createBarcodeOption(image, entry.getKey(), value, text);
|
||||
}
|
||||
}
|
||||
|
||||
private void setButtonListener(final View button, final String cardId)
|
||||
{
|
||||
private void setButtonListener(final View button, final String cardId) {
|
||||
button.setOnClickListener(view -> {
|
||||
Log.d(TAG, "Selected no barcode");
|
||||
Intent result = new Intent();
|
||||
@@ -127,8 +127,7 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity
|
||||
});
|
||||
}
|
||||
|
||||
private void createBarcodeOption(final ImageView image, final String formatType, final String cardId, final TextView text)
|
||||
{
|
||||
private void createBarcodeOption(final ImageView image, final String formatType, final String cardId, final TextView text) {
|
||||
final CatimaBarcode format = CatimaBarcode.fromName(formatType);
|
||||
|
||||
image.setImageBitmap(null);
|
||||
@@ -147,40 +146,32 @@ public class BarcodeSelectorActivity extends CatimaAppCompatActivity
|
||||
finish();
|
||||
});
|
||||
|
||||
if(image.getHeight() == 0)
|
||||
{
|
||||
if (image.getHeight() == 0) {
|
||||
// The size of the ImageView is not yet available as it has not
|
||||
// yet been drawn. Wait for it to be drawn so the size is available.
|
||||
image.getViewTreeObserver().addOnGlobalLayoutListener(
|
||||
new ViewTreeObserver.OnGlobalLayoutListener()
|
||||
{
|
||||
@Override
|
||||
public void onGlobalLayout()
|
||||
{
|
||||
Log.d(TAG, "Global layout finished, type: + " + formatType + ", width: " + image.getWidth());
|
||||
image.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
Log.d(TAG, "Global layout finished, type: + " + formatType + ", width: " + image.getWidth());
|
||||
image.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
|
||||
Log.d(TAG, "Generating barcode for type " + formatType);
|
||||
BarcodeImageWriterTask task = new BarcodeImageWriterTask(getApplicationContext(), image, cardId, format, text, true, null);
|
||||
barcodeGeneratorTasks.add(task);
|
||||
task.execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "Generating barcode for type " + formatType);
|
||||
|
||||
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), image, cardId, format, text, true, null);
|
||||
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Log.d(TAG, "Generating barcode for type " + formatType);
|
||||
BarcodeImageWriterTask task = new BarcodeImageWriterTask(getApplicationContext(), image, cardId, format, text, true, null);
|
||||
barcodeGeneratorTasks.add(task);
|
||||
task.execute();
|
||||
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), image, cardId, format, text, true, null);
|
||||
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
if (item.getItemId() == android.R.id.home)
|
||||
{
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
return true;
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.math.BigDecimal;
|
||||
@@ -21,7 +22,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
{
|
||||
public static final String DATABASE_NAME = "Catima.db";
|
||||
public static final int ORIGINAL_DATABASE_VERSION = 1;
|
||||
public static final int DATABASE_VERSION = 13;
|
||||
public static final int DATABASE_VERSION = 14;
|
||||
|
||||
public static class LoyaltyCardDbGroups
|
||||
{
|
||||
@@ -46,6 +47,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
public static final String BARCODE_TYPE = "barcodetype";
|
||||
public static final String STAR_STATUS = "starstatus";
|
||||
public static final String LAST_USED = "lastused";
|
||||
public static final String ZOOM_LEVEL = "zoomlevel";
|
||||
}
|
||||
|
||||
public static class LoyaltyCardDbIdsGroups
|
||||
@@ -105,7 +107,8 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
LoyaltyCardDbIds.BARCODE_ID + " TEXT," +
|
||||
LoyaltyCardDbIds.BARCODE_TYPE + " TEXT," +
|
||||
LoyaltyCardDbIds.STAR_STATUS + " INTEGER DEFAULT '0'," +
|
||||
LoyaltyCardDbIds.LAST_USED + " INTEGER DEFAULT '0')");
|
||||
LoyaltyCardDbIds.LAST_USED + " INTEGER DEFAULT '0', "+
|
||||
LoyaltyCardDbIds.ZOOM_LEVEL + " INTEGER DEFAULT '100' )");
|
||||
|
||||
// create associative table for cards in groups
|
||||
db.execSQL("CREATE TABLE " + LoyaltyCardDbIdsGroups.TABLE + "(" +
|
||||
@@ -119,6 +122,7 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
"tokenize=unicode61);");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
|
||||
{
|
||||
@@ -290,8 +294,10 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
cursor.moveToFirst();
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(cursor);
|
||||
insertFTS(db, loyaltyCard.id, loyaltyCard.store, loyaltyCard.note);
|
||||
int id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID));
|
||||
String store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE));
|
||||
String note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE));
|
||||
insertFTS(db, id, store, note);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,16 +308,25 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
Cursor cursor = db.rawQuery("SELECT * FROM " + LoyaltyCardDbIds.TABLE + ";", null, null);
|
||||
|
||||
if (cursor.moveToFirst()) {
|
||||
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(cursor);
|
||||
insertFTS(db, loyaltyCard.id, loyaltyCard.store, loyaltyCard.note);
|
||||
int id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID));
|
||||
String store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE));
|
||||
String note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE));
|
||||
insertFTS(db, id, store, note);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
loyaltyCard = LoyaltyCard.toLoyaltyCard(cursor);
|
||||
insertFTS(db, loyaltyCard.id, loyaltyCard.store, loyaltyCard.note);
|
||||
id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID));
|
||||
store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE));
|
||||
note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE));
|
||||
insertFTS(db, id, store, note);
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
if(oldVersion < 14 && newVersion >= 14){
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.ZOOM_LEVEL + " INTEGER DEFAULT '100' ");
|
||||
}
|
||||
}
|
||||
|
||||
private ContentValues generateFTSContentValues(final int id, final String store, final String note) {
|
||||
@@ -508,6 +523,18 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
return (rowsUpdated == 1);
|
||||
}
|
||||
|
||||
public boolean updateLoyaltyCardZoomLevel(int loyaltyCardId, int zoomLevel){
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(LoyaltyCardDbIds.ZOOM_LEVEL,zoomLevel);
|
||||
Log.d("updateLoyaltyCardZLevel","Card Id = "+loyaltyCardId+" Zoom level= "+zoomLevel);
|
||||
int rowsUpdated = db.update(LoyaltyCardDbIds.TABLE,contentValues,
|
||||
whereAttrs(LoyaltyCardDbIds.ID),
|
||||
withArgs(loyaltyCardId));
|
||||
Log.d("updateLoyaltyCardZLevel","Rows changed = "+rowsUpdated);
|
||||
return (rowsUpdated == 1);
|
||||
}
|
||||
|
||||
public LoyaltyCard getLoyaltyCard(final int id)
|
||||
{
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.util.Log;
|
||||
@@ -32,11 +31,12 @@ import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import protect.card_locker.async.TaskHandler;
|
||||
import protect.card_locker.importexport.DataFormat;
|
||||
import protect.card_locker.importexport.ImportExportResult;
|
||||
|
||||
public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
{
|
||||
public class ImportExportActivity extends CatimaAppCompatActivity {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
private static final int PERMISSIONS_EXTERNAL_STORAGE = 1;
|
||||
@@ -50,17 +50,17 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
private DataFormat importDataFormat;
|
||||
private String exportPassword;
|
||||
|
||||
final private TaskHandler mTasks = new TaskHandler();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(R.string.importExport);
|
||||
setContentView(R.layout.import_export_activity);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@@ -69,12 +69,11 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
|
||||
if (ContextCompat.checkSelfPermission(ImportExportActivity.this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
|
||||
ContextCompat.checkSelfPermission(ImportExportActivity.this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
ContextCompat.checkSelfPermission(ImportExportActivity.this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(ImportExportActivity.this,
|
||||
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
PERMISSIONS_EXTERNAL_STORAGE);
|
||||
}
|
||||
|
||||
@@ -85,16 +84,14 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
intentCreateDocumentAction.putExtra(Intent.EXTRA_TITLE, "catima.zip");
|
||||
|
||||
Button exportButton = findViewById(R.id.exportButton);
|
||||
exportButton.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
exportButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
public void onClick(View v) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ImportExportActivity.this);
|
||||
builder.setTitle(R.string.exportPassword);
|
||||
|
||||
FrameLayout container = new FrameLayout(ImportExportActivity.this);
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
params.leftMargin = 50;
|
||||
params.rightMargin = 50;
|
||||
|
||||
@@ -121,11 +118,9 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
intentGetContentAction.setType("*/*");
|
||||
|
||||
Button importFilesystem = findViewById(R.id.importOptionFilesystemButton);
|
||||
importFilesystem.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
importFilesystem.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
public void onClick(View v) {
|
||||
chooseImportType(intentGetContentAction);
|
||||
}
|
||||
});
|
||||
@@ -134,11 +129,9 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
final Intent intentPickAction = new Intent(Intent.ACTION_PICK);
|
||||
|
||||
Button importApplication = findViewById(R.id.importOptionApplicationButton);
|
||||
importApplication.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
importApplication.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
public void onClick(View v) {
|
||||
chooseImportType(intentPickAction);
|
||||
}
|
||||
});
|
||||
@@ -200,24 +193,22 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
.setTitle(importAlertTitle)
|
||||
.setMessage(importAlertMessage)
|
||||
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
chooseFileWithIntent(baseIntent, IMPORT);
|
||||
}
|
||||
})
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
chooseFileWithIntent(baseIntent, IMPORT);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void startImport(final InputStream target, final Uri targetUri, final DataFormat dataFormat, final char[] password, final boolean closeWhenDone)
|
||||
{
|
||||
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener()
|
||||
{
|
||||
private void startImport(final InputStream target, final Uri targetUri, final DataFormat dataFormat, final char[] password, final boolean closeWhenDone) {
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.IMPORT, true, false, false);
|
||||
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener() {
|
||||
@Override
|
||||
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat)
|
||||
{
|
||||
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat) {
|
||||
onImportComplete(result, targetUri, dataFormat);
|
||||
if (closeWhenDone) {
|
||||
try {
|
||||
@@ -231,13 +222,12 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
|
||||
importExporter = new ImportExportTask(ImportExportActivity.this,
|
||||
dataFormat, target, password, listener);
|
||||
importExporter.execute();
|
||||
mTasks.executeTask(TaskHandler.TYPE.IMPORT, importExporter);
|
||||
}
|
||||
|
||||
private void startExport(final OutputStream target, final Uri targetUri,char[] password, final boolean closeWhenDone)
|
||||
{
|
||||
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener()
|
||||
{
|
||||
private void startExport(final OutputStream target, final Uri targetUri, char[] password, final boolean closeWhenDone) {
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.EXPORT, true, false, false);
|
||||
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener() {
|
||||
@Override
|
||||
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat) {
|
||||
onExportComplete(result, targetUri);
|
||||
@@ -252,8 +242,8 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
};
|
||||
|
||||
importExporter = new ImportExportTask(ImportExportActivity.this,
|
||||
DataFormat.Catima, target,password, listener);
|
||||
importExporter.execute();
|
||||
DataFormat.Catima, target, password, listener);
|
||||
mTasks.executeTask(TaskHandler.TYPE.EXPORT, importExporter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -281,22 +271,17 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy()
|
||||
{
|
||||
if(importExporter != null && importExporter.getStatus() != AsyncTask.Status.RUNNING)
|
||||
{
|
||||
importExporter.cancel(true);
|
||||
}
|
||||
protected void onDestroy() {
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.IMPORT, true, false, false);
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.EXPORT, true, false, false);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
|
||||
if(id == android.R.id.home)
|
||||
{
|
||||
if (id == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
@@ -330,13 +315,10 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
|
||||
int messageId;
|
||||
|
||||
if (result == ImportExportResult.Success)
|
||||
{
|
||||
if (result == ImportExportResult.Success) {
|
||||
builder.setTitle(R.string.importSuccessfulTitle);
|
||||
messageId = R.string.importSuccessful;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
builder.setTitle(R.string.importFailedTitle);
|
||||
messageId = R.string.importFailed;
|
||||
}
|
||||
@@ -344,11 +326,9 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
final String message = getResources().getString(messageId);
|
||||
|
||||
builder.setMessage(message);
|
||||
builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener()
|
||||
{
|
||||
builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
@@ -356,19 +336,15 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
private void onExportComplete(ImportExportResult result, final Uri path)
|
||||
{
|
||||
private void onExportComplete(ImportExportResult result, final Uri path) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
|
||||
int messageId;
|
||||
|
||||
if(result == ImportExportResult.Success)
|
||||
{
|
||||
if (result == ImportExportResult.Success) {
|
||||
builder.setTitle(R.string.exportSuccessfulTitle);
|
||||
messageId = R.string.exportSuccessful;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
builder.setTitle(R.string.exportFailedTitle);
|
||||
messageId = R.string.exportFailed;
|
||||
}
|
||||
@@ -378,8 +354,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
builder.setMessage(message);
|
||||
builder.setNeutralButton(R.string.ok, (dialog, which) -> dialog.dismiss());
|
||||
|
||||
if(result == ImportExportResult.Success)
|
||||
{
|
||||
if (result == ImportExportResult.Success) {
|
||||
final CharSequence sendLabel = ImportExportActivity.this.getResources().getText(R.string.sendLabel);
|
||||
|
||||
builder.setPositiveButton(sendLabel, (dialog, which) -> {
|
||||
@@ -400,58 +375,42 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
private void chooseFileWithIntent(Intent intent, int requestCode)
|
||||
{
|
||||
try
|
||||
{
|
||||
private void chooseFileWithIntent(Intent intent, int requestCode) {
|
||||
try {
|
||||
startActivityForResult(intent, requestCode);
|
||||
}
|
||||
catch (ActivityNotFoundException e)
|
||||
{
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(getApplicationContext(), R.string.failedOpeningFileManager, Toast.LENGTH_LONG).show();
|
||||
Log.e(TAG, "No activity found to handle intent", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void activityResultParser(int requestCode, int resultCode, Uri uri, char[] password) {
|
||||
if (resultCode != RESULT_OK)
|
||||
{
|
||||
if (resultCode != RESULT_OK) {
|
||||
Log.w(TAG, "Failed onActivityResult(), result=" + resultCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if(uri == null)
|
||||
{
|
||||
if (uri == null) {
|
||||
Log.e(TAG, "Activity returned a NULL URI");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (requestCode == CHOOSE_EXPORT_LOCATION)
|
||||
{
|
||||
try {
|
||||
if (requestCode == CHOOSE_EXPORT_LOCATION) {
|
||||
|
||||
OutputStream writer;
|
||||
if (uri.getScheme() != null)
|
||||
{
|
||||
if (uri.getScheme() != null) {
|
||||
writer = getContentResolver().openOutputStream(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
writer = new FileOutputStream(new File(uri.toString()));
|
||||
}
|
||||
Log.e(TAG, "Starting file export with: " + uri.toString());
|
||||
startExport(writer, uri,exportPassword.toCharArray(),true);
|
||||
}
|
||||
else
|
||||
{
|
||||
startExport(writer, uri, exportPassword.toCharArray(), true);
|
||||
} else {
|
||||
InputStream reader;
|
||||
if(uri.getScheme() != null)
|
||||
{
|
||||
if (uri.getScheme() != null) {
|
||||
reader = getContentResolver().openInputStream(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
reader = new FileInputStream(new File(uri.toString()));
|
||||
}
|
||||
|
||||
@@ -459,28 +418,21 @@ public class ImportExportActivity extends CatimaAppCompatActivity
|
||||
|
||||
startImport(reader, uri, importDataFormat, password, true);
|
||||
}
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to import/export file: " + uri.toString(), e);
|
||||
if (requestCode == CHOOSE_EXPORT_LOCATION)
|
||||
{
|
||||
if (requestCode == CHOOSE_EXPORT_LOCATION) {
|
||||
onExportComplete(ImportExportResult.GenericFailure, uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
onImportComplete(ImportExportResult.GenericFailure, uri, importDataFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if(data == null)
|
||||
{
|
||||
if (data == null) {
|
||||
Log.e(TAG, "Activity returned NULL data");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -13,13 +12,13 @@ import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import protect.card_locker.async.CompatCallable;
|
||||
import protect.card_locker.importexport.DataFormat;
|
||||
import protect.card_locker.importexport.ImportExportResult;
|
||||
import protect.card_locker.importexport.MultiFormatExporter;
|
||||
import protect.card_locker.importexport.MultiFormatImporter;
|
||||
|
||||
class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
{
|
||||
public class ImportExportTask implements CompatCallable<ImportExportResult> {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
private Activity activity;
|
||||
@@ -35,9 +34,8 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
/**
|
||||
* Constructor which will setup a task for exporting to the given file
|
||||
*/
|
||||
ImportExportTask(Activity activity, DataFormat format, OutputStream output,char[] password,
|
||||
TaskCompleteListener listener)
|
||||
{
|
||||
ImportExportTask(Activity activity, DataFormat format, OutputStream output, char[] password,
|
||||
TaskCompleteListener listener) {
|
||||
super();
|
||||
this.activity = activity;
|
||||
this.doImport = false;
|
||||
@@ -51,8 +49,7 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
* Constructor which will setup a task for importing from the given InputStream.
|
||||
*/
|
||||
ImportExportTask(Activity activity, DataFormat format, InputStream input, char[] password,
|
||||
TaskCompleteListener listener)
|
||||
{
|
||||
TaskCompleteListener listener) {
|
||||
super();
|
||||
this.activity = activity;
|
||||
this.doImport = true;
|
||||
@@ -62,8 +59,7 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
private ImportExportResult performImport(Context context, InputStream stream, DBHelper db, char[] password)
|
||||
{
|
||||
private ImportExportResult performImport(Context context, InputStream stream, DBHelper db, char[] password) {
|
||||
ImportExportResult importResult = MultiFormatImporter.importData(context, db, stream, format, password);
|
||||
|
||||
Log.i(TAG, "Import result: " + importResult.name());
|
||||
@@ -71,18 +67,14 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
return importResult;
|
||||
}
|
||||
|
||||
private ImportExportResult performExport(Context context, OutputStream stream, DBHelper db,char[] password)
|
||||
{
|
||||
private ImportExportResult performExport(Context context, OutputStream stream, DBHelper db, char[] password) {
|
||||
ImportExportResult result = ImportExportResult.GenericFailure;
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8);
|
||||
result = MultiFormatExporter.exportData(context, db, stream, format,password);
|
||||
result = MultiFormatExporter.exportData(context, db, stream, format, password);
|
||||
writer.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to export file", e);
|
||||
}
|
||||
|
||||
@@ -91,55 +83,55 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void onPreExecute()
|
||||
{
|
||||
public void onPreExecute() {
|
||||
progress = new ProgressDialog(activity);
|
||||
progress.setTitle(doImport ? R.string.importing : R.string.exporting);
|
||||
|
||||
progress.setOnDismissListener(new DialogInterface.OnDismissListener()
|
||||
{
|
||||
progress.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog)
|
||||
{
|
||||
ImportExportTask.this.cancel(true);
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
ImportExportTask.this.stop();
|
||||
}
|
||||
});
|
||||
|
||||
progress.show();
|
||||
}
|
||||
|
||||
protected ImportExportResult doInBackground(Void... nothing)
|
||||
{
|
||||
protected ImportExportResult doInBackground(Void... nothing) {
|
||||
final DBHelper db = new DBHelper(activity);
|
||||
ImportExportResult result;
|
||||
|
||||
if(doImport)
|
||||
{
|
||||
if (doImport) {
|
||||
result = performImport(activity.getApplicationContext(), inputStream, db, password);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = performExport(activity.getApplicationContext(), outputStream, db,password);
|
||||
} else {
|
||||
result = performExport(activity.getApplicationContext(), outputStream, db, password);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void onPostExecute(ImportExportResult result)
|
||||
{
|
||||
listener.onTaskComplete(result, format);
|
||||
public void onPostExecute(Object castResult) {
|
||||
listener.onTaskComplete((ImportExportResult) castResult, format);
|
||||
|
||||
progress.dismiss();
|
||||
Log.i(TAG, (doImport ? "Import" : "Export") + " Complete");
|
||||
}
|
||||
|
||||
protected void onCancelled()
|
||||
{
|
||||
protected void onCancelled() {
|
||||
progress.dismiss();
|
||||
Log.i(TAG, (doImport ? "Import" : "Export") + " Cancelled");
|
||||
}
|
||||
interface TaskCompleteListener
|
||||
{
|
||||
|
||||
protected void stop() {
|
||||
// Whelp
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportExportResult call() {
|
||||
return doInBackground();
|
||||
}
|
||||
|
||||
interface TaskCompleteListener {
|
||||
void onTaskComplete(ImportExportResult result, DataFormat format);
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ public class ImportURIHelper {
|
||||
headerColor = Integer.parseInt(unparsedHeaderColor);
|
||||
}
|
||||
|
||||
return new LoyaltyCard(-1, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, 0, Utils.getUnixTime());
|
||||
return new LoyaltyCard(-1, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, 0, Utils.getUnixTime(),100);
|
||||
} catch (NullPointerException | NumberFormatException | UnsupportedEncodingException ex) {
|
||||
throw new InvalidObjectException("Not a valid import URI");
|
||||
}
|
||||
|
||||
@@ -30,11 +30,12 @@ public class LoyaltyCard implements Parcelable {
|
||||
|
||||
public final int starStatus;
|
||||
public final long lastUsed;
|
||||
public int zoomLevel;
|
||||
|
||||
public LoyaltyCard(final int id, final String store, final String note, final Date expiry,
|
||||
final BigDecimal balance, final Currency balanceType, final String cardId,
|
||||
@Nullable final String barcodeId, @Nullable final CatimaBarcode barcodeType,
|
||||
@Nullable final Integer headerColor, final int starStatus, final long lastUsed)
|
||||
@Nullable final Integer headerColor, final int starStatus, final long lastUsed,final int zoomLevel)
|
||||
{
|
||||
this.id = id;
|
||||
this.store = store;
|
||||
@@ -48,6 +49,7 @@ public class LoyaltyCard implements Parcelable {
|
||||
this.headerColor = headerColor;
|
||||
this.starStatus = starStatus;
|
||||
this.lastUsed = lastUsed;
|
||||
this.zoomLevel = zoomLevel;
|
||||
}
|
||||
|
||||
protected LoyaltyCard(Parcel in) {
|
||||
@@ -66,6 +68,7 @@ public class LoyaltyCard implements Parcelable {
|
||||
headerColor = tmpHeaderColor != -1 ? tmpHeaderColor : null;
|
||||
starStatus = in.readInt();
|
||||
lastUsed = in.readLong();
|
||||
zoomLevel = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,6 +85,7 @@ public class LoyaltyCard implements Parcelable {
|
||||
parcel.writeInt(headerColor != null ? headerColor : -1);
|
||||
parcel.writeInt(starStatus);
|
||||
parcel.writeLong(lastUsed);
|
||||
parcel.writeInt(zoomLevel);
|
||||
}
|
||||
|
||||
public static LoyaltyCard toLoyaltyCard(Cursor cursor)
|
||||
@@ -95,6 +99,7 @@ public class LoyaltyCard implements Parcelable {
|
||||
String barcodeId = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_ID));
|
||||
int starred = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STAR_STATUS));
|
||||
long lastUsed = cursor.getLong(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.LAST_USED));
|
||||
int zoomLevel = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ZOOM_LEVEL));
|
||||
|
||||
int barcodeTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_TYPE);
|
||||
int balanceTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BALANCE_TYPE);
|
||||
@@ -125,7 +130,7 @@ public class LoyaltyCard implements Parcelable {
|
||||
headerColor = cursor.getInt(headerColorColumn);
|
||||
}
|
||||
|
||||
return new LoyaltyCard(id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starred, lastUsed);
|
||||
return new LoyaltyCard(id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starred, lastUsed,zoomLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -21,11 +22,13 @@ import java.math.BigDecimal;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.core.graphics.BlendModeColorFilterCompat;
|
||||
import androidx.core.graphics.BlendModeCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import protect.card_locker.preferences.Settings;
|
||||
|
||||
public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder>
|
||||
{
|
||||
public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder> {
|
||||
private int mCurrentSelectedIndex = -1;
|
||||
private Cursor mCursor;
|
||||
Settings mSettings;
|
||||
@@ -36,8 +39,7 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
private SparseBooleanArray mAnimationItemsIndex;
|
||||
private boolean mReverseAllAnimations = false;
|
||||
|
||||
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener)
|
||||
{
|
||||
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener) {
|
||||
super(inputCursor);
|
||||
setHasStableIds(true);
|
||||
mSettings = new Settings(inputContext);
|
||||
@@ -58,14 +60,12 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoyaltyCardListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType)
|
||||
{
|
||||
public LoyaltyCardListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType) {
|
||||
View itemView = LayoutInflater.from(inputParent.getContext()).inflate(R.layout.loyalty_card_layout, inputParent, false);
|
||||
return new LoyaltyCardListItemViewHolder(itemView, mListener);
|
||||
}
|
||||
|
||||
public Cursor getCursor()
|
||||
{
|
||||
public Cursor getCursor() {
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
@@ -73,8 +73,10 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
// Invisible until we want to show something more
|
||||
inputHolder.mDivider.setVisibility(View.GONE);
|
||||
|
||||
int size = mSettings.getFontSizeMax(mSettings.getSmallFont());
|
||||
|
||||
if (mDarkModeEnabled) {
|
||||
inputHolder.mStarIcon.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
|
||||
inputHolder.mStarIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP));
|
||||
}
|
||||
|
||||
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(inputCursor);
|
||||
@@ -84,49 +86,86 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
if (!loyaltyCard.note.isEmpty()) {
|
||||
inputHolder.mNoteField.setVisibility(View.VISIBLE);
|
||||
inputHolder.mNoteField.setText(loyaltyCard.note);
|
||||
inputHolder.mNoteField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
|
||||
inputHolder.mNoteField.setTextSize(size);
|
||||
} else {
|
||||
inputHolder.mNoteField.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (!loyaltyCard.balance.equals(new BigDecimal("0"))) {
|
||||
int drawableSize = dpToPx((size*24)/14, mContext);
|
||||
inputHolder.mDivider.setVisibility(View.VISIBLE);
|
||||
inputHolder.mBalanceField.setVisibility(View.VISIBLE);
|
||||
Drawable balanceIcon = inputHolder.mBalanceField.getCompoundDrawables()[0];
|
||||
balanceIcon.setBounds(0,0,drawableSize,drawableSize);
|
||||
inputHolder.mBalanceField.setCompoundDrawablesRelative(balanceIcon, null, null, null);
|
||||
if (mDarkModeEnabled) {
|
||||
inputHolder.mBalanceField.getCompoundDrawables()[0].setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
|
||||
balanceIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP));
|
||||
}
|
||||
inputHolder.mBalanceField.setText(Utils.formatBalance(mContext, loyaltyCard.balance, loyaltyCard.balanceType));
|
||||
inputHolder.mBalanceField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
|
||||
inputHolder.mBalanceField.setTextSize(size);
|
||||
} else {
|
||||
inputHolder.mBalanceField.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (loyaltyCard.expiry != null) {
|
||||
int drawableSize = dpToPx((size*24)/14, mContext);
|
||||
inputHolder.mDivider.setVisibility(View.VISIBLE);
|
||||
inputHolder.mExpiryField.setVisibility(View.VISIBLE);
|
||||
Drawable expiryIcon = inputHolder.mExpiryField.getCompoundDrawables()[0];
|
||||
expiryIcon.setBounds(0,0, drawableSize, drawableSize);
|
||||
inputHolder.mExpiryField.setCompoundDrawablesRelative(expiryIcon, null, null, null);
|
||||
if (Utils.hasExpired(loyaltyCard.expiry)) {
|
||||
expiryIcon.setColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP);
|
||||
expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.RED, BlendModeCompat.SRC_ATOP));
|
||||
inputHolder.mExpiryField.setTextColor(Color.RED);
|
||||
} else if (mDarkModeEnabled) {
|
||||
expiryIcon.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
|
||||
expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP));
|
||||
}
|
||||
inputHolder.mExpiryField.setText(DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.expiry));
|
||||
inputHolder.mExpiryField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
|
||||
inputHolder.mExpiryField.setTextSize(size);
|
||||
} else {
|
||||
inputHolder.mExpiryField.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
inputHolder.mStarIcon.setVisibility(loyaltyCard.starStatus != 0 ? View.VISIBLE : View.GONE);
|
||||
inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, loyaltyCard.store, loyaltyCard.headerColor).getLetterTile());
|
||||
int imageSize = dpToPx( (size*46)/14, mContext);
|
||||
inputHolder.mCardIcon.getLayoutParams().height = imageSize;
|
||||
inputHolder.mCardIcon.getLayoutParams().width = imageSize;
|
||||
inputHolder.mStarIcon.getLayoutParams().height = imageSize;
|
||||
inputHolder.mStarIcon.getLayoutParams().width = imageSize;
|
||||
inputHolder.mTickIcon.getLayoutParams().height = imageSize;
|
||||
inputHolder.mTickIcon.getLayoutParams().width = imageSize;
|
||||
|
||||
/* Changing Padding and Mragin of different views according to font size
|
||||
* Views Included:
|
||||
* a) InformationContainer padding
|
||||
* b) Store left padding
|
||||
* c) Divider Margin
|
||||
* d) note top margin
|
||||
* e) row margin
|
||||
* */
|
||||
int marginPaddingSize = dpToPx((size*16)/14, mContext );
|
||||
inputHolder.mInformationContainer.setPadding(marginPaddingSize, marginPaddingSize, marginPaddingSize, marginPaddingSize);
|
||||
inputHolder.mStoreField.setPadding(marginPaddingSize, 0, 0, 0);
|
||||
LinearLayout.LayoutParams lpDivider = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT );
|
||||
lpDivider.setMargins(0, marginPaddingSize, 0, marginPaddingSize);
|
||||
inputHolder.mDivider.setLayoutParams(lpDivider);
|
||||
LinearLayout.LayoutParams lpNoteField = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT );
|
||||
lpNoteField.setMargins(0, marginPaddingSize/2, 0, 0);
|
||||
inputHolder.mNoteField.setLayoutParams(lpNoteField);
|
||||
LinearLayout.LayoutParams lpRow = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT );
|
||||
lpRow.setMargins(marginPaddingSize/2, marginPaddingSize/2, marginPaddingSize/2, marginPaddingSize/2);
|
||||
inputHolder.mRow.setLayoutParams(lpRow);
|
||||
|
||||
inputHolder.itemView.setActivated(mSelectedItems.get(inputCursor.getPosition(), false));
|
||||
applyIconAnimation(inputHolder, inputCursor.getPosition());
|
||||
applyClickEvents(inputHolder, inputCursor.getPosition());
|
||||
}
|
||||
|
||||
private void applyClickEvents(LoyaltyCardListItemViewHolder inputHolder, final int inputPosition)
|
||||
{
|
||||
private void applyClickEvents(LoyaltyCardListItemViewHolder inputHolder, final int inputPosition) {
|
||||
inputHolder.mRow.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition));
|
||||
inputHolder.mInformationContainer.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition));
|
||||
|
||||
@@ -143,85 +182,68 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
});
|
||||
}
|
||||
|
||||
private void applyIconAnimation(LoyaltyCardListItemViewHolder inputHolder, int inputPosition)
|
||||
{
|
||||
if (mSelectedItems.get(inputPosition, false))
|
||||
{
|
||||
private void applyIconAnimation(LoyaltyCardListItemViewHolder inputHolder, int inputPosition) {
|
||||
if (mSelectedItems.get(inputPosition, false)) {
|
||||
inputHolder.mThumbnailFrontContainer.setVisibility(View.GONE);
|
||||
resetIconYAxis(inputHolder.mThumbnailBackContainer);
|
||||
inputHolder.mThumbnailBackContainer.setVisibility(View.VISIBLE);
|
||||
inputHolder.mThumbnailBackContainer.setAlpha(1);
|
||||
if (mCurrentSelectedIndex == inputPosition)
|
||||
{
|
||||
if (mCurrentSelectedIndex == inputPosition) {
|
||||
LoyaltyCardAnimator.flipView(mContext, inputHolder.mThumbnailBackContainer, inputHolder.mThumbnailFrontContainer, true);
|
||||
resetCurrentIndex();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
inputHolder.mThumbnailBackContainer.setVisibility(View.GONE);
|
||||
resetIconYAxis(inputHolder.mThumbnailFrontContainer);
|
||||
inputHolder.mThumbnailFrontContainer.setVisibility(View.VISIBLE);
|
||||
inputHolder.mThumbnailFrontContainer.setAlpha(1);
|
||||
if ((mReverseAllAnimations && mAnimationItemsIndex.get(inputPosition, false)) || mCurrentSelectedIndex == inputPosition)
|
||||
{
|
||||
if ((mReverseAllAnimations && mAnimationItemsIndex.get(inputPosition, false)) || mCurrentSelectedIndex == inputPosition) {
|
||||
LoyaltyCardAnimator.flipView(mContext, inputHolder.mThumbnailBackContainer, inputHolder.mThumbnailFrontContainer, false);
|
||||
resetCurrentIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resetIconYAxis(View inputView)
|
||||
{
|
||||
if (inputView.getRotationY() != 0)
|
||||
{
|
||||
private void resetIconYAxis(View inputView) {
|
||||
if (inputView.getRotationY() != 0) {
|
||||
inputView.setRotationY(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetAnimationIndex()
|
||||
{
|
||||
public void resetAnimationIndex() {
|
||||
mReverseAllAnimations = false;
|
||||
mAnimationItemsIndex.clear();
|
||||
}
|
||||
|
||||
|
||||
public void toggleSelection(int inputPosition)
|
||||
{
|
||||
public void toggleSelection(int inputPosition) {
|
||||
mCurrentSelectedIndex = inputPosition;
|
||||
if (mSelectedItems.get(inputPosition, false))
|
||||
{
|
||||
if (mSelectedItems.get(inputPosition, false)) {
|
||||
mSelectedItems.delete(inputPosition);
|
||||
mAnimationItemsIndex.delete(inputPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
mSelectedItems.put(inputPosition, true);
|
||||
mAnimationItemsIndex.put(inputPosition, true);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void clearSelections()
|
||||
{
|
||||
public void clearSelections() {
|
||||
mReverseAllAnimations = true;
|
||||
mSelectedItems.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public int getSelectedItemCount()
|
||||
{
|
||||
public int getSelectedItemCount() {
|
||||
return mSelectedItems.size();
|
||||
}
|
||||
|
||||
public ArrayList<LoyaltyCard> getSelectedItems()
|
||||
{
|
||||
public ArrayList<LoyaltyCard> getSelectedItems() {
|
||||
|
||||
ArrayList<LoyaltyCard> result = new ArrayList<>();
|
||||
|
||||
int i;
|
||||
for(i = 0; i < mSelectedItems.size(); i++)
|
||||
{
|
||||
for (i = 0; i < mSelectedItems.size(); i++) {
|
||||
mCursor.moveToPosition(mSelectedItems.keyAt(i));
|
||||
result.add(LoyaltyCard.toLoyaltyCard(mCursor));
|
||||
}
|
||||
@@ -229,29 +251,26 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
return result;
|
||||
}
|
||||
|
||||
private void resetCurrentIndex()
|
||||
{
|
||||
private void resetCurrentIndex() {
|
||||
mCurrentSelectedIndex = -1;
|
||||
}
|
||||
|
||||
public interface CardAdapterListener
|
||||
{
|
||||
public interface CardAdapterListener {
|
||||
void onRowClicked(int inputPosition);
|
||||
|
||||
void onRowLongClicked(int inputPosition);
|
||||
}
|
||||
|
||||
public static class LoyaltyCardListItemViewHolder extends RecyclerView.ViewHolder
|
||||
{
|
||||
public static class LoyaltyCardListItemViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public TextView mStoreField, mNoteField, mBalanceField, mExpiryField;
|
||||
public LinearLayout mInformationContainer;
|
||||
public ImageView mCardIcon, mStarIcon;
|
||||
public ImageView mCardIcon, mStarIcon, mTickIcon;
|
||||
public MaterialCardView mRow;
|
||||
public View mDivider;
|
||||
public RelativeLayout mThumbnailFrontContainer, mThumbnailBackContainer;
|
||||
|
||||
public LoyaltyCardListItemViewHolder(View inputView, CardAdapterListener inputListener)
|
||||
{
|
||||
public LoyaltyCardListItemViewHolder(View inputView, CardAdapterListener inputListener) {
|
||||
super(inputView);
|
||||
mRow = inputView.findViewById(R.id.row);
|
||||
mDivider = inputView.findViewById(R.id.info_divider);
|
||||
@@ -264,6 +283,7 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
mExpiryField = inputView.findViewById(R.id.expiry);
|
||||
mCardIcon = inputView.findViewById(R.id.thumbnail);
|
||||
mStarIcon = inputView.findViewById(R.id.star);
|
||||
mTickIcon = inputView.findViewById(R.id.selected_thumbnail);
|
||||
inputView.setOnLongClickListener(view -> {
|
||||
inputListener.onRowClicked(getAdapterPosition());
|
||||
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
@@ -271,4 +291,10 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int dpToPx(int dp, Context mContext){
|
||||
Resources r = mContext.getResources();
|
||||
int px = (int)TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());
|
||||
return px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ import com.google.android.material.chip.ChipGroup;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.jaredrummler.android.colorpicker.ColorPickerDialog;
|
||||
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;
|
||||
|
||||
@@ -72,8 +71,9 @@ import androidx.core.content.FileProvider;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
{
|
||||
import protect.card_locker.async.TaskHandler;
|
||||
|
||||
public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
private final String STATE_TAB_INDEX = "savedTab";
|
||||
@@ -141,6 +141,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
|
||||
LoyaltyCard tempLoyaltyCard;
|
||||
|
||||
final private TaskHandler mTasks = new TaskHandler();
|
||||
|
||||
private static LoyaltyCard updateTempState(LoyaltyCard loyaltyCard, LoyaltyCardField fieldName, Object value) {
|
||||
return new LoyaltyCard(
|
||||
(int) (fieldName == LoyaltyCardField.id ? value : loyaltyCard.id),
|
||||
@@ -154,7 +156,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
(CatimaBarcode) (fieldName == LoyaltyCardField.barcodeType ? value : loyaltyCard.barcodeType),
|
||||
(Integer) (fieldName == LoyaltyCardField.headerColor ? value : loyaltyCard.headerColor),
|
||||
(int) (fieldName == LoyaltyCardField.starStatus ? value : loyaltyCard.starStatus),
|
||||
Utils.getUnixTime()
|
||||
Utils.getUnixTime(),100
|
||||
);
|
||||
}
|
||||
|
||||
@@ -164,8 +166,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
hasChanged = true;
|
||||
}
|
||||
|
||||
private void extractIntentFields(Intent intent)
|
||||
{
|
||||
private void extractIntentFields(Intent intent) {
|
||||
final Bundle b = intent.getExtras();
|
||||
loyaltyCardId = b != null ? b.getInt(BUNDLE_ID) : 0;
|
||||
updateLoyaltyCard = b != null && b.getBoolean(BUNDLE_UPDATE, false);
|
||||
@@ -205,8 +206,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@@ -416,7 +416,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
} else if (s.toString().equals(getString(R.string.setBarcodeId))) {
|
||||
if (!lastValue.toString().equals(getString(R.string.setBarcodeId))) {
|
||||
barcodeIdField.setText(lastValue);
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(LoyaltyCardEditActivity.this);
|
||||
builder.setTitle(R.string.setBarcodeId);
|
||||
@@ -471,7 +472,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
if (!barcodeFormat.isSupported()) {
|
||||
Toast.makeText(LoyaltyCardEditActivity.this, getString(R.string.unsupportedBarcodeType), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
} catch (IllegalArgumentException e) {}
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
|
||||
generateOrHideBarcode();
|
||||
@@ -510,8 +512,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent)
|
||||
{
|
||||
public void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
Log.i(TAG, "Received new intent");
|
||||
@@ -520,15 +521,14 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
Log.i(TAG, "To view card: " + loyaltyCardId);
|
||||
|
||||
onResuming = true;
|
||||
|
||||
if(tempLoyaltyCard == null) {
|
||||
if (tempLoyaltyCard == null) {
|
||||
if (updateLoyaltyCard) {
|
||||
tempLoyaltyCard = db.getLoyaltyCard(loyaltyCardId);
|
||||
if (tempLoyaltyCard == null) {
|
||||
@@ -551,7 +551,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
setTitle(R.string.addCardTitle);
|
||||
} else {
|
||||
// New card, use default values
|
||||
tempLoyaltyCard = new LoyaltyCard(-1, "", "", null, new BigDecimal("0"), null, "", null, null, null, 0, Utils.getUnixTime());
|
||||
tempLoyaltyCard = new LoyaltyCard(-1, "", "", null, new BigDecimal("0"), null, "", null, null, null, 0, Utils.getUnixTime(),100);
|
||||
setTitle(R.string.addCardTitle);
|
||||
}
|
||||
}
|
||||
@@ -564,8 +564,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
barcodeIdField.setText(tempLoyaltyCard.barcodeId != null ? tempLoyaltyCard.barcodeId : getString(R.string.sameAsCardId));
|
||||
barcodeTypeField.setText(tempLoyaltyCard.barcodeType != null ? tempLoyaltyCard.barcodeType.prettyName() : getString(R.string.noBarcode));
|
||||
|
||||
if(groupsChips.getChildCount() == 0)
|
||||
{
|
||||
if (groupsChips.getChildCount() == 0) {
|
||||
List<Group> existingGroups = db.getGroups();
|
||||
|
||||
List<Group> loyaltyCardGroups = db.getLoyaltyCardGroups(loyaltyCardId);
|
||||
@@ -604,18 +603,17 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
}
|
||||
|
||||
// Generate random header color
|
||||
if(tempLoyaltyCard.headerColor == null)
|
||||
{
|
||||
if (tempLoyaltyCard.headerColor == null) {
|
||||
// Select a random color to start out with.
|
||||
TypedArray colors = getResources().obtainTypedArray(R.array.letter_tile_colors);
|
||||
final int color = (int)(Math.random() * colors.length());
|
||||
final int color = (int) (Math.random() * colors.length());
|
||||
updateTempState(LoyaltyCardField.headerColor, colors.getColor(color, Color.BLACK));
|
||||
colors.recycle();
|
||||
}
|
||||
|
||||
// It can't be null because we set it in updateTempState but SpotBugs insists it can be
|
||||
// NP_NULL_ON_SOME_PATH: Possible null pointer dereference
|
||||
if(tempLoyaltyCard.headerColor != null) {
|
||||
if (tempLoyaltyCard.headerColor != null) {
|
||||
thumbnail.setOnClickListener(new ColorSelectListener());
|
||||
}
|
||||
|
||||
@@ -806,11 +804,9 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
startActivityForResult(i, type);
|
||||
}
|
||||
|
||||
class EditCardIdAndBarcode implements View.OnClickListener
|
||||
{
|
||||
class EditCardIdAndBarcode implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
public void onClick(View v) {
|
||||
Intent i = new Intent(getApplicationContext(), ScanActivity.class);
|
||||
final Bundle b = new Bundle();
|
||||
b.putString(LoyaltyCardEditActivity.BUNDLE_CARDID, cardIdFieldView.getText().toString());
|
||||
@@ -819,11 +815,9 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
}
|
||||
}
|
||||
|
||||
class ChooseCardImage implements View.OnClickListener
|
||||
{
|
||||
class ChooseCardImage implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick(View v) throws NoSuchElementException
|
||||
{
|
||||
public void onClick(View v) throws NoSuchElementException {
|
||||
ImageView targetView = v.getId() == ID_IMAGE_FRONT ? cardImageFront : cardImageBack;
|
||||
|
||||
LinkedHashMap<String, Callable<Void>> cardOptions = new LinkedHashMap<>();
|
||||
@@ -870,11 +864,9 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
}
|
||||
}
|
||||
|
||||
class ColorSelectListener implements View.OnClickListener
|
||||
{
|
||||
class ColorSelectListener implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
public void onClick(View v) {
|
||||
ColorPickerDialog.Builder dialogBuilder = ColorPickerDialog.newBuilder();
|
||||
|
||||
if (tempLoyaltyCard.headerColor != null) {
|
||||
@@ -882,19 +874,16 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
}
|
||||
|
||||
ColorPickerDialog dialog = dialogBuilder.create();
|
||||
dialog.setColorPickerDialogListener(new ColorPickerDialogListener()
|
||||
{
|
||||
dialog.setColorPickerDialogListener(new ColorPickerDialogListener() {
|
||||
@Override
|
||||
public void onColorSelected(int dialogId, int color)
|
||||
{
|
||||
public void onColorSelected(int dialogId, int color) {
|
||||
updateTempState(LoyaltyCardField.headerColor, color);
|
||||
|
||||
generateIcon(storeFieldEdit.getText().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogDismissed(int dialogId)
|
||||
{
|
||||
public void onDialogDismissed(int dialogId) {
|
||||
// Nothing to do, no change made
|
||||
}
|
||||
});
|
||||
@@ -955,20 +944,17 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
return;
|
||||
}
|
||||
|
||||
if(tempLoyaltyCard.store.isEmpty())
|
||||
{
|
||||
if (tempLoyaltyCard.store.isEmpty()) {
|
||||
Snackbar.make(storeFieldEdit, R.string.noStoreError, Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if(tempLoyaltyCard.cardId.isEmpty())
|
||||
{
|
||||
if (tempLoyaltyCard.cardId.isEmpty()) {
|
||||
Snackbar.make(cardIdFieldView, R.string.noCardIdError, Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!validBalance)
|
||||
{
|
||||
if (!validBalance) {
|
||||
Snackbar.make(balanceField, getString(R.string.parsingBalanceFailed, balanceField.getText().toString()), Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
@@ -980,8 +966,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
selectedGroups.add((Group) chip.getTag());
|
||||
}
|
||||
|
||||
if(updateLoyaltyCard)
|
||||
{ //update of "starStatus" not necessary, since it cannot be changed in this activity (only in ViewActivity)
|
||||
if (updateLoyaltyCard) { //update of "starStatus" not necessary, since it cannot be changed in this activity (only in ViewActivity)
|
||||
db.updateLoyaltyCard(loyaltyCardId, tempLoyaltyCard.store, tempLoyaltyCard.note, tempLoyaltyCard.expiry, tempLoyaltyCard.balance, tempLoyaltyCard.balanceType, tempLoyaltyCard.cardId, tempLoyaltyCard.barcodeId, tempLoyaltyCard.barcodeType, tempLoyaltyCard.headerColor);
|
||||
try {
|
||||
Utils.saveCardImage(this, (Bitmap) cardImageFront.getTag(), loyaltyCardId, true);
|
||||
@@ -990,9 +975,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
e.printStackTrace();
|
||||
}
|
||||
Log.i(TAG, "Updated " + loyaltyCardId + " to " + cardId);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
loyaltyCardId = (int) db.insertLoyaltyCard(tempLoyaltyCard.store, tempLoyaltyCard.note, tempLoyaltyCard.expiry, tempLoyaltyCard.balance, tempLoyaltyCard.balanceType, tempLoyaltyCard.cardId, tempLoyaltyCard.barcodeId, tempLoyaltyCard.barcodeType, tempLoyaltyCard.headerColor, 0, tempLoyaltyCard.lastUsed);
|
||||
try {
|
||||
Utils.saveCardImage(this, (Bitmap) cardImageFront.getTag(), loyaltyCardId, true);
|
||||
@@ -1008,14 +991,10 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
if(updateLoyaltyCard)
|
||||
{
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
if (updateLoyaltyCard) {
|
||||
getMenuInflater().inflate(R.menu.card_update_menu, menu);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
getMenuInflater().inflate(R.menu.card_add_menu, menu);
|
||||
}
|
||||
|
||||
@@ -1023,12 +1002,10 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
|
||||
switch(id)
|
||||
{
|
||||
switch (id) {
|
||||
case android.R.id.home:
|
||||
askBeforeQuitIfChanged();
|
||||
break;
|
||||
@@ -1059,8 +1036,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent)
|
||||
{
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
|
||||
if (resultCode == RESULT_OK) {
|
||||
@@ -1143,6 +1119,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
}
|
||||
|
||||
private void generateBarcode(String cardIdString, CatimaBarcode barcodeFormat) {
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.BARCODE, true, false, false);
|
||||
|
||||
if (barcodeImage.getHeight() == 0) {
|
||||
Log.d(TAG, "ImageView size is not known known at start, waiting for load");
|
||||
// The size of the ImageView is not yet available as it has not
|
||||
@@ -1154,12 +1132,14 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity
|
||||
barcodeImage.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
|
||||
Log.d(TAG, "ImageView size now known");
|
||||
new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, warnOnInvalidBarcodeType).execute();
|
||||
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, warnOnInvalidBarcodeType);
|
||||
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Log.d(TAG, "ImageView size known known, creating barcode");
|
||||
new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, warnOnInvalidBarcodeType).execute();
|
||||
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, warnOnInvalidBarcodeType);
|
||||
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
|
||||
}
|
||||
|
||||
showBarcode();
|
||||
|
||||
@@ -30,7 +30,6 @@ import android.widget.Toast;
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
@@ -48,10 +47,11 @@ import androidx.constraintlayout.widget.Guideline;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import androidx.core.widget.TextViewCompat;
|
||||
|
||||
import protect.card_locker.async.TaskHandler;
|
||||
import protect.card_locker.preferences.Settings;
|
||||
|
||||
public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements GestureDetector.OnGestureListener
|
||||
{
|
||||
public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements GestureDetector.OnGestureListener {
|
||||
private static final String TAG = "Catima";
|
||||
|
||||
private GestureDetector mGestureDetector;
|
||||
@@ -102,6 +102,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
static final String STATE_IMAGEINDEX = "imageIndex";
|
||||
static final String STATE_FULLSCREEN = "isFullscreen";
|
||||
|
||||
final private TaskHandler mTasks = new TaskHandler();
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
return true;
|
||||
@@ -182,8 +184,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
IMAGE_BACK
|
||||
}
|
||||
|
||||
private void extractIntentFields(Intent intent)
|
||||
{
|
||||
private void extractIntentFields(Intent intent) {
|
||||
final Bundle b = intent.getExtras();
|
||||
loyaltyCardId = b != null ? b.getInt("id") : 0;
|
||||
Log.d(TAG, "View activity: id=" + loyaltyCardId);
|
||||
@@ -198,17 +199,13 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
return wrappedIcon;
|
||||
}
|
||||
|
||||
private Drawable getIcon(int icon, boolean dark)
|
||||
{
|
||||
private Drawable getIcon(int icon, boolean dark) {
|
||||
Drawable unwrappedIcon = AppCompatResources.getDrawable(this, icon);
|
||||
assert unwrappedIcon != null;
|
||||
Drawable wrappedIcon = DrawableCompat.wrap(unwrappedIcon);
|
||||
if(dark)
|
||||
{
|
||||
if (dark) {
|
||||
DrawableCompat.setTint(wrappedIcon, Color.BLACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
DrawableCompat.setTintList(wrappedIcon, null);
|
||||
}
|
||||
|
||||
@@ -216,8 +213,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
@@ -251,9 +247,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
appBarLayout = findViewById(R.id.app_bar_layout);
|
||||
|
||||
centerGuideline = findViewById(R.id.centerGuideline);
|
||||
centerGuideline.setGuidelinePercent(0.5f);
|
||||
barcodeScaler = findViewById(R.id.barcodeScaler);
|
||||
barcodeScaler.setProgress(100);
|
||||
maximizeButton.setBackgroundColor(getThemeColor());
|
||||
minimizeButton.setBackgroundColor(getThemeColor());
|
||||
bottomSheetButton.setBackgroundColor(getThemeColor());
|
||||
@@ -265,13 +259,18 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
float scale = (float) progress / (float) barcodeScaler.getMax();
|
||||
Log.d(TAG, "Scaling to " + scale);
|
||||
|
||||
if (imageTypes.get(mainImageIndex) == ImageType.BARCODE) {
|
||||
redrawBarcodeAfterResize();
|
||||
if(isFullscreen){
|
||||
loyaltyCard.zoomLevel = progress;
|
||||
db.updateLoyaltyCardZoomLevel(loyaltyCardId, loyaltyCard.zoomLevel);
|
||||
}
|
||||
if(loyaltyCard!=null && format!=null && format.isSquare())
|
||||
|
||||
if (format != null && format.isSquare()) {
|
||||
centerGuideline.setGuidelinePercent(0.75f * scale);
|
||||
else
|
||||
} else {
|
||||
centerGuideline.setGuidelinePercent(0.5f * scale);
|
||||
}
|
||||
|
||||
drawMainImage(mainImageIndex, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -324,7 +323,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlide(@NonNull View bottomSheet, float slideOffset) { }
|
||||
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
|
||||
}
|
||||
});
|
||||
|
||||
bottomSheetButton.setOnClickListener(v -> {
|
||||
@@ -360,8 +360,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent)
|
||||
{
|
||||
public void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
Log.i(TAG, "Received new intent");
|
||||
@@ -377,8 +376,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
Log.i(TAG, "To view card: " + loyaltyCardId);
|
||||
@@ -387,12 +385,10 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
// '1' is the brightest. We attempt to maximize the brightness
|
||||
// to help barcode readers scan the barcode.
|
||||
Window window = getWindow();
|
||||
if(window != null)
|
||||
{
|
||||
if (window != null) {
|
||||
WindowManager.LayoutParams attributes = window.getAttributes();
|
||||
|
||||
if (settings.useMaxBrightnessDisplayingBarcode())
|
||||
{
|
||||
if (settings.useMaxBrightnessDisplayingBarcode()) {
|
||||
attributes.screenBrightness = 1F;
|
||||
}
|
||||
|
||||
@@ -401,7 +397,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
}
|
||||
|
||||
if (settings.getDisableLockscreenWhileViewingCard()) {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD|
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
|
||||
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
|
||||
}
|
||||
|
||||
@@ -409,8 +405,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
}
|
||||
|
||||
loyaltyCard = db.getLoyaltyCard(loyaltyCardId);
|
||||
if(loyaltyCard == null)
|
||||
{
|
||||
if (loyaltyCard == null) {
|
||||
Log.w(TAG, "Could not lookup loyalty card " + loyaltyCardId);
|
||||
Toast.makeText(this, R.string.noCardExistsError, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
@@ -420,12 +415,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
setupOrientation();
|
||||
|
||||
format = loyaltyCard.barcodeType;
|
||||
if(format != null && format.isSquare()){
|
||||
centerGuideline.setGuidelinePercent(0.75f);
|
||||
}
|
||||
else{
|
||||
centerGuideline.setGuidelinePercent(0.5f);
|
||||
}
|
||||
cardIdString = loyaltyCard.cardId;
|
||||
barcodeIdString = loyaltyCard.barcodeId;
|
||||
|
||||
@@ -434,20 +423,17 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
settings.getFontSizeMin(settings.getLargeFont()), settings.getFontSizeMax(settings.getLargeFont()),
|
||||
1, TypedValue.COMPLEX_UNIT_SP);
|
||||
|
||||
if(loyaltyCard.note.length() > 0)
|
||||
{
|
||||
if (loyaltyCard.note.length() > 0) {
|
||||
noteView.setVisibility(View.VISIBLE);
|
||||
noteView.setText(loyaltyCard.note);
|
||||
noteView.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
noteView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
List<Group> loyaltyCardGroups = db.getLoyaltyCardGroups(loyaltyCardId);
|
||||
|
||||
if(loyaltyCardGroups.size() > 0) {
|
||||
if (loyaltyCardGroups.size() > 0) {
|
||||
List<String> groupNames = new ArrayList<>();
|
||||
for (Group group : loyaltyCardGroups) {
|
||||
groupNames.add(group._id);
|
||||
@@ -456,35 +442,29 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
groupsView.setVisibility(View.VISIBLE);
|
||||
groupsView.setText(getString(R.string.groupsList, TextUtils.join(", ", groupNames)));
|
||||
groupsView.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
groupsView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if(!loyaltyCard.balance.equals(new BigDecimal(0))) {
|
||||
if (!loyaltyCard.balance.equals(new BigDecimal(0))) {
|
||||
balanceView.setVisibility(View.VISIBLE);
|
||||
balanceView.setText(getString(R.string.balanceSentence, Utils.formatBalance(this, loyaltyCard.balance, loyaltyCard.balanceType)));
|
||||
balanceView.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
balanceView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if(loyaltyCard.expiry != null) {
|
||||
if (loyaltyCard.expiry != null) {
|
||||
expiryView.setVisibility(View.VISIBLE);
|
||||
|
||||
int expiryString = R.string.expiryStateSentence;
|
||||
if(Utils.hasExpired(loyaltyCard.expiry)) {
|
||||
if (Utils.hasExpired(loyaltyCard.expiry)) {
|
||||
expiryString = R.string.expiryStateSentenceExpired;
|
||||
expiryView.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.alert));
|
||||
}
|
||||
expiryView.setText(getString(expiryString, DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.expiry)));
|
||||
expiryView.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
expiryView.setVisibility(View.GONE);
|
||||
}
|
||||
expiryView.setTag(loyaltyCard.expiry);
|
||||
@@ -503,12 +483,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
TypedValue.COMPLEX_UNIT_DIP);
|
||||
|
||||
int backgroundHeaderColor;
|
||||
if(loyaltyCard.headerColor != null)
|
||||
{
|
||||
if (loyaltyCard.headerColor != null) {
|
||||
backgroundHeaderColor = loyaltyCard.headerColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
backgroundHeaderColor = LetterBitmap.getDefaultColor(this, loyaltyCard.store);
|
||||
}
|
||||
|
||||
@@ -516,12 +493,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
appBarLayout.setBackgroundColor(backgroundHeaderColor);
|
||||
|
||||
int textColor;
|
||||
if(Utils.needsDarkForeground(backgroundHeaderColor))
|
||||
{
|
||||
if (Utils.needsDarkForeground(backgroundHeaderColor)) {
|
||||
textColor = Color.BLACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
textColor = Color.WHITE;
|
||||
}
|
||||
storeName.setTextColor(textColor);
|
||||
@@ -530,14 +504,12 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
// If the background is very bright, we should use dark icons
|
||||
backgroundNeedsDarkIcons = Utils.needsDarkForeground(backgroundHeaderColor);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.setHomeAsUpIndicator(getIcon(R.drawable.ic_arrow_back_white, backgroundNeedsDarkIcons));
|
||||
}
|
||||
|
||||
// Make notification area light if dark icons are needed
|
||||
if(Build.VERSION.SDK_INT >= 23)
|
||||
{
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
window.getDecorView().setSystemUiVisibility(backgroundNeedsDarkIcons ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : 0);
|
||||
}
|
||||
window.setStatusBarColor(Color.TRANSPARENT);
|
||||
@@ -594,8 +566,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (isFullscreen)
|
||||
{
|
||||
if (isFullscreen) {
|
||||
setFullscreen(false);
|
||||
return;
|
||||
}
|
||||
@@ -604,16 +575,14 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.card_view_menu, menu);
|
||||
|
||||
// Always calculate lockscreen icon, it may need a black color
|
||||
boolean lockBarcodeScreenOrientation = settings.getLockBarcodeScreenOrientation();
|
||||
MenuItem item = menu.findItem(R.id.action_lock_unlock);
|
||||
setOrientatonLock(item, lockBarcodeScreenOrientation);
|
||||
if(lockBarcodeScreenOrientation)
|
||||
{
|
||||
if (lockBarcodeScreenOrientation) {
|
||||
item.setVisible(false);
|
||||
}
|
||||
|
||||
@@ -632,8 +601,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
if (starred) {
|
||||
menu.findItem(R.id.action_star_unstar).setIcon(getIcon(R.drawable.ic_starred_white, backgroundNeedsDarkIcons));
|
||||
menu.findItem(R.id.action_star_unstar).setTitle(R.string.unstar);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
menu.findItem(R.id.action_star_unstar).setIcon(getIcon(R.drawable.ic_unstarred_white, backgroundNeedsDarkIcons));
|
||||
menu.findItem(R.id.action_star_unstar).setTitle(R.string.star);
|
||||
}
|
||||
@@ -641,12 +609,10 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
|
||||
switch(id)
|
||||
{
|
||||
switch (id) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
break;
|
||||
@@ -661,12 +627,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
return true;
|
||||
|
||||
case R.id.action_lock_unlock:
|
||||
if(rotationEnabled)
|
||||
{
|
||||
if (rotationEnabled) {
|
||||
setOrientatonLock(item, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
setOrientatonLock(item, false);
|
||||
}
|
||||
rotationEnabled = !rotationEnabled;
|
||||
@@ -682,8 +645,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void setupOrientation()
|
||||
{
|
||||
private void setupOrientation() {
|
||||
Toolbar portraitToolbar = findViewById(R.id.toolbar);
|
||||
Toolbar landscapeToolbar = findViewById(R.id.toolbar_landscape);
|
||||
|
||||
@@ -711,51 +673,44 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
}
|
||||
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void setOrientatonLock(MenuItem item, boolean lock)
|
||||
{
|
||||
if(lock)
|
||||
{
|
||||
private void setOrientatonLock(MenuItem item, boolean lock) {
|
||||
if (lock) {
|
||||
|
||||
item.setIcon(getIcon(R.drawable.ic_lock_outline_white_24dp, backgroundNeedsDarkIcons));
|
||||
item.setTitle(R.string.unlockScreen);
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
item.setIcon(getIcon(R.drawable.ic_lock_open_white_24dp, backgroundNeedsDarkIcons));
|
||||
item.setTitle(R.string.lockScreen);
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
private void makeBottomSheetVisibleIfUseful()
|
||||
{
|
||||
private void makeBottomSheetVisibleIfUseful() {
|
||||
if (noteView.getVisibility() == View.VISIBLE || groupsView.getVisibility() == View.VISIBLE || balanceView.getVisibility() == View.VISIBLE || expiryView.getVisibility() == View.VISIBLE) {
|
||||
bottomSheet.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
bottomSheet.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawBarcode() {
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.BARCODE, true, false, false);
|
||||
if (format != null) {
|
||||
new BarcodeImageWriterTask(
|
||||
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(
|
||||
getApplicationContext(),
|
||||
mainImage,
|
||||
barcodeIdString != null ? barcodeIdString : cardIdString,
|
||||
format,
|
||||
null,
|
||||
false,
|
||||
null)
|
||||
.execute();
|
||||
null);
|
||||
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -771,7 +726,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
drawBarcode();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void drawMainImage(int index, boolean waitForResize) {
|
||||
@@ -831,6 +786,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
* by machines which offer no space to insert the complete device.
|
||||
*/
|
||||
private void setFullscreen(boolean enabled) {
|
||||
isFullscreen = enabled;
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
|
||||
if (enabled && !imageTypes.isEmpty()) {
|
||||
@@ -838,14 +794,15 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
|
||||
drawMainImage(mainImageIndex, true);
|
||||
|
||||
barcodeScaler.setProgress(loyaltyCard.zoomLevel);
|
||||
|
||||
// Hide maximize and show minimize button and scaler
|
||||
maximizeButton.setVisibility(View.GONE);
|
||||
minimizeButton.setVisibility(View.VISIBLE);
|
||||
barcodeScaler.setVisibility(View.VISIBLE);
|
||||
|
||||
// Hide actionbar
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.hide();
|
||||
}
|
||||
|
||||
@@ -870,9 +827,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Log.d(TAG, "Move out of fullscreen");
|
||||
|
||||
// Reset center guideline
|
||||
@@ -887,8 +842,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
barcodeScaler.setVisibility(View.GONE);
|
||||
|
||||
// Show actionbar
|
||||
if(actionBar != null)
|
||||
{
|
||||
if (actionBar != null) {
|
||||
actionBar.show();
|
||||
}
|
||||
|
||||
@@ -912,6 +866,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
|
||||
);
|
||||
}
|
||||
|
||||
isFullscreen = enabled;
|
||||
Log.d("setFullScreen","Is full screen enabled? "+enabled+" Zoom Level = "+barcodeScaler.getProgress());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.database.CursorIndexOutOfBoundsException;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
@@ -737,7 +737,21 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
|
||||
{
|
||||
Cursor selected = mAdapter.getCursor();
|
||||
selected.moveToPosition(inputPosition);
|
||||
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
|
||||
// FIXME
|
||||
//
|
||||
// There is a really nasty edge case that can happen when someone taps a card but right
|
||||
// after it swipes (very small window, hard to reproduce). The cursor gets replaced and
|
||||
// may not have a card at the ID number that is returned from onRowClicked.
|
||||
//
|
||||
// The proper fix, obviously, would involve makes sure an onFling can't happen while a
|
||||
// click is being processed. Sadly, I have not yet found a way to make that possible.
|
||||
LoyaltyCard loyaltyCard;
|
||||
try {
|
||||
loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
|
||||
} catch (CursorIndexOutOfBoundsException e) {
|
||||
Log.w(TAG, "Prevented crash from tap + swipe on ID " + inputPosition + ": " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
Intent i = new Intent(this, LoyaltyCardViewActivity.class);
|
||||
i.setAction("");
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package protect.card_locker.async;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public interface CompatCallable<T> extends Callable<T> {
|
||||
void onPostExecute(Object result);
|
||||
void onPreExecute();
|
||||
}
|
||||
174
app/src/main/java/protect/card_locker/async/TaskHandler.java
Normal file
174
app/src/main/java/protect/card_locker/async/TaskHandler.java
Normal file
@@ -0,0 +1,174 @@
|
||||
package protect.card_locker.async;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* AsyncTask has been deprecated so this provides very rudimentary compatibility without
|
||||
* needing to redo too many Parts.
|
||||
*
|
||||
* However this is a much, much more cooperative Behaviour than before so
|
||||
* the callers need to ensure we do NOT rely on forced cancellation and feed less into the
|
||||
* ThreadPools so we don't OOM/Overload the Users device
|
||||
*
|
||||
* This assumes single-threaded callers.
|
||||
*/
|
||||
public class TaskHandler {
|
||||
|
||||
public enum TYPE {
|
||||
BARCODE,
|
||||
IMPORT,
|
||||
EXPORT
|
||||
}
|
||||
|
||||
HashMap<TYPE, ThreadPoolExecutor> executors = generateExecutors();
|
||||
|
||||
final private HashMap<TYPE, LinkedList<Future<?>>> taskList = new HashMap<>();
|
||||
|
||||
private final Handler uiHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
private HashMap<TYPE, ThreadPoolExecutor> generateExecutors() {
|
||||
HashMap<TYPE, ThreadPoolExecutor> initExecutors = new HashMap<>();
|
||||
for (TYPE type : TYPE.values()) {
|
||||
replaceExecutor(initExecutors, type, false, false);
|
||||
}
|
||||
return initExecutors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces (or initializes) an Executor with a clean (new) one
|
||||
* @param executors Map Reference
|
||||
* @param type Which Queue
|
||||
* @param flushOld attempt shutdown
|
||||
* @param waitOnOld wait for Termination
|
||||
*/
|
||||
private void replaceExecutor(HashMap<TYPE, ThreadPoolExecutor> executors, TYPE type, Boolean flushOld, Boolean waitOnOld) {
|
||||
ThreadPoolExecutor oldExecutor = executors.get(type);
|
||||
if (oldExecutor != null) {
|
||||
if (flushOld) {
|
||||
oldExecutor.shutdownNow();
|
||||
}
|
||||
if (waitOnOld) {
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
executors.put(type, (ThreadPoolExecutor) Executors.newCachedThreadPool());
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a Pseudo-AsyncTask for execution
|
||||
*
|
||||
* @param type Queue
|
||||
* @param callable PseudoAsyncTask
|
||||
*/
|
||||
public void executeTask(TYPE type, CompatCallable<?> callable) {
|
||||
Runnable runner = () -> {
|
||||
try {
|
||||
// Run on the UI Thread
|
||||
uiHandler.post(callable::onPreExecute);
|
||||
|
||||
// Background
|
||||
final Object result = callable.call();
|
||||
|
||||
// Post results on UI Thread so we can show them
|
||||
uiHandler.post(() -> {
|
||||
callable.onPostExecute(result);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
};
|
||||
|
||||
LinkedList<Future<?>> list = taskList.get(type);
|
||||
|
||||
if (list == null) {
|
||||
list = new LinkedList<>();
|
||||
}
|
||||
|
||||
ThreadPoolExecutor executor = executors.get(type);
|
||||
|
||||
if (executor != null) {
|
||||
Future<?> task = executor.submit(runner);
|
||||
// Test Queue Cancellation:
|
||||
// task.cancel(true);
|
||||
list.push(task);
|
||||
taskList.put(type, list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will attempt to cancel a currently running list of Tasks
|
||||
* Useful to ignore scheduled tasks - but not able to hard-stop tasks that are running
|
||||
*
|
||||
* @param type Which Queue to target
|
||||
* @param forceCancel attempt to close the Queue and force-replace it after
|
||||
* @param waitForFinish wait and return after the old executor finished. Times out after 5s
|
||||
* @param waitForCurrentlyRunning wait before cancelling tasks. Useful for tests.
|
||||
*/
|
||||
public void flushTaskList(TYPE type, Boolean forceCancel, Boolean waitForFinish, Boolean waitForCurrentlyRunning) {
|
||||
// Only used for Testing
|
||||
if (waitForCurrentlyRunning) {
|
||||
ThreadPoolExecutor oldExecutor = executors.get(type);
|
||||
|
||||
if (oldExecutor != null) {
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to cancel known Tasks and clean the List
|
||||
LinkedList<Future<?>> tasks = taskList.get(type);
|
||||
if (tasks != null) {
|
||||
for (Future<?> task : tasks) {
|
||||
if (!task.isDone() || !task.isCancelled()) {
|
||||
// Interrupt any Task we can
|
||||
task.cancel(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks = new LinkedList<>();
|
||||
taskList.put(type, tasks);
|
||||
|
||||
if (forceCancel || waitForFinish) {
|
||||
ThreadPoolExecutor oldExecutor = executors.get(type);
|
||||
|
||||
if (oldExecutor != null) {
|
||||
if (forceCancel) {
|
||||
if (waitForFinish) {
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
oldExecutor.shutdownNow();
|
||||
replaceExecutor(executors, type, true, false);
|
||||
} else {
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
oldExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ public class CatimaImporter implements Importer
|
||||
|
||||
public void parseV1(Context context, DBHelper db, BufferedReader input) throws IOException, FormatException, InterruptedException
|
||||
{
|
||||
final CSVParser parser = new CSVParser(input, CSVFormat.RFC4180.withHeader());
|
||||
final CSVParser parser = new CSVParser(input, CSVFormat.RFC4180.builder().setHeader().build());
|
||||
|
||||
SQLiteDatabase database = db.getWritableDatabase();
|
||||
database.beginTransaction();
|
||||
@@ -209,7 +209,7 @@ public class CatimaImporter implements Importer
|
||||
public void parseV2Groups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
|
||||
{
|
||||
// Parse groups
|
||||
final CSVParser groupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
|
||||
final CSVParser groupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
|
||||
|
||||
List<CSVRecord> records = new ArrayList<>();
|
||||
|
||||
@@ -235,7 +235,7 @@ public class CatimaImporter implements Importer
|
||||
public void parseV2Cards(Context context, DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
|
||||
{
|
||||
// Parse cards
|
||||
final CSVParser cardParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
|
||||
final CSVParser cardParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
|
||||
|
||||
List<CSVRecord> records = new ArrayList<>();
|
||||
|
||||
@@ -261,7 +261,7 @@ public class CatimaImporter implements Importer
|
||||
public void parseV2CardGroups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
|
||||
{
|
||||
// Parse card group mappings
|
||||
final CSVParser cardGroupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
|
||||
final CSVParser cardGroupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());
|
||||
|
||||
List<CSVRecord> records = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -32,8 +32,7 @@ import protect.card_locker.Utils;
|
||||
* The database's loyalty cards are expected to appear in the CSV data.
|
||||
* A header is expected for the each table showing the names of the columns.
|
||||
*/
|
||||
public class FidmeImporter implements Importer
|
||||
{
|
||||
public class FidmeImporter implements Importer {
|
||||
public void importData(Context context, DBHelper db, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
|
||||
// We actually retrieve a .zip file
|
||||
ZipInputStream zipInputStream = new ZipInputStream(input, password);
|
||||
@@ -59,7 +58,7 @@ public class FidmeImporter implements Importer
|
||||
SQLiteDatabase database = db.getWritableDatabase();
|
||||
database.beginTransaction();
|
||||
|
||||
final CSVParser fidmeParser = new CSVParser(new StringReader(loyaltyCards.toString()), CSVFormat.RFC4180.withDelimiter(';').withHeader());
|
||||
final CSVParser fidmeParser = new CSVParser(new StringReader(loyaltyCards.toString()), CSVFormat.RFC4180.builder().setDelimiter(';').setHeader().build());
|
||||
|
||||
try {
|
||||
for (CSVRecord record : fidmeParser) {
|
||||
@@ -87,8 +86,7 @@ public class FidmeImporter implements Importer
|
||||
* session.
|
||||
*/
|
||||
private void importLoyaltyCard(SQLiteDatabase database, DBHelper helper, CSVRecord record)
|
||||
throws IOException, FormatException
|
||||
{
|
||||
throws IOException, FormatException {
|
||||
// A loyalty card export from Fidme contains the following fields:
|
||||
// Retailer (store name)
|
||||
// Program (program name)
|
||||
@@ -100,8 +98,7 @@ public class FidmeImporter implements Importer
|
||||
// The store is called Retailer
|
||||
String store = CSVHelpers.extractString("Retailer", record, "");
|
||||
|
||||
if (store.isEmpty())
|
||||
{
|
||||
if (store.isEmpty()) {
|
||||
throw new FormatException("No store listed, but is required");
|
||||
}
|
||||
|
||||
@@ -121,8 +118,7 @@ public class FidmeImporter implements Importer
|
||||
|
||||
// The ID is called reference
|
||||
String cardId = CSVHelpers.extractString("Reference", record, "");
|
||||
if(cardId.isEmpty())
|
||||
{
|
||||
if (cardId.isEmpty()) {
|
||||
throw new FormatException("No card ID listed, but is required");
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public class StocardImporter implements Importer
|
||||
HashMap<String, HashMap<String, Object>> loyaltyCardHashMap = new HashMap<>();
|
||||
HashMap<String, HashMap<String, String>> providers = new HashMap<>();
|
||||
|
||||
final CSVParser parser = new CSVParser(new InputStreamReader(context.getResources().openRawResource(R.raw.stocard_stores), StandardCharsets.UTF_8), CSVFormat.RFC4180.withHeader());
|
||||
final CSVParser parser = new CSVParser(new InputStreamReader(context.getResources().openRawResource(R.raw.stocard_stores), StandardCharsets.UTF_8), CSVFormat.RFC4180.builder().setHeader().build());
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -27,20 +27,27 @@
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/thumbnail_container"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="4dp"
|
||||
android:layout_alignParentStart="true">
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/thumbnail_front"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize">
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/storeContainer"
|
||||
android:layout_alignBottom="@+id/storeContainer"
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
android:layout_centerVertical="true"
|
||||
android:contentDescription="@string/thumbnailDescription"
|
||||
android:src="@mipmap/ic_launcher" />
|
||||
|
||||
@@ -48,25 +55,29 @@
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/thumbnail_back"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize">
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/selected_thumbnail"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerInParent="true"
|
||||
android:contentDescription="@string/thumbnailDescription"
|
||||
android:scaleType="centerCrop"
|
||||
app:srcCompat="@drawable/ic_done" />
|
||||
|
||||
</RelativeLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<LinearLayout
|
||||
android:minHeight="@dimen/cardThumbnailSize"
|
||||
android:id="@+id/storeContainer"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_toEndOf="@+id/thumbnail_container">
|
||||
|
||||
<TextView
|
||||
@@ -82,6 +93,8 @@
|
||||
android:id="@+id/star"
|
||||
android:layout_width="@dimen/cardThumbnailSize"
|
||||
android:layout_height="@dimen/cardThumbnailSize"
|
||||
android:layout_centerVertical="true"
|
||||
android:scaleType="centerCrop"
|
||||
app:srcCompat="@drawable/ic_starred_white"
|
||||
android:contentDescription="@string/starImage"
|
||||
app:tint="?attr/colorControlNormal"
|
||||
@@ -114,6 +127,8 @@
|
||||
android:id="@+id/balance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingEnd="8dp"
|
||||
android:textAppearance="?attr/textAppearanceBody2"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
@@ -125,6 +140,8 @@
|
||||
android:id="@+id/expiry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center_vertical"
|
||||
android:textAppearance="?attr/textAppearanceBody2"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:drawableLeftCompat="@drawable/ic_baseline_access_time_24"
|
||||
|
||||
@@ -122,6 +122,10 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cardIdView"
|
||||
android:enabled="true"
|
||||
android:textIsSelectable="true"
|
||||
android:focusable="true"
|
||||
android:longClickable="true"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginLeft="10.0dip"
|
||||
@@ -181,6 +185,10 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/noteView"
|
||||
android:enabled="true"
|
||||
android:textIsSelectable="true"
|
||||
android:focusable="true"
|
||||
android:longClickable="true"
|
||||
android:autoLink="all"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -190,6 +198,10 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/groupsView"
|
||||
android:enabled="true"
|
||||
android:textIsSelectable="true"
|
||||
android:focusable="true"
|
||||
android:longClickable="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
@@ -198,6 +210,10 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/balanceView"
|
||||
android:enabled="true"
|
||||
android:textIsSelectable="true"
|
||||
android:focusable="true"
|
||||
android:longClickable="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
@@ -206,6 +222,10 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/expiryView"
|
||||
android:enabled="true"
|
||||
android:textIsSelectable="true"
|
||||
android:focusable="true"
|
||||
android:longClickable="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
|
||||
@@ -8,25 +8,26 @@ mondstern
|
||||
Taco
|
||||
IllusiveMan196
|
||||
Petr Novák
|
||||
Oğuz Ersen
|
||||
Gediminas Murauskas
|
||||
Joel A
|
||||
Oğuz Ersen
|
||||
StoyanDimitrov
|
||||
Samantaz Fox
|
||||
Nyatsuki
|
||||
arno-github
|
||||
Sergio Paredes
|
||||
Ankit Tiwari
|
||||
Sergio Paredes
|
||||
arshbeerSingh
|
||||
huuhaa
|
||||
Michael Moroni
|
||||
Olivia (Zoe)
|
||||
betsythefc
|
||||
waffshappen
|
||||
Miha Frangež
|
||||
K. Herbert
|
||||
Quentin PAGÈS
|
||||
String E. Fighter
|
||||
Yurical
|
||||
waffshappen
|
||||
Adolfo Jayme-Barrientos
|
||||
Alessandro Mandelli
|
||||
KovalevArtem
|
||||
@@ -41,9 +42,8 @@ Thomas Bertels
|
||||
inesre
|
||||
lgasp
|
||||
phlostically
|
||||
Kevin Sicong Jiang
|
||||
Miha Frangež
|
||||
Aditya Das
|
||||
Kevin Sicong Jiang
|
||||
Airat
|
||||
BMN
|
||||
Biren
|
||||
@@ -61,6 +61,7 @@ QuangDNguyen2211
|
||||
Rohan Babbar
|
||||
Rose Liverman
|
||||
Simone Dotto
|
||||
Still Hsu
|
||||
Subhashish Anand
|
||||
Tymofii Lytvynenko
|
||||
Tjipke van der Heide
|
||||
|
||||
@@ -208,5 +208,6 @@
|
||||
<string name="on_google_play">в Google Play</string>
|
||||
<string name="and_data_usage">и използване на данни</string>
|
||||
<string name="help_translate_this_app">Помогнете за превода на приложението</string>
|
||||
</resources>
|
||||
|
||||
<string name="exportPasswordHint">Въведете парола</string>
|
||||
<string name="exportPassword">Задаване на парола за защита на изнесеното (по избор)</string>
|
||||
</resources>
|
||||
@@ -212,4 +212,6 @@
|
||||
<string name="help_translate_this_app">Pomozte s překladem této aplikace</string>
|
||||
<string name="report_error">Nahlásit chybu</string>
|
||||
<string name="on_google_play">na Google Play</string>
|
||||
<string name="exportPassword">Nastavení hesla pro ochranu exportu (volitelné)</string>
|
||||
<string name="exportPasswordHint">Zadejte heslo</string>
|
||||
</resources>
|
||||
@@ -86,4 +86,11 @@
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Forebyg låseskærm</string>
|
||||
<string name="settings_keep_screen_on">LHold skærm tændt</string>
|
||||
<string name="settings_lock_barcode_orientation">Lås stregkode-orientering</string>
|
||||
<string name="moveUp">Bevæg dig opad</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Forlade uden at gemme\?</string>
|
||||
<string name="settings_display_barcode_max_brightness">Lysere stregkodevisning</string>
|
||||
<string name="failedOpeningFileManager">Installer først en filhåndteringsprogram.</string>
|
||||
<string name="moveDown">Bevæger sig nedad</string>
|
||||
<string name="leaveWithoutSaveTitle">Afslut</string>
|
||||
<string name="addManually">Indtast kort-ID manuelt</string>
|
||||
</resources>
|
||||
@@ -79,4 +79,13 @@
|
||||
<string name="unlockScreen">Malbloki Rotacio</string>
|
||||
<string name="lockScreen">Bloko Rotacio</string>
|
||||
<string name="star">Aldoni al miaj plej ŝatataj</string>
|
||||
<string name="copy_to_clipboard_toast">Card ID kopiita al la tondujo</string>
|
||||
<string name="settings_keep_screen_on">Teni sur ekrano</string>
|
||||
<string name="importSuccessful">Karto datumo importitaj</string>
|
||||
<string name="enter_group_name">Eniri nomo de la grupo</string>
|
||||
<string name="noGroups">Klaki la + plus butonon por aldoni grupoj por categorization unua.</string>
|
||||
<string name="all">Ĉiuj</string>
|
||||
<string name="intent_import_card_from_url_share_text">Mi deziras dividi karto kun vi</string>
|
||||
<string name="exportSuccessful">Karto datumo eksportita</string>
|
||||
<string name="noGroupCards">Ĉi tiu grupo ne enhavas ajnan kartoj</string>
|
||||
</resources>
|
||||
2
app/src/main/res/values-hr/strings.xml
Normal file
2
app/src/main/res/values-hr/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
190
app/src/main/res/values-in-rID/strings.xml
Normal file
190
app/src/main/res/values-in-rID/strings.xml
Normal file
@@ -0,0 +1,190 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="app_revision_url">https://github.com/TheLastProject/Catima/releases</string>
|
||||
<string name="storeName">Nama</string>
|
||||
<string name="note">Keterangan</string>
|
||||
<string name="delete">Hapus</string>
|
||||
<string name="edit">Ubah</string>
|
||||
<string name="save">Simpan</string>
|
||||
<string name="deleteTitle">Hapus kartu</string>
|
||||
<string name="cardId">Kartu ID</string>
|
||||
<string name="barcodeType">Tipe barcode</string>
|
||||
<string name="star">Tambahkan ke favorit</string>
|
||||
<string name="unstar">Hapus dari favorit</string>
|
||||
<string name="action_add">Tambah</string>
|
||||
<string name="action_search">Cari</string>
|
||||
<string name="sort_by_name">Nama</string>
|
||||
<string name="sort_by_balance">Saldo</string>
|
||||
<string name="sort_by">Sortir dengan</string>
|
||||
<string name="sort">Sortir</string>
|
||||
<string name="credits">Kredit</string>
|
||||
<string name="license">Lisensi</string>
|
||||
<string name="settings">Pengaturan</string>
|
||||
<string name="settings_system_theme">Sistem</string>
|
||||
<string name="selectBarcodeTitle">Pilih Barcode</string>
|
||||
<string name="deleteConfirmation">Hapus kartu ini secara permanen?</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="share">Bagikan</string>
|
||||
<string name="editCardTitle">Ubah Kartu</string>
|
||||
<string name="addCardTitle">Tambah Kartu</string>
|
||||
<string name="scanCardBarcode">Pindai Kartu Barcode</string>
|
||||
<string name="barcodeNoBarcode">Kartu ini tidak memiliki barcode</string>
|
||||
<string name="cancel">Batalkan</string>
|
||||
<string name="importExport">Import/Ekspor</string>
|
||||
<string name="settings_category_title_ui">Tampilan Pengguna</string>
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="all">Semua</string>
|
||||
<string name="leaveWithoutSaveTitle">Keluar</string>
|
||||
<string name="card">Kartu</string>
|
||||
<string name="barcode">Barcode</string>
|
||||
<string name="chooseExpiryDate">Pilih masa berlaku</string>
|
||||
<string name="noBarcodeFound">Barcode tidak ditemukan</string>
|
||||
<string name="errorReadingImage">TIdak dapat membaca gambar</string>
|
||||
<string name="balance">Saldo</string>
|
||||
<string name="currency">Mata uang</string>
|
||||
<string name="chooseImportType">Impor data dari?</string>
|
||||
<string name="accept">Terima</string>
|
||||
<string name="importCatima">Impor dari Catima</string>
|
||||
<string name="importFidme">Impor dari FidMe</string>
|
||||
<string name="barcodeId">Nilai barcode</string>
|
||||
<string name="sameAsCardId">Sama denga kartu ID</string>
|
||||
<string name="setBarcodeId">Tentukan nilai barcode</string>
|
||||
<string name="photos">Foto</string>
|
||||
<string name="setFrontImage">Atur gambar bagian depan</string>
|
||||
<string name="report_error">Lapor Kesalahan</string>
|
||||
<string name="rate_this_app">Beri nilai pada aplikasi ini</string>
|
||||
<string name="sort_by_expiry">Masa berlaku</string>
|
||||
<string name="sort_by_most_recently_used">Paling banyak digunakan</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_pink_theme">Merah Muda</string>
|
||||
<string name="settings_blue_theme">Biru</string>
|
||||
<string name="settings_green_theme">Hijau</string>
|
||||
<string name="settings_sky_blue_theme">Biru Langit</string>
|
||||
<string name="settings_grey_theme">Abu-abu</string>
|
||||
<string name="settings_brown_theme">Cokelat</string>
|
||||
<string name="settings_violet_theme">Ungu</string>
|
||||
<string name="settings_magenta_theme">Magenta</string>
|
||||
<string name="settings_theme_color">Warna tema</string>
|
||||
<string name="settings_system_locale">Sistem</string>
|
||||
<string name="settings_locale">Bahasa</string>
|
||||
<string name="turn_flashlight_on">Hidupkan lampu flash</string>
|
||||
<string name="turn_flashlight_off">Matikan lampu flash</string>
|
||||
<string name="exportPasswordHint">Masukan kata sandi</string>
|
||||
<string name="yes">Ya</string>
|
||||
<string name="no">Tidak</string>
|
||||
<string name="takePhoto">Ambil foto</string>
|
||||
<string name="removeImage">Hapus gambar</string>
|
||||
<string name="setBackImage">Atur gambar bagian belakang</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">Saya ingin berbagi kartu dengan anda</string>
|
||||
<string name="noGiftCards">Klik tanda + tombol tambah untuk menambahkan kartu, atau mengimpor beberapa kartu melalui menu ⋮ terlebih dahulu.</string>
|
||||
<string name="noMatchingGiftCards">Tidak menemukan apapun. Coba untuk mengubah pencarian anda.</string>
|
||||
<string name="noBarcode">Bukan barcode</string>
|
||||
<string name="confirm">Konfirmasi</string>
|
||||
<string name="copy_to_clipboard">Salin ID</string>
|
||||
<string name="sendLabel">Kirim…</string>
|
||||
<string name="noCardsMessage">Tambah kartu terlebih dahulu</string>
|
||||
<string name="noStoreError">Nama masih kosong</string>
|
||||
<string name="noCardIdError">Kartu ID masih kosong</string>
|
||||
<string name="noCardExistsError">Tidak dapat menemukan kartu</string>
|
||||
<string name="failedParsingImportUriError">Tidak dapat menguraikan alamat impor situs web</string>
|
||||
<string name="exportName">Ekspor</string>
|
||||
<string name="importSuccessfulTitle">Sudah diimpor</string>
|
||||
<string name="importFailedTitle">Impor gagal</string>
|
||||
<string name="importFailed">Tidak dapat mengimpor kartu</string>
|
||||
<string name="exportSuccessfulTitle">Sudah diekspor</string>
|
||||
<string name="exportFailedTitle">Ekspor gagal</string>
|
||||
<string name="exportFailed">Tidak dapat mengekspor kartu</string>
|
||||
<string name="importing">Mengimpor…</string>
|
||||
<string name="exporting">Mengekspor…</string>
|
||||
<string name="noExternalStoragePermissionError">Berikan izin penyimpanan eksternal untuk mengimpor atau mengekspor kartu terlebih dahulu</string>
|
||||
<string name="exportOptionExplanation">The data will be written to a location of your choice.</string>
|
||||
<string name="importOptionFilesystemTitle">Impor dari sistem</string>
|
||||
<string name="importOptionFilesystemExplanation">Pilih file dari sistem</string>
|
||||
<string name="importOptionFilesystemButton">Dari sistem</string>
|
||||
<string name="importOptionApplicationTitle">Gunakan aplikasi lain</string>
|
||||
<string name="importOptionApplicationExplanation">Gunakan aplikasi lain atau pengelola file favorit anda untuk membuka file.</string>
|
||||
<string name="importOptionApplicationButton">Gunakan aplikasi lain</string>
|
||||
<string name="about">Tentang</string>
|
||||
<string name="app_copyright_fmt">Hak Cipta © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="app_copyright_old">Berdasarkan Loyalty Card Keychain hak cipta © 2016–2020 Branden Archer</string>
|
||||
<string name="app_license">Perangkat lunak bebas copyleft, berlisensi GPLv3+</string>
|
||||
<string name="about_title_fmt">Tentang <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Versi: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Info Revisi: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="app_libraries">Pustaka pihak ketiga gratis: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="app_resources">Sumber daya pihak ketiga gratis: <xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="enterBarcodeInstructions">Masukkan ID kartu, dan pilih jenis barcodenya di bawah atau \"Kartu ini tidak memiliki barcode\".</string>
|
||||
<string name="copy_to_clipboard_toast">ID kartu telah disalin</string>
|
||||
<string name="thumbnailDescription">Gambar tampilan untuk kartu</string>
|
||||
<string name="starImage">Favorit</string>
|
||||
<string name="settings_light_theme">Terang</string>
|
||||
<string name="settings_dark_theme">Gelap</string>
|
||||
<string name="settings_max_font_size_scale">Ukuran maksimal huruf</string>
|
||||
<string name="settings_display_barcode_max_brightness">Terangkan tampilan barcode</string>
|
||||
<string name="settings_lock_barcode_orientation">Kunci orientasi barcode</string>
|
||||
<string name="settings_keep_screen_on">Biarkan layar menyala</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Mencegah layar menyala</string>
|
||||
<string name="intent_import_card_from_url_share_text">Saya ingin berbagi kartu dengan anda</string>
|
||||
<string name="importSuccessful">Data kartu terimpor</string>
|
||||
<string name="exportSuccessful">Data kartu terekspor</string>
|
||||
<string name="enter_group_name">Masukan nama grup</string>
|
||||
<string name="groups">Grup</string>
|
||||
<string name="noGroups">Klik pada tombol tambah + untuk menambahkan grup atau kategori terlebih dahulu.</string>
|
||||
<string name="noGroupCards">Grup ini tidak memilik kartu</string>
|
||||
<string name="deleteConfirmationGroup">Hapus grup?</string>
|
||||
<string name="failedOpeningFileManager">Instal aplikasi pengelola file terlebih dahulu.</string>
|
||||
<string name="moveUp">Pindah ke atas</string>
|
||||
<string name="moveDown">Pindah ke bawah</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Keluar tanpa menyimpan?</string>
|
||||
<string name="addManually">Masukan ID kartu</string>
|
||||
<string name="addFromImage">Pilih gambar dari galeri</string>
|
||||
<string name="groupsList">Grup: <xliff:g>%s</xliff:g></string>
|
||||
<string name="expiryStateSentence">Masa ber: <xliff:g>%s</xliff:g></string>
|
||||
<string name="expiryStateSentenceExpired">Kadaluwarsa: <xliff:g>%s</xliff:g></string>
|
||||
<string name="balanceSentence">Saldo: <xliff:g>%s</xliff:g></string>
|
||||
<string name="balancePoints"><xliff:g>%s</xliff:g> poin</string>
|
||||
<string name="editBarcode">Ubah barcode</string>
|
||||
<string name="expiryDate">Tanggal masa berlaku</string>
|
||||
<string name="never">Tidak pernah</string>
|
||||
<string name="moveBarcodeToTopOfScreen">Pindah barcode ke bagian paling depan</string>
|
||||
<string name="moveBarcodeToCenterOfScreen">Pusatkan barcode pada layar</string>
|
||||
<string name="points">Poin</string>
|
||||
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> sepertinya bukan saldo yang valid.</string>
|
||||
<string name="app_loyalty_card_keychain">Loyalty Card Keychain</string>
|
||||
<string name="privacy_policy">Kebijakan Privasi</string>
|
||||
<string name="privacy_policy_popup_text">Pemberitahuan kebijakan privasi (diperlukan oleh beberapa toko aplikasi): TIDAK ADA DATA YANG DIKUMPULKAN SAMA SEKALI, yang dapat dikonfirmasi oleh siapa pun karena aplikasi kami adalah perangkat lunak gratis.</string>
|
||||
<string name="importCatimaMessage">Pilih ekspor <i>catima.zip</i> Anda dari Catima untuk diimpor. Buat dari menu Impor/Ekspor aplikasi Catima lain dengan menekan Ekspor di sana terlebih dahulu.</string>
|
||||
<string name="importFidmeMessage">Pilih ekspor <i>fidme-export-request-xxxxxx.zip</i> Anda dari FidMe untuk diimpor, dan pilih jenis barcode secara manual setelahnya. Buat dari profil FidMe Anda dengan memilih Perlindungan Data lalu tekan Ekstrak data saya terlebih dahulu.</string>
|
||||
<string name="importLoyaltyCardKeychain">Impor dari Loyalty Card Keychain</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">Pilih ekspor <i>LoyaltyCardKeychain.csv</i> Anda dari Loyalty Card Keychain untuk diimpor. Buat dari menu Import/Export di Loyalty Card Keychain dengan menekan Export terlebih dahulu.</string>
|
||||
<string name="importStocard">Impor dari Stocard</string>
|
||||
<string name="importStocardMessage">Pilih ekspor <i>***-sync.zip</i> Anda dari Stocard untuk diimpor. Dapatkan dengan mengirim email ke support@stocardapp.com untuk meminta ekspor data Anda.</string>
|
||||
<string name="importVoucherVault">Impor dari Voucher Vault</string>
|
||||
<string name="importVoucherVaultMessage">Pilih ekspor <i>vouchervault.json</i> Anda dari Vault Voucher untuk diimpor. Buat dengan menekan Ekspor di Vault Voucher terlebih dahulu.</string>
|
||||
<string name="unsupportedBarcodeType">Jenis barcode ini belum dapat ditampilkan. Ini mungkin didukung di versi aplikasi yang lebih baru.</string>
|
||||
<string name="wrongValueForBarcodeType">Nilai tidak berlaku untuk jenis barcode yang dipilih</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">ID kartu telah disalin</string>
|
||||
<string name="frontImageDescription">Gambar depan kartu</string>
|
||||
<string name="backImageDescription">Gambar belakang kartu</string>
|
||||
<string name="updateBarcodeQuestionTitle">Perbarui barcode?</string>
|
||||
<string name="updateBarcodeQuestionText">Anda mengubah ID kartu. Apakah Anda juga ingin memperbarui barcode untuk menggunakan nilai yang sama?</string>
|
||||
<string name="passwordRequired">Silahkan masukan kata sandi</string>
|
||||
<string name="exportPassword">Tetapkan kata sandi untuk melindungi ekspor anda (opsional)</string>
|
||||
<string name="failedGeneratingShareURL">Tidak dapat membuat alamat berbagi. Mohon laporkan ini.</string>
|
||||
<string name="app_contributors">Pengembangan dibantu oleh: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="toggleMoreInfo">Tampilkan info selengkapnya</string>
|
||||
<string name="swipeToSwitchImages">Geser atau tekan yang lama untuk mengganti gambar</string>
|
||||
<string name="reverse">Ubah urutan</string>
|
||||
<string name="version_history">Riwayat Versi</string>
|
||||
<string name="help_translate_this_app">Bantu terjemahkan aplikasi ini</string>
|
||||
<string name="source_repository">Sumber Repositori</string>
|
||||
<string name="on_github">di GitHub</string>
|
||||
<string name="and_data_usage">dan penggunaan data</string>
|
||||
<string name="on_google_play">di Google Play</string>
|
||||
<string name="lockScreen">Blokir rotasi</string>
|
||||
<string name="unlockScreen">Buka blokir rotasi</string>
|
||||
<string name="cardShortcut">Pintasan kartu</string>
|
||||
<string name="card_ids_copied">ID kartu yang tersalin</string>
|
||||
<string name="barcodeImageDescriptionWithType">Gambar dari jenis barcode <xliff:g>%s</xliff:g></string>
|
||||
<string name="importExportHelp">Mencadangkan kartu memungkinkan anda memindahkannya ke perangkat lain.</string>
|
||||
</resources>
|
||||
42
app/src/main/res/values-is/strings.xml
Normal file
42
app/src/main/res/values-is/strings.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="action_add">Bæta</string>
|
||||
<string name="noBarcode">Nei strikamerkið</string>
|
||||
<string name="action_search">Leita að</string>
|
||||
<string name="delete">Eyða</string>
|
||||
<string name="unlockScreen">Opna Snúningur</string>
|
||||
<string name="noGiftCards">Smelltu á + plús takka til að bæta kort, eða að flytja inn sumir frá ⋮ matseðill fyrst.</string>
|
||||
<string name="note">Athugið</string>
|
||||
<string name="barcodeType">Strikamerkið tegund</string>
|
||||
<string name="cancel">Hætta</string>
|
||||
<string name="noMatchingGiftCards">Vissi ekki að finna neitt. Reyna að breyta leita.</string>
|
||||
<string name="storeName">Nafnið</string>
|
||||
<string name="barcodeNoBarcode">Þetta kort hefur ekki strikamerkið</string>
|
||||
<string name="star">Bæta við eftirlæti</string>
|
||||
<string name="unstar">Fjarlægja frá eftirlæti</string>
|
||||
<string name="save">Sparaðu</string>
|
||||
<string name="edit">Breyta</string>
|
||||
<string name="confirm">Staðfesta</string>
|
||||
<string name="lockScreen">Blokk Snúningur</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="sendLabel">Sendu…</string>
|
||||
<string name="deleteConfirmation">Eyða þetta kort til frambúðar\?</string>
|
||||
<string name="share">Deila</string>
|
||||
<string name="editCardTitle">Breyta Kort</string>
|
||||
<string name="addCardTitle">Bæta Kort</string>
|
||||
<string name="scanCardBarcode">Skanna Kort Strikamerkið</string>
|
||||
<string name="noCardsMessage">Bæta kort fyrstu</string>
|
||||
<string name="exportFailedTitle">Flytja mistókst</string>
|
||||
<string name="exportSuccessfulTitle">Flutt</string>
|
||||
<string name="noStoreError">Ekkert nafn slegið</string>
|
||||
<string name="noCardExistsError">Gæti ekki fundið kort</string>
|
||||
<string name="failedParsingImportUriError">Get ekki lesið inn URI</string>
|
||||
<string name="exportName">Flytja</string>
|
||||
<string name="importExportHelp">Stuðningur upp spil gerir þér kleift að færa þá til annar tæki.</string>
|
||||
<string name="importSuccessfulTitle">Flutt</string>
|
||||
<string name="importFailedTitle">Innflutningur mistókst</string>
|
||||
<string name="noExternalStoragePermissionError">Grant ytri geymslu leyfi til að flytja eða flytja spil fyrstu</string>
|
||||
<string name="exportOptionExplanation">Gögnum verður skrifað á stað af eigin vali.</string>
|
||||
<string name="importOptionFilesystemTitle">Innflutningur frá möppuna</string>
|
||||
<string name="importOptionFilesystemExplanation">Velja ákveðna skrá frá möppuna.</string>
|
||||
</resources>
|
||||
@@ -76,10 +76,10 @@
|
||||
<string name="app_revision_fmt">Revision Info: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Version: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="about_title_fmt">About <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="app_license">Copylefted libre software, licensed GPLv3+.</string>
|
||||
<string name="app_license">Copylefted libre software, licensed GPLv3+</string>
|
||||
<string name="app_copyright_old">Based on Loyalty Card Keychain
|
||||
\ncopyright © 2016–2020 Branden Archer.</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019–<xliff:g>%d</xliff:g> Sylvia van Os.</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="app_resources">Libre third-party resources: <xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="about">Catimaについて</string>
|
||||
<string name="importOptionApplicationButton">外部のアプリを使う</string>
|
||||
@@ -95,7 +95,7 @@
|
||||
<string name="exportFailed">カードをエクスポートできませんでした</string>
|
||||
<string name="exportFailedTitle">エクスポートに失敗しました</string>
|
||||
<string name="exportSuccessfulTitle">エクスポートしました</string>
|
||||
<string name="sameAsCardId">カードの表記と同一</string>
|
||||
<string name="sameAsCardId">カード番号に合わせる</string>
|
||||
<string name="barcodeId">バーコード番号</string>
|
||||
<string name="importVoucherVaultMessage">Voucher Vaultでエクスポートした <i>vouchervault.json</i>ファイルを選択してください。
|
||||
\nファイルがない場合、Voucher Vaultでファイルをエクスポートしてください。</string>
|
||||
@@ -152,10 +152,10 @@
|
||||
<string name="takePhoto">写真を撮影する</string>
|
||||
<string name="removeImage">画像を削除</string>
|
||||
<string name="setBackImage">裏面の画像を設定</string>
|
||||
<string name="setFrontImage">表面の画像を設定</string>
|
||||
<string name="setFrontImage">オモテ面の画像を設定</string>
|
||||
<string name="photos">フォト</string>
|
||||
<string name="backImageDescription">裏面</string>
|
||||
<string name="frontImageDescription">表面</string>
|
||||
<string name="backImageDescription">カードの裏面</string>
|
||||
<string name="frontImageDescription">カードのオモテ面</string>
|
||||
<string name="importStocardMessage">Stocardでエクスポートした<i>***-sync.zip</i>ファイルを選択してください。
|
||||
\nファイルがない場合、e-mailing support@stocardapp.comにデータのエクスポートを要求してください。</string>
|
||||
<string name="importStocard">Stocardからインポート</string>
|
||||
@@ -183,7 +183,7 @@
|
||||
<string name="settings_pink_theme">Pink</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_theme_color">テーマカラー</string>
|
||||
<string name="settings_system_locale">システム</string>
|
||||
<string name="settings_system_locale">システムに従う</string>
|
||||
<string name="settings_locale">言語</string>
|
||||
<string name="noGroupCards">このグループにはカードがありません</string>
|
||||
<string name="swipeToSwitchImages">画像を切り替えるには長押し、またはスワイプ</string>
|
||||
@@ -192,5 +192,18 @@
|
||||
<string name="sort_by_expiry">期限</string>
|
||||
<string name="sort_by_most_recently_used">最近使用したカード</string>
|
||||
<string name="sort_by_name">名前</string>
|
||||
<string name="sort">ソート</string>
|
||||
<string name="sort">並び替え</string>
|
||||
<string name="rate_this_app">このアプリを評価する</string>
|
||||
<string name="on_github">GitHub</string>
|
||||
<string name="source_repository">ソースリポジトリ</string>
|
||||
<string name="exportPassword">パスワードを設定してエクスポートしたファイルを保護する(任意)</string>
|
||||
<string name="exportPasswordHint">パスワードを入力してください</string>
|
||||
<string name="version_history">更新履歴</string>
|
||||
<string name="credits">貢献者</string>
|
||||
<string name="help_translate_this_app">このアプリの翻訳を手伝う</string>
|
||||
<string name="license">ライセンス</string>
|
||||
<string name="on_google_play">Google Play</string>
|
||||
<string name="report_error">エラーを報告する</string>
|
||||
<string name="reverse">逆順</string>
|
||||
<string name="and_data_usage">and data usage</string>
|
||||
</resources>
|
||||
2
app/src/main/res/values-lb/strings.xml
Normal file
2
app/src/main/res/values-lb/strings.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
@@ -212,4 +212,6 @@
|
||||
<string name="on_google_play">Google Play</string>
|
||||
<string name="help_translate_this_app">Padėkite išversti šią programėlę</string>
|
||||
<string name="report_error">Pranešti apie klaidą</string>
|
||||
<string name="exportPasswordHint">Įveskite slaptažodį</string>
|
||||
<string name="exportPassword">Nustatykite slaptažodį, kad apsaugotumėte eksportavimą (neprivaloma)</string>
|
||||
</resources>
|
||||
24
app/src/main/res/values-pt/strings.xml
Normal file
24
app/src/main/res/values-pt/strings.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="action_add">Acrescentar</string>
|
||||
<string name="importOptionFilesystemExplanation">Escolha um ficheiro específico a partir do sistema de ficheiros.</string>
|
||||
<string name="action_search">Pesquisa</string>
|
||||
<string name="star">Adicionar aos favoritos</string>
|
||||
<string name="noMatchingGiftCards">Não encontrei nada. Tente alterar a sua pesquisa.</string>
|
||||
<string name="storeName">Nome</string>
|
||||
<string name="note">Nota</string>
|
||||
<string name="barcodeType">Tipo de código de barras</string>
|
||||
<string name="barcodeNoBarcode">Este cartão não tem código de barras</string>
|
||||
<string name="cancel">Cancelar</string>
|
||||
<string name="save">Guardar</string>
|
||||
<string name="edit">Edição</string>
|
||||
<string name="noGiftCards">Clique no botão + + para adicionar um cartão, ou importe algum do menu ⋮ primeiro.</string>
|
||||
<string name="noBarcode">Não há código de barras</string>
|
||||
<string name="unstar">Retirar dos favoritos</string>
|
||||
<string name="importOptionFilesystemButton">Do sistema de arquivo</string>
|
||||
<string name="importOptionApplicationTitle">Use outro aplicativo</string>
|
||||
<string name="importOptionApplicationExplanation">Utilize qualquer aplicação ou o seu gestor de ficheiros favorito para abrir um ficheiro.</string>
|
||||
<string name="importOptionApplicationButton">Utilize outro aplicativo</string>
|
||||
<string name="about">Sobre</string>
|
||||
<string name="app_license">Copylefted software livre, licenciado GPLv3+</string>
|
||||
</resources>
|
||||
@@ -24,4 +24,79 @@
|
||||
<string name="star">Adaugă la favorite</string>
|
||||
<string name="noBarcode">Fără cod de bare</string>
|
||||
<string name="barcodeNoBarcode">Acest card nu are cod de bare</string>
|
||||
<string name="moveDown">Mutarea în jos</string>
|
||||
<string name="card">Cardul</string>
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="all">Toate</string>
|
||||
<string name="noCardsMessage">Adăugați mai întâi o carte</string>
|
||||
<string name="noCardExistsError">Nu a putut găsi cardul</string>
|
||||
<string name="failedParsingImportUriError">Nu s-a putut analiza URI-ul de import</string>
|
||||
<string name="importExport">Importație/Export</string>
|
||||
<string name="exportName">Exportați</string>
|
||||
<string name="importSuccessfulTitle">Importat</string>
|
||||
<string name="importFailedTitle">Importul a eșuat</string>
|
||||
<string name="importFailed">Nu s-a putut importa carduri</string>
|
||||
<string name="noCardIdError">Nu s-a introdus niciun ID de card</string>
|
||||
<string name="exportFailed">Nu s-a putut exporta carduri</string>
|
||||
<string name="importing">Importul…</string>
|
||||
<string name="exporting">Exportul…</string>
|
||||
<string name="noExternalStoragePermissionError">Acordați mai întâi permisiunea de stocare externă pentru a importa sau exporta carduri</string>
|
||||
<string name="exportOptionExplanation">Datele vor fi scrise într-o locație aleasă de dumneavoastră.</string>
|
||||
<string name="importOptionFilesystemTitle">Import din sistemul de fișiere</string>
|
||||
<string name="importOptionApplicationTitle">Utilizați o altă aplicație</string>
|
||||
<string name="starImage">Steaua preferată</string>
|
||||
<string name="settings">Setări</string>
|
||||
<string name="settings_category_title_ui">Interfață utilizator</string>
|
||||
<string name="intent_import_card_from_url_share_text">Vreau să împărtășesc o carte cu tine</string>
|
||||
<string name="moveUp">Mutarea în sus</string>
|
||||
<string name="editCardTitle">Editare card</string>
|
||||
<string name="addCardTitle">Adaugă card</string>
|
||||
<string name="importOptionFilesystemButton">Din sistemul de fișiere</string>
|
||||
<string name="importOptionApplicationExplanation">Utilizați orice aplicație sau managerul de fișiere preferat pentru a deschide un fișier.</string>
|
||||
<string name="about">Despre</string>
|
||||
<string name="app_license">Software liber cu copyleft, licențiat GPLv3+</string>
|
||||
<string name="enterBarcodeInstructions">Introduceți ID-ul cardului și alegeți fie tipul de cod de bare de mai jos, fie \"Acest card nu are cod de bare\".</string>
|
||||
<string name="settings_system_theme">Sistemul</string>
|
||||
<string name="settings_light_theme">Lumină</string>
|
||||
<string name="settings_dark_theme">Întuneric</string>
|
||||
<string name="noBarcodeFound">Nu a fost găsit niciun cod de bare</string>
|
||||
<string name="settings_max_font_size_scale">Mărimea maximă a fontului</string>
|
||||
<string name="settings_display_barcode_max_brightness">Luminați vizualizarea codurilor de bare</string>
|
||||
<string name="settings_lock_barcode_orientation">Blocare orientare cod de bare</string>
|
||||
<string name="settings_keep_screen_on">Păstrați ecranul pornit</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">Evitați ecranul de blocare</string>
|
||||
<string name="balance">Balanță</string>
|
||||
<string name="importSuccessful">Date de card importate</string>
|
||||
<string name="exportSuccessful">Datele cardului exportate</string>
|
||||
<string name="noGroups">Faceți clic pe butonul + plus pentru a adăuga mai întâi grupuri pentru clasificare.</string>
|
||||
<string name="deleteConfirmationGroup">Ștergeți grupul\?</string>
|
||||
<string name="failedOpeningFileManager">Instalați mai întâi un manager de fișiere.</string>
|
||||
<string name="leaveWithoutSaveTitle">Ieșire</string>
|
||||
<string name="addManually">Introduceți manual ID-ul cardului</string>
|
||||
<string name="barcode">Cod de bare</string>
|
||||
<string name="currency">Monedă</string>
|
||||
<string name="editBarcode">Editarea codului de bare</string>
|
||||
<string name="chooseExpiryDate">Alegeți data de expirare</string>
|
||||
<string name="moveBarcodeToCenterOfScreen">Centrați codul de bare pe ecran</string>
|
||||
<string name="copy_to_clipboard_toast">ID-ul cardului copiat în clipboard</string>
|
||||
<string name="noStoreError">Nici un nume introdus</string>
|
||||
<string name="selectBarcodeTitle">Selectare cod de bare</string>
|
||||
<string name="noGroupCards">Acest grup nu conține nicio carte</string>
|
||||
<string name="addFromImage">Selectați imaginea din galerie</string>
|
||||
<string name="never">Niciodată</string>
|
||||
<string name="groups">Grupuri</string>
|
||||
<string name="leaveWithoutSaveConfirmation">Să pleci fără să salvezi\?</string>
|
||||
<string name="expiryDate">Data expirării</string>
|
||||
<string name="moveBarcodeToTopOfScreen">Mutați codul de bare în partea de sus a ecranului</string>
|
||||
<string name="errorReadingImage">Nu s-a putut citi imaginea</string>
|
||||
<string name="points">Puncte</string>
|
||||
<string name="cardShortcut">Scurtătură de card</string>
|
||||
<string name="scanCardBarcode">Scanarea codului de bare al cardului</string>
|
||||
<string name="importExportHelp">Copierea de rezervă a cardurilor vă permite să le mutați pe un alt dispozitiv.</string>
|
||||
<string name="exportSuccessfulTitle">Exportată</string>
|
||||
<string name="exportFailedTitle">Export eșuat</string>
|
||||
<string name="importOptionFilesystemExplanation">Alegeți un anumit fișier din sistemul de fișiere.</string>
|
||||
<string name="importOptionApplicationButton">Utilizați o altă aplicație</string>
|
||||
<string name="thumbnailDescription">Miniatură pentru card</string>
|
||||
<string name="enter_group_name">Introduceți numele grupului</string>
|
||||
</resources>
|
||||
@@ -50,7 +50,7 @@
|
||||
<string name="noBarcodeFound">Жодного штрих-коду не знайдено</string>
|
||||
<string name="moveBarcodeToCenterOfScreen">Відцентрувати штрих-код на екрані</string>
|
||||
<string name="moveBarcodeToTopOfScreen">Посунути штрих-код наверх екрану</string>
|
||||
<string name="chooseExpiryDate">Оберіть дату закінчення терміну дії</string>
|
||||
<string name="chooseExpiryDate">Оберіть дату</string>
|
||||
<string name="never">Ніколи</string>
|
||||
<string name="expiryDate">Дата закінчення терміну дії</string>
|
||||
<string name="editBarcode">Редагувати штрих-код</string>
|
||||
@@ -101,7 +101,7 @@
|
||||
\nавторські права © 2016–2020 Branden Archer</string>
|
||||
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Авторські права © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="about">Про програму</string>
|
||||
<string name="importOptionApplicationButton">Використайте іншу програму</string>
|
||||
<string name="importOptionApplicationButton">Вибір програми</string>
|
||||
<string name="importOptionApplicationExplanation">Використайте іншу програму чи ваш улюблений файл-менеджер для відкриття файлу.</string>
|
||||
<string name="importOptionApplicationTitle">З іншої програми</string>
|
||||
<string name="importOptionFilesystemButton">Обрати файл</string>
|
||||
@@ -216,4 +216,6 @@
|
||||
<string name="rate_this_app">Оцінити програму</string>
|
||||
<string name="on_google_play">у Google Play</string>
|
||||
<string name="report_error">Повідомити про помилку</string>
|
||||
<string name="exportPassword">Встановіть пароль для захисту експорту (необов\'язково)</string>
|
||||
<string name="exportPasswordHint">Введіть пароль</string>
|
||||
</resources>
|
||||
207
app/src/main/res/values-zh-rTW/strings.xml
Normal file
207
app/src/main/res/values-zh-rTW/strings.xml
Normal file
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="app_revision_url">https://github.com/TheLastProject/Catima/releases</string>
|
||||
<string name="action_search">搜尋</string>
|
||||
<string name="action_add">新增</string>
|
||||
<string name="noGiftCards">點選 + 按鈕以新增卡片\n或從 ⋮ 選單中匯入卡片</string>
|
||||
<string name="noMatchingGiftCards">沒有找到任何東西。試試其他關鍵字。</string>
|
||||
<string name="storeName">名稱</string>
|
||||
<string name="note">註記</string>
|
||||
<string name="cardId">卡片 ID</string>
|
||||
<string name="barcodeType">條碼種類</string>
|
||||
<string name="barcodeNoBarcode">此卡片沒有可用的條碼</string>
|
||||
<string name="noBarcode">無條碼</string>
|
||||
<string name="privacy_policy_popup_text">隱私權政策(某些應用程式商店需要此條目): 我們並不會收集任何資料!任何人都可以檢視我們的原始碼並驗證這點。</string>
|
||||
<string name="star">新增至收藏</string>
|
||||
<string name="app_license">公共版權 (Copylefted) 的自由軟體,許可 GPLv3+</string>
|
||||
<string name="unstar">從收藏中移除</string>
|
||||
<string name="cancel">取消</string>
|
||||
<string name="save">儲存</string>
|
||||
<string name="edit">編輯</string>
|
||||
<string name="delete">刪除</string>
|
||||
<string name="confirm">確認</string>
|
||||
<string name="about">關於</string>
|
||||
<string name="about_title_fmt">關於 <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="accept">接受</string>
|
||||
<string name="addCardTitle">新增卡片</string>
|
||||
<string name="addFromImage">從圖庫中選擇圖片</string>
|
||||
<string name="addManually">手動輸入卡片 ID</string>
|
||||
<string name="all">全部</string>
|
||||
<string name="balance">餘額</string>
|
||||
<string name="balanceSentence">餘額: <xliff:g>%s</xliff:g></string>
|
||||
<string name="balancePoints"><xliff:g>%s</xliff:g> 點</string>
|
||||
<string name="app_copyright_old">基於 Loyalty Card Keychain\n著作權所有 © 2016–2020 Branden Archer</string>
|
||||
<string name="barcode">條碼</string>
|
||||
<string name="barcodeId">條碼內容</string>
|
||||
<string name="barcodeImageDescriptionWithType">條碼種類 <xliff:g>%s</xliff:g> 的圖片</string>
|
||||
<string name="card">卡片</string>
|
||||
<string name="card_ids_copied">已複製卡片 ID(s)</string>
|
||||
<string name="cardShortcut">卡片捷徑</string>
|
||||
<string name="chooseExpiryDate">選擇逾期日期</string>
|
||||
<string name="chooseImportType">從哪裡匯入資料?</string>
|
||||
<string name="copy_to_clipboard">已複製 ID 至剪貼簿中</string>
|
||||
<string name="copy_to_clipboard_multiple_toast">已複製多個卡片 ID 至剪貼簿中</string>
|
||||
<string name="copy_to_clipboard_toast">已複製卡片 ID 至剪貼簿中</string>
|
||||
<string name="credits">貢獻者</string>
|
||||
<string name="currency">幣別</string>
|
||||
<string name="debug_version_fmt">版本:<xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="deleteConfirmation">永久刪除此卡片?</string>
|
||||
<string name="deleteConfirmationGroup">刪除此群組?</string>
|
||||
<string name="deleteTitle">刪除卡片</string>
|
||||
<string name="editBarcode">編輯條碼</string>
|
||||
<string name="editCardTitle">編輯圖片</string>
|
||||
<string name="enter_group_name">輸入群組名稱</string>
|
||||
<string name="enterBarcodeInstructions">輸入卡片 ID、選擇條碼種類、或選擇「此卡片沒有可用的條碼」。</string>
|
||||
<string name="errorReadingImage">無法讀取此圖片</string>
|
||||
<string name="expiryDate">逾期日期</string>
|
||||
<string name="expiryStateSentence">逾期於:<xliff:g>%s</xliff:g></string>
|
||||
<string name="expiryStateSentenceExpired">已逾期:<xliff:g>%s</xliff:g></string>
|
||||
<string name="exportFailed">無法匯出卡片</string>
|
||||
<string name="exportFailedTitle">匯出失敗</string>
|
||||
<string name="exporting">匯出中…</string>
|
||||
<string name="exportName">匯出</string>
|
||||
<string name="exportOptionExplanation">資料將寫至您所選的位置。</string>
|
||||
<string name="exportPassword">透過密碼保護您的匯出檔 (選用)</string>
|
||||
<string name="exportPasswordHint">輸入密碼</string>
|
||||
<string name="exportSuccessful">已匯出卡片資訊</string>
|
||||
<string name="exportSuccessfulTitle">已匯出</string>
|
||||
<string name="failedOpeningFileManager">請先安裝檔案管理員。</string>
|
||||
<string name="failedParsingImportUriError">無法讀取匯入 URI</string>
|
||||
<string name="frontImageDescription">卡片 (正面)</string>
|
||||
<string name="groups">群組</string>
|
||||
<string name="groupsList">群組:<xliff:g>%s</xliff:g></string>
|
||||
<string name="help_translate_this_app">幫助翻譯本程式</string>
|
||||
<string name="importExport">匯入/匯出</string>
|
||||
<string name="importFailedTitle">匯入失敗</string>
|
||||
<string name="importFailed">無法匯入卡片</string>
|
||||
<string name="importing">匯入中…</string>
|
||||
<string name="importSuccessfulTitle">已匯入</string>
|
||||
<string name="intent_import_card_from_url_share_multiple_text">我想要分享些卡片給你</string>
|
||||
<string name="intent_import_card_from_url_share_text">我想要分享張卡片給你</string>
|
||||
<string name="leaveWithoutSaveConfirmation">不保存就離開?</string>
|
||||
<string name="leaveWithoutSaveTitle">離開</string>
|
||||
<string name="license">許可</string>
|
||||
<string name="never">永不</string>
|
||||
<string name="no">否</string>
|
||||
<string name="noBarcodeFound">找不到可用的條碼</string>
|
||||
<string name="noCardExistsError">無法找到卡片</string>
|
||||
<string name="noCardIdError">尚未輸入卡片 ID</string>
|
||||
<string name="noCardsMessage">請先新增卡片</string>
|
||||
<string name="sort">排列</string>
|
||||
<string name="settings_catima_theme">Catima</string>
|
||||
<string name="settings_pink_theme">粉紅</string>
|
||||
<string name="settings_magenta_theme">品紅</string>
|
||||
<string name="settings_violet_theme">紫色</string>
|
||||
<string name="settings_blue_theme">藍色</string>
|
||||
<string name="settings_sky_blue_theme">天空藍</string>
|
||||
<string name="settings_green_theme">綠色</string>
|
||||
<string name="settings_grey_theme">灰色</string>
|
||||
<string name="settings_brown_theme">棕色</string>
|
||||
<string name="sort_by_name">名稱</string>
|
||||
<string name="sort_by_most_recently_used">最近使用</string>
|
||||
<string name="sort_by_expiry">逾期日期</string>
|
||||
<string name="sort_by_balance">餘額</string>
|
||||
<string name="reverse">反序</string>
|
||||
<string name="sort_by">排列方式</string>
|
||||
<string name="version_history">版本歷史</string>
|
||||
<string name="source_repository">原始碼版本庫</string>
|
||||
<string name="on_github">於 GitHub</string>
|
||||
<string name="and_data_usage">及資料使用</string>
|
||||
<string name="rate_this_app">替本 App 評分</string>
|
||||
<string name="on_google_play">於 Google Play</string>
|
||||
<string name="report_error">回報錯誤</string>
|
||||
<string name="setBarcodeId">設定條碼內容</string>
|
||||
<string name="sameAsCardId">與卡片 ID 相同</string>
|
||||
<string name="photos">圖片</string>
|
||||
<string name="setFrontImage">設定正面圖片</string>
|
||||
<string name="setBackImage">設定背面圖片</string>
|
||||
<string name="removeImage">移除圖片</string>
|
||||
<string name="takePhoto">拍照</string>
|
||||
<string name="updateBarcodeQuestionTitle">更新條碼內容?</string>
|
||||
<string name="yes">是</string>
|
||||
<string name="passwordRequired">請輸入密碼</string>
|
||||
<string name="turn_flashlight_on">開啟手電筒</string>
|
||||
<string name="turn_flashlight_off">關閉手電筒</string>
|
||||
<string name="settings_locale">語言</string>
|
||||
<string name="settings_system_locale">系統語言</string>
|
||||
<string name="settings_theme_color">主題顏色</string>
|
||||
<string name="app_contributors">感謝以下貢獻者: <xliff:g id="app_contributors">%s</xliff:g></string>
|
||||
<string name="privacy_policy">隱私權政策</string>
|
||||
<plurals name="selectedCardCount">
|
||||
<item quantity="other">已選取 <xliff:g>%d</xliff:g> 張卡片</item>
|
||||
</plurals>
|
||||
<plurals name="deleteCardsTitle">
|
||||
<item quantity="other">刪除 <xliff:g>%d</xliff:g> 張卡片</item>
|
||||
</plurals>
|
||||
<plurals name="deleteCardsConfirmation">
|
||||
<item quantity="other">永久刪除 <xliff:g>%d</xliff:g> 張卡片?</item>
|
||||
</plurals>
|
||||
<plurals name="groupCardCount">
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> 張卡片</item>
|
||||
</plurals>
|
||||
<string name="settings">設定</string>
|
||||
<string name="share">分享</string>
|
||||
<string name="settings_system_theme">系統主題</string>
|
||||
<string name="settings_theme">主題</string>
|
||||
<string name="thumbnailDescription">卡片縮圖</string>
|
||||
<string name="noGroupCards">此群組中無任何卡片</string>
|
||||
<string name="settings_category_title_ui">用戶界面</string>
|
||||
<string name="settings_max_font_size_scale">最大字體大小</string>
|
||||
<string name="settings_light_theme">淺色</string>
|
||||
<string name="settings_dark_theme">深色</string>
|
||||
<string name="settings_display_barcode_max_brightness">調高條碼介面螢幕亮度</string>
|
||||
<string name="settings_lock_barcode_orientation">鎖定條碼螢幕方向</string>
|
||||
<string name="settings_keep_screen_on">螢幕恆亮</string>
|
||||
<string name="settings_disable_lockscreen_while_viewing_card">防止螢幕鎖定</string>
|
||||
<string name="importSuccessful">已匯入卡片資訊</string>
|
||||
<string name="moveUp">往上移動</string>
|
||||
<string name="moveDown">往下移動</string>
|
||||
<string name="lockScreen">禁止旋轉</string>
|
||||
<string name="unlockScreen">允許旋轉</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="sendLabel">送出…</string>
|
||||
<string name="scanCardBarcode">掃描卡片條碼</string>
|
||||
<string name="noStoreError">尚未輸入卡片名稱</string>
|
||||
<string name="importExportHelp">備份您的卡片以將這些卡片移至其他裝置中。</string>
|
||||
<string name="noExternalStoragePermissionError">在匯入及匯出卡片前,請先允許外部儲存裝置存取權限</string>
|
||||
<string name="importOptionFilesystemTitle">自檔案系統中匯入</string>
|
||||
<string name="importOptionFilesystemExplanation">自檔案系統中選取檔案。</string>
|
||||
<string name="importOptionFilesystemButton">自檔案系統</string>
|
||||
<string name="importOptionApplicationTitle">使用其他應用程式</string>
|
||||
<string name="importOptionApplicationButton">使用其他應用程式</string>
|
||||
<string name="importOptionApplicationExplanation">使用任何應用程式選擇您所想要匯入的檔案。</string>
|
||||
<string name="app_copyright_fmt">著作權所有 © 2019–<xliff:g>%d</xliff:g> Sylvia van Os</string>
|
||||
<string name="importVoucherVault">自 Voucher Vault 中匯入</string>
|
||||
<string name="importVoucherVaultMessage">選取您自 Voucher Vault 匯出的 <i>vouchervault.json</i> 檔案以進行匯入。
|
||||
\n請您先透過 Voucher Vault 進行匯出。</string>
|
||||
<string name="importStocard">自 Stocard 中匯入</string>
|
||||
<string name="importStocardMessage">>選取您自 Stocard 匯出的 <i>***-sync.zip</i> 檔案以進行匯入。
|
||||
\n請您寫封 Email 至 support@stocardapp.com 索取您的資料。</string>
|
||||
<string name="importLoyaltyCardKeychain">自 Loyalty Card Keychain 中匯入</string>
|
||||
<string name="importLoyaltyCardKeychainMessage">選取您自 Loyalty Card Keychain <i>LoyaltyCardKeychain.csv</i> 檔案以進行匯入。
|
||||
\n請您先透過 Loyalty Card Keychain 的匯入/匯出選單進行匯出。</string>
|
||||
<string name="importFidme">自 FidMe 匯入</string>
|
||||
<string name="importFidmeMessage">選取您自 FidMe 匯出的<i>fidme-export-request-xxxxxx.zip</i> 檔案以進行匯入,並手動選擇條碼種類。
|
||||
\n請您先透過您的 FidMe 個人檔案選取『Data Protection』,並選擇『Extract my data』。</string>
|
||||
<string name="importCatima">自 Catima 匯入</string>
|
||||
<string name="importCatimaMessage">選取您自 Catima 匯出的 <i>catima.zip</i> 檔案以進行匯入。
|
||||
\n您可透過其他裝置的 Catima 程式中的匯入/匯出選單進行匯出。</string>
|
||||
<string name="points">點</string>
|
||||
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> 似乎不是個可用的餘額數值。</string>
|
||||
<string name="app_revision_fmt">修訂版本資訊:<xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="app_libraries">第三方自由函示庫:<xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="app_resources">第三方自由資源:<xliff:g id="app_resources_list">%s</xliff:g></string>
|
||||
<string name="selectBarcodeTitle">選擇條碼</string>
|
||||
<string name="noGroups">請先點選 + 加號按鈕新增群組。</string>
|
||||
<string name="moveBarcodeToTopOfScreen">將條碼移至螢幕上方</string>
|
||||
<string name="moveBarcodeToCenterOfScreen">將條碼移至螢幕中央</string>
|
||||
<string name="app_loyalty_card_keychain">Loyalty Card Keychain</string>
|
||||
<string name="unsupportedBarcodeType">尚支援此條碼種類,但未來版本的應用程式可能會支援此條碼種類。</string>
|
||||
<string name="wrongValueForBarcodeType">條碼內容不適用於此條碼種類</string>
|
||||
<string name="backImageDescription">卡片 (背面)</string>
|
||||
<string name="updateBarcodeQuestionText">您已更新了條碼 ID,是否要更新條碼內容以匹配此 ID?</string>
|
||||
<string name="failedGeneratingShareURL">無法建立可分享的 URL,請回報此錯誤。</string>
|
||||
<string name="toggleMoreInfo">切換顯示更多內容</string>
|
||||
<string name="swipeToSwitchImages">滑動或長按以切換圖片</string>
|
||||
<string name="starImage">收藏標示</string>
|
||||
</resources>
|
||||
@@ -40,15 +40,20 @@
|
||||
<string-array name="locale_values">
|
||||
<item />
|
||||
<item>bg</item>
|
||||
<item>bn-rIN</item>
|
||||
<item>bs</item>
|
||||
<item>cs</item>
|
||||
<item>da</item>
|
||||
<item>de</item>
|
||||
<item>el-rGR</item>
|
||||
<item>eo</item>
|
||||
<item>es-rAR</item>
|
||||
<item>es</item>
|
||||
<item>es-rAR</item>
|
||||
<item>fi</item>
|
||||
<item>fr</item>
|
||||
<item>he-rIL</item>
|
||||
<item>hr</item>
|
||||
<item>in-rID</item>
|
||||
<item>it</item>
|
||||
<item>ja</item>
|
||||
<item>ko</item>
|
||||
@@ -57,11 +62,15 @@
|
||||
<item>nl</item>
|
||||
<item>oc</item>
|
||||
<item>pl</item>
|
||||
<item>pt</item>
|
||||
<item>ro-rRO</item>
|
||||
<item>ru</item>
|
||||
<item>sk</item>
|
||||
<item>sl</item>
|
||||
<item>sv</item>
|
||||
<item>tr</item>
|
||||
<item>uk</item>
|
||||
<item>zh-TW</item>
|
||||
<item>zh-rCN</item>
|
||||
</string-array>
|
||||
|
||||
@@ -82,4 +91,4 @@
|
||||
<!-- Constraints -->
|
||||
<integer name="settings_max_font_size_scale_pct_min">50</integer>
|
||||
<integer name="settings_max_font_size_scale_pct_max">200</integer>
|
||||
</resources>
|
||||
</resources>
|
||||
|
||||
@@ -2,7 +2,6 @@ package protect.card_locker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Looper;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
@@ -13,16 +12,19 @@ import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.android.controller.ActivityController;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowLooper;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(sdk = 23)
|
||||
public class BarcodeSelectorActivityTest {
|
||||
@Test
|
||||
public void emptyStateTest()
|
||||
{
|
||||
public void emptyStateTest() {
|
||||
ActivityController activityController = Robolectric.buildActivity(BarcodeSelectorActivity.class).create();
|
||||
activityController.start();
|
||||
activityController.resume();
|
||||
@@ -41,8 +43,7 @@ public class BarcodeSelectorActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonEmptyStateTest() throws InterruptedException
|
||||
{
|
||||
public void nonEmptyStateTest() throws InterruptedException {
|
||||
ActivityController activityController = Robolectric.buildActivity(BarcodeSelectorActivity.class).create();
|
||||
activityController.start();
|
||||
activityController.resume();
|
||||
@@ -54,11 +55,12 @@ public class BarcodeSelectorActivityTest {
|
||||
|
||||
cardId.setText("abcdefg");
|
||||
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
// Run the delayed Handler
|
||||
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
|
||||
|
||||
// Button should be visible and enabled
|
||||
assertEquals(View.VISIBLE, noBarcodeButton.getVisibility());
|
||||
assertEquals(true, noBarcodeButton.isEnabled());
|
||||
assertTrue(noBarcodeButton.isEnabled());
|
||||
|
||||
// Clicking button should create "empty" barcode
|
||||
activity.findViewById(R.id.noBarcode).performClick();
|
||||
@@ -70,8 +72,7 @@ public class BarcodeSelectorActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonEmptyToEmptyStateTest() throws InterruptedException
|
||||
{
|
||||
public void nonEmptyToEmptyStateTest() throws InterruptedException {
|
||||
ActivityController activityController = Robolectric.buildActivity(BarcodeSelectorActivity.class).create();
|
||||
activityController.start();
|
||||
activityController.resume();
|
||||
@@ -83,18 +84,20 @@ public class BarcodeSelectorActivityTest {
|
||||
|
||||
cardId.setText("abcdefg");
|
||||
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
// Run the delayed Handler
|
||||
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
|
||||
|
||||
// Button should be visible and enabled
|
||||
assertEquals(View.VISIBLE, noBarcodeButton.getVisibility());
|
||||
assertEquals(true, noBarcodeButton.isEnabled());
|
||||
assertTrue(noBarcodeButton.isEnabled());
|
||||
|
||||
cardId.setText("");
|
||||
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
// Run the delayed Handler
|
||||
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
|
||||
|
||||
// Button should be visible but disabled
|
||||
assertEquals(View.VISIBLE, noBarcodeButton.getVisibility());
|
||||
assertEquals(false, noBarcodeButton.isEnabled());
|
||||
assertFalse(noBarcodeButton.isEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,6 +503,8 @@ public class DatabaseTest
|
||||
assertEquals(BarcodeFormat.UPC_A, card.barcodeType.format());
|
||||
assertEquals(null, card.headerColor);
|
||||
assertEquals(0, card.starStatus);
|
||||
assertEquals(0,card.lastUsed);
|
||||
assertEquals(100,card.zoomLevel);
|
||||
|
||||
// Determine that the entries are queryable and the fields are correct
|
||||
LoyaltyCard card2 = db.getLoyaltyCard(newCardId2);
|
||||
@@ -516,6 +518,8 @@ public class DatabaseTest
|
||||
assertEquals(null, card2.barcodeType); // Empty string should've become null
|
||||
assertEquals(null, card2.headerColor);
|
||||
assertEquals(0, card2.starStatus);
|
||||
assertEquals(0,card2.lastUsed);
|
||||
assertEquals(100,card2.zoomLevel);
|
||||
|
||||
database.close();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.os.Environment;
|
||||
import android.os.Looper;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
@@ -20,6 +21,7 @@ import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.annotation.LooperMode;
|
||||
import org.robolectric.shadows.ShadowLog;
|
||||
import org.robolectric.shadows.ShadowLooper;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -33,6 +35,7 @@ import java.io.OutputStreamWriter;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.ParseException;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
@@ -42,6 +45,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import protect.card_locker.async.TaskHandler;
|
||||
import protect.card_locker.importexport.DataFormat;
|
||||
import protect.card_locker.importexport.ImportExportResult;
|
||||
import protect.card_locker.importexport.MultiFormatExporter;
|
||||
@@ -51,11 +56,11 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(sdk = 23)
|
||||
public class ImportExportTest
|
||||
{
|
||||
public class ImportExportTest {
|
||||
private Activity activity;
|
||||
private DBHelper db;
|
||||
private long nowMs;
|
||||
@@ -66,8 +71,7 @@ public class ImportExportTest
|
||||
private final CatimaBarcode BARCODE_TYPE = CatimaBarcode.fromBarcode(BarcodeFormat.UPC_A);
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
public void setUp() {
|
||||
ShadowLog.stream = System.out;
|
||||
|
||||
activity = Robolectric.setupActivity(MainActivity.class);
|
||||
@@ -75,20 +79,19 @@ public class ImportExportTest
|
||||
nowMs = System.currentTimeMillis();
|
||||
|
||||
Calendar lastYear = Calendar.getInstance();
|
||||
lastYear.set(Calendar.YEAR, lastYear.get(Calendar.YEAR)-1);
|
||||
lastYear.set(Calendar.YEAR, lastYear.get(Calendar.YEAR) - 1);
|
||||
lastYearMs = lastYear.getTimeInMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given number of cards, each with
|
||||
* an index in the store name.
|
||||
*
|
||||
* @param cardsToAdd
|
||||
*/
|
||||
private void addLoyaltyCards(int cardsToAdd)
|
||||
{
|
||||
private void addLoyaltyCards(int cardsToAdd) {
|
||||
// Add in reverse order to test sorting
|
||||
for(int index = cardsToAdd; index > 0; index--)
|
||||
{
|
||||
for (int index = cardsToAdd; index > 0; index--) {
|
||||
String storeName = String.format("store, \"%4d", index);
|
||||
String note = String.format("note, \"%4d", index);
|
||||
long id = db.insertLoyaltyCard(storeName, note, null, new BigDecimal(String.valueOf(index)), null, BARCODE_DATA, null, BARCODE_TYPE, index, 0, null);
|
||||
@@ -99,20 +102,17 @@ public class ImportExportTest
|
||||
assertEquals(cardsToAdd, db.getLoyaltyCardCount());
|
||||
}
|
||||
|
||||
private void addLoyaltyCardsFiveStarred()
|
||||
{
|
||||
private void addLoyaltyCardsFiveStarred() {
|
||||
int cardsToAdd = 9;
|
||||
// Add in reverse order to test sorting
|
||||
for(int index = cardsToAdd; index > 4; index--)
|
||||
{
|
||||
for (int index = cardsToAdd; index > 4; index--) {
|
||||
String storeName = String.format("store, \"%4d", index);
|
||||
String note = String.format("note, \"%4d", index);
|
||||
long id = db.insertLoyaltyCard(storeName, note, null, new BigDecimal(String.valueOf(index)), null, BARCODE_DATA, null, BARCODE_TYPE, index, 1, null);
|
||||
boolean result = (id != -1);
|
||||
assertTrue(result);
|
||||
}
|
||||
for(int index = cardsToAdd-5; index > 0; index--)
|
||||
{
|
||||
for (int index = cardsToAdd - 5; index > 0; index--) {
|
||||
String storeName = String.format("store, \"%4d", index);
|
||||
String note = String.format("note, \"%4d", index);
|
||||
//if index is even
|
||||
@@ -124,8 +124,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addLoyaltyCardsWithExpiryNeverPastTodayFuture()
|
||||
{
|
||||
public void addLoyaltyCardsWithExpiryNeverPastTodayFuture() {
|
||||
long id = db.insertLoyaltyCard("No Expiry", "", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, 0, 0, null);
|
||||
boolean result = (id != -1);
|
||||
assertTrue(result);
|
||||
@@ -165,8 +164,8 @@ public class ImportExportTest
|
||||
card = db.getLoyaltyCard((int) id);
|
||||
assertEquals("Today", card.store);
|
||||
assertEquals("", card.note);
|
||||
assertTrue(card.expiry.before(new Date(new Date().getTime()+86400)));
|
||||
assertTrue(card.expiry.after(new Date(new Date().getTime()-86400)));
|
||||
assertTrue(card.expiry.before(new Date(new Date().getTime() + 86400)));
|
||||
assertTrue(card.expiry.after(new Date(new Date().getTime() - 86400)));
|
||||
assertEquals(new BigDecimal("0"), card.balance);
|
||||
assertEquals(null, card.balanceType);
|
||||
assertEquals(BARCODE_DATA, card.cardId);
|
||||
@@ -184,7 +183,7 @@ public class ImportExportTest
|
||||
card = db.getLoyaltyCard((int) id);
|
||||
assertEquals("Future", card.store);
|
||||
assertEquals("", card.note);
|
||||
assertTrue(card.expiry.after(new Date(new Date().getTime()+86400)));
|
||||
assertTrue(card.expiry.after(new Date(new Date().getTime() + 86400)));
|
||||
assertEquals(new BigDecimal("0"), card.balance);
|
||||
assertEquals(null, card.balanceType);
|
||||
assertEquals(BARCODE_DATA, card.cardId);
|
||||
@@ -196,11 +195,9 @@ public class ImportExportTest
|
||||
assertEquals(4, db.getLoyaltyCardCount());
|
||||
}
|
||||
|
||||
private void addGroups(int groupsToAdd)
|
||||
{
|
||||
private void addGroups(int groupsToAdd) {
|
||||
// Add in reverse order to test sorting
|
||||
for(int index = groupsToAdd; index > 0; index--)
|
||||
{
|
||||
for (int index = groupsToAdd; index > 0; index--) {
|
||||
String groupName = String.format("group, \"%4d", index);
|
||||
long id = db.insertGroup(groupName);
|
||||
boolean result = (id != -1);
|
||||
@@ -215,13 +212,11 @@ public class ImportExportTest
|
||||
* specified in addLoyaltyCards(), and are in sequential order
|
||||
* where the smallest card's index is 1
|
||||
*/
|
||||
private void checkLoyaltyCards()
|
||||
{
|
||||
private void checkLoyaltyCards() {
|
||||
Cursor cursor = db.getLoyaltyCardCursor();
|
||||
int index = 1;
|
||||
|
||||
while(cursor.moveToNext())
|
||||
{
|
||||
while (cursor.moveToNext()) {
|
||||
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cursor);
|
||||
|
||||
String expectedStore = String.format("store, \"%4d", index);
|
||||
@@ -248,13 +243,11 @@ public class ImportExportTest
|
||||
* specified in addLoyaltyCardsSomeStarred(), and are in sequential order
|
||||
* with starred ones first
|
||||
*/
|
||||
private void checkLoyaltyCardsFiveStarred()
|
||||
{
|
||||
Cursor cursor = db.getLoyaltyCardCursor();
|
||||
int index = 5;
|
||||
private void checkLoyaltyCardsFiveStarred() {
|
||||
Cursor cursor = db.getLoyaltyCardCursor();
|
||||
int index = 5;
|
||||
|
||||
while(index<10)
|
||||
{
|
||||
while (index < 10) {
|
||||
cursor.moveToNext();
|
||||
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cursor);
|
||||
|
||||
@@ -276,26 +269,25 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
index = 1;
|
||||
while(cursor.moveToNext() && index<5)
|
||||
{
|
||||
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cursor);
|
||||
while (cursor.moveToNext() && index < 5) {
|
||||
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cursor);
|
||||
|
||||
String expectedStore = String.format("store, \"%4d", index);
|
||||
String expectedNote = String.format("note, \"%4d", index);
|
||||
String expectedStore = String.format("store, \"%4d", index);
|
||||
String expectedNote = String.format("note, \"%4d", index);
|
||||
|
||||
assertEquals(expectedStore, card.store);
|
||||
assertEquals(expectedNote, card.note);
|
||||
assertEquals(null, card.expiry);
|
||||
assertEquals(new BigDecimal(String.valueOf(index)), card.balance);
|
||||
assertEquals(null, card.balanceType);
|
||||
assertEquals(BARCODE_DATA, card.cardId);
|
||||
assertEquals(null, card.barcodeId);
|
||||
assertEquals(BARCODE_TYPE.format(), card.barcodeType.format());
|
||||
assertEquals(Integer.valueOf(index), card.headerColor);
|
||||
assertEquals(0, card.starStatus);
|
||||
assertEquals(expectedStore, card.store);
|
||||
assertEquals(expectedNote, card.note);
|
||||
assertEquals(null, card.expiry);
|
||||
assertEquals(new BigDecimal(String.valueOf(index)), card.balance);
|
||||
assertEquals(null, card.balanceType);
|
||||
assertEquals(BARCODE_DATA, card.cardId);
|
||||
assertEquals(null, card.barcodeId);
|
||||
assertEquals(BARCODE_TYPE.format(), card.barcodeType.format());
|
||||
assertEquals(Integer.valueOf(index), card.headerColor);
|
||||
assertEquals(0, card.starStatus);
|
||||
|
||||
index++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
}
|
||||
@@ -305,13 +297,11 @@ public class ImportExportTest
|
||||
* specified in addGroups(), and are in sequential order
|
||||
* where the smallest group's index is 1
|
||||
*/
|
||||
private void checkGroups()
|
||||
{
|
||||
private void checkGroups() {
|
||||
Cursor cursor = db.getGroupCursor();
|
||||
int index = db.getGroupCount();
|
||||
|
||||
while(cursor.moveToNext())
|
||||
{
|
||||
while (cursor.moveToNext()) {
|
||||
Group group = Group.toGroup(cursor);
|
||||
|
||||
String expectedGroupName = String.format("group, \"%4d", index);
|
||||
@@ -324,8 +314,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleCardsExportImport() throws IOException
|
||||
{
|
||||
public void multipleCardsExportImport() throws IOException {
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
addLoyaltyCards(NUM_CARDS);
|
||||
@@ -334,7 +323,7 @@ public class ImportExportTest
|
||||
OutputStreamWriter outStream = new OutputStreamWriter(outData);
|
||||
|
||||
// Export data to CSV format
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,null);
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, null);
|
||||
assertEquals(ImportExportResult.Success, result);
|
||||
outStream.close();
|
||||
|
||||
@@ -354,18 +343,17 @@ public class ImportExportTest
|
||||
TestHelpers.getEmptyDb(activity);
|
||||
}
|
||||
|
||||
public void multipleCardsExportImportPasswordProtected() throws IOException
|
||||
{
|
||||
public void multipleCardsExportImportPasswordProtected() throws IOException {
|
||||
final int NUM_CARDS = 10;
|
||||
List<char[]> passwords = Arrays.asList(null, "123456789".toCharArray());
|
||||
for(char[] password : passwords){
|
||||
for (char[] password : passwords) {
|
||||
addLoyaltyCards(NUM_CARDS);
|
||||
|
||||
ByteArrayOutputStream outData = new ByteArrayOutputStream();
|
||||
OutputStreamWriter outStream = new OutputStreamWriter(outData);
|
||||
|
||||
// Export data to CSV format
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,password);
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, password);
|
||||
assertEquals(ImportExportResult.Success, result);
|
||||
outStream.close();
|
||||
|
||||
@@ -388,8 +376,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleCardsExportImportSomeStarred() throws IOException
|
||||
{
|
||||
public void multipleCardsExportImportSomeStarred() throws IOException {
|
||||
final int NUM_CARDS = 9;
|
||||
|
||||
addLoyaltyCardsFiveStarred();
|
||||
@@ -398,7 +385,7 @@ public class ImportExportTest
|
||||
OutputStreamWriter outStream = new OutputStreamWriter(outData);
|
||||
|
||||
// Export data to CSV format
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,null);
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, null);
|
||||
assertEquals(ImportExportResult.Success, result);
|
||||
outStream.close();
|
||||
|
||||
@@ -418,8 +405,7 @@ public class ImportExportTest
|
||||
TestHelpers.getEmptyDb(activity);
|
||||
}
|
||||
|
||||
private List<String> groupsToGroupNames(List<Group> groups)
|
||||
{
|
||||
private List<String> groupsToGroupNames(List<Group> groups) {
|
||||
List<String> groupNames = new ArrayList<>();
|
||||
|
||||
for (Group group : groups) {
|
||||
@@ -430,8 +416,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleCardsExportImportWithGroups() throws IOException
|
||||
{
|
||||
public void multipleCardsExportImportWithGroups() throws IOException {
|
||||
final int NUM_CARDS = 10;
|
||||
final int NUM_GROUPS = 3;
|
||||
|
||||
@@ -471,7 +456,7 @@ public class ImportExportTest
|
||||
OutputStreamWriter outStream = new OutputStreamWriter(outData);
|
||||
|
||||
// Export data to CSV format
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,null);
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, null);
|
||||
assertEquals(ImportExportResult.Success, result);
|
||||
outStream.close();
|
||||
|
||||
@@ -505,8 +490,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importExistingCardsNotReplace() throws IOException
|
||||
{
|
||||
public void importExistingCardsNotReplace() throws IOException {
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
addLoyaltyCards(NUM_CARDS);
|
||||
@@ -515,7 +499,7 @@ public class ImportExportTest
|
||||
OutputStreamWriter outStream = new OutputStreamWriter(outData);
|
||||
|
||||
// Export into CSV data
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,null);
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, null);
|
||||
assertEquals(ImportExportResult.Success, result);
|
||||
outStream.close();
|
||||
|
||||
@@ -534,19 +518,17 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void corruptedImportNothingSaved() throws IOException
|
||||
{
|
||||
public void corruptedImportNothingSaved() throws IOException {
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
for(DataFormat format : DataFormat.values())
|
||||
{
|
||||
for (DataFormat format : DataFormat.values()) {
|
||||
addLoyaltyCards(NUM_CARDS);
|
||||
|
||||
ByteArrayOutputStream outData = new ByteArrayOutputStream();
|
||||
OutputStreamWriter outStream = new OutputStreamWriter(outData);
|
||||
|
||||
// Export data to CSV format
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,null);
|
||||
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima, null);
|
||||
assertEquals(ImportExportResult.Success, result);
|
||||
|
||||
TestHelpers.getEmptyDb(activity);
|
||||
@@ -569,20 +551,17 @@ public class ImportExportTest
|
||||
}
|
||||
}
|
||||
|
||||
class TestTaskCompleteListener implements ImportExportTask.TaskCompleteListener
|
||||
{
|
||||
class TestTaskCompleteListener implements ImportExportTask.TaskCompleteListener {
|
||||
ImportExportResult result;
|
||||
|
||||
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat)
|
||||
{
|
||||
public void onTaskComplete(ImportExportResult result, DataFormat dataFormat) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@LooperMode(LooperMode.Mode.LEGACY)
|
||||
public void useImportExportTask() throws FileNotFoundException
|
||||
{
|
||||
@LooperMode(LooperMode.Mode.PAUSED)
|
||||
public void useImportExportTask() throws FileNotFoundException {
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
final File sdcardDir = Environment.getExternalStorageDirectory();
|
||||
@@ -595,11 +574,15 @@ public class ImportExportTest
|
||||
// Export to the file
|
||||
final String password = "123456789";
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(exportFile);
|
||||
ImportExportTask task = new ImportExportTask(activity, DataFormat.Catima, fileOutputStream,password.toCharArray(), listener);
|
||||
task.execute();
|
||||
ImportExportTask task = new ImportExportTask(activity, DataFormat.Catima, fileOutputStream, password.toCharArray(), listener);
|
||||
TaskHandler mTasks = new TaskHandler();
|
||||
mTasks.executeTask(TaskHandler.TYPE.EXPORT, task);
|
||||
|
||||
// Actually run the task to completion
|
||||
Robolectric.flushBackgroundThreadScheduler();
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.EXPORT, false, false, true);
|
||||
shadowOf(Looper.getMainLooper()).idleFor(Duration.ofMillis(5000));
|
||||
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
|
||||
|
||||
|
||||
// Check that the listener was executed
|
||||
assertNotNull(listener.result);
|
||||
@@ -614,10 +597,13 @@ public class ImportExportTest
|
||||
FileInputStream fileStream = new FileInputStream(exportFile);
|
||||
|
||||
task = new ImportExportTask(activity, DataFormat.Catima, fileStream, password.toCharArray(), listener);
|
||||
task.execute();
|
||||
mTasks.executeTask(TaskHandler.TYPE.IMPORT, task);
|
||||
|
||||
// Actually run the task to completion
|
||||
Robolectric.flushBackgroundThreadScheduler();
|
||||
// I am CONVINCED there must be a better way than to wait on this Queue with a flush.
|
||||
mTasks.flushTaskList(TaskHandler.TYPE.IMPORT, false, false, true);
|
||||
shadowOf(Looper.getMainLooper()).idleFor(Duration.ofMillis(5000));
|
||||
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
|
||||
|
||||
// Check that the listener was executed
|
||||
assertNotNull(listener.result);
|
||||
@@ -632,8 +618,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importWithoutColorsV1() throws IOException
|
||||
{
|
||||
public void importWithoutColorsV1() throws IOException {
|
||||
String csvText = "";
|
||||
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
|
||||
DBHelper.LoyaltyCardDbIds.STORE + "," +
|
||||
@@ -668,8 +653,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importWithoutNullColorsV1() throws IOException
|
||||
{
|
||||
public void importWithoutNullColorsV1() throws IOException {
|
||||
String csvText = "";
|
||||
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
|
||||
DBHelper.LoyaltyCardDbIds.STORE + "," +
|
||||
@@ -706,8 +690,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importWithoutInvalidColorsV1() throws IOException
|
||||
{
|
||||
public void importWithoutInvalidColorsV1() throws IOException {
|
||||
String csvText = "";
|
||||
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
|
||||
DBHelper.LoyaltyCardDbIds.STORE + "," +
|
||||
@@ -731,8 +714,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importWithNoBarcodeTypeV1() throws IOException
|
||||
{
|
||||
public void importWithNoBarcodeTypeV1() throws IOException {
|
||||
String csvText = "";
|
||||
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
|
||||
DBHelper.LoyaltyCardDbIds.STORE + "," +
|
||||
@@ -769,8 +751,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importWithStarredFieldV1() throws IOException
|
||||
{
|
||||
public void importWithStarredFieldV1() throws IOException {
|
||||
String csvText = "";
|
||||
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
|
||||
DBHelper.LoyaltyCardDbIds.STORE + "," +
|
||||
@@ -807,8 +788,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importWithNoStarredFieldV1() throws IOException
|
||||
{
|
||||
public void importWithNoStarredFieldV1() throws IOException {
|
||||
String csvText = "";
|
||||
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
|
||||
DBHelper.LoyaltyCardDbIds.STORE + "," +
|
||||
@@ -845,8 +825,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importWithInvalidStarFieldV1() throws IOException
|
||||
{
|
||||
public void importWithInvalidStarFieldV1() throws IOException {
|
||||
String csvText = "";
|
||||
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
|
||||
DBHelper.LoyaltyCardDbIds.STORE + "," +
|
||||
@@ -902,8 +881,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exportImportV2Zip() throws FileNotFoundException
|
||||
{
|
||||
public void exportImportV2Zip() throws FileNotFoundException {
|
||||
// Prepare images
|
||||
BitmapDrawable launcher = (BitmapDrawable) ResourcesCompat.getDrawableForDensity(activity.getResources(), R.mipmap.ic_launcher, DisplayMetrics.DENSITY_XXXHIGH, activity.getTheme());
|
||||
BitmapDrawable roundLauncher = (BitmapDrawable) ResourcesCompat.getDrawableForDensity(activity.getResources(), R.mipmap.ic_launcher_round, DisplayMetrics.DENSITY_XXXHIGH, activity.getTheme());
|
||||
@@ -935,7 +913,7 @@ public class ImportExportTest
|
||||
|
||||
// Export everything
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
MultiFormatExporter.exportData(activity.getApplicationContext(), db, outputStream, DataFormat.Catima,null);
|
||||
MultiFormatExporter.exportData(activity.getApplicationContext(), db, outputStream, DataFormat.Catima, null);
|
||||
|
||||
// Wipe database
|
||||
TestHelpers.getEmptyDb(activity);
|
||||
@@ -959,25 +937,25 @@ public class ImportExportTest
|
||||
assertEquals(loyaltyCard.cardId, dbLoyaltyCard.cardId);
|
||||
assertEquals(loyaltyCard.barcodeId, dbLoyaltyCard.barcodeId);
|
||||
assertEquals(loyaltyCard.starStatus, dbLoyaltyCard.starStatus);
|
||||
assertEquals(loyaltyCard.barcodeType != null ? loyaltyCard.barcodeType.format() : null, dbLoyaltyCard.barcodeType != null? dbLoyaltyCard.barcodeType.format() : null);
|
||||
assertEquals(loyaltyCard.barcodeType != null ? loyaltyCard.barcodeType.format() : null, dbLoyaltyCard.barcodeType != null ? dbLoyaltyCard.barcodeType.format() : null);
|
||||
assertEquals(loyaltyCard.balanceType, dbLoyaltyCard.balanceType);
|
||||
assertEquals(loyaltyCard.headerColor, dbLoyaltyCard.headerColor);
|
||||
|
||||
List<Group> emptyGroup = new ArrayList<>();
|
||||
|
||||
assertEquals(
|
||||
groupsToGroupNames(
|
||||
(List<Group>) Utils.mapGetOrDefault(
|
||||
loyaltyCardGroups,
|
||||
loyaltyCardID,
|
||||
emptyGroup
|
||||
groupsToGroupNames(
|
||||
(List<Group>) Utils.mapGetOrDefault(
|
||||
loyaltyCardGroups,
|
||||
loyaltyCardID,
|
||||
emptyGroup
|
||||
)
|
||||
),
|
||||
groupsToGroupNames(
|
||||
db.getLoyaltyCardGroups(
|
||||
loyaltyCardID
|
||||
)
|
||||
)
|
||||
),
|
||||
groupsToGroupNames(
|
||||
db.getLoyaltyCardGroups(
|
||||
loyaltyCardID
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
Bitmap expectedFrontImage = loyaltyCardFrontImages.get(loyaltyCardID);
|
||||
@@ -1000,8 +978,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importV2CSV()
|
||||
{
|
||||
public void importV2CSV() {
|
||||
String csvText = "2\n" +
|
||||
"\n" +
|
||||
"_id\n" +
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
- QR_CODE
|
||||
- UPC_A
|
||||
|
||||
- Vygenerované čárové kódy jsou větší, snadněji se skenují ze skenovacího zařízení.
|
||||
- Vygenerované čárové kódy jsou větší, snadněji se skenují ze skenovacího zařízení
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
- Překlad do nizozemštiny
|
||||
- Umožnit editaci pole se jménem po přidání věrnostní karty
|
||||
- Přidat nepovinné pole pro poznámku
|
||||
- Vyřešit všechny problémy identifikované nástrojem FindBugs a vyžadovat vyřešení všech problémů FindBugs před přijetím požadavku na stažení.
|
||||
- Vyřešit všechny problémy identifikované nástrojem FindBugs a vyžadovat vyřešení všech problémů FindBugs před přijetím požadavku na stažení
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
Počínaje touto verzí již není systém Android 4.4 podporován. Pokud chcete používat Catimu v systému Android 4.4, použijte verzi 2.6.1.
|
||||
|
||||
- Vylepšená podpora systému Android 12
|
||||
- Vylepšená obrazovka o aplikaci
|
||||
- Vylepšená obrazovka s informacemi
|
||||
- Vyhledávání nyní ignoruje diakritiku
|
||||
|
||||
3
fastlane/metadata/android/cs_CZ/changelogs/89.txt
Normal file
3
fastlane/metadata/android/cs_CZ/changelogs/89.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
- Oprava nefunkčního přecházení mezi skupinami v prázdné skupině
|
||||
- Povolení exportu chráněného heslem
|
||||
- Zlepšení využití prostoru pro kódy QR
|
||||
@@ -1,3 +1,5 @@
|
||||
- Fix swiping between groups not working on an empty group
|
||||
- Allow password-protecting exports
|
||||
- Improve usage of space for QR codes
|
||||
- Improve usage of space for QR codes
|
||||
- Save the last used zoom level per card
|
||||
- Fix a crash when swiping right after a tap
|
||||
@@ -1,2 +1,5 @@
|
||||
- Gruplar arasında kaydırmanın boş bir grup üzerinde çalışmaması düzeltildi
|
||||
- Parola korumalı dışa aktarmalara izin ver
|
||||
- QR kodları için boşluk kullanımını iyileştir
|
||||
- Kart başına en son kullanılan yakınlaştırma seviyesini kaydet
|
||||
- Dokunduktan sonra sağa kaydırmada çökmeyi düzelt
|
||||
|
||||
@@ -20,4 +20,3 @@
|
||||
|
||||
Спростіть своє життя та покупки, і ніколи більше не втрачайте паперову квитанцію, подарункову картку магазину або квиток на літак.
|
||||
Візьміть із собою всі свої нагороди та бонуси та економте на ходу.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user