Compare commits

..

2 Commits

Author SHA1 Message Date
Sylvia van Os
a434397551 Merge branch 'master' of github.com:TheLastProject/loyalty-card-locker into fix/deprecatedProgressDialog 2021-12-18 14:48:13 +01:00
Sylvia van Os
ae1ccab059 Replace ProgressDialog with notification 2021-11-28 21:48:48 +01:00
423 changed files with 1731 additions and 4228 deletions

View File

@@ -17,8 +17,7 @@ jobs:
days-before-close: 90
close-issue-message: 'This issue is missing necessary information and cannot be worked on in its current state. It has therefore been closed to keep the issue tracker clean. If you have more information, feel free to reopen it.'
close-pr-message: 'This PR is missing necessary information and cannot be merged in its current state. It has therefore been closed to keep the issue tracker clean. If you have more information, feel free to reopen it.'
only-labels: 'state: needs info'
stale-issue-label: 'state: needs info'
stale-pr-label: 'state: needs info'
only-labels: 'needs info'
stale-issue-label: 'needs info'
stale-pr-label: 'needs info'
remove-stale-when-updated: false
enable-statistics: true

View File

@@ -1,71 +1,8 @@
# Changelog
## v2.17.0 - 108
- Add card duplication feature
- Don't allow choosing expiry before 1970 (they never worked anyway)
- Add support for archiving cards
- Move delete from edit to view
- Remove rotation lock icon in favour of a new rotation lock setting
## v2.16.3 - 107 (2022-04-15)
- Stocard import fixes
## v2.16.2 - 106 (2022-03-31)
- Fix some character sequences being shown as a single character
## v2.16.1 - 105 (2022-03-25)
- Fix gray block appearing on invalid value for barcode
- Stocard import fixes
## v2.16.0 - 104 (2022-03-09)
- Save card detail expansion state
- Minor UI fixes
## v2.15.2 - 103 (2022-02-11)
- Fix manual language selection not applying everywhere
- Fix crash in edit view on regionless locale
## v2.15.1 - 102 (2022-02-10)
- Various minor fixes
- Fix crash when using Norwegian translation
## v2.15.0 - 101 (2022-02-06)
- Fix cropper not using theme colour
- Fix minor theming issues
- Add pure black dark theme for OLED screens
## v2.14.1 - 100 (2022-01-15)
- Hide search, expand and sort icons until there is at least 1 card
- Various theming fixes
## v2.14.0 - 99 (2022-01-14)
- Material You redesign
## v2.13.1 - 98 (2022-01-09)
- Fix various TalkBack-related bugs
## v2.13.0 - 97 (2022-01-03)
- Fixed pressing the save button multiple times creating multiple entries
- Lower card header size when hiding details to fit even more cards
- Restructure edit screen
- Improve star icon contrast in main view
## v2.12.0 - 96 (2021-12-23)
## Unreleased - 96
- Add CODE 93 support
- Various minor bugfixes and improvements
## v2.11.2 - 95 (2021-12-04)

View File

@@ -1,3 +0,0 @@
github: TheLastProject
custom:
- "https://paypal.me/sylviavanos"

View File

@@ -1,30 +1,29 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.5)
rexml
CFPropertyList (3.0.3)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.597.0)
aws-sdk-core (3.131.1)
aws-partitions (1.501.0)
aws-sdk-core (3.121.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.57.0)
aws-sdk-core (~> 3, >= 3.127.0)
jmespath (~> 1.0)
aws-sdk-kms (1.48.0)
aws-sdk-core (~> 3, >= 3.120.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.114.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-s3 (1.102.0)
aws-sdk-core (~> 3, >= 3.120.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.0)
aws-sigv4 (1.4.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
claide (1.0.3)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
@@ -35,19 +34,18 @@ GEM
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
emoji_regex (3.2.3)
excon (0.92.3)
faraday (1.10.0)
emoji_regex (3.2.2)
excon (0.85.0)
faraday (1.7.2)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-httpclient (~> 1.0.1)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-net_http_persistent (~> 1.1)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
multipart-post (>= 1.2, < 3)
ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
@@ -56,17 +54,14 @@ GEM
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday_middleware (1.1.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.206.2)
fastimage (2.2.5)
fastlane (2.193.1)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@@ -106,9 +101,9 @@ GEM
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.21.0)
google-apis-androidpublisher_v3 (0.11.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-core (0.5.0)
google-apis-core (0.4.1)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -117,53 +112,53 @@ GEM
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.10.0)
google-apis-iamcredentials_v1 (0.7.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-playcustomapp_v1 (0.7.0)
google-apis-playcustomapp_v1 (0.5.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-storage_v1 (0.14.0)
google-apis-storage_v1 (0.6.0)
google-apis-core (>= 0.4, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.2.0)
google-cloud-storage (1.36.2)
addressable (~> 2.8)
google-cloud-env (1.5.0)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.1.0)
google-cloud-storage (1.34.1)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.1)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.1.3)
faraday (>= 0.17.3, < 3.a)
googleauth (0.17.1)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
signet (~> 0.15)
highline (2.0.3)
http-cookie (1.0.5)
http-cookie (1.0.4)
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.6.1)
json (2.6.2)
jwt (2.4.1)
jmespath (1.4.0)
json (2.5.1)
jwt (2.2.3)
memoist (0.16.2)
mini_magick (4.11.0)
mini_mime (1.1.2)
mini_mime (1.1.1)
multi_json (1.15.0)
multipart-post (2.0.0)
nanaimo (0.3.0)
naturally (2.2.1)
optparse (0.1.1)
os (1.1.4)
os (1.1.1)
plist (3.6.0)
public_suffix (4.0.7)
public_suffix (4.0.6)
rake (13.0.6)
representable (3.2.0)
representable (3.1.1)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
@@ -173,9 +168,9 @@ GEM
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.16.1)
signet (0.16.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.0)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.8)
@@ -184,7 +179,7 @@ GEM
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
trailblazer-option (0.1.2)
trailblazer-option (0.1.1)
tty-cursor (0.7.1)
tty-screen (0.8.1)
tty-spinner (0.9.3)
@@ -192,8 +187,8 @@ GEM
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
unf_ext (0.0.8)
unicode-display_width (1.7.0)
webrick (1.7.0)
word_wrap (1.0.0)
xcodeproj (1.21.0)

View File

@@ -18,8 +18,8 @@ android {
applicationId "me.hackerchick.catima"
minSdkVersion 21
targetSdkVersion 31
versionCode 108
versionName "2.17.0"
versionCode 95
versionName "2.11.2"
vectorDrawables.useSupportLibrary true
multiDexEnabled true
@@ -80,25 +80,25 @@ android {
dependencies {
// AndroidX
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
implementation 'androidx.exifinterface:exifinterface:1.3.3'
implementation 'androidx.palette:palette:1.0.0'
implementation 'androidx.preference:preference:1.2.0'
implementation 'com.google.android.material:material:1.6.1'
implementation 'com.github.yalantis:ucrop:2.2.8'
implementation 'androidx.preference:preference:1.1.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'com.github.yalantis:ucrop:2.2.7'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
// Splash Screen
implementation 'androidx.core:core-splashscreen:1.0.0-rc01'
implementation 'androidx.core:core-splashscreen:1.0.0-alpha02'
// Third-party
implementation 'com.journeyapps:zxing-android-embedded:4.3.0@aar'
implementation 'com.google.zxing:core:3.5.0'
implementation 'com.google.zxing:core:3.4.1'
implementation 'org.apache.commons:commons-csv:1.9.0'
implementation 'com.jaredrummler:colorpicker:1.1.0'
implementation 'com.github.invissvenska:NumberPickerPreference:1.0.4'
implementation 'net.lingala.zip4j:zip4j:2.11.1'
implementation 'net.lingala.zip4j:zip4j:2.9.1'
// SpotBugs
implementation 'io.wcm.tooling.spotbugs:io.wcm.tooling.spotbugs.annotations:1.0.0'
@@ -106,7 +106,7 @@ dependencies {
// Testing
testImplementation 'androidx.test:core:1.4.0'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.8.1'
testImplementation 'org.robolectric:robolectric:4.7.3'
}
tasks.withType(SpotBugsTask) {

View File

@@ -116,7 +116,7 @@
</activity>
<activity
android:name=".UCropWrapper"
android:name="com.yalantis.ucrop.UCropActivity"
android:theme="@style/AppTheme.NoActionBar" />
<provider
@@ -134,5 +134,7 @@
<action android:name="android.service.controls.ControlsProviderService" />
</intent-filter>
</service>
</application>
</manifest>

View File

@@ -151,13 +151,13 @@ public class AboutActivity extends CatimaAppCompatActivity implements View.OnCli
} else if (id == R.id.translate) {
url = "https://hosted.weblate.org/engage/catima/";
} else if (id == R.id.license) {
url = "https://github.com/CatimaLoyalty/Android/blob/master/LICENSE";
url = "https://github.com/TheLastProject/Catima/blob/master/LICENSE";
} else if (id == R.id.repo) {
url = "https://github.com/CatimaLoyalty/Android/";
url = "https://github.com/TheLastProject/Catima/";
} else if (id == R.id.privacy) {
url = "https://catima.app/privacy-policy/";
} else if (id == R.id.report_error) {
url = "https://github.com/CatimaLoyalty/Android/issues";
url = "https://github.com/TheLastProject/Catima/issues";
} else if (id == R.id.rate) {
url = "https://play.google.com/store/apps/details?id=me.hackerchick.catima";
} else {

View File

@@ -5,7 +5,6 @@ import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
@@ -47,7 +46,7 @@ public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
BarcodeImageWriterTask(
Context context, ImageView imageView, String cardIdString,
CatimaBarcode barcodeFormat, TextView textView,
boolean showFallback, Runnable callback, boolean roundCornerPadding
boolean showFallback, Runnable callback
) {
mContext = context;
@@ -61,32 +60,18 @@ public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
cardId = cardIdString;
format = barcodeFormat;
int padding = 0;
// Some barcodes already have internal whitespace and shouldn't get extra padding
// TODO: Get rid of this hack by somehow detecting this extra whitespace
if (roundCornerPadding && !barcodeFormat.hasInternalPadding()) {
padding = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, context.getResources().getDisplayMetrics()));
}
final int MAX_WIDTH = getMaxWidth(format);
int tempImageHeight;
int tempImageWidth;
if (imageView.getWidth() < MAX_WIDTH) {
tempImageHeight = imageView.getHeight();
tempImageWidth = imageView.getWidth();
imageHeight = imageView.getHeight();
imageWidth = imageView.getWidth();
} else {
// Scale down the image to reduce the memory needed to produce it
tempImageWidth = MAX_WIDTH;
imageWidth = MAX_WIDTH;
double ratio = (double) MAX_WIDTH / (double) imageView.getWidth();
tempImageHeight = (int) (imageView.getHeight() * ratio);
imageHeight = (int) (imageView.getHeight() * ratio);
}
// Ensure space for padding if wanted
imageWidth = tempImageWidth;
imageHeight = tempImageHeight - padding;
this.showFallback = showFallback;
}

View File

@@ -76,7 +76,6 @@ public class BarcodeSelectorAdapter extends ArrayAdapter<CatimaBarcodeWithValue>
final CatimaBarcode format = CatimaBarcode.fromName(formatType);
image.setImageBitmap(null);
image.setClipToOutline(true);
if (image.getHeight() == 0) {
// The size of the ImageView is not yet available as it has not
@@ -90,13 +89,13 @@ public class BarcodeSelectorAdapter extends ArrayAdapter<CatimaBarcodeWithValue>
Log.d(TAG, "Generating barcode for type " + formatType);
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getContext(), image, cardId, format, text, true, null, true);
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getContext(), image, cardId, format, text, true, null);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
});
} else {
Log.d(TAG, "Generating barcode for type " + formatType);
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getContext(), image, cardId, format, text, true, null, true);
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getContext(), image, cardId, format, text, true, null);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
}

View File

@@ -4,8 +4,6 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
@@ -18,10 +16,9 @@ import androidx.recyclerview.widget.RecyclerView;
/**
* The configuration screen for creating a shortcut.
*/
public class CardShortcutConfigure extends CatimaAppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener {
public class CardShortcutConfigure extends AppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener {
static final String TAG = "Catima";
private SQLiteDatabase mDatabase;
private LoyaltyCardCursorAdapter mAdapter;
@Override
public void onCreate(Bundle bundle) {
@@ -36,34 +33,26 @@ public class CardShortcutConfigure extends CatimaAppCompatActivity implements Lo
setContentView(R.layout.simple_toolbar_list_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle(R.string.shortcutSelectCard);
setSupportActionBar(toolbar);
// If there are no cards, bail
int cardCount = DBHelper.getLoyaltyCardCount(mDatabase);
if (cardCount == 0) {
if (DBHelper.getLoyaltyCardCount(mDatabase) == 0) {
Toast.makeText(this, R.string.noCardsMessage, Toast.LENGTH_LONG).show();
finish();
}
// If all cards are archived, bail
if (DBHelper.getArchivedCardsCount(mDatabase) == cardCount) {
Toast.makeText(this, R.string.noUnarchivedCardsMessage, Toast.LENGTH_LONG).show();
finish();
}
final RecyclerView cardList = findViewById(R.id.list);
GridLayoutManager layoutManager = (GridLayoutManager) cardList.getLayoutManager();
if (layoutManager != null) {
layoutManager.setSpanCount(getResources().getInteger(R.integer.main_view_card_columns));
}
Cursor cardCursor = DBHelper.getLoyaltyCardCursor(mDatabase, DBHelper.LoyaltyCardArchiveFilter.Unarchived);
mAdapter = new LoyaltyCardCursorAdapter(this, cardCursor, this);
cardList.setAdapter(mAdapter);
Cursor cardCursor = DBHelper.getLoyaltyCardCursor(mDatabase);
final LoyaltyCardCursorAdapter adapter = new LoyaltyCardCursorAdapter(this, cardCursor, this);
cardList.setAdapter(adapter);
}
private void onClickAction(int position) {
Cursor selected = DBHelper.getLoyaltyCardCursor(mDatabase, DBHelper.LoyaltyCardArchiveFilter.Unarchived);
Cursor selected = DBHelper.getLoyaltyCardCursor(mDatabase);
selected.moveToPosition(position);
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
@@ -76,26 +65,6 @@ public class CardShortcutConfigure extends CatimaAppCompatActivity implements Lo
finish();
}
@Override
public boolean onCreateOptionsMenu(Menu inputMenu) {
getMenuInflater().inflate(R.menu.card_details_menu, inputMenu);
Utils.updateMenuCardDetailsButtonState(inputMenu.findItem(R.id.action_unfold), mAdapter.showingDetails());
return super.onCreateOptionsMenu(inputMenu);
}
@Override
public boolean onOptionsItemSelected(MenuItem inputItem) {
int id = inputItem.getItemId();
if (id == R.id.action_unfold) {
mAdapter.showDetails(!mAdapter.showingDetails());
invalidateOptionsMenu();
return true;
}
return super.onOptionsItemSelected(inputItem);
}
@Override
public void onRowClicked(int inputPosition) {

View File

@@ -40,7 +40,7 @@ public class CardsOnPowerScreenService extends ControlsProviderService {
@NonNull
@Override
public Flow.Publisher<Control> createPublisherForAllAvailable() {
Cursor loyaltyCardCursor = DBHelper.getLoyaltyCardCursor(mDatabase, DBHelper.LoyaltyCardArchiveFilter.Unarchived);
Cursor loyaltyCardCursor = DBHelper.getLoyaltyCardCursor(mDatabase);
return subscriber -> {
while (loyaltyCardCursor.moveToNext()) {
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(loyaltyCardCursor);

View File

@@ -1,15 +1,20 @@
package protect.card_locker;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.util.TypedValue;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.preference.PreferenceManager;
import java.util.HashMap;
public class CatimaAppCompatActivity extends AppCompatActivity {
SharedPreferences pref;
HashMap<String, Integer> supportedThemes;
@Override
protected void attachBaseContext(Context base) {
// Apply chosen language
@@ -17,28 +22,32 @@ public class CatimaAppCompatActivity extends AppCompatActivity {
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// XXX splash screen activity has to do this after installing splash screen before view inflate
if (!this.getClass().getSimpleName().equals(MainActivity.class.getSimpleName())) {
Utils.patchColors(this);
public Resources.Theme getTheme() {
if (supportedThemes == null) {
supportedThemes = new HashMap<>();
supportedThemes.put(getString(R.string.settings_key_blue_theme), R.style.AppTheme_blue);
supportedThemes.put(getString(R.string.settings_key_brown_theme), R.style.AppTheme_brown);
supportedThemes.put(getString(R.string.settings_key_green_theme), R.style.AppTheme_green);
supportedThemes.put(getString(R.string.settings_key_grey_theme), R.style.AppTheme_grey);
supportedThemes.put(getString(R.string.settings_key_magenta_theme), R.style.AppTheme_magenta);
supportedThemes.put(getString(R.string.settings_key_pink_theme), R.style.AppTheme_pink);
supportedThemes.put(getString(R.string.settings_key_sky_blue_theme), R.style.AppTheme_sky_blue);
supportedThemes.put(getString(R.string.settings_key_violet_theme), R.style.AppTheme_violet);
}
Resources.Theme theme = super.getTheme();
pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
String themeName = pref.getString(getString(R.string.setting_key_theme_color), getString(R.string.settings_key_catima_theme));
theme.applyStyle(Utils.mapGetOrDefault(supportedThemes, themeName, R.style.AppTheme_NoActionBar), true);
return theme;
}
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// material 3 designer does not consider status bar colors
// XXX changing this in onCreate causes issues with the splash screen activity, so doing this here
boolean darkMode = Utils.isDarkModeEnabled(this);
if (Build.VERSION.SDK_INT >= 23) {
getWindow().setStatusBarColor(Color.TRANSPARENT);
getWindow().getDecorView().setSystemUiVisibility(darkMode ? 0 : View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
// icons are always white back then
getWindow().setStatusBarColor(darkMode ? Color.TRANSPARENT : Color.argb(127, 0, 0, 0));
}
// XXX android 9 and below has a nasty rendering bug if the theme was patched earlier
Utils.postPatchColors(this);
public int getThemeColor() {
TypedValue typedValue = new TypedValue();
Resources.Theme theme = getTheme();
theme.resolveAttribute(R.attr.colorPrimary, typedValue, true);
return typedValue.data;
}
}

View File

@@ -72,11 +72,6 @@ public class CatimaBarcode {
|| mBarcodeFormat == BarcodeFormat.QR_CODE;
}
public boolean hasInternalPadding() {
return mBarcodeFormat == BarcodeFormat.PDF_417
|| mBarcodeFormat == BarcodeFormat.QR_CODE;
}
public BarcodeFormat format() {
return mBarcodeFormat;
}

View File

@@ -21,7 +21,7 @@ import java.util.List;
public class DBHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "Catima.db";
public static final int ORIGINAL_DATABASE_VERSION = 1;
public static final int DATABASE_VERSION = 15;
public static final int DATABASE_VERSION = 14;
public static class LoyaltyCardDbGroups {
public static final String TABLE = "groups";
@@ -45,7 +45,6 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String STAR_STATUS = "starstatus";
public static final String LAST_USED = "lastused";
public static final String ZOOM_LEVEL = "zoomlevel";
public static final String ARCHIVE_STATUS = "archive";
}
public static class LoyaltyCardDbIdsGroups {
@@ -72,12 +71,6 @@ public class DBHelper extends SQLiteOpenHelper {
Descending
}
public enum LoyaltyCardArchiveFilter {
All,
Archived,
Unarchived
}
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@@ -104,8 +97,7 @@ public class DBHelper extends SQLiteOpenHelper {
LoyaltyCardDbIds.BARCODE_TYPE + " TEXT," +
LoyaltyCardDbIds.STAR_STATUS + " INTEGER DEFAULT '0'," +
LoyaltyCardDbIds.LAST_USED + " INTEGER DEFAULT '0', " +
LoyaltyCardDbIds.ZOOM_LEVEL + " INTEGER DEFAULT '100', " +
LoyaltyCardDbIds.ARCHIVE_STATUS + " INTEGER DEFAULT '0' )");
LoyaltyCardDbIds.ZOOM_LEVEL + " INTEGER DEFAULT '100' )");
// create associative table for cards in groups
db.execSQL("CREATE TABLE " + LoyaltyCardDbIdsGroups.TABLE + "(" +
@@ -310,10 +302,6 @@ public class DBHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
+ " ADD COLUMN " + LoyaltyCardDbIds.ZOOM_LEVEL + " INTEGER DEFAULT '100' ");
}
if (oldVersion < 15 && newVersion >= 15) {
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
+ " ADD COLUMN " + LoyaltyCardDbIds.ARCHIVE_STATUS + " INTEGER DEFAULT '0' ");
}
}
private static ContentValues generateFTSContentValues(final int id, final String store, final String note) {
@@ -361,7 +349,7 @@ public class DBHelper extends SQLiteOpenHelper {
final SQLiteDatabase database, final String store, final String note, final Date expiry,
final BigDecimal balance, final Currency balanceType, final String cardId,
final String barcodeId, final CatimaBarcode barcodeType, final Integer headerColor,
final int starStatus, final Long lastUsed,final int archiveStatus) {
final int starStatus, final Long lastUsed) {
database.beginTransaction();
// Card
@@ -377,7 +365,6 @@ public class DBHelper extends SQLiteOpenHelper {
contentValues.put(LoyaltyCardDbIds.HEADER_COLOR, headerColor);
contentValues.put(LoyaltyCardDbIds.STAR_STATUS, starStatus);
contentValues.put(LoyaltyCardDbIds.LAST_USED, lastUsed != null ? lastUsed : Utils.getUnixTime());
contentValues.put(LoyaltyCardDbIds.ARCHIVE_STATUS, archiveStatus);
long id = database.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
// FTS
@@ -393,7 +380,7 @@ public class DBHelper extends SQLiteOpenHelper {
final SQLiteDatabase database, final int id, final String store, final String note,
final Date expiry, final BigDecimal balance, final Currency balanceType,
final String cardId, final String barcodeId, final CatimaBarcode barcodeType,
final Integer headerColor, final int starStatus, final Long lastUsed, final int archiveStatus) {
final Integer headerColor, final int starStatus, final Long lastUsed) {
database.beginTransaction();
// Card
@@ -410,7 +397,6 @@ public class DBHelper extends SQLiteOpenHelper {
contentValues.put(LoyaltyCardDbIds.HEADER_COLOR, headerColor);
contentValues.put(LoyaltyCardDbIds.STAR_STATUS, starStatus);
contentValues.put(LoyaltyCardDbIds.LAST_USED, lastUsed != null ? lastUsed : Utils.getUnixTime());
contentValues.put(LoyaltyCardDbIds.ARCHIVE_STATUS, archiveStatus);
database.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
// FTS
@@ -452,15 +438,6 @@ public class DBHelper extends SQLiteOpenHelper {
return (rowsUpdated == 1);
}
public static boolean updateLoyaltyCardArchiveStatus(SQLiteDatabase database, final int id, final int archiveStatus) {
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbIds.ARCHIVE_STATUS, archiveStatus);
int rowsUpdated = database.update(LoyaltyCardDbIds.TABLE, contentValues,
whereAttrs(LoyaltyCardDbIds.ID),
withArgs(id));
return (rowsUpdated == 1);
}
public static boolean updateLoyaltyCardStarStatus(SQLiteDatabase database, final int id, final int starStatus) {
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbIds.STAR_STATUS, starStatus);
@@ -572,19 +549,9 @@ public class DBHelper extends SQLiteOpenHelper {
return (rowsDeleted == 1);
}
public static int getArchivedCardsCount(SQLiteDatabase database) {
return (int) DatabaseUtils.queryNumEntries(database, LoyaltyCardDbIds.TABLE,
whereAttrs(LoyaltyCardDbIds.ARCHIVE_STATUS), withArgs(1));
}
public static Cursor getLoyaltyCardCursor(SQLiteDatabase database) {
// An empty string will match everything
return getLoyaltyCardCursor(database, LoyaltyCardArchiveFilter.All);
}
public static Cursor getLoyaltyCardCursor(SQLiteDatabase database, LoyaltyCardArchiveFilter archiveFilter) {
// An empty string will match everything
return getLoyaltyCardCursor(database, "", archiveFilter);
return getLoyaltyCardCursor(database, "");
}
/**
@@ -593,8 +560,8 @@ public class DBHelper extends SQLiteOpenHelper {
* @param filter
* @return Cursor
*/
public static Cursor getLoyaltyCardCursor(SQLiteDatabase database, final String filter, LoyaltyCardArchiveFilter archiveFilter) {
return getLoyaltyCardCursor(database, filter, null, archiveFilter);
public static Cursor getLoyaltyCardCursor(SQLiteDatabase database, final String filter) {
return getLoyaltyCardCursor(database, filter, null);
}
/**
@@ -604,8 +571,8 @@ public class DBHelper extends SQLiteOpenHelper {
* @param group
* @return Cursor
*/
public static Cursor getLoyaltyCardCursor(SQLiteDatabase database, final String filter, Group group, LoyaltyCardArchiveFilter archiveFilter) {
return getLoyaltyCardCursor(database, filter, group, LoyaltyCardOrder.Alpha, LoyaltyCardOrderDirection.Ascending, archiveFilter);
public static Cursor getLoyaltyCardCursor(SQLiteDatabase database, final String filter, Group group) {
return getLoyaltyCardCursor(database, filter, group, LoyaltyCardOrder.Alpha, LoyaltyCardOrderDirection.Ascending);
}
/**
@@ -616,7 +583,7 @@ public class DBHelper extends SQLiteOpenHelper {
* @param order
* @return Cursor
*/
public static Cursor getLoyaltyCardCursor(SQLiteDatabase database, String filter, Group group, LoyaltyCardOrder order, LoyaltyCardOrderDirection direction, LoyaltyCardArchiveFilter archiveFilter) {
public static Cursor getLoyaltyCardCursor(SQLiteDatabase database, String filter, Group group, LoyaltyCardOrder order, LoyaltyCardOrderDirection direction) {
StringBuilder groupFilter = new StringBuilder();
String limitString = "";
@@ -639,11 +606,6 @@ public class DBHelper extends SQLiteOpenHelper {
}
}
String archiveFilterString = "";
if (archiveFilter != LoyaltyCardArchiveFilter.All) {
archiveFilterString = " AND " + LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.ARCHIVE_STATUS + " = " + (archiveFilter.equals(LoyaltyCardArchiveFilter.Unarchived) ? 0 : 1);
}
String orderField = getFieldForOrder(order);
return database.rawQuery("SELECT " + LoyaltyCardDbIds.TABLE + ".* FROM " + LoyaltyCardDbIds.TABLE +
@@ -651,9 +613,7 @@ public class DBHelper extends SQLiteOpenHelper {
" ON " + LoyaltyCardDbFTS.TABLE + "." + LoyaltyCardDbFTS.ID + " = " + LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.ID +
(filter.trim().isEmpty() ? " " : " AND " + LoyaltyCardDbFTS.TABLE + " MATCH ? ") +
groupFilter.toString() +
archiveFilterString +
" ORDER BY " + LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.ARCHIVE_STATUS + " ASC, " +
LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.STAR_STATUS + " DESC, " +
" ORDER BY " + LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.STAR_STATUS + " DESC, " +
" (CASE WHEN " + LoyaltyCardDbIds.TABLE + "." + orderField + " IS NULL THEN 1 ELSE 0 END), " +
LoyaltyCardDbIds.TABLE + "." + orderField + " COLLATE NOCASE " + getDbDirection(order, direction) + ", " +
LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.STORE + " COLLATE NOCASE ASC " +

View File

@@ -15,7 +15,7 @@ import protect.card_locker.preferences.Settings;
public class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.GroupListItemViewHolder> {
Settings mSettings;
public final Context mContext;
private final Context mContext;
private final GroupAdapterListener mListener;
SQLiteDatabase mDatabase;
@@ -23,7 +23,7 @@ public class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.Gro
super(inputCursor, DBHelper.LoyaltyCardDbGroups.ORDER);
setHasStableIds(true);
mSettings = new Settings(inputContext);
mContext = inputContext;
mContext = inputContext.getApplicationContext();
mListener = inputListener;
mDatabase = new DBHelper(inputContext).getReadableDatabase();

View File

@@ -1,7 +1,10 @@
package protect.card_locker;
import android.Manifest;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -22,6 +25,7 @@ import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import java.io.FileInputStream;
@@ -35,7 +39,6 @@ import java.util.List;
import protect.card_locker.async.TaskHandler;
import protect.card_locker.importexport.DataFormat;
import protect.card_locker.importexport.ImportExportResult;
import protect.card_locker.importexport.ImportExportResultType;
public class ImportExportActivity extends CatimaAppCompatActivity {
private static final String TAG = "Catima";
@@ -55,6 +58,12 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
final private TaskHandler mTasks = new TaskHandler();
private NotificationManager mNotifyManager;
private NotificationCompat.Builder mBuilder;
private static final int NOTIFICATION_IMPORT = 1;
private static final int NOTIFICATION_EXPORT = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -95,10 +104,10 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
try {
OutputStream writer = getContentResolver().openOutputStream(uri);
Log.e(TAG, "Starting file export with: " + result.toString());
startExport(writer, uri, exportPassword.toCharArray(), true);
startExport(writer, uri, exportPassword != null ? exportPassword.toCharArray() : null, true);
} catch (IOException e) {
Log.e(TAG, "Failed to export file: " + result.toString(), e);
onExportComplete(new ImportExportResult(ImportExportResultType.GenericFailure, result.toString()), uri);
onExportComplete(ImportExportResult.GenericFailure, uri);
}
});
@@ -176,7 +185,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
startImport(reader, uri, importDataFormat, password, true);
} catch (IOException e) {
Log.e(TAG, "Failed to import file: " + uri.toString(), e);
onImportComplete(new ImportExportResult(ImportExportResultType.GenericFailure, e.toString()), uri, importDataFormat);
onImportComplete(ImportExportResult.GenericFailure, uri, importDataFormat);
}
}
@@ -257,22 +266,59 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
builder.show();
}
private void startProgressNotification(boolean importing) {
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this, NotificationType.getImportExportChannel(this));
mBuilder.setContentTitle(getString(importing ? R.string.importing : R.string.exporting))
.setContentText(null)
.setSmallIcon(R.drawable.ic_import_export_white_24dp)
.setColor(getThemeColor())
.setProgress(0, 0, true);
mNotifyManager.notify(importing ? NOTIFICATION_IMPORT : NOTIFICATION_EXPORT, mBuilder.build());
}
private void endProgressNotification(boolean importing, ImportExportResult result, PendingIntent sendIntent) {
String notificationTitle;
String notificationMessage;
if (result.equals(ImportExportResult.Success)) {
notificationTitle = getString(importing ? R.string.importSuccessfulTitle : R.string.exportSuccessfulTitle);
notificationMessage = getString(importing ? R.string.importSuccessful : R.string.exportSuccessful);
} else {
int reason = R.string.unknown_failure;
if (result.equals(ImportExportResult.BadPassword)) {
reason = R.string.incorrect_password;
}
notificationTitle = getString(importing ? R.string.importFailedTitle : R.string.exportFailedTitle);
notificationMessage = String.format(getString(importing ? R.string.importFailed : R.string.exportFailed), getString(reason));
}
mBuilder.setContentTitle(notificationTitle)
.setContentText(notificationMessage)
.setProgress(0,0, false);
if (sendIntent != null) {
mBuilder.addAction(R.drawable.ic_share, getString(R.string.sendLabel), sendIntent);
}
mNotifyManager.notify(importing ? NOTIFICATION_IMPORT : NOTIFICATION_EXPORT, mBuilder.build());
}
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) {
onImportComplete(result, targetUri, dataFormat);
if (closeWhenDone) {
try {
target.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
ImportExportTask.TaskCompleteListener listener = (result, dataFormat1) -> {
onImportComplete(result, targetUri, dataFormat1);
if (closeWhenDone) {
try {
target.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
};
startProgressNotification(true);
importExporter = new ImportExportTask(ImportExportActivity.this,
dataFormat, target, password, listener);
mTasks.executeTask(TaskHandler.TYPE.IMPORT, importExporter);
@@ -280,20 +326,18 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
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);
if (closeWhenDone) {
try {
target.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
ImportExportTask.TaskCompleteListener listener = (result, dataFormat) -> {
onExportComplete(result, targetUri);
if (closeWhenDone) {
try {
target.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
};
startProgressNotification(false);
importExporter = new ImportExportTask(ImportExportActivity.this,
DataFormat.Catima, target, password, listener);
mTasks.executeTask(TaskHandler.TYPE.EXPORT, importExporter);
@@ -358,68 +402,28 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
builder.show();
}
private String buildResultDialogMessage(ImportExportResult result, boolean isImport) {
int messageId;
if (result.resultType() == ImportExportResultType.Success) {
messageId = isImport ? R.string.importSuccessful : R.string.exportSuccessful;
} else {
messageId = isImport ? R.string.importFailed : R.string.exportFailed;
}
StringBuilder messageBuilder = new StringBuilder(getResources().getString(messageId));
if (result.developerDetails() != null) {
messageBuilder.append("\n\n");
messageBuilder.append(getResources().getString(R.string.include_if_asking_support));
messageBuilder.append("\n\n");
messageBuilder.append(result.developerDetails());
}
return messageBuilder.toString();
}
private void onImportComplete(ImportExportResult result, Uri path, DataFormat dataFormat) {
ImportExportResultType resultType = result.resultType();
endProgressNotification(true, result, null);
if (resultType == ImportExportResultType.BadPassword) {
if (result == ImportExportResult.BadPassword) {
retryWithPassword(dataFormat, path);
return;
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(resultType == ImportExportResultType.Success ? R.string.importSuccessfulTitle : R.string.importFailedTitle);
builder.setMessage(buildResultDialogMessage(result, true));
builder.setNeutralButton(R.string.ok, (dialog, which) -> dialog.dismiss());
builder.create().show();
}
private void onExportComplete(ImportExportResult result, final Uri path) {
ImportExportResultType resultType = result.resultType();
PendingIntent pendingIntent = null;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(resultType == ImportExportResultType.Success ? R.string.exportSuccessfulTitle : R.string.exportFailedTitle);
builder.setMessage(buildResultDialogMessage(result, false));
builder.setNeutralButton(R.string.ok, (dialog, which) -> dialog.dismiss());
if (result == ImportExportResult.Success) {
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, path);
sendIntent.setType("text/csv");
if (resultType == ImportExportResultType.Success) {
final CharSequence sendLabel = ImportExportActivity.this.getResources().getText(R.string.sendLabel);
// set flag to give temporary permission to external app to use the FileProvider
sendIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
builder.setPositiveButton(sendLabel, (dialog, which) -> {
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, path);
sendIntent.setType("text/csv");
// set flag to give temporary permission to external app to use the FileProvider
sendIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
ImportExportActivity.this.startActivity(Intent.createChooser(sendIntent,
sendLabel));
dialog.dismiss();
});
pendingIntent = PendingIntent.getActivity(this, NOTIFICATION_EXPORT, sendIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
builder.create().show();
endProgressNotification(false, result, pendingIntent);
}
}

View File

@@ -1,7 +1,7 @@
package protect.card_locker;
import android.app.Activity;
import android.app.ProgressDialog;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.database.sqlite.SQLiteDatabase;
@@ -13,25 +13,23 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import androidx.core.app.NotificationCompat;
import protect.card_locker.async.CompatCallable;
import protect.card_locker.importexport.DataFormat;
import protect.card_locker.importexport.ImportExportResult;
import protect.card_locker.importexport.ImportExportResultType;
import protect.card_locker.importexport.MultiFormatExporter;
import protect.card_locker.importexport.MultiFormatImporter;
public class ImportExportTask implements CompatCallable<ImportExportResult> {
private static final String TAG = "Catima";
private Activity activity;
private boolean doImport;
private DataFormat format;
private final Activity activity;
private final boolean doImport;
private final DataFormat format;
private OutputStream outputStream;
private InputStream inputStream;
private char[] password;
private TaskCompleteListener listener;
private ProgressDialog progress;
private final char[] password;
private final TaskCompleteListener listener;
/**
* Constructor which will setup a task for exporting to the given file
@@ -62,22 +60,21 @@ public class ImportExportTask implements CompatCallable<ImportExportResult> {
}
private ImportExportResult performImport(Context context, InputStream stream, SQLiteDatabase database, char[] password) {
ImportExportResult importResult = MultiFormatImporter.importData(context, database, stream, format, password);
ImportExportResult result = MultiFormatImporter.importData(context, database, stream, format, password);
Log.i(TAG, "Import result: " + importResult);
Log.i(TAG, "Import result: " + result.name());
return importResult;
return result;
}
private ImportExportResult performExport(Context context, OutputStream stream, SQLiteDatabase database, char[] password) {
ImportExportResult result;
ImportExportResult result = ImportExportResult.GenericFailure;
try {
OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8);
result = MultiFormatExporter.exportData(context, database, stream, format, password);
writer.close();
} catch (IOException e) {
result = new ImportExportResult(ImportExportResultType.GenericFailure, e.toString());
Log.e(TAG, "Unable to export file", e);
}
@@ -86,20 +83,6 @@ public class ImportExportTask implements CompatCallable<ImportExportResult> {
return result;
}
public void onPreExecute() {
progress = new ProgressDialog(activity);
progress.setTitle(doImport ? R.string.importing : R.string.exporting);
progress.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
ImportExportTask.this.stop();
}
});
progress.show();
}
protected ImportExportResult doInBackground(Void... nothing) {
final SQLiteDatabase database = new DBHelper(activity).getWritableDatabase();
ImportExportResult result;
@@ -116,15 +99,15 @@ public class ImportExportTask implements CompatCallable<ImportExportResult> {
}
public void onPostExecute(Object castResult) {
listener.onTaskComplete((ImportExportResult) castResult, format);
ImportExportResult result = (ImportExportResult) castResult;
listener.onTaskComplete(result, format);
progress.dismiss();
Log.i(TAG, (doImport ? "Import" : "Export") + " Complete");
}
protected void onCancelled() {
progress.dismiss();
Log.i(TAG, (doImport ? "Import" : "Export") + " Cancelled");
@Override
public void onPreExecute() {
}
protected void stop() {

View File

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

View File

@@ -10,9 +10,6 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.util.Log;
import androidx.core.graphics.PaintCompat;
/**
* Original from https://github.com/andOTP/andOTP/blob/master/app/src/main/java/org/shadowice/flocke/andotp/Utilities/LetterBitmap.java
@@ -51,6 +48,7 @@ class LetterBitmap {
public LetterBitmap(Context context, String displayName, String key, int tileLetterFontSize,
int width, int height, Integer backgroundColor, Integer textColor) {
TextPaint paint = new TextPaint();
paint.setTypeface(Typeface.create("sans-serif-light", Typeface.BOLD));
if (textColor != null) {
paint.setColor(textColor);
@@ -60,8 +58,6 @@ class LetterBitmap {
paint.setTextAlign(Paint.Align.CENTER);
paint.setAntiAlias(true);
paint.setTextSize(tileLetterFontSize);
paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
if (backgroundColor == null) {
mColor = getDefaultColor(context, key);
@@ -70,31 +66,22 @@ class LetterBitmap {
}
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
String firstChar = displayName.substring(0, 1).toUpperCase();
int firstCharEnd = 2;
while (firstCharEnd <= displayName.length()) {
// Test for the longest render-able string
// But ignore containing only a-Z0-9 to not render things like ffi as a single character
String test = displayName.substring(0, firstCharEnd);
if (!isAlphabetical(test) && PaintCompat.hasGlyph(paint, test)) {
firstChar = test;
}
firstCharEnd++;
}
Log.d("LetterBitmap", "using sequence " + firstChar + " to render first char which has length " + firstChar.length());
String firstChar = displayName.substring(0, 1);
final Canvas c = new Canvas();
c.setBitmap(mBitmap);
c.drawColor(mColor);
Rect bounds = new Rect();
paint.getTextBounds(firstChar, 0, firstChar.length(), bounds);
c.drawText(firstChar,
0, firstChar.length(),
width / 2.0f, (height - (bounds.bottom + bounds.top)) / 2.0f
, paint);
char[] firstCharArray = new char[1];
firstCharArray[0] = firstChar.toUpperCase().charAt(0);
paint.setTextSize(tileLetterFontSize);
// The bounds that enclose the letter
Rect bounds = new Rect();
paint.getTextBounds(firstCharArray, 0, 1, bounds);
c.drawText(firstCharArray, 0, 1, width / 2.0f, height / 2.0f
+ (bounds.bottom - bounds.top) / 2.0f, paint);
}
/**
@@ -125,10 +112,6 @@ class LetterBitmap {
return colors.getColor(color, Color.BLACK);
}
private static boolean isAlphabetical(String string) {
return string.matches("[a-zA-Z0-9]*");
}
/**
* Determine the color which the letter tile will use if no default
* color is provided.

View File

@@ -29,14 +29,13 @@ public class LoyaltyCard implements Parcelable {
public final Integer headerColor;
public final int starStatus;
public final int archiveStatus;
public final long lastUsed;
public int zoomLevel;
public LoyaltyCard(final int id, final String store, final String note, final Date expiry,
final BigDecimal balance, final Currency balanceType, final String cardId,
@Nullable final String barcodeId, @Nullable final CatimaBarcode barcodeType,
@Nullable final Integer headerColor, final int starStatus, final long lastUsed, final int zoomLevel,final int archiveStatus) {
@Nullable final Integer headerColor, final int starStatus, final long lastUsed, final int zoomLevel) {
this.id = id;
this.store = store;
this.note = note;
@@ -50,7 +49,6 @@ public class LoyaltyCard implements Parcelable {
this.starStatus = starStatus;
this.lastUsed = lastUsed;
this.zoomLevel = zoomLevel;
this.archiveStatus = archiveStatus;
}
protected LoyaltyCard(Parcel in) {
@@ -70,7 +68,6 @@ public class LoyaltyCard implements Parcelable {
starStatus = in.readInt();
lastUsed = in.readLong();
zoomLevel = in.readInt();
archiveStatus = in.readInt();
}
@Override
@@ -88,7 +85,6 @@ public class LoyaltyCard implements Parcelable {
parcel.writeInt(starStatus);
parcel.writeLong(lastUsed);
parcel.writeInt(zoomLevel);
parcel.writeInt(archiveStatus);
}
public static LoyaltyCard toLoyaltyCard(Cursor cursor) {
@@ -102,7 +98,6 @@ public class LoyaltyCard implements Parcelable {
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 archived = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ARCHIVE_STATUS));
int barcodeTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_TYPE);
int balanceTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BALANCE_TYPE);
@@ -129,7 +124,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, zoomLevel,archived);
return new LoyaltyCard(id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starred, lastUsed, zoomLevel);
}
@Override

View File

@@ -1,7 +1,6 @@
package protect.card_locker;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -36,48 +35,30 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
private int mCurrentSelectedIndex = -1;
Settings mSettings;
boolean mDarkModeEnabled;
public final Context mContext;
private final Context mContext;
private final CardAdapterListener mListener;
protected SparseBooleanArray mSelectedItems;
protected SparseBooleanArray mAnimationItemsIndex;
private boolean mReverseAllAnimations = false;
private boolean mShowDetails;
private boolean mShowDetails = true;
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener) {
super(inputCursor, DBHelper.LoyaltyCardDbIds.ID);
setHasStableIds(true);
mSettings = new Settings(inputContext);
mContext = inputContext;
mContext = inputContext.getApplicationContext();
mListener = inputListener;
mSelectedItems = new SparseBooleanArray();
mAnimationItemsIndex = new SparseBooleanArray();
mDarkModeEnabled = Utils.isDarkModeEnabled(inputContext);
refreshState();
swapCursor(inputCursor);
}
public void refreshState() {
// Retrieve user details preference
SharedPreferences cardDetailsPref = mContext.getSharedPreferences(
mContext.getString(R.string.sharedpreference_card_details),
Context.MODE_PRIVATE);
mShowDetails = cardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_show), true);
}
public void showDetails(boolean show) {
mShowDetails = show;
notifyDataSetChanged();
// Store in Shared Preference to restore next adapter launch
SharedPreferences cardDetailsPref = mContext.getSharedPreferences(
mContext.getString(R.string.sharedpreference_card_details),
Context.MODE_PRIVATE);
SharedPreferences.Editor cardDetailsPrefEditor = cardDetailsPref.edit();
cardDetailsPrefEditor.putBoolean(mContext.getString(R.string.sharedpreference_card_details_show), show);
cardDetailsPrefEditor.apply();
}
public boolean showingDetails() {
@@ -120,7 +101,6 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
inputHolder.setExpiryField(null);
}
setHeaderHeight(inputHolder, mShowDetails);
Bitmap cardIcon = Utils.retrieveCardImage(mContext, loyaltyCard.id, ImageLocationType.icon);
if (cardIcon != null) {
inputHolder.mCardIcon.setImageBitmap(cardIcon);
@@ -129,9 +109,9 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, loyaltyCard.store, loyaltyCard.headerColor).getLetterTile());
inputHolder.mCardIcon.setScaleType(ImageView.ScaleType.FIT_CENTER);
}
inputHolder.setIconBackgroundColor(loyaltyCard.headerColor != null ? loyaltyCard.headerColor : R.attr.colorPrimary);
inputHolder.setIconBackgroundColor(loyaltyCard.headerColor != null ? loyaltyCard.headerColor : ContextCompat.getColor(mContext, R.color.colorPrimary));
inputHolder.toggleCardStateIcon(loyaltyCard.starStatus != 0, loyaltyCard.archiveStatus != 0, itemSelected(inputCursor.getPosition()));
inputHolder.toggleStar(loyaltyCard.starStatus != 0, itemSelected(inputCursor.getPosition()));
inputHolder.itemView.setActivated(mSelectedItems.get(inputCursor.getPosition(), false));
applyIconAnimation(inputHolder, inputCursor.getPosition());
@@ -141,19 +121,6 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
inputHolder.mRow.requestLayout();
}
private void setHeaderHeight(LoyaltyCardListItemViewHolder inputHolder, boolean expanded) {
int iconHeight;
if (expanded) {
iconHeight = ViewGroup.LayoutParams.MATCH_PARENT;
} else {
iconHeight = (int) mContext.getResources().getDimension(R.dimen.cardThumbnailSize);
}
inputHolder.mIconLayout.getLayoutParams().height = expanded ? 0 : iconHeight;
inputHolder.mCardIcon.getLayoutParams().height = iconHeight;
inputHolder.mTickIcon.getLayoutParams().height = iconHeight;
}
private void applyClickEvents(LoyaltyCardListItemViewHolder inputHolder, final int inputPosition) {
inputHolder.mRow.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition));
@@ -232,15 +199,13 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
public class LoyaltyCardListItemViewHolder extends RecyclerView.ViewHolder {
public TextView mStoreField, mNoteField, mBalanceField, mExpiryField;
public ImageView mCardIcon, mStarBackground, mStarBorder, mTickIcon, mArchivedBackground;
public MaterialCardView mRow, mIconLayout;
public ConstraintLayout mStar, mArchived;
public ImageView mCardIcon, mStarBackground, mStarBorder, mTickIcon;
public MaterialCardView mRow;
public ConstraintLayout mStar;
public View mDivider;
private int mIconBackgroundColor;
protected LoyaltyCardListItemViewHolder(View inputView, CardAdapterListener inputListener) {
super(inputView);
mRow = inputView.findViewById(R.id.row);
@@ -249,13 +214,11 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
mNoteField = inputView.findViewById(R.id.note);
mBalanceField = inputView.findViewById(R.id.balance);
mExpiryField = inputView.findViewById(R.id.expiry);
mIconLayout = inputView.findViewById(R.id.icon_layout);
mCardIcon = inputView.findViewById(R.id.thumbnail);
mStar = inputView.findViewById(R.id.star);
mStarBackground = inputView.findViewById(R.id.star_background);
mStarBorder = inputView.findViewById(R.id.star_border);
mArchived = inputView.findViewById(R.id.archivedIcon);
mArchivedBackground = inputView.findViewById(R.id.archive_background);
mTickIcon = inputView.findViewById(R.id.selected_thumbnail);
inputView.setOnLongClickListener(view -> {
inputListener.onRowClicked(getAdapterPosition());
@@ -324,7 +287,7 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
mExpiryField.requestLayout();
}
public void toggleCardStateIcon(boolean enableStar, boolean enableArchive, boolean colorByTheme) {
public void toggleStar(boolean enable, boolean colorByTheme) {
/* the below code does not work in android 5! hence the change of drawable instead
boolean needDarkForeground = Utils.needsDarkForeground(mIconBackgroundColor);
Drawable borderDrawable = mStarBorder.getDrawable().mutate();
@@ -338,33 +301,20 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
if (colorByTheme) {
dark = !mDarkModeEnabled;
}
if (dark) {
mStarBorder.setImageResource(R.drawable.ic_unstarred_white);
mStarBackground.setImageResource(R.drawable.ic_starred_black);
mArchivedBackground.setImageResource(R.drawable.ic_baseline_archive_24_black);
} else {
mStarBorder.setImageResource(R.drawable.ic_unstarred_black);
mStarBackground.setImageResource(R.drawable.ic_starred_black);
} else {
mStarBorder.setImageResource(R.drawable.ic_unstarred_white);
mStarBackground.setImageResource(R.drawable.ic_starred_white);
mArchivedBackground.setImageResource(R.drawable.ic_baseline_archive_24);
}
if (enableStar) {
if (enable) {
mStar.setVisibility(View.VISIBLE);
} else{
} else {
mStar.setVisibility(View.GONE);
}
if (enableArchive) {
mArchived.setVisibility(View.VISIBLE);
} else{
mArchived.setVisibility(View.GONE);
}
mStarBorder.invalidate();
mStarBackground.invalidate();
mArchivedBackground.invalidate();
}
public void setIconBackgroundColor(int color) {

View File

@@ -36,7 +36,6 @@ import android.widget.Toast;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
@@ -69,7 +68,6 @@ import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
@@ -108,7 +106,6 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
private static final int PERMISSION_REQUEST_CAMERA_IMAGE_ICON = 102;
public static final String BUNDLE_ID = "id";
public static final String BUNDLE_DUPLICATE_ID = "duplicateId";
public static final String BUNDLE_UPDATE = "update";
public static final String BUNDLE_CARDID = "cardId";
public static final String BUNDLE_BARCODEID = "barcodeId";
@@ -137,11 +134,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
Button enterButton;
Toolbar toolbar;
int loyaltyCardId;
boolean updateLoyaltyCard;
boolean duplicateFromLoyaltyCardId;
String cardId;
String barcodeId;
String barcodeType;
@@ -159,7 +153,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
AlertDialog confirmExitDialog = null;
boolean validBalance = true;
Runnable barcodeImageGenerationFinishedCallback;
Runnable warnOnInvalidBarcodeType;
HashMap<String, Currency> currencies = new HashMap<>();
@@ -207,17 +201,13 @@ 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(), 100, (int) (fieldName == LoyaltyCardField.archiveStatus ? value : loyaltyCard.archiveStatus)
Utils.getUnixTime(), 100
);
}
private void updateTempState(LoyaltyCardField fieldName, Object value) {
tempLoyaltyCard = updateTempState(tempLoyaltyCard, fieldName, value);
if (initDone && (fieldName == LoyaltyCardField.cardId || fieldName == LoyaltyCardField.barcodeId || fieldName == LoyaltyCardField.barcodeType)) {
generateBarcode();
}
hasChanged = true;
}
@@ -225,7 +215,6 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
final Bundle b = intent.getExtras();
loyaltyCardId = b != null ? b.getInt(BUNDLE_ID) : 0;
updateLoyaltyCard = b != null && b.getBoolean(BUNDLE_UPDATE, false);
duplicateFromLoyaltyCardId = b != null && b.getBoolean(BUNDLE_DUPLICATE_ID, false);
cardId = b != null ? b.getString(BUNDLE_CARDID) : null;
barcodeId = b != null ? b.getString(BUNDLE_BARCODEID) : null;
@@ -234,7 +223,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
importLoyaltyCardUri = intent.getData();
Log.d(TAG, "Edit activity: id=" + loyaltyCardId
Log.d(TAG, "View activity: id=" + loyaltyCardId
+ ", updateLoyaltyCard=" + updateLoyaltyCard);
}
@@ -297,7 +286,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.loyalty_card_edit_activity);
toolbar = findViewById(R.id.toolbar);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
@@ -326,7 +315,6 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
barcodeIdField = findViewById(R.id.barcodeIdField);
barcodeTypeField = findViewById(R.id.barcodeTypeField);
barcodeImage = findViewById(R.id.barcode);
barcodeImage.setClipToOutline(true);
barcodeImageLayout = findViewById(R.id.barcodeLayout);
barcodeCaptureLayout = findViewById(R.id.barcodeCaptureLayout);
cardImageFrontHolder = findViewById(R.id.frontImageHolder);
@@ -335,10 +323,11 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
cardImageBack = findViewById(R.id.backImage);
enterButton = findViewById(R.id.enterButton);
cardImageFront.setBackgroundColor(getThemeColor());
cardImageBack.setBackgroundColor(getThemeColor());
barcodeImageGenerationFinishedCallback = () -> {
warnOnInvalidBarcodeType = () -> {
if (!(boolean) barcodeImage.getTag()) {
barcodeImageLayout.setVisibility(View.GONE);
Toast.makeText(LoyaltyCardEditActivity.this, getString(R.string.wrongValueForBarcodeType), Toast.LENGTH_LONG).show();
}
};
@@ -452,10 +441,14 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
for (int i = locales.size() - 1; i >= 0; i--) {
Locale locale = locales.get(i);
currencyPrioritizeLocaleSymbols(currencyList, locale);
String currencySymbol = Currency.getInstance(locale).getSymbol();
currencyList.remove(currencySymbol);
currencyList.add(0, currencySymbol);
}
} else {
currencyPrioritizeLocaleSymbols(currencyList, mSystemLocale);
String currencySymbol = Currency.getInstance(mSystemLocale).getSymbol();
currencyList.remove(currencySymbol);
currencyList.add(0, currencySymbol);
}
currencyList.add(0, getString(R.string.points));
@@ -531,6 +524,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
} else {
updateTempState(LoyaltyCardField.barcodeId, s.toString());
}
generateOrHideBarcode();
}
@Override
@@ -561,6 +556,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
} catch (IllegalArgumentException e) {
}
}
generateOrHideBarcode();
}
}
@@ -672,6 +669,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
});
mCropperOptions = new UCrop.Options();
setCropperTheme();
}
// ucrop 2.2.6 initial aspect ratio is glitched when 0x0 is used as the initial ratio option
@@ -691,24 +689,13 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
new AspectRatio(getResources().getString(R.string.ucrop_label_original).toUpperCase(), sourceWidth, sourceHeight),
new AspectRatio(getResources().getString(R.string.card).toUpperCase(), 85.6f, 53.98f)
);
}
// Fix theming
int colorPrimary = MaterialColors.getColor(this, R.attr.colorPrimary, ContextCompat.getColor(this, R.color.md_theme_light_primary));
int colorOnPrimary = MaterialColors.getColor(this, R.attr.colorOnPrimary, ContextCompat.getColor(this, R.color.md_theme_light_onPrimary));
int colorSurface = MaterialColors.getColor(this, R.attr.colorSurface, ContextCompat.getColor(this, R.color.md_theme_light_surface));
int colorOnSurface = MaterialColors.getColor(this, R.attr.colorOnSurface, ContextCompat.getColor(this, R.color.md_theme_light_onSurface));
int colorBackground = MaterialColors.getColor(this, android.R.attr.colorBackground, ContextCompat.getColor(this, R.color.md_theme_light_onSurface));
mCropperOptions.setToolbarColor(colorSurface);
mCropperOptions.setStatusBarColor(colorSurface);
mCropperOptions.setToolbarWidgetColor(colorOnSurface);
mCropperOptions.setRootViewBackgroundColor(colorBackground);
// set tool tip to be the darker of primary color
if (Utils.isDarkModeEnabled(this)) {
mCropperOptions.setActiveControlsWidgetColor(colorOnPrimary);
} else {
mCropperOptions.setActiveControlsWidgetColor(colorPrimary);
}
private void setCropperTheme() {
mCropperOptions.setToolbarColor(getThemeColor());
mCropperOptions.setStatusBarColor(getThemeColor());
mCropperOptions.setToolbarWidgetColor(Color.WHITE);
mCropperOptions.setActiveControlsWidgetColor(getThemeColor());
}
@Override
@@ -752,8 +739,9 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
onResuming = true;
if (tempLoyaltyCard == null) {
if (updateLoyaltyCard || duplicateFromLoyaltyCardId) {
if (updateLoyaltyCard) {
tempLoyaltyCard = DBHelper.getLoyaltyCard(mDatabase, loyaltyCardId);
if (tempLoyaltyCard == null) {
Log.w(TAG, "Could not lookup loyalty card " + loyaltyCardId);
@@ -771,7 +759,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
}
} else {
// New card, use default values
tempLoyaltyCard = new LoyaltyCard(-1, "", "", null, new BigDecimal("0"), null, "", null, null, null, 0, Utils.getUnixTime(), 100,0);
tempLoyaltyCard = new LoyaltyCard(-1, "", "", null, new BigDecimal("0"), null, "", null, null, null, 0, Utils.getUnixTime(), 100);
}
}
@@ -779,11 +767,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
if (!initDone) {
if (updateLoyaltyCard) {
setTitle(R.string.editCardTitle);
} else {
setTitle(R.string.addCardTitle);
}
if (updateLoyaltyCard || duplicateFromLoyaltyCardId) {
if (!mFrontImageUnsaved && !croppedFrontImage() && !mFrontImageRemoved) {
setCardImage(cardImageFront, Utils.retrieveCardImage(this, tempLoyaltyCard.id, ImageLocationType.front), true);
}
@@ -861,7 +845,10 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
// Generate random header color
if (tempLoyaltyCard.headerColor == null) {
// Select a random color to start out with.
updateTempState(LoyaltyCardField.headerColor, Utils.getRandomHeaderColor(this));
TypedArray colors = getResources().obtainTypedArray(R.array.letter_tile_colors);
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
@@ -902,7 +889,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
hasChanged = hadChanges;
}
generateBarcode();
generateOrHideBarcode();
enterButton.setOnClickListener(new EditCardIdAndBarcode());
barcodeImage.setOnClickListener(new EditCardIdAndBarcode());
@@ -922,7 +909,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
protected void setColorFromIcon() {
Object icon = thumbnail.getTag();
if (icon != null && (icon instanceof Bitmap)) {
updateTempState(LoyaltyCardField.headerColor, Utils.getHeaderColorFromImage((Bitmap) icon, tempLoyaltyCard.headerColor != null ? tempLoyaltyCard.headerColor : R.attr.colorPrimary));
updateTempState(LoyaltyCardField.headerColor, new Palette.Builder((Bitmap) icon).generate().getDominantColor(tempLoyaltyCard.headerColor != null ? tempLoyaltyCard.headerColor : ContextCompat.getColor(this, R.color.colorPrimary)));
} else {
Log.d("setColorFromIcon", "attempting header color change from icon but icon does not exist");
}
@@ -1234,16 +1221,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
int day = c.get(Calendar.DAY_OF_MONTH);
// Create a new instance of DatePickerDialog and return it
DatePickerDialog datePickerDialog = new DatePickerDialog(getActivity(), this, year, month, day);
datePickerDialog.getDatePicker().setMinDate(getMinDateOfDatePicker());
return datePickerDialog;
}
private long getMinDateOfDatePicker()
{
Calendar minDateCalendar = Calendar.getInstance();
minDateCalendar.set(1970, 0, 1);
return minDateCalendar.getTimeInMillis();
return new DatePickerDialog(getActivity(), this, year, month, day);
}
public void onDateSet(DatePicker view, int year, int month, int day) {
@@ -1265,11 +1243,6 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
}
private void doSave() {
if (isFinishing()) {
// If we are done saving, ignore any queued up save button presses
return;
}
if (tempStoredOldBarcodeValue != null) {
askBarcodeChange(this::doSave);
return;
@@ -1308,7 +1281,7 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
}
Log.i(TAG, "Updated " + loyaltyCardId + " to " + cardId);
} else {
loyaltyCardId = (int) DBHelper.insertLoyaltyCard(mDatabase, tempLoyaltyCard.store, tempLoyaltyCard.note, tempLoyaltyCard.expiry, tempLoyaltyCard.balance, tempLoyaltyCard.balanceType, tempLoyaltyCard.cardId, tempLoyaltyCard.barcodeId, tempLoyaltyCard.barcodeType, tempLoyaltyCard.headerColor, 0, tempLoyaltyCard.lastUsed,0);
loyaltyCardId = (int) DBHelper.insertLoyaltyCard(mDatabase, 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, ImageLocationType.front);
Utils.saveCardImage(this, (Bitmap) cardImageBack.getTag(), loyaltyCardId, ImageLocationType.back);
@@ -1322,16 +1295,16 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
ShortcutHelper.updateShortcuts(this, DBHelper.getLoyaltyCard(mDatabase, loyaltyCardId));
if(duplicateFromLoyaltyCardId){
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
}
finish();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.card_add_menu, menu);
if (updateLoyaltyCard) {
getMenuInflater().inflate(R.menu.card_update_menu, menu);
} else {
getMenuInflater().inflate(R.menu.card_add_menu, menu);
}
return super.onCreateOptionsMenu(menu);
}
@@ -1340,9 +1313,30 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
askBeforeQuitIfChanged();
return true;
switch (id) {
case android.R.id.home:
askBeforeQuitIfChanged();
break;
case R.id.action_delete:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.deleteTitle);
builder.setMessage(R.string.deleteConfirmation);
builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
Log.e(TAG, "Deleting card: " + loyaltyCardId);
DBHelper.deleteLoyaltyCard(mDatabase, LoyaltyCardEditActivity.this, loyaltyCardId);
ShortcutHelper.removeShortcut(LoyaltyCardEditActivity.this, loyaltyCardId);
finish();
dialog.dismiss();
});
builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
AlertDialog dialog = builder.create();
dialog.show();
return true;
}
return super.onOptionsItemSelected(item);
@@ -1395,40 +1389,36 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
}
}
}
Intent ucropIntent = UCrop.of(
sourceUri,
destUri
).withOptions(mCropperOptions)
.getIntent(this);
ucropIntent.setClass(this, UCropWrapper.class);
for (int i = 0; i < toolbar.getChildCount(); i++) {
// send toolbar font details to ucrop wrapper
View child = toolbar.getChildAt(i);
if (child instanceof AppCompatTextView) {
AppCompatTextView childTextView = (AppCompatTextView) child;
ucropIntent.putExtra(UCropWrapper.UCROP_TOOLBAR_TYPEFACE_STYLE, childTextView.getTypeface().getStyle());
break;
}
}
mCropperLauncher.launch(ucropIntent);
mCropperLauncher.launch(
UCrop.of(
sourceUri,
destUri
).withOptions(mCropperOptions)
.getIntent(this)
);
}
private void generateBarcode() {
if (tempLoyaltyCard == null) {
return;
}
private void showBarcode() {
barcodeImageLayout.setVisibility(View.VISIBLE);
}
mTasks.flushTaskList(TaskHandler.TYPE.BARCODE, true, false, false);
private void hideBarcode() {
barcodeImageLayout.setVisibility(View.GONE);
}
private void generateOrHideBarcode() {
String cardIdString = tempLoyaltyCard.barcodeId != null ? tempLoyaltyCard.barcodeId : tempLoyaltyCard.cardId;
CatimaBarcode barcodeFormat = tempLoyaltyCard.barcodeType;
if (cardIdString == null || barcodeFormat == null) {
barcodeImageLayout.setVisibility(View.GONE);
return;
if (barcodeFormat == null || cardIdString.isEmpty() || !barcodeFormat.isSupported()) {
hideBarcode();
} else {
generateBarcode(cardIdString, barcodeFormat);
}
}
barcodeImageLayout.setVisibility(View.VISIBLE);
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");
@@ -1441,15 +1431,17 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
barcodeImage.getViewTreeObserver().removeOnGlobalLayoutListener(this);
Log.d(TAG, "ImageView size now known");
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, barcodeImageGenerationFinishedCallback, true);
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");
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, barcodeImageGenerationFinishedCallback, true);
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, warnOnInvalidBarcodeType);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
showBarcode();
}
private void generateIcon(String store) {
@@ -1479,36 +1471,32 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
}
View cardPart = findViewById(R.id.cardPart);
View optionsPart = findViewById(R.id.optionsPart);
View barcodePart = findViewById(R.id.barcodePart);
View picturesPart = findViewById(R.id.picturesPart);
if (getString(R.string.card).equals(part)) {
cardPart.setVisibility(View.VISIBLE);
optionsPart.setVisibility(View.GONE);
barcodePart.setVisibility(View.GONE);
picturesPart.setVisibility(View.GONE);
// Explicitly hide barcode (fixes blurriness on redraw)
hideBarcode();
} else if (getString(R.string.barcode).equals(part)) {
cardPart.setVisibility(View.GONE);
barcodePart.setVisibility(View.VISIBLE);
picturesPart.setVisibility(View.GONE);
// Redraw barcode due to size change (Visibility.GONE sets it to 0)
generateBarcode();
} else if (getString(R.string.options).equals(part)) {
cardPart.setVisibility(View.GONE);
optionsPart.setVisibility(View.VISIBLE);
picturesPart.setVisibility(View.GONE);
generateOrHideBarcode();
} else if (getString(R.string.photos).equals(part)) {
cardPart.setVisibility(View.GONE);
optionsPart.setVisibility(View.GONE);
barcodePart.setVisibility(View.GONE);
picturesPart.setVisibility(View.VISIBLE);
// Explicitly hide barcode (fixes blurriness on redraw)
hideBarcode();
} else {
throw new UnsupportedOperationException();
}
}
private void currencyPrioritizeLocaleSymbols(ArrayList<String> currencyList, Locale locale) {
try {
String currencySymbol = Currency.getInstance(locale).getSymbol();
currencyList.remove(currencySymbol);
currencyList.add(0, currencySymbol);
} catch (IllegalArgumentException e) {
Log.d(TAG, "Could not get currency data for locale info: " + e);
}
}
}

View File

@@ -11,6 +11,5 @@ public enum LoyaltyCardField {
barcodeId,
barcodeType,
headerColor,
starStatus,
archiveStatus
starStatus
}

View File

@@ -3,9 +3,6 @@ package protect.card_locker;
import android.app.Application;
import androidx.appcompat.app.AppCompatDelegate;
import com.google.android.material.color.DynamicColors;
import protect.card_locker.preferences.Settings;
public class LoyaltyCardLockerApplication extends Application {

View File

@@ -2,7 +2,6 @@ package protect.card_locker;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
@@ -33,7 +32,6 @@ import android.widget.Toast;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.io.UnsupportedEncodingException;
@@ -45,11 +43,9 @@ import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Guideline;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.content.ContextCompat;
@@ -67,7 +63,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
private GestureDetector mGestureDetector;
CoordinatorLayout coordinatorLayout;
ConstraintLayout mainLayout;
TextView cardIdFieldView;
BottomSheetBehavior behavior;
LinearLayout bottomSheet;
@@ -123,7 +118,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
private final int HEADER_FILTER_ALPHA = 127;
final private TaskHandler mTasks = new TaskHandler();
Runnable barcodeImageGenerationFinishedCallback;
@Override
public boolean onDown(MotionEvent e) {
@@ -252,25 +246,13 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
settings = new Settings(this);
String cardOrientation = settings.getCardViewOrientation();
if (cardOrientation.equals(getString(R.string.settings_key_lock_on_opening_orientation))) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
} else if (cardOrientation.equals(getString(R.string.settings_key_portrait_orientation))) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else if (cardOrientation.equals(getString(R.string.settings_key_landscape_orientation))) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
if (savedInstanceState != null) {
mainImageIndex = savedInstanceState.getInt(STATE_IMAGEINDEX);
isFullscreen = savedInstanceState.getBoolean(STATE_FULLSCREEN);
bottomSheetState = savedInstanceState.getInt(STATE_BOTTOMSHEET);
}
settings = new Settings(this);
extractIntentFields(getIntent());
@@ -280,7 +262,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
importURIHelper = new ImportURIHelper(this);
coordinatorLayout = findViewById(R.id.coordinator_layout);
mainLayout = findViewById(R.id.mainLayout);
cardIdFieldView = findViewById(R.id.cardIdView);
bottomSheet = findViewById(R.id.bottom_sheet);
bottomSheetContentWrapper = findViewById(R.id.bottomSheetContentWrapper);
@@ -292,7 +273,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
storeName = findViewById(R.id.storeName);
maximizeButton = findViewById(R.id.maximizeButton);
mainImage = findViewById(R.id.mainImage);
mainImage.setClipToOutline(true);
dotIndicator = findViewById(R.id.dotIndicator);
minimizeButton = findViewById(R.id.minimizeButton);
collapsingToolbarLayout = findViewById(R.id.collapsingToolbarLayout);
@@ -300,21 +280,11 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
iconImage = findViewById(R.id.icon_image);
landscapeToolbar = findViewById(R.id.toolbar_landscape);
barcodeImageGenerationFinishedCallback = () -> {
if (!(boolean) mainImage.getTag()) {
mainImage.setVisibility(View.GONE);
imageTypes.remove(ImageType.BARCODE);
// Redraw UI
setDotIndicator(Utils.isDarkModeEnabled(LoyaltyCardViewActivity.this));
setFullscreen(isFullscreen);
Toast.makeText(LoyaltyCardViewActivity.this, getString(R.string.wrongValueForBarcodeType), Toast.LENGTH_LONG).show();
}
};
centerGuideline = findViewById(R.id.centerGuideline);
barcodeScaler = findViewById(R.id.barcodeScaler);
maximizeButton.setBackgroundColor(getThemeColor());
minimizeButton.setBackgroundColor(getThemeColor());
bottomSheetButton.setBackgroundColor(getThemeColor());
barcodeScaler.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
@@ -332,7 +302,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
setCenterGuideline(loyaltyCard.zoomLevel);
drawMainImage(mainImageIndex, true, isFullscreen);
drawMainImage(mainImageIndex, true);
}
@Override
@@ -409,13 +379,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
editButton.hide();
} else if (newState == BottomSheetBehavior.STATE_EXPANDED) {
bottomSheetButton.setImageResource(R.drawable.ic_baseline_arrow_drop_down_24);
bottomSheetButton.setContentDescription(getString(R.string.hideMoreInfo));
mainLayout.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
editButton.hide();
} else if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
bottomSheetButton.setImageResource(R.drawable.ic_baseline_arrow_drop_up_24);
bottomSheetButton.setContentDescription(getString(R.string.showMoreInfo));
mainLayout.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
if (!isFullscreen) {
editButton.show();
}
@@ -428,7 +394,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
private void adjustLayoutHeights() {
// use getLayoutParams instead of getHeight when heights are pre-determined in xml! getHeight could return 0 if a View is not inflated
if (appBarLayout.getHeight() != 0 && iconImage.getLayoutParams().height != appBarLayout.getHeight()) {
if (iconImage.getLayoutParams().height != appBarLayout.getHeight()) {
Log.d("adjustLayoutHeights", "setting imageIcon height from: " + iconImage.getLayoutParams().height + " to: " + appBarLayout.getHeight());
iconImage.setLayoutParams(new CoordinatorLayout.LayoutParams(
CoordinatorLayout.LayoutParams.MATCH_PARENT, appBarLayout.getHeight())
@@ -557,7 +523,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
int expiryString = R.string.expiryStateSentence;
if (Utils.hasExpired(loyaltyCard.expiry)) {
expiryString = R.string.expiryStateSentenceExpired;
expiryView.setTextColor(Color.RED);
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()));
@@ -595,30 +561,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
storeName.setTextColor(textColor);
landscapeToolbar.setTitleTextColor(textColor);
// Also apply colours to UI elements
int darkenedColor = ColorUtils.blendARGB(backgroundHeaderColor, Color.BLACK, 0.1f);
barcodeScaler.setProgressTintList(ColorStateList.valueOf(darkenedColor));
barcodeScaler.setThumbTintList(ColorStateList.valueOf(darkenedColor));
maximizeButton.setBackgroundColor(darkenedColor);
minimizeButton.setBackgroundColor(darkenedColor);
bottomSheetButton.setBackgroundColor(darkenedColor);
maximizeButton.setColorFilter(textColor);
minimizeButton.setColorFilter(textColor);
bottomSheetButton.setColorFilter(textColor);
int complementaryColor = Utils.getComplementaryColor(darkenedColor);
editButton.setBackgroundTintList(ColorStateList.valueOf(complementaryColor));
Drawable editButtonIcon = editButton.getDrawable();
editButtonIcon.mutate();
int colorPrimary = MaterialColors.getColor(this, R.attr.colorPrimary, ContextCompat.getColor(this, R.color.md_theme_light_primary));
int colorOnPrimary = MaterialColors.getColor(this, R.attr.colorOnPrimary, ContextCompat.getColor(this, R.color.md_theme_light_onPrimary));
boolean darkMode = Utils.isDarkModeEnabled(this);
if (Utils.needsDarkForeground(complementaryColor)) {
editButtonIcon.setTint(darkMode ? colorOnPrimary : colorPrimary);
} else {
editButtonIcon.setTint(darkMode ? colorPrimary : colorOnPrimary);
}
editButton.setImageDrawable(editButtonIcon);
Bitmap icon = Utils.retrieveCardImage(this, loyaltyCard.id, ImageLocationType.icon);
if (icon != null) {
int backgroundAlphaColor = Utils.needsDarkForeground(backgroundHeaderColor) ? Color.WHITE : Color.BLACK;
@@ -676,7 +618,23 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
imageTypes.add(ImageType.IMAGE_BACK);
}
setDotIndicator(darkMode);
dotIndicator.removeAllViews();
if (imageTypes.size() >= 2) {
dots = new ImageView[imageTypes.size()];
boolean darkMode = Utils.isDarkModeEnabled(getApplicationContext());
for (int i = 0; i < imageTypes.size(); i++) {
dots[i] = new ImageView(this);
dots[i].setImageDrawable(getDotIcon(false, darkMode));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(8, 0, 8, 0);
dotIndicator.addView(dots[i], params);
}
dotIndicator.setVisibility(View.VISIBLE);
}
setFullscreen(isFullscreen);
@@ -699,19 +657,18 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
@Override
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) {
item.setVisible(false);
}
loyaltyCard = DBHelper.getLoyaltyCard(database, loyaltyCardId);
starred = loyaltyCard.starStatus != 0;
if(loyaltyCard.archiveStatus != 0){
menu.findItem(R.id.action_unarchive).setVisible(true);
menu.findItem(R.id.action_archive).setVisible(false);
}
else{
menu.findItem(R.id.action_unarchive).setVisible(false);
menu.findItem(R.id.action_archive).setVisible(true);
}
menu.findItem(R.id.action_overflow).setIcon(getIcon(R.drawable.ic_overflow_menu, backgroundNeedsDarkIcons));
menu.findItem(R.id.action_share).setIcon(getIcon(R.drawable.ic_share_white, backgroundNeedsDarkIcons));
return super.onCreateOptionsMenu(menu);
@@ -749,14 +706,13 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
return true;
case R.id.action_duplicate:
loyaltyCard = DBHelper.getLoyaltyCard(database, loyaltyCardId);
Intent intent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("id", loyaltyCardId);
bundle.putBoolean("duplicateId", true);
intent.putExtras(bundle);
startActivity(intent);
case R.id.action_lock_unlock:
if (rotationEnabled) {
setOrientatonLock(item, true);
} else {
setOrientatonLock(item, false);
}
rotationEnabled = !rotationEnabled;
return true;
case R.id.action_star_unstar:
@@ -764,38 +720,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
DBHelper.updateLoyaltyCardStarStatus(database, loyaltyCardId, starred ? 1 : 0);
invalidateOptionsMenu();
return true;
case R.id.action_archive:
DBHelper.updateLoyaltyCardArchiveStatus(database, loyaltyCardId, 1);
Toast.makeText(LoyaltyCardViewActivity.this, R.string.archived, Toast.LENGTH_LONG).show();
invalidateOptionsMenu();
return true;
case R.id.action_unarchive:
DBHelper.updateLoyaltyCardArchiveStatus(database, loyaltyCardId, 0);
Toast.makeText(LoyaltyCardViewActivity.this, R.string.unarchived, Toast.LENGTH_LONG).show();
invalidateOptionsMenu();
return true;
case R.id.action_delete:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.deleteTitle);
builder.setMessage(R.string.deleteConfirmation);
builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
Log.e(TAG, "Deleting card: " + loyaltyCardId);
DBHelper.deleteLoyaltyCard(database, LoyaltyCardViewActivity.this, loyaltyCardId);
ShortcutHelper.removeShortcut(LoyaltyCardViewActivity.this, loyaltyCardId);
finish();
dialog.dismiss();
});
builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
AlertDialog dialog = builder.create();
dialog.show();
return true;
}
return super.onOptionsItemSelected(item);
@@ -807,6 +731,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.d(TAG, "Detected landscape mode");
setTitle(loyaltyCard.store);
collapsingToolbarLayout.setVisibility(View.GONE);
@@ -832,6 +757,19 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
}
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 {
item.setIcon(getIcon(R.drawable.ic_lock_open_white_24dp, backgroundNeedsDarkIcons));
item.setTitle(R.string.lockScreen);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
}
private void makeBottomSheetVisibleIfUseful() {
if (noteView.getVisibility() == View.VISIBLE || groupsView.getVisibility() == View.VISIBLE || balanceView.getVisibility() == View.VISIBLE || expiryView.getVisibility() == View.VISIBLE) {
bottomSheet.setVisibility(View.VISIBLE);
@@ -840,7 +778,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
}
private void drawBarcode(boolean addPadding) {
private void drawBarcode() {
mTasks.flushTaskList(TaskHandler.TYPE.BARCODE, true, false, false);
if (format != null) {
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(
@@ -850,13 +788,12 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
format,
null,
false,
barcodeImageGenerationFinishedCallback,
addPadding);
null);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
}
private void redrawBarcodeAfterResize(boolean addPadding) {
private void redrawBarcodeAfterResize() {
if (format != null) {
mainImage.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@@ -865,13 +802,13 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
mainImage.getViewTreeObserver().removeOnGlobalLayoutListener(this);
Log.d(TAG, "ImageView size now known");
drawBarcode(addPadding);
drawBarcode();
}
});
}
}
private void drawMainImage(int index, boolean waitForResize, boolean isFullscreen) {
private void drawMainImage(int index, boolean waitForResize) {
if (imageTypes.isEmpty()) {
mainImage.setVisibility(View.GONE);
return;
@@ -887,28 +824,18 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
ImageType wantedImageType = imageTypes.get(index);
if (wantedImageType == ImageType.BARCODE) {
// Use border in non-fullscreen mode
if (!isFullscreen) {
mainImage.setBackground(AppCompatResources.getDrawable(this, R.drawable.round_outline));
} else {
mainImage.setBackgroundColor(Color.WHITE);
}
if (waitForResize) {
redrawBarcodeAfterResize(!isFullscreen);
redrawBarcodeAfterResize();
} else {
drawBarcode(!isFullscreen);
drawBarcode();
}
mainImage.setContentDescription(getString(R.string.barcodeImageDescriptionWithType, format.prettyName()));
mainImage.setBackgroundColor(Color.WHITE);
} else if (wantedImageType == ImageType.IMAGE_FRONT) {
mainImage.setImageBitmap(frontImageBitmap);
mainImage.setBackgroundColor(Color.TRANSPARENT);
mainImage.setContentDescription(getString(R.string.frontImageDescription));
} else if (wantedImageType == ImageType.IMAGE_BACK) {
mainImage.setImageBitmap(backImageBitmap);
mainImage.setBackgroundColor(Color.TRANSPARENT);
mainImage.setContentDescription(getString(R.string.backImageDescription));
} else {
throw new IllegalArgumentException("Unknown image type: " + wantedImageType);
}
@@ -929,26 +856,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
mainImageIndex = newIndex;
drawMainImage(newIndex, false, isFullscreen);
}
private void setDotIndicator(boolean darkMode) {
dotIndicator.removeAllViews();
if (imageTypes.size() >= 2) {
dots = new ImageView[imageTypes.size()];
for (int i = 0; i < imageTypes.size(); i++) {
dots[i] = new ImageView(this);
dots[i].setImageDrawable(getDotIcon(false, darkMode));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(8, 0, 8, 0);
dotIndicator.addView(dots[i], params);
}
dotIndicator.setVisibility(View.VISIBLE);
}
drawMainImage(newIndex, false);
}
/**
@@ -964,7 +872,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
if (enabled && !imageTypes.isEmpty()) {
Log.d(TAG, "Move into fullscreen");
drawMainImage(mainImageIndex, true, isFullscreen);
drawMainImage(mainImageIndex, true);
barcodeScaler.setProgress(loyaltyCard.zoomLevel);
setCenterGuideline(loyaltyCard.zoomLevel);
@@ -985,7 +893,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
// Or the barcode will be centered instead of on top of the screen
// Don't ask me why...
appBarLayout.setVisibility(View.INVISIBLE);
iconImage.setVisibility(View.INVISIBLE);
collapsingToolbarLayout.setVisibility(View.GONE);
landscapeToolbar.setVisibility(View.GONE);
@@ -1010,7 +917,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
// Reset center guideline
setCenterGuideline(100);
drawMainImage(mainImageIndex, true, isFullscreen);
drawMainImage(mainImageIndex, true);
// Show maximize and hide minimize button and scaler
maximizeButton.setVisibility(imageTypes.isEmpty() ? View.GONE : View.VISIBLE);
@@ -1027,7 +934,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
// And restore 24dp paddingTop for appBarLayout
appBarLayout.setVisibility(View.VISIBLE);
setupOrientation();
iconImage.setVisibility(View.VISIBLE);
// Show other UI elements
cardIdFieldView.setVisibility(View.VISIBLE);

View File

@@ -21,7 +21,6 @@ import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.SearchView;
@@ -48,7 +47,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
private ActionMode mCurrentActionMode;
private SearchView mSearchView;
private GestureDetector mGestureDetector;
private int mLoyaltyCardCount = 0;
protected String mFilter = "";
protected Object mGroup = null;
protected DBHelper.LoyaltyCardOrder mOrder = DBHelper.LoyaltyCardOrder.Alpha;
@@ -59,9 +57,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
private View mNoMatchingCardsText;
private View mNoGroupCardsText;
private boolean mArchiveMode;
public static final String BUNDLE_ARCHIVE_MODE = "archiveMode";
private ActivityResultLauncher<Intent> mBarcodeScannerLauncher;
private ActivityResultLauncher<Intent> mSettingsLauncher;
@@ -145,8 +140,10 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
DBHelper db = new DBHelper(MainActivity.this);
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
Log.d(TAG, "Deleting card: " + loyaltyCard.id);
Log.e(TAG, "Deleting card: " + loyaltyCard.id);
DBHelper.deleteLoyaltyCard(mDatabase, MainActivity.this, loyaltyCard.id);
@@ -156,7 +153,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
TabLayout.Tab tab = ((TabLayout) findViewById(R.id.groups)).getTabAt(selectedTab);
mGroup = tab != null ? tab.getTag() : null;
updateLoyaltyCardList(true);
updateLoyaltyCardList();
dialog.dismiss();
});
@@ -166,44 +163,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
return true;
}
else if(inputItem.getItemId() == R.id.action_archive){
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
Log.d(TAG, "Archiving card: " + loyaltyCard.id);
DBHelper.updateLoyaltyCardArchiveStatus(mDatabase, loyaltyCard.id,1);
updateLoyaltyCardList(false);
inputMode.finish();
invalidateOptionsMenu();
}
return true;
}
else if(inputItem.getItemId() == R.id.action_unarchive){
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
Log.d(TAG, "Unarchiving card: " + loyaltyCard.id);
DBHelper.updateLoyaltyCardArchiveStatus(mDatabase, loyaltyCard.id,0);
updateLoyaltyCardList(false);
inputMode.finish();
invalidateOptionsMenu();
}
return true;
}
else if(inputItem.getItemId() == R.id.action_star){
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
Log.d(TAG, "Starring card: " + loyaltyCard.id);
DBHelper.updateLoyaltyCardStarStatus(mDatabase, loyaltyCard.id, 1);
updateLoyaltyCardList(false);
inputMode.finish();
}
return true;
}
else if(inputItem.getItemId() == R.id.action_unstar){
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
Log.d(TAG, "Unstarring card: " + loyaltyCard.id);
DBHelper.updateLoyaltyCardStarStatus(mDatabase, loyaltyCard.id, 0);
updateLoyaltyCardList(false);
inputMode.finish();
}
return true;
}
return false;
}
@@ -217,33 +176,15 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
@Override
protected void onCreate(Bundle inputSavedInstanceState) {
extractIntentFields(getIntent());
super.onCreate(inputSavedInstanceState);
SplashScreen.installSplashScreen(this);
if(!mArchiveMode) {
setTitle(R.string.app_name);
setContentView(R.layout.main_activity);
}
else{
setTitle(R.string.archiveList);
setContentView(R.layout.archive_activity);
}
// XXX color patching has to be done again after setting splash screen
Utils.patchColors(this);
setTitle(R.string.app_name);
setContentView(R.layout.main_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if(mArchiveMode){
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
mDatabase = new DBHelper(this).getWritableDatabase();
TabLayout groupsTabLayout = findViewById(R.id.groups);
groupsTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
@@ -251,7 +192,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
selectedTab = tab.getPosition();
Log.d("onTabSelected", "Tab Position " + tab.getPosition());
mGroup = tab.getTag();
updateLoyaltyCardList(false);
updateLoyaltyCardList();
// Store active tab in Shared Preference to restore next app launch
SharedPreferences activeTabPref = getApplicationContext().getSharedPreferences(
getString(R.string.sharedpreference_active_tab),
@@ -291,7 +232,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
registerForContextMenu(mCardList);
mGroup = null;
updateLoyaltyCardList(true);
updateLoyaltyCardList();
/*
* This was added for Huawei, but Huawei is just too much of a fucking pain.
@@ -356,8 +297,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
protected void onResume() {
super.onResume();
mAdapter.refreshState();
if (mCurrentActionMode != null) {
mAdapter.clearSelections();
mCurrentActionMode.finish();
@@ -397,28 +336,24 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
assert tab != null;
mGroup = tab.getTag();
}
updateLoyaltyCardList(true);
updateLoyaltyCardList();
// End of active tab logic
if (!mArchiveMode) {
FloatingActionButton addButton = findViewById(R.id.fabAdd);
addButton.setOnClickListener(v -> {
Intent intent = new Intent(getApplicationContext(), ScanActivity.class);
Bundle bundle = new Bundle();
if (selectedTab != 0) {
bundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, groupsTabLayout.getTabAt(selectedTab).getText().toString());
}
intent.putExtras(bundle);
mBarcodeScannerLauncher.launch(intent);
});
addButton.bringToFront();
}
FloatingActionButton addButton = findViewById(R.id.fabAdd);
addButton.setOnClickListener(v -> {
Intent intent = new Intent(getApplicationContext(), ScanActivity.class);
Bundle bundle = new Bundle();
if (selectedTab != 0) {
bundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, groupsTabLayout.getTabAt(selectedTab).getText().toString());
}
intent.putExtras(bundle);
mBarcodeScannerLauncher.launch(intent);
});
addButton.bringToFront();
}
@Override
public void onBackPressed() {
if (!mSearchView.isIconified()) {
mSearchView.setIconified(true);
return;
@@ -427,37 +362,20 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
super.onBackPressed();
}
private void displayCardSetupOptions(Menu menu, boolean shouldShow) {
for (int id : new int[]{R.id.action_search, R.id.action_unfold, R.id.action_sort}) {
menu.findItem(id).setVisible(shouldShow);
}
}
private void updateLoyaltyCardCount() {
mLoyaltyCardCount = DBHelper.getLoyaltyCardCount(mDatabase);
}
private void updateLoyaltyCardList(boolean updateCount) {
private void updateLoyaltyCardList() {
Group group = null;
if (mGroup != null) {
group = (Group) mGroup;
}
mAdapter.swapCursor(DBHelper.getLoyaltyCardCursor(mDatabase, mFilter, group, mOrder, mOrderDirection, mArchiveMode ? DBHelper.LoyaltyCardArchiveFilter.Archived : DBHelper.LoyaltyCardArchiveFilter.Unarchived));
mAdapter.swapCursor(DBHelper.getLoyaltyCardCursor(mDatabase, mFilter, group, mOrder, mOrderDirection));
if (updateCount) {
updateLoyaltyCardCount();
// Update menu icons if necessary
invalidateOptionsMenu();
}
if (mLoyaltyCardCount > 0) {
if (DBHelper.getLoyaltyCardCount(mDatabase) > 0) {
// We want the cardList to be visible regardless of the filtered match count
// to ensure that the noMatchingCardsText doesn't end up being shown below
// the keyboard
mHelpText.setVisibility(View.GONE);
mNoGroupCardsText.setVisibility(View.GONE);
if (mAdapter.getItemCount() > 0) {
mCardList.setVisibility(View.VISIBLE);
mNoMatchingCardsText.setVisibility(View.GONE);
@@ -476,7 +394,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
} else {
mCardList.setVisibility(View.GONE);
mHelpText.setVisibility(View.VISIBLE);
mNoMatchingCardsText.setVisibility(View.GONE);
mNoGroupCardsText.setVisibility(View.GONE);
}
@@ -486,11 +403,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
}
private void extractIntentFields(Intent intent) {
final Bundle b = intent.getExtras();
mArchiveMode = b != null && b.getBoolean(BUNDLE_ARCHIVE_MODE, false);
}
public void updateTabGroups(TabLayout groupsTabLayout) {
List<Group> newGroups = DBHelper.getGroups(mDatabase);
@@ -515,19 +427,11 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
groupsTabLayout.setVisibility(View.VISIBLE);
}
@Override
public boolean onCreateOptionsMenu(Menu inputMenu) {
if(!mArchiveMode)
getMenuInflater().inflate(R.menu.main_menu, inputMenu);
else{
getMenuInflater().inflate(R.menu.archive_menu, inputMenu);
}
Utils.updateMenuCardDetailsButtonState(inputMenu.findItem(R.id.action_unfold), mAdapter.showingDetails());
displayCardSetupOptions(inputMenu, mLoyaltyCardCount > 0);
getMenuInflater().inflate(R.menu.main_menu, inputMenu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
if (searchManager != null) {
@@ -554,20 +458,12 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
TabLayout.Tab currentTab = groupsTabLayout.getTabAt(groupsTabLayout.getSelectedTabPosition());
mGroup = currentTab != null ? currentTab.getTag() : null;
updateLoyaltyCardList(false);
updateLoyaltyCardList();
return true;
}
});
}
if(!mArchiveMode) {
if (DBHelper.getArchivedCardsCount(mDatabase) == 0) {
inputMenu.findItem(R.id.action_archived).setVisible(false);
} else {
inputMenu.findItem(R.id.action_archived).setVisible(true);
}
}
return super.onCreateOptionsMenu(inputMenu);
}
@@ -575,18 +471,24 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
public boolean onOptionsItemSelected(MenuItem inputItem) {
int id = inputItem.getItemId();
if (id == android.R.id.home) {
onBackPressed();
}
if (id == R.id.action_unfold) {
mAdapter.showDetails(!mAdapter.showingDetails());
invalidateOptionsMenu();
boolean shouldShow = !mAdapter.showingDetails();
if (shouldShow) {
inputItem.setIcon(R.drawable.ic_baseline_unfold_less_24);
inputItem.setTitle(R.string.action_hide_details);
} else {
inputItem.setIcon(R.drawable.ic_baseline_unfold_more_24);
inputItem.setTitle(R.string.action_show_details);
}
mAdapter.showDetails(shouldShow);
return true;
}
if (id == R.id.action_sort) {
TabLayout.Tab tab = ((TabLayout) findViewById(R.id.groups)).getTabAt(selectedTab);
AtomicInteger currentIndex = new AtomicInteger();
List<DBHelper.LoyaltyCardOrder> loyaltyCardOrders = Arrays.asList(DBHelper.LoyaltyCardOrder.values());
for (int i = 0; i < loyaltyCardOrders.size(); i++) {
@@ -602,21 +504,17 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
final View customLayout = getLayoutInflater().inflate(R.layout.sorting_option, null);
builder.setView(customLayout);
CheckBox showReversed = (CheckBox) customLayout.findViewById(R.id.checkBox_reverse);
showReversed.setChecked(mOrderDirection == DBHelper.LoyaltyCardOrderDirection.Descending);
CheckBox ch = (CheckBox) customLayout.findViewById(R.id.checkBox_reverse);
ch.setChecked(mOrderDirection == DBHelper.LoyaltyCardOrderDirection.Descending);
builder.setSingleChoiceItems(R.array.sort_types_array, currentIndex.get(), (dialog, which) -> currentIndex.set(which));
builder.setPositiveButton(R.string.sort, (dialog, which) -> {
setSort(
loyaltyCardOrders.get(currentIndex.get()),
showReversed.isChecked() ? DBHelper.LoyaltyCardOrderDirection.Descending : DBHelper.LoyaltyCardOrderDirection.Ascending
);
if (ch.isChecked()) {
setSort(loyaltyCardOrders.get(currentIndex.get()), DBHelper.LoyaltyCardOrderDirection.Descending);
} else {
setSort(loyaltyCardOrders.get(currentIndex.get()), DBHelper.LoyaltyCardOrderDirection.Ascending);
}
dialog.dismiss();
});
@@ -652,16 +550,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
return true;
}
if(id == R.id.action_archived){
Intent i = new Intent(getApplicationContext(), MainActivity.class);
Bundle bundle = new Bundle();
bundle.putBoolean("archiveMode", true);
i.putExtras(bundle);
startActivity(i);
return true;
}
return super.onOptionsItemSelected(inputItem);
}
@@ -680,7 +568,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
sortPrefEditor.apply();
// Update card list
updateLoyaltyCardList(false);
updateLoyaltyCardList();
}
@Override
@@ -783,47 +671,10 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
mCurrentActionMode.setTitle(getResources().getQuantityString(R.plurals.selectedCardCount, count, count));
MenuItem editItem = mCurrentActionMode.getMenu().findItem(R.id.action_edit);
MenuItem archiveItem = mCurrentActionMode.getMenu().findItem(R.id.action_archive);
MenuItem unarchiveItem = mCurrentActionMode.getMenu().findItem(R.id.action_unarchive);
MenuItem starItem = mCurrentActionMode.getMenu().findItem(R.id.action_star);
MenuItem unstarItem = mCurrentActionMode.getMenu().findItem(R.id.action_unstar);
boolean hasStarred = false;
boolean hasUnstarred = false;
if(!mArchiveMode) {
unarchiveItem.setVisible(false);
archiveItem.setVisible(true);
}
else{
unarchiveItem.setVisible(true);
archiveItem.setVisible(false);
}
for (LoyaltyCard loyaltyCard : mAdapter.getSelectedItems()) {
if (loyaltyCard.starStatus == 1) {
hasStarred = true;
} else {
hasUnstarred = true;
}
if (hasStarred && hasUnstarred) {
hasStarred = true;
hasUnstarred = true;
break;
}
}
if (count == 1) {
starItem.setVisible(!hasStarred);
unstarItem.setVisible(!hasUnstarred);
editItem.setVisible(true);
editItem.setEnabled(true);
} else {
starItem.setVisible(hasUnstarred);
unstarItem.setVisible(hasStarred);
editItem.setVisible(false);
editItem.setEnabled(false);
}
@@ -832,7 +683,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
}
@Override
public void onRowClicked(int inputPosition) {
if (mAdapter.getSelectedItemCount() > 0) {

View File

@@ -1,13 +1,12 @@
package protect.card_locker;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
@@ -157,26 +156,6 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana
return ret;
}
@Override
public boolean onCreateOptionsMenu(Menu inputMenu) {
getMenuInflater().inflate(R.menu.card_details_menu, inputMenu);
Utils.updateMenuCardDetailsButtonState(inputMenu.findItem(R.id.action_unfold), mAdapter.showingDetails());
return super.onCreateOptionsMenu(inputMenu);
}
@Override
public boolean onOptionsItemSelected(MenuItem inputItem) {
int id = inputItem.getItemId();
if (id == R.id.action_unfold) {
mAdapter.showDetails(!mAdapter.showingDetails());
invalidateOptionsMenu();
return true;
}
return super.onOptionsItemSelected(inputItem);
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {

View File

@@ -8,8 +8,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import androidx.recyclerview.widget.RecyclerView;
public class ManageGroupCursorAdapter extends LoyaltyCardCursorAdapter {
private HashMap<Integer, Integer> mIndexCardMap;
private HashMap<Integer, Boolean> mInGroupOverlay;

View File

@@ -109,7 +109,7 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro
}
private void createGroup() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AlertDialogTheme);
builder.setTitle(R.string.enter_group_name);
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);

View File

@@ -0,0 +1,29 @@
package protect.card_locker;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
public class NotificationType {
private final static String NOTIFICATION_IMPORT_EXPORT = "NOTIFICATION_IMPORT_EXPORT";
public static String getImportExportChannel(Context context) {
createNotificationChannel(context, NOTIFICATION_IMPORT_EXPORT, context.getString(R.string.importExport), context.getString(R.string.importExportDescription), NotificationManager.IMPORTANCE_HIGH);
return NOTIFICATION_IMPORT_EXPORT;
}
private static void createNotificationChannel(Context context, String channelId, CharSequence name, String description, int importance) {
// Create the NotificationType, but only on API 26+ because
// the NotificationType class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}

View File

@@ -1,79 +0,0 @@
package protect.card_locker;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.textview.MaterialTextView;
import com.yalantis.ucrop.UCropActivity;
public class UCropWrapper extends UCropActivity {
public static final String UCROP_TOOLBAR_TYPEFACE_STYLE = "ucop_toolbar_typeface_style";
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
boolean darkMode = Utils.isDarkModeEnabled(this);
// setup status bar to look like the rest of the app
if (Build.VERSION.SDK_INT >= 23) {
getWindow().getDecorView().setSystemUiVisibility(darkMode ? 0 : View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
// icons are always white back then
if (!darkMode) {
getWindow().setStatusBarColor(ColorUtils.compositeColors(Color.argb(127, 0, 0, 0), getWindow().getStatusBarColor()));
}
}
// find and check views that we wish to color modify
// for when we update ucrop or switch to another cropper
View check = findViewById(com.yalantis.ucrop.R.id.wrapper_controls);
if (check instanceof FrameLayout) {
FrameLayout controls = (FrameLayout) check;
check = findViewById(com.yalantis.ucrop.R.id.wrapper_states);
if (check instanceof LinearLayout) {
LinearLayout states = (LinearLayout) check;
for (int i = 0; i < controls.getChildCount(); i++) {
check = controls.getChildAt(i);
if (check instanceof AppCompatImageView) {
AppCompatImageView controlsBackgroundImage = (AppCompatImageView) check;
// everything gathered and are as expected, now perform color patching
Utils.patchColors(this);
int colorSurface = MaterialColors.getColor(this, R.attr.colorSurface, ContextCompat.getColor(this, R.color.md_theme_light_surface));
int colorOnSurface = MaterialColors.getColor(this, R.attr.colorOnSurface, ContextCompat.getColor(this, R.color.md_theme_light_onSurface));
Drawable controlsBackgroundImageDrawable = controlsBackgroundImage.getBackground();
controlsBackgroundImageDrawable.mutate();
controlsBackgroundImageDrawable.setTint(darkMode ? colorOnSurface : colorSurface);
controlsBackgroundImage.setBackgroundDrawable(controlsBackgroundImageDrawable);
states.setBackgroundColor(darkMode ? colorSurface : colorOnSurface);
break;
}
}
}
}
// change toolbar font
check = findViewById(com.yalantis.ucrop.R.id.toolbar_title);
if (check instanceof MaterialTextView) {
MaterialTextView toolbarTextview = (MaterialTextView) check;
Intent intent = getIntent();
int style = intent.getIntExtra(UCROP_TOOLBAR_TYPEFACE_STYLE, -1);
if (style != -1) {
toolbarTextview.setTypeface(Typeface.defaultFromStyle(style));
}
}
}
}

View File

@@ -5,7 +5,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
@@ -15,12 +14,8 @@ import android.os.Build;
import android.os.LocaleList;
import android.provider.MediaStore;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.google.android.material.color.DynamicColors;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
@@ -44,12 +39,9 @@ import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Map;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.graphics.ColorUtils;
import androidx.exifinterface.media.ExifInterface;
import androidx.palette.graphics.Palette;
import protect.card_locker.preferences.Settings;
public class Utils {
@@ -214,7 +206,7 @@ public class Utils {
if (currency == null) {
numberFormat.setMaximumFractionDigits(0);
return context.getResources().getQuantityString(R.plurals.balancePoints, value.intValue(), numberFormat.format(value));
return context.getString(R.string.balancePoints, numberFormat.format(value));
}
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
@@ -456,82 +448,4 @@ public class Utils {
return loadImage(context.getCacheDir() + "/" + name);
}
// https://stackoverflow.com/a/59324801/8378787
public static int getComplementaryColor(int color) {
int R = color & 255;
int G = (color >> 8) & 255;
int B = (color >> 16) & 255;
int A = (color >> 24) & 255;
R = 255 - R;
G = 255 - G;
B = 255 - B;
return R + (G << 8) + (B << 16) + (A << 24);
}
// replace colors in the current theme
public static void patchColors(AppCompatActivity activity) {
Settings settings = new Settings(activity);
String color = settings.getColor();
Resources.Theme theme = activity.getTheme();
Resources resources = activity.getResources();
if (color.equals(resources.getString(R.string.settings_key_pink_theme))) {
theme.applyStyle(R.style.pink, true);
} else if (color.equals(resources.getString(R.string.settings_key_magenta_theme))) {
theme.applyStyle(R.style.magenta, true);
} else if (color.equals(resources.getString(R.string.settings_key_violet_theme))) {
theme.applyStyle(R.style.violet, true);
} else if (color.equals(resources.getString(R.string.settings_key_blue_theme))) {
theme.applyStyle(R.style.blue, true);
} else if (color.equals(resources.getString(R.string.settings_key_sky_blue_theme))) {
theme.applyStyle(R.style.skyblue, true);
} else if (color.equals(resources.getString(R.string.settings_key_green_theme))) {
theme.applyStyle(R.style.green, true);
} else if (color.equals(resources.getString(R.string.settings_key_brown_theme))) {
theme.applyStyle(R.style.brown, true);
} else if (color.equals(resources.getString(R.string.settings_key_catima_theme))) {
// catima theme is AppTheme itself, no dynamic colors nor applyStyle
} else {
// final catch all in case of invalid theme value from older versions
// also handles R.string.settings_key_system_theme
DynamicColors.applyIfAvailable(activity);
}
if (isDarkModeEnabled(activity) && settings.getOledDark()) {
theme.applyStyle(R.style.DarkBackground, true);
}
}
// XXX android 9 and below has issues with patched theme where the background becomes a
// rendering mess
// use after views are inflated
public static void postPatchColors(AppCompatActivity activity) {
TypedValue typedValue = new TypedValue();
activity.getTheme().resolveAttribute(android.R.attr.colorBackground, typedValue, true);
activity.findViewById(android.R.id.content).setBackgroundColor(typedValue.data);
}
public static void updateMenuCardDetailsButtonState(MenuItem item, boolean currentlyExpanded) {
if (currentlyExpanded) {
item.setIcon(R.drawable.ic_baseline_unfold_less_24);
item.setTitle(R.string.action_hide_details);
} else {
item.setIcon(R.drawable.ic_baseline_unfold_more_24);
item.setTitle(R.string.action_show_details);
}
}
public static int getHeaderColorFromImage(Bitmap image, int fallback) {
if (image == null) {
return fallback;
}
return new Palette.Builder(image).generate().getDominantColor(R.attr.colorPrimary);
}
public static int getRandomHeaderColor(Context context) {
TypedArray colors = context.getResources().obtainTypedArray(R.array.letter_tile_colors);
final int color = (int) (Math.random() * colors.length());
return colors.getColor(color, Color.BLACK);
}
}

View File

@@ -135,8 +135,7 @@ public class CatimaExporter implements Exporter {
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE,
DBHelper.LoyaltyCardDbIds.HEADER_COLOR,
DBHelper.LoyaltyCardDbIds.STAR_STATUS,
DBHelper.LoyaltyCardDbIds.LAST_USED,
DBHelper.LoyaltyCardDbIds.ARCHIVE_STATUS);
DBHelper.LoyaltyCardDbIds.LAST_USED);
Cursor cardCursor = DBHelper.getLoyaltyCardCursor(database);
@@ -154,8 +153,7 @@ public class CatimaExporter implements Exporter {
card.barcodeType != null ? card.barcodeType.name() : "",
card.headerColor,
card.starStatus,
card.lastUsed,
card.archiveStatus);
card.lastUsed);
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();

View File

@@ -321,15 +321,6 @@ public class CatimaImporter implements Importer {
}
if (starStatus != 1) starStatus = 0;
int archiveStatus = 0;
try {
archiveStatus = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ARCHIVE_STATUS, record, false);
} catch (FormatException _e) {
// This field did not exist in versions 2.16.3 and before
// We catch this exception so we can still import old backups
}
if (archiveStatus != 1) archiveStatus = 0;
Long lastUsed = 0L;
try {
lastUsed = CSVHelpers.extractLong(DBHelper.LoyaltyCardDbIds.LAST_USED, record, false);
@@ -338,7 +329,7 @@ public class CatimaImporter implements Importer {
// We catch this exception so we can still import old backups
}
DBHelper.insertLoyaltyCard(database, id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starStatus, lastUsed,archiveStatus);
DBHelper.insertLoyaltyCard(database, id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starStatus, lastUsed);
}
/**

View File

@@ -6,6 +6,8 @@ import android.database.sqlite.SQLiteDatabase;
import java.io.IOException;
import java.io.OutputStream;
import protect.card_locker.DBHelper;
/**
* Interface for a class which can export the contents of the database
* in a given format.

View File

@@ -21,7 +21,6 @@ import java.text.ParseException;
import protect.card_locker.CatimaBarcode;
import protect.card_locker.DBHelper;
import protect.card_locker.FormatException;
import protect.card_locker.Utils;
/**
* Class for importing a database from CSV (Comma Separate Values)
@@ -57,7 +56,7 @@ public class FidmeImporter implements Importer {
try {
for (CSVRecord record : fidmeParser) {
importLoyaltyCard(context, database, record);
importLoyaltyCard(database, record);
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
@@ -76,7 +75,7 @@ public class FidmeImporter implements Importer {
* Import a single loyalty card into the database using the given
* session.
*/
private void importLoyaltyCard(Context context, SQLiteDatabase database, CSVRecord record)
private void importLoyaltyCard(SQLiteDatabase database, CSVRecord record)
throws FormatException {
// A loyalty card export from Fidme contains the following fields:
// Retailer (store name)
@@ -118,13 +117,11 @@ public class FidmeImporter implements Importer {
// TODO: Hook this into our own loyalty card DB if we ever get one
CatimaBarcode barcodeType = null;
// No favourite data or colour in the export either
// No favourite data in the export either
int starStatus = 0;
int archiveStatus = 0;
int headerColor = Utils.getRandomHeaderColor(context);
// TODO: Front and back image
DBHelper.insertLoyaltyCard(database, store, note, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, headerColor, starStatus, null,archiveStatus);
DBHelper.insertLoyaltyCard(database, store, note, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, null, starStatus, null);
}
}

View File

@@ -1,23 +1,7 @@
package protect.card_locker.importexport;
public class ImportExportResult {
private ImportExportResultType resultType;
private String developerDetails;
public ImportExportResult(ImportExportResultType resultType) {
this(resultType, null);
}
public ImportExportResult(ImportExportResultType resultType, String developerDetails) {
this.resultType = resultType;
this.developerDetails = developerDetails;
}
public ImportExportResultType resultType() {
return resultType;
}
public String developerDetails() {
return developerDetails;
}
public enum ImportExportResult {
Success,
GenericFailure,
BadPassword;
}

View File

@@ -1,7 +0,0 @@
package protect.card_locker.importexport;
public enum ImportExportResultType {
Success,
GenericFailure,
BadPassword;
}

View File

@@ -7,6 +7,8 @@ import android.util.Log;
import java.io.IOException;
import java.io.OutputStream;
import protect.card_locker.DBHelper;
public class MultiFormatExporter {
private static final String TAG = "Catima";
@@ -32,20 +34,20 @@ public class MultiFormatExporter {
break;
}
String error;
if (exporter != null) {
try {
exporter.exportData(context, database, output, password);
return new ImportExportResult(ImportExportResultType.Success);
} catch (Exception e) {
return ImportExportResult.Success;
} catch (IOException e) {
Log.e(TAG, "Failed to export data", e);
} catch (InterruptedException e) {
Log.e(TAG, "Failed to export data", e);
error = e.toString();
}
} else {
error = "Unsupported data format exported: " + format.name();
Log.e(TAG, error);
}
return new ImportExportResult(ImportExportResultType.GenericFailure, error);
return ImportExportResult.GenericFailure;
} else {
Log.e(TAG, "Unsupported data format exported: " + format.name());
return ImportExportResult.GenericFailure;
}
}
}

View File

@@ -12,6 +12,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import protect.card_locker.DBHelper;
import protect.card_locker.FormatException;
public class MultiFormatImporter {
@@ -46,31 +47,23 @@ public class MultiFormatImporter {
break;
}
String error = null;
if (importer != null) {
database.beginTransaction();
try {
importer.importData(context, database, input, password);
database.setTransactionSuccessful();
return new ImportExportResult(ImportExportResultType.Success);
return ImportExportResult.Success;
} catch (ZipException e) {
if (e.getType().equals(ZipException.Type.WRONG_PASSWORD)) {
return new ImportExportResult(ImportExportResultType.BadPassword);
} else {
Log.e(TAG, "Failed to import data", e);
error = e.toString();
}
} catch (Exception e) {
return ImportExportResult.BadPassword;
} catch (IOException | FormatException | InterruptedException | JSONException | ParseException | NullPointerException e) {
Log.e(TAG, "Failed to import data", e);
error = e.toString();
} finally {
database.endTransaction();
}
} else {
error = "Unsupported data format imported: " + format.name();
Log.e(TAG, error);
Log.e(TAG, "Unsupported data format imported: " + format.name());
}
return new ImportExportResult(ImportExportResultType.GenericFailure, error);
return ImportExportResult.GenericFailure;
}
}

View File

@@ -3,7 +3,6 @@ package protect.card_locker.importexport;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.util.Log;
import com.google.zxing.BarcodeFormat;
@@ -40,17 +39,15 @@ import protect.card_locker.ZipUtils;
* A header is expected for the each table showing the names of the columns.
*/
public class StocardImporter implements Importer {
private static final String TAG = "Catima";
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
HashMap<String, HashMap<String, Object>> loyaltyCardHashMap = new HashMap<>();
HashMap<String, HashMap<String, Object>> providers = new HashMap<>();
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.builder().setHeader().build());
try {
for (CSVRecord record : parser) {
HashMap<String, Object> recordData = new HashMap<>();
HashMap<String, String> recordData = new HashMap<>();
recordData.put("name", record.get("name"));
recordData.put("barcodeFormat", record.get("barcodeFormat"));
@@ -65,8 +62,6 @@ public class StocardImporter implements Importer {
ZipInputStream zipInputStream = new ZipInputStream(input, password);
String[] providersFileName = null;
String[] customProvidersBaseName = null;
String customProviderId = "";
String[] cardBaseName = null;
String cardName = "";
LocalFileHeader localFileHeader;
@@ -83,14 +78,6 @@ public class StocardImporter implements Importer {
nameParts[0],
"analytics-properties.json"
};
customProvidersBaseName = new String[]{
nameParts[0],
"sync",
"data",
"users",
nameParts[0],
"loyalty-card-custom-providers"
};
cardBaseName = new String[]{
nameParts[0],
"sync",
@@ -101,33 +88,6 @@ public class StocardImporter implements Importer {
};
}
if (startsWith(nameParts, customProvidersBaseName, 1)) {
// Extract providerId
customProviderId = nameParts[customProvidersBaseName.length].split("\\.", 2)[0];
// Name file
if (nameParts.length == customProvidersBaseName.length + 1) {
// Ignore the .txt file
if (fileName.endsWith(".json")) {
JSONObject jsonObject = ZipUtils.readJSON(zipInputStream);
providers = appendToHashMap(
providers,
customProviderId,
"name",
jsonObject.getString("name")
);
}
} else if (fileName.endsWith("logo.png")) {
providers = appendToHashMap(
providers,
customProviderId,
"logo",
ZipUtils.readImage(zipInputStream)
);
}
}
if (startsWith(nameParts, cardBaseName, 1)) {
// Extract cardName
cardName = nameParts[cardBaseName.length].split("\\.", 2)[0];
@@ -138,33 +98,24 @@ public class StocardImporter implements Importer {
if (fileName.endsWith(".json")) {
JSONObject jsonObject = ZipUtils.readJSON(zipInputStream);
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap = appendToLoyaltyCardHashMap(
loyaltyCardHashMap,
cardName,
"cardId",
jsonObject.getString("input_id")
);
// Provider ID can be either custom or not, extract whatever version is relevant
String customProviderPrefix = "/users/" + nameParts[0] + "/loyalty-card-custom-providers/";
String providerId = jsonObject
.getJSONObject("input_provider_reference")
.getString("identifier");
if (providerId.startsWith(customProviderPrefix)) {
providerId = providerId.substring(customProviderPrefix.length());
} else {
providerId = providerId.substring("/loyalty-card-providers/".length());
}
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap = appendToLoyaltyCardHashMap(
loyaltyCardHashMap,
cardName,
"_providerId",
providerId
jsonObject
.getJSONObject("input_provider_reference")
.getString("identifier")
.substring("/loyalty-card-providers/".length())
);
if (jsonObject.has("input_barcode_format")) {
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap = appendToLoyaltyCardHashMap(
loyaltyCardHashMap,
cardName,
"barcodeType",
@@ -173,7 +124,7 @@ public class StocardImporter implements Importer {
}
}
} else if (fileName.endsWith("notes/default.json")) {
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap = appendToLoyaltyCardHashMap(
loyaltyCardHashMap,
cardName,
"note",
@@ -181,14 +132,14 @@ public class StocardImporter implements Importer {
.getString("content")
);
} else if (fileName.endsWith("/images/front.png")) {
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap = appendToLoyaltyCardHashMap(
loyaltyCardHashMap,
cardName,
"frontImage",
ZipUtils.readImage(zipInputStream)
);
} else if (fileName.endsWith("/images/back.png")) {
loyaltyCardHashMap = appendToHashMap(
loyaltyCardHashMap = appendToLoyaltyCardHashMap(
loyaltyCardHashMap,
cardName,
"backImage",
@@ -204,41 +155,22 @@ public class StocardImporter implements Importer {
for (HashMap<String, Object> loyaltyCardData : loyaltyCardHashMap.values()) {
String providerId = (String) loyaltyCardData.get("_providerId");
HashMap<String, String> providerData = providers.get(providerId);
if (providerId == null) {
Log.d(TAG, "Missing providerId for card " + loyaltyCardData + ", ignoring...");
continue;
}
HashMap<String, Object> providerData = providers.get(providerId);
String store = providerData != null ? providerData.get("name").toString() : providerId;
String store = providerData != null ? providerData.get("name") : providerId;
String note = (String) Utils.mapGetOrDefault(loyaltyCardData, "note", "");
String cardId = (String) loyaltyCardData.get("cardId");
String barcodeTypeString = (String) Utils.mapGetOrDefault(loyaltyCardData, "barcodeType", providerData != null ? providerData.get("barcodeFormat") : null);
CatimaBarcode barcodeType = null;
if (barcodeTypeString != null && !barcodeTypeString.isEmpty()) {
if (barcodeTypeString != null) {
if (barcodeTypeString.equals("RSS_DATABAR_EXPANDED")) {
barcodeType = CatimaBarcode.fromBarcode(BarcodeFormat.RSS_EXPANDED);
} else if (barcodeTypeString.equals("GS1_128")) {
barcodeType = CatimaBarcode.fromBarcode(BarcodeFormat.CODE_128);
} else {
barcodeType = CatimaBarcode.fromName(barcodeTypeString);
}
}
int headerColor = Utils.getRandomHeaderColor(context);
Bitmap cardIcon = null;
if (providerData != null && providerData.containsKey("logo")) {
cardIcon = (Bitmap) providerData.get("logo");
headerColor = Utils.getHeaderColorFromImage(cardIcon, headerColor);
}
long loyaltyCardInternalId = DBHelper.insertLoyaltyCard(database, store, note, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, headerColor, 0, null,0);
if (cardIcon != null) {
Utils.saveCardImage(context, cardIcon, (int) loyaltyCardInternalId, ImageLocationType.icon);
}
long loyaltyCardInternalId = DBHelper.insertLoyaltyCard(database, store, note, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, null, 0, null);
if (loyaltyCardData.containsKey("frontImage")) {
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("frontImage"), (int) loyaltyCardInternalId, ImageLocationType.front);
@@ -265,7 +197,7 @@ public class StocardImporter implements Importer {
return true;
}
private HashMap<String, HashMap<String, Object>> appendToHashMap(HashMap<String, HashMap<String, Object>> loyaltyCardHashMap, String cardID, String key, Object value) {
private HashMap<String, HashMap<String, Object>> appendToLoyaltyCardHashMap(HashMap<String, HashMap<String, Object>> loyaltyCardHashMap, String cardID, String key, Object value) {
HashMap<String, Object> loyaltyCardData = loyaltyCardHashMap.get(cardID);
if (loyaltyCardData == null) {
loyaltyCardData = new HashMap<>();

View File

@@ -126,7 +126,7 @@ public class VoucherVaultImporter implements Importer {
throw new FormatException("Unknown colour type found: " + colorFromJSON);
}
DBHelper.insertLoyaltyCard(database, store, "", expiry, balance, balanceType, cardId, null, barcodeType, headerColor, 0, Utils.getUnixTime(),0);
DBHelper.insertLoyaltyCard(database, store, "", expiry, balance, balanceType, cardId, null, barcodeType, headerColor, 0, Utils.getUnixTime());
}
bufferedReader.close();

View File

@@ -9,7 +9,6 @@ import androidx.annotation.IntegerRes;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
import protect.card_locker.R;
import protect.card_locker.Utils;
@@ -92,8 +91,8 @@ public class Settings {
return getBoolean(R.string.settings_key_display_barcode_max_brightness, true);
}
public String getCardViewOrientation() {
return getString(R.string.settings_key_card_orientation, getResString(R.string.settings_key_follow_system_orientation));
public boolean getLockBarcodeScreenOrientation() {
return getBoolean(R.string.settings_key_lock_barcode_orientation, false);
}
public boolean getKeepScreenOn() {
@@ -103,12 +102,4 @@ public class Settings {
public boolean getDisableLockscreenWhileViewingCard() {
return getBoolean(R.string.settings_key_disable_lockscreen_while_viewing_card, true);
}
public boolean getOledDark() {
return getBoolean(R.string.settings_key_oled_dark, false);
}
public String getColor() {
return getString(R.string.setting_key_theme_color, mContext.getResources().getString(R.string.settings_key_system_theme));
}
}

View File

@@ -6,10 +6,6 @@ import android.content.Intent;
import android.os.Bundle;
import android.view.MenuItem;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatDelegate;
@@ -19,7 +15,9 @@ import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import com.google.android.material.color.DynamicColors;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import nl.invissvenska.numberpickerpreference.NumberDialogPreference;
import nl.invissvenska.numberpickerpreference.NumberPickerPreferenceDialogFragment;
@@ -131,28 +129,16 @@ public class SettingsActivity extends CatimaAppCompatActivity {
return true;
});
localePreference.setOnPreferenceChangeListener((preference, newValue) -> {
refreshActivity(true);
return true;
});
Preference oledDarkPreference = findPreference(getResources().getString(R.string.settings_key_oled_dark));
assert oledDarkPreference != null;
oledDarkPreference.setOnPreferenceChangeListener((preference, newValue) -> {
refreshActivity(true);
return true;
});
ListPreference colorPreference = findPreference(getResources().getString(R.string.setting_key_theme_color));
Preference colorPreference = findPreference(getResources().getString(R.string.setting_key_theme_color));
assert colorPreference != null;
colorPreference.setOnPreferenceChangeListener((preference, o) -> {
refreshActivity(true);
return true;
});
if (!DynamicColors.isDynamicColorAvailable()) {
colorPreference.setEntryValues(R.array.color_values_no_dynamic);
colorPreference.setEntries(R.array.color_value_strings_no_dynamic);
}
localePreference.setOnPreferenceChangeListener((preference, newValue) -> {
refreshActivity(true);
return true;
});
}
private void refreshActivity(boolean reloadMain) {

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@android:color/white">
<path
android:fillColor="@android:color/white"
android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5V19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5zM5.12,5l0.81,-1h12l0.94,1H5.12z"/>
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@android:color/black">
<path
android:fillColor="@android:color/black"
android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5V19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5zM5.12,5l0.81,-1h12l0.94,1H5.12z"/>
</vector>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7,10l5,5 5,-5z"/>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7,14l5,-5 5,5z"/>

View File

@@ -1,5 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="?attr/colorControlNormal" android:viewportHeight="24"
android:tint="#FFFFFF" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/>
</vector>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7.41,18.59L8.83,20 12,16.83 15.17,20l1.41,-1.41L12,14l-4.59,4.59zM16.59,5.41L15.17,4 12,7.17 8.83,4 7.41,5.41 12,10l4.59,-4.59z"/>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,5.83L15.17,9l1.41,-1.41L12,3 7.41,7.59 8.83,9 12,5.83zM12,18.17L8.83,15l-1.41,1.41L12,21l4.59,-4.59L15.17,15 12,18.17z"/>

View File

@@ -2,8 +2,7 @@
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@color/colorPrimary"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>

View File

@@ -2,8 +2,7 @@
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
android:viewportHeight="24">
<path
android:pathData="M18,5l0,-3l-12,0l0,1.17l1.83,1.83z"
android:fillColor="#FFFFFF"/>

View File

@@ -2,8 +2,7 @@
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
android:viewportHeight="24">
<path
android:pathData="M6,2h12v3h-12z"
android:fillColor="#FFFFFF"/>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z"/>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M9,3L5,6.99h3L8,14h2L10,6.99h3L9,3zM16,17.01L16,10h-2v7.01h-3L15,21l4,-3.99h-3z"/>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h1.9c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z"/>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/listItemHighlight" android:state_activated="true" />
</selector>

View File

@@ -1,5 +0,0 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFFFF" />
<corners android:radius="10dp" />
</shape>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>

View File

@@ -10,13 +10,15 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.MaterialToolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</com.google.android.material.appbar.AppBarLayout>
@@ -44,6 +46,7 @@
android:fontFamily="sans-serif-medium"
android:padding="2dp"
android:text="@string/version_history"
android:textColor="@color/colorSecondaryText"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -58,12 +61,12 @@
app:layout_constraintTop_toBottomOf="@id/version_history_main" />
<TextView
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:fontFamily="sans-serif-medium"
android:text="@string/arrow"
android:textColor="@color/colorSecondaryText"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -83,6 +86,7 @@
android:fontFamily="sans-serif-medium"
android:padding="2dp"
android:text="@string/credits"
android:textColor="@color/colorSecondaryText"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -97,12 +101,12 @@
app:layout_constraintTop_toBottomOf="@id/credits_main" />
<TextView
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:fontFamily="sans-serif-medium"
android:text="@string/arrow"
android:textColor="@color/colorSecondaryText"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -122,6 +126,7 @@
android:fontFamily="sans-serif-medium"
android:padding="2dp"
android:text="@string/help_translate_this_app"
android:textColor="@color/colorSecondaryText"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -138,12 +143,12 @@
app:layout_constraintTop_toBottomOf="@id/translate_main"/>
<TextView
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:fontFamily="sans-serif-medium"
android:text="@string/arrow"
android:textColor="@color/colorSecondaryText"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -163,6 +168,7 @@
android:fontFamily="sans-serif-medium"
android:padding="2dp"
android:text="@string/license"
android:textColor="@color/colorSecondaryText"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -179,12 +185,12 @@
app:layout_constraintTop_toBottomOf="@id/license_main"/>
<TextView
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:fontFamily="sans-serif-medium"
android:text="@string/arrow"
android:textColor="@color/colorSecondaryText"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -204,6 +210,7 @@
android:fontFamily="sans-serif-medium"
android:padding="2dp"
android:text="@string/source_repository"
android:textColor="@color/colorSecondaryText"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -219,12 +226,12 @@
app:layout_constraintTop_toBottomOf="@id/repo_main" />
<TextView
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:fontFamily="sans-serif-medium"
android:text="@string/arrow"
android:textColor="@color/colorSecondaryText"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -244,6 +251,7 @@
android:fontFamily="sans-serif-medium"
android:padding="2dp"
android:text="@string/privacy_policy"
android:textColor="@color/colorSecondaryText"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -259,12 +267,12 @@
app:layout_constraintTop_toBottomOf="@id/privacy_main" />
<TextView
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:fontFamily="sans-serif-medium"
android:text="@string/arrow"
android:textColor="@color/colorSecondaryText"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -284,6 +292,7 @@
android:fontFamily="sans-serif-medium"
android:padding="2dp"
android:text="@string/rate_this_app"
android:textColor="@color/colorSecondaryText"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -299,12 +308,12 @@
app:layout_constraintTop_toBottomOf="@id/rate_main" />
<TextView
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:fontFamily="sans-serif-medium"
android:text="@string/arrow"
android:textColor="@color/colorSecondaryText"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -324,6 +333,7 @@
android:fontFamily="sans-serif-medium"
android:padding="2dp"
android:text="@string/report_error"
android:textColor="@color/colorSecondaryText"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -339,12 +349,12 @@
android:padding="2dp"/>
<TextView
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:fontFamily="sans-serif-medium"
android:text="@string/arrow"
android:textColor="@color/colorSecondaryText"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"

View File

@@ -22,13 +22,15 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.MaterialToolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/groups"

View File

@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="protect.card_locker.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/groups"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable"
android:visibility="gone"/>
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_main"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -5,8 +5,6 @@
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:background="@drawable/round_outline"
android:importantForAccessibility="no"
android:layout_width="match_parent"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"

View File

@@ -2,19 +2,19 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
@@ -62,8 +62,7 @@
android:hint="AB1234"
android:importantForAutofill="no"
android:inputType="text"
android:minHeight="48dp"
tools:ignore="ContentDescription" />
android:minHeight="48dp" />
</LinearLayout>
<Button
android:id="@+id/noBarcode"

View File

@@ -42,9 +42,8 @@
app:spanCount="@integer/main_view_card_columns"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="80dp"
android:clipToPadding="false"
android:scrollbars="vertical"
android:background="@color/mainLoyaltyCardBackground"
android:visibility="gone"/>
</RelativeLayout>

View File

@@ -43,7 +43,8 @@
android:layout_height="@dimen/cardThumbnailSize"
android:layout_weight="1"
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24"
android:contentDescription="@string/moveUp"/>
android:contentDescription="@string/moveUp"
app:tint="@color/iconColor"/>
<ImageButton
android:id="@+id/moveDown"
@@ -51,7 +52,8 @@
android:layout_height="@dimen/cardThumbnailSize"
android:layout_weight="1"
app:srcCompat="@drawable/ic_baseline_arrow_drop_down_24"
android:contentDescription="@string/moveDown"/>
android:contentDescription="@string/moveDown"
app:tint="@color/iconColor"/>
<ImageButton
android:id="@+id/edit"
@@ -59,7 +61,8 @@
android:layout_height="@dimen/cardThumbnailSize"
android:layout_weight="1"
app:srcCompat="@drawable/ic_mode_edit_white_24dp"
android:contentDescription="@string/edit"/>
android:contentDescription="@string/edit"
app:tint="@color/iconColor"/>
<ImageButton
android:id="@+id/delete"
@@ -67,7 +70,8 @@
android:layout_height="@dimen/cardThumbnailSize"
android:layout_weight="1"
app:srcCompat="@drawable/ic_delete_white_24dp"
android:contentDescription="@string/delete"/>
android:contentDescription="@string/delete"
app:tint="@color/iconColor"/>
</LinearLayout>

View File

@@ -21,8 +21,6 @@
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="80dp"
android:clipToPadding="false"
android:scrollbars="vertical"
android:visibility="gone" />
</RelativeLayout>

View File

@@ -7,13 +7,15 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.MaterialToolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>

View File

@@ -4,6 +4,6 @@
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingRight="8dp"
style="@style/Widget.MaterialComponents.Chip.Filter"
style="@style/Widget.MaterialComponents.Chip.Choice"
app:checkedIconVisible="true"
android:textAppearance="?android:attr/textAppearance" />
android:textAppearance="?android:attr/textAppearance" />

View File

@@ -18,13 +18,15 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.MaterialToolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
@@ -37,7 +39,7 @@
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/options"/>
android:text="@string/barcode"/>
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -48,6 +50,7 @@
<ScrollView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@color/inputContrastBackground"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<TableLayout
android:layout_width="match_parent"
@@ -73,7 +76,8 @@
app:cardCornerRadius="4dp"
android:paddingHorizontal="@dimen/inputPadding"
app:cardElevation="0dp"
app:cardBackgroundColor="@android:color/transparent">
app:cardBackgroundColor="@android:color/transparent"
android:outlineProvider="none">
<ImageView
android:id="@+id/thumbnail"
@@ -124,95 +128,6 @@
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<!-- Barcode ID -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/inputPadding"
android:paddingTop="@dimen/inputPadding"
android:orientation="horizontal">
<!-- Barcode ID -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/barcodeIdView"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:hint="@string/barcodeId"
android:labelFor="@+id/barcodeIdView">
<AutoCompleteTextView
android:id="@+id/barcodeIdField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<!-- Barcode type -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/inputPadding"
android:paddingTop="@dimen/inputPadding"
android:orientation="horizontal">
<!-- Barcode type -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/barcodeTypeView"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:hint="@string/barcodeType"
android:labelFor="@+id/barcodeTypeField">
<AutoCompleteTextView
android:id="@+id/barcodeTypeField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<!-- Barcode -->
<LinearLayout android:orientation="horizontal"
android:layout_marginTop="10.0dp"
android:layout_marginStart="10.0dp"
android:layout_marginEnd="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/barcodeLayout">
<ImageView
android:background="@drawable/round_outline"
android:importantForAccessibility="no"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/barcode"
android:layout_weight="1.0"/>
</LinearLayout>
<!-- Buttons -->
<LinearLayout android:orientation="horizontal"
android:padding="10.0dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/barcodeCaptureLayout">
<Button android:id="@+id/enterButton"
android:layout_margin="@dimen/inputMargin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/editBarcode"
android:layout_weight="1.0"/>
</LinearLayout>
</TableLayout>
<TableLayout
android:id="@+id/optionsPart"
android:visibility="gone">
<!-- Note -->
<LinearLayout
android:layout_width="match_parent"
@@ -246,7 +161,6 @@
android:orientation="horizontal">
<com.google.android.material.chip.ChipGroup
android:contentDescription="@string/groups"
android:id="@+id/groupChips"
android:layout_height="match_parent"
android:layout_width="match_parent"
@@ -326,6 +240,99 @@
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</TableLayout>
<TableLayout
android:id="@+id/barcodePart"
android:visibility="gone">
<!-- Barcode ID -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/inputPadding"
android:paddingTop="@dimen/inputPadding"
android:orientation="horizontal">
<!-- Barcode ID -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/barcodeIdView"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:hint="@string/barcodeId"
android:labelFor="@+id/barcodeIdView">
<AutoCompleteTextView
android:id="@+id/barcodeIdField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<!-- Barcode type -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/inputPadding"
android:paddingTop="@dimen/inputPadding"
android:orientation="horizontal">
<!-- Barcode type -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/barcodeTypeView"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:hint="@string/barcodeType"
android:labelFor="@+id/barcodeTypeField">
<AutoCompleteTextView
android:id="@+id/barcodeTypeField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<!-- Barcode -->
<View
android:layout_height="@dimen/inputBorderThickness"
android:layout_width="match_parent" />
<LinearLayout android:orientation="horizontal"
android:padding="10.0dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:id="@+id/barcodeLayout">
<ImageView
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:padding="10.0dp"
android:background="#ffffff"
android:id="@+id/barcode"
android:layout_weight="1.0"/>
</LinearLayout>
<!-- Buttons -->
<LinearLayout android:orientation="horizontal"
android:padding="10.0dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/barcodeCaptureLayout">
<Button android:id="@+id/enterButton"
android:layout_margin="@dimen/inputMargin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/editBarcode"
android:textColor="#FFFFFF"
android:layout_weight="1.0"/>
</LinearLayout>
</TableLayout>
<TableLayout
android:id="@+id/picturesPart"
@@ -362,8 +369,7 @@
android:minHeight="50dp"
android:contentDescription="@string/frontImageDescription"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_camera_white"
android:background="?attr/colorPrimary" />
app:srcCompat="@drawable/ic_camera_white" />
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
@@ -398,8 +404,7 @@
android:minHeight="50dp"
android:contentDescription="@string/backImageDescription"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_camera_white"
android:background="?attr/colorPrimary" />
app:srcCompat="@drawable/ic_camera_white" />
</com.google.android.material.card.MaterialCardView>
</LinearLayout>

View File

@@ -18,13 +18,11 @@
android:layout_height="0dp"
android:outlineProvider="none"
app:cardCornerRadius="8dp"
app:strokeWidth="0dp"
app:layout_constraintBottom_toTopOf="@+id/store"
app:layout_constraintDimensionRatio="85.6f:53.98f"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:importantForAccessibility="no"
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -37,7 +35,6 @@
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:importantForAccessibility="no"
android:id="@+id/selected_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -53,8 +50,7 @@
android:id="@+id/star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
tools:ignore="ExtraText">
android:layout_gravity="end">
<ImageView
android:id="@+id/star_background"
@@ -62,7 +58,7 @@
android:layout_height="@dimen/cardThumbnailSize"
android:layout_gravity="end"
android:alpha="0.5"
android:contentDescription="@string/starred"
android:contentDescription="@string/starImage"
android:elevation="4dp"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
@@ -71,7 +67,6 @@
tools:ignore="ImageContrastCheck" />
<ImageView
android:importantForAccessibility="no"
android:id="@+id/star_border"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
@@ -82,38 +77,11 @@
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_unstarred_black"
app:srcCompat="@drawable/ic_unstarred_white"
tools:ignore="ImageContrastCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/archivedIcon"
android:layout_width="match_parent"
android:layout_height="149dp"
android:layout_gravity="end"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/thumbnail"
tools:layout_editor_absoluteX="355dp">
<ImageView
android:id="@+id/archive_background"
android:layout_width="41dp"
android:layout_height="44dp"
android:layout_gravity="end"
android:alpha="0.5"
android:contentDescription="@string/archived"
android:elevation="4dp"
android:rotationX="2"
android:visibility="visible"
app:srcCompat="@drawable/ic_baseline_archive_24"
tools:ignore="ImageContrastCheck,MissingConstraints"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="-1dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<TextView
@@ -199,6 +167,5 @@
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible"
tools:text="Tomorrow"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</com.google.android.material.card.MaterialCardView>

View File

@@ -25,7 +25,6 @@
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical">
@@ -55,12 +54,11 @@
android:padding="0dp"
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24"
android:contentDescription="@string/moveBarcodeToTopOfScreen"
app:tint="?attr/colorOnPrimary"
app:tint="#ffffff"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/mainImage"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:background="?attr/colorPrimary" />
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/mainImage"
@@ -87,11 +85,10 @@
android:padding="0dp"
app:srcCompat="@drawable/ic_baseline_arrow_drop_down_24"
android:contentDescription="@string/moveBarcodeToCenterOfScreen"
app:tint="?attr/colorOnPrimary"
app:tint="#ffffff"
app:layout_constraintTop_toBottomOf="@+id/mainImage"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:background="?attr/colorPrimary" />
app:layout_constraintStart_toStartOf="parent" />
<LinearLayout
android:id="@+id/dotIndicator"
@@ -110,7 +107,6 @@
app:layout_constraintTop_toBottomOf="@+id/minimizeButton"/>
<SeekBar
android:contentDescription="@string/set_scale"
android:id="@+id/barcodeScaler"
android:visibility="gone"
android:max="100"
@@ -158,7 +154,7 @@
android:id="@+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:colorBackground"
android:background="@color/inputBackground"
android:orientation="vertical"
android:paddingTop="0px"
android:visibility="gone"
@@ -172,11 +168,10 @@
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_gravity="top|start"
android:contentDescription="@string/showMoreInfo"
android:contentDescription="@string/toggleMoreInfo"
android:scaleType="fitCenter"
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24"
app:tint="?attr/colorOnPrimary"
android:background="?attr/colorPrimary" />
app:tint="#ffffff" />
<androidx.core.widget.NestedScrollView
android:id="@+id/bottomSheetContentWrapper"
@@ -252,13 +247,14 @@
android:weightSum="1.0"
>
<com.google.android.material.appbar.MaterialToolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar_landscape"
android:layout_width="fill_parent"
android:layout_height="?actionBarSize"
android:background="@android:color/transparent"
android:fitsSystemWindows="false"
android:paddingTop="0dp"
android:theme="@style/CardView.ActionBarTheme"
android:visibility="gone"
app:contentInsetStart="72.0dip"
app:layout_collapseMode="pin" />
@@ -294,6 +290,7 @@
android:layout_width="fill_parent"
android:layout_height="?actionBarSize"
android:background="@android:color/transparent"
android:theme="@style/CardView.ActionBarTheme"
app:contentInsetStart="72.0dip"
app:layout_collapseMode="pin" />

View File

@@ -19,13 +19,15 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.MaterialToolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/groups"

View File

@@ -19,13 +19,15 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.MaterialToolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</com.google.android.material.appbar.AppBarLayout>

View File

@@ -9,13 +9,15 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.MaterialToolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
@@ -23,7 +25,6 @@
android:id="@+id/zxing_barcode_scanner"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
app:zxing_scanner_layout="@layout/custom_barcode_scanner">
</com.journeyapps.barcodescanner.DecoratedBarcodeView>
</RelativeLayout>
</RelativeLayout>

View File

@@ -1,28 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="protect.card_locker.preferences.SettingsActivity">
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.MaterialToolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
style="?attr/toolbarStyle"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/settings_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize" />
android:layout_height="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>

View File

@@ -3,18 +3,19 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.MaterialToolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</com.google.android.material.appbar.AppBarLayout>

View File

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

View File

@@ -1,9 +0,0 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_unfold"
android:title="@string/action_hide_details"
android:icon="@drawable/ic_baseline_unfold_less_24"
app:showAsAction="always"
android:visible="true"/>
</menu>

View File

@@ -2,6 +2,20 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_copy_to_clipboard"
android:title="@string/copy_to_clipboard"
android:icon="@drawable/ic_copy"
android:titleCondensed="@string/copy_to_clipboard"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_share"
android:title="@string/share"
android:icon="@drawable/ic_share"
android:titleCondensed="@string/share"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_edit"
android:icon="@drawable/ic_edit"
@@ -9,48 +23,11 @@
android:titleCondensed="@string/editCardTitle"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_copy_to_clipboard"
android:icon="@drawable/ic_copy"
android:title="@string/copy_to_clipboard"
android:titleCondensed="@string/copy_to_clipboard"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_share"
android:icon="@drawable/ic_share"
android:title="@string/share"
android:titleCondensed="@string/share"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_star"
android:title="@string/star"
android:titleCondensed="@string/star"
app:showAsAction="never"/>
<item
android:id="@+id/action_unstar"
android:title="@string/unstar"
android:titleCondensed="@string/unstar"
app:showAsAction="never"/>
<item
android:id="@+id/action_archive"
android:title="@string/archive"
android:titleCondensed="@string/archive"
app:showAsAction="never"/>
<item
android:id="@+id/action_unarchive"
android:title="@string/unarchive"
android:titleCondensed="@string/unarchive"
app:showAsAction="never"/>
<item
android:id="@+id/action_delete"
android:icon="@drawable/ic_delete_white_24dp"
android:title="@string/delete"
android:titleCondensed="@string/delete"
app:showAsAction="never"/>
app:showAsAction="ifRoom"/>
</menu>

View File

@@ -2,46 +2,19 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_lock_unlock"
android:icon="@drawable/ic_lock_open_white_24dp"
android:title="@string/lockScreen"
app:showAsAction="always"/>
<item
android:id="@+id/action_share"
android:icon="@drawable/ic_share_white"
android:title="@string/share"
app:showAsAction="always"/>
<item
android:id="@+id/action_star_unstar"
android:icon="@drawable/ic_unstarred_white"
android:title="@string/star"
app:showAsAction="always" />
<item
android:id="@+id/action_overflow"
android:title="@string/overflowMenu"
android:icon="@drawable/ic_overflow_menu"
app:showAsAction="always">
<menu>
<item
android:id="@+id/action_duplicate"
android:title="@string/duplicateCard"
app:showAsAction="never" />
<item
android:id="@+id/action_archive"
android:title="@string/archive"
app:showAsAction="never"/>
<item
android:id="@+id/action_unarchive"
android:title="@string/unarchive"
app:showAsAction="never"/>
<item
android:id="@+id/action_delete"
android:title="@string/delete"
app:showAsAction="never"/>
</menu>
</item>
</menu>
</menu>

View File

@@ -7,29 +7,22 @@
android:title="@string/action_search"
android:icon="@drawable/ic_search_white"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="always|collapseActionView"
android:visible="false"/>
app:showAsAction="always|collapseActionView"/>
<item
android:id="@+id/action_unfold"
android:title="@string/action_hide_details"
android:icon="@drawable/ic_baseline_unfold_less_24"
app:showAsAction="always"
android:visible="false"/>
app:showAsAction="always"/>
<item
android:id="@+id/action_sort"
android:title="@string/sort"
android:icon="@drawable/ic_baseline_sort_24"
app:showAsAction="always"
android:visible="false"/>
app:showAsAction="always"/>
<item
android:id="@+id/action_manage_groups"
android:icon="@drawable/ic_folder_white"
android:title="@string/groups"
app:showAsAction="never"/>
<item
android:id="@+id/action_archived"
android:title="@string/archiveList"
app:showAsAction="never"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_import_export"
android:icon="@drawable/ic_import_export_white_24dp"

View File

@@ -4,41 +4,34 @@ J. Lavoie
Allan Nordhøy
Heimen Stoffels
solokot
mondstern
Katharine Chui
Oğuz Ersen
mondstern
IllusiveMan196
Altonss
StoyanDimitrov
Petr Novák
Joel A
Taco
Gediminas Murauskas
Joel A
StoyanDimitrov
Nyatsuki
Michael Moroni
Altonss
Samantaz Fox
arno-github
Ankit Tiwari
Sergio Paredes
huuhaa
laralem
arshbeerSingh
Quentin PAGÈS
huuhaa
Miha Frangež
sr093906
mdvhimself
Maciej Błędkowski
Michael Moroni
Olivia (Zoe)
betsythefc
Silvério Santos
waffshappen
ati3
Jane Kong
sr093906
K. Herbert
Still Hsu
Quentin PAGÈS
String E. Fighter
Yurical
rr-vesp
/usr/local/ΕΨΗΕΛΩΝ
Adolfo Jayme-Barrientos
Alessandro Mandelli
@@ -46,54 +39,46 @@ KovalevArtem
Clonewayx
D. Domig
Diego
Jane Kong
Lukas Grassauer
Marnick L'Eau
Michalis
Rosdyana Kusuma
umoenks
schirinowski
Thomas Bertels
inesre
lgasp
phlostically
Aditya Das
Asier
Kevin Sicong Jiang
Airat
sNiXx
Andreas Blaser
BMN
Biren
Mylou53
Kasina Dheeraj
Eric
Flav
Franciszek Stefan
Giovanni
Grzegorz
Izzy
Karol Kosek
bittin
Maciej Błędkowski
Marco
Mattia
Michael Gangolf
Moi Toi
pbeckmann
Peer Beckmann
Quang Nguyen
Ratnesh
Reza
Rohan Babbar
Ronak Upadhyay
Rose Liverman
Simone Dotto
SlavekB
Still Hsu
Subhashish Anand
darkodo
Tymofii Lytvynenko
Tjipke van der Heide
Yevgeny M
Avik Kundu
avikkundu
opsik
pooyanazari
psa-jforestier
Robin
sergio

View File

@@ -440,7 +440,7 @@ _id,name,barcodeFormat
450,CAD,EAN_13
451,Camomilla,EAN_13
452,"Carpisa Yamamay",EAN_13
453,Carrefour,CODE_128
453,Carrefour,EAN_13
454,"Cisalfa Sport",EAN_13
455,Coin,ITF
456,Comet,EAN_13
1 _id name barcodeFormat
440 450 CAD EAN_13
441 451 Camomilla EAN_13
442 452 Carpisa Yamamay EAN_13
443 453 Carrefour CODE_128 EAN_13
444 454 Cisalfa Sport EAN_13
445 455 Coin ITF
446 456 Comet EAN_13

View File

@@ -11,7 +11,7 @@
<string name="unstar">Премахва от любими</string>
<string name="star">Добавя към любими</string>
<string name="noBarcode">Без щрихкод</string>
<string name="barcodeNoBarcode">Липсва щрихкод</string>
<string name="barcodeNoBarcode">Картата няма щрихкод</string>
<string name="barcodeType">Вид на щрихкод</string>
<string name="cardId">Идентификатор на карта</string>
<string name="note">Бележка</string>
@@ -25,18 +25,18 @@
</plurals>
<string name="failedOpeningFileManager">Инсталирайте приложение за управление на файлове.</string>
<string name="app_license">Свободен софтуер с авторски права, лицензиран под GPLv3+</string>
<string name="frontImageDescription">Снимка на предната страна</string>
<string name="backImageDescription">Снимка на задната страна</string>
<string name="frontImageDescription">Снимка на предната страна на карта</string>
<string name="backImageDescription">Снимка на задната страна на карта</string>
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> не изглежда истинска наличност.</string>
<string name="no">Не</string>
<string name="yes">Да</string>
<string name="setBackImage">Снимка на задната страна</string>
<string name="setFrontImage">Снимка на предната страна</string>
<string name="photos">Снимки</string>
<string name="importOptionApplicationExplanation">Изберете файл на друго приложение.</string>
<string name="noExternalStoragePermissionError">Разрешете достъп до хранилището, за да работи внасянето и изнасянето</string>
<string name="importOptionApplicationExplanation">Изберете файл чрез друго приложение.</string>
<string name="noExternalStoragePermissionError">Дайте разрешение за достъп до хранилището, за да работи внасянето и изнасянето</string>
<string name="noCardExistsError">Картата не е намерена</string>
<string name="updateBarcodeQuestionText">Идентификаторът е променен. Желаете ли с неговата стойност да бъде променен и щрихкодът\?</string>
<string name="updateBarcodeQuestionText">Идентификаторът е променен. Желаете ли с неговата стойност да бъде променен и щрихкода\?</string>
<string name="updateBarcodeQuestionTitle">Обновяване на щрихкода\?</string>
<string name="noCardIdError">Не е въведен идентификатор</string>
<string name="noCardsMessage">Добавете карта</string>
@@ -80,6 +80,7 @@
<string name="groupsList">Списъци: <xliff:g>%s</xliff:g></string>
<string name="expiryStateSentence">Валидност: <xliff:g>%s</xliff:g></string>
<string name="expiryStateSentenceExpired">Изтекла: <xliff:g>%s</xliff:g></string>
<string name="balancePoints"><xliff:g>%s</xliff:g> точки</string>
<string name="balanceSentence">Наличност: <xliff:g>%s</xliff:g></string>
<string name="noGroups">Докоснете бутона +, за да добавите списък.</string>
<string name="noStoreError">Не е въведено наименование</string>
@@ -87,6 +88,7 @@
<string name="enter_group_name">Въведете име на списъка</string>
<string name="intent_import_card_from_url_share_text">Искам да споделя тази карта с вас</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="settings_max_font_size_scale">Максимален размер на шрифта</string>
@@ -97,33 +99,33 @@
<string name="settings_category_title_ui">Потребителски интерфейс</string>
<string name="settings">Настройки</string>
<string name="starImage">Звезда за любимо</string>
<string name="thumbnailDescription">Миниатюра</string>
<string name="copy_to_clipboard_toast">Идентификаторът е копиран в междинната памет</string>
<string name="enterBarcodeInstructions">Въведете идентификатор и или изберете вида на щрихкода, или докоснете бутона „Липсва щрихкод“.</string>
<string name="thumbnailDescription">Миниатюра на картата</string>
<string name="copy_to_clipboard_toast">Идентификаторът на картата е копиран в междинната памет</string>
<string name="enterBarcodeInstructions">Въведете идентификатор на картата или като изберете вида на щрихкода или докоснете бутона „Картата няма щрихкод“.</string>
<string name="selectBarcodeTitle">Избиране на щрихкод</string>
<string name="importOptionApplicationButton">Избиране чрез приложение</string>
<string name="importing">Внасяне…</string>
<string name="exporting">Изнасяне…</string>
<string name="exportFailed">Данните не могат да бъдат изнесени</string>
<string name="exportFailed">Картите не могат да бъдат изнесени: <xliff:g>%s</xliff:g></string>
<string name="exportFailedTitle">Грешка при изнасяне</string>
<string name="importFailed">Данните не могат да бъдат внесени</string>
<string name="importFailed">Картите не могат да бъдат внесени: <xliff:g>%s</xliff:g></string>
<string name="importFailedTitle">Грешка при внасяне</string>
<string name="exportSuccessfulTitle">Резултат от изнасяне</string>
<string name="importSuccessfulTitle">Резултат от внасяне</string>
<string name="importExportHelp">Резервните копия на данните ви дават възможност да ги премествате на друго устройство.</string>
<string name="importExportHelp">Резервните копия на картите ви дават възможност да ги преместите на друго устройство.</string>
<string name="exportName">Изнасяне</string>
<string name="importExport">Внасяне/изнасяне</string>
<string name="sendLabel">Изпращане…</string>
<string name="scanCardBarcode">Снемане на щрихкод</string>
<string name="scanCardBarcode">Снемане на щрихкод от карта</string>
<string name="editCardTitle">Редактиране на карта</string>
<string name="share">Споделя</string>
<string name="copy_to_clipboard">Копира идентификатора в междинната памет</string>
<string name="ok">Добре</string>
<string name="importSuccessful">Данните са внесени</string>
<string name="chooseImportType">Внасяне на данни на</string>
<string name="importSuccessful">Картите са внесени успешно</string>
<string name="chooseImportType">От къде ще внесете\?</string>
<string name="importCatimaMessage">Изберете файла <i>catima.zip</i>, предварително изнесен от Catima.
\nСъздайте такъв файл от меню Внасяне/изнасяне от друго устройство с Catima като изберете Изнасяне.</string>
<string name="importOptionApplicationTitle">Чрез друго приложение</string>
<string name="importOptionApplicationTitle">От друго приложение</string>
<string name="importOptionFilesystemButton">Избиране от файлова система</string>
<string name="importOptionFilesystemExplanation">Изберете определен файл от файловата система.</string>
<string name="app_resources">Свободни ресурси: <xliff:g id="app_resources_list">%s</xliff:g></string>
@@ -137,10 +139,12 @@
<string name="about">Относно</string>
<string name="importOptionFilesystemTitle">Внасяне от файловата система</string>
<string name="importCatima">Внасяне от Catima</string>
<string name="exportSuccessful">Данните са изнесени</string>
<string name="exportSuccessful">Картите са изнесени успешно</string>
<string name="unlockScreen">Разрешава автоматичното завъртане</string>
<string name="lockScreen">Спира автоматичното завъртане</string>
<plurals name="selectedCardCount">
<item quantity="one"><xliff:g>%d</xliff:g> избрана</item>
<item quantity="other"><xliff:g>%d</xliff:g> избрани</item>
<item quantity="one"><xliff:g>%d</xliff:g> избрана карта</item>
<item quantity="other"><xliff:g>%d</xliff:g> избрани карти</item>
</plurals>
<string name="deleteConfirmationGroup">Изтриване на група\?</string>
<string name="moveDown">Преместване надолу</string>
@@ -158,13 +162,14 @@
<string name="importLoyaltyCardKeychainMessage">Изберете файла <i>LoyaltyCardKeychain.csv</i>, предварително изнесен от Loyalty Card Keychain.
\nСъздайте такъв файл от меню Внасяне/изнасяне от друго устройство с Loyalty Card Keychain като изберете Изнасяне.</string>
<string name="failedParsingImportUriError">Препратката не може да бъде анализирана за внасяне</string>
<string name="card_ids_copied">[не превеждай този низ, https://github.com/TheLastProject/Catima/issues/278]</string>
<string name="failedGeneratingShareURL">Грешка при създаване на адрес за споделяне. Изпратете доклад за дефект.</string>
<string name="deleteTitle">Премахване на карта</string>
<plurals name="deleteCardsTitle">
<item quantity="one">Изтриване на <xliff:g>%d</xliff:g> карта</item>
<item quantity="other">Изтриване на <xliff:g>%d</xliff:g> карти</item>
</plurals>
<string name="deleteConfirmation">Потвърждавате ли премахване на картата\?</string>
<string name="deleteConfirmation">Потвърдете премахване на картата.</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">Желаете ли <xliff:g>%d</xliff:g> карта да бъде премахната\?</item>
<item quantity="other">Желаете ли тези <xliff:g>%d</xliff:g> карти да бъдат премахнати\?</item>
@@ -182,11 +187,12 @@
<string name="settings_theme_color">Цвят на темата</string>
<string name="settings_system_locale">Система</string>
<string name="settings_locale">Език</string>
<string name="noGroupCards">Групата е празна</string>
<string name="barcodeImageDescriptionWithType">Изображение на щрихкод от вид <xliff:g>%s</xliff:g></string>
<string name="noGroupCards">Групата не съдържа карти</string>
<string name="toggleMoreInfo">Превключване на повече информация</string>
<string name="barcodeImageDescriptionWithType">Изображение на щрихкод на карта от вида <xliff:g>%s</xliff:g></string>
<string name="swipeToSwitchImages">Плъзване или задържане за смяна на изображения</string>
<string name="sort_by">Сортиране по</string>
<string name="reverse">…в обратен ред</string>
<string name="reverse">Наобратно</string>
<string name="sort_by_balance">Наличност</string>
<string name="sort_by_expiry">Валидност</string>
<string name="sort_by_most_recently_used">Последно използване</string>
@@ -213,31 +219,5 @@
<string name="group_edit">Редактиране на списък</string>
<string name="action_show_details">Повече детайли</string>
<string name="action_hide_details">По-малко детайли</string>
<string name="noGiftCardsGroup">Създайте карти и ги зачислите към списък от тук.</string>
<string name="translate_platform">в Weblate</string>
<string name="shortcutSelectCard">Избор на карта</string>
<string name="starred">Със звезда</string>
<string name="set_scale">Мащаб</string>
<string name="showMoreInfo">Показване на информация</string>
<string name="hideMoreInfo">Скриване на информация</string>
<string name="options">Настройки</string>
<string name="card_ids_copied">Идентификаторите са копирани</string>
<plurals name="balancePoints">
<item quantity="one"><xliff:g>%s</xliff:g> точка</item>
<item quantity="other"><xliff:g>%s</xliff:g> точки</item>
</plurals>
<string name="settings_oled_dark">Чисто черен фон за тъмната тема</string>
<string name="include_if_asking_support">Ако искате да потърсите поддръжка, включете следната информация:</string>
<string name="settings_card_orientation">Положение на щрихкода</string>
<string name="settings_follow_system_orientation">Според системата</string>
<string name="settings_portrait_orientation">Портретно</string>
<string name="settings_landscape_orientation">Пейзажно</string>
<string name="settings_lock_on_opening_orientation">Използване на положението, използвано при отваряне на картата</string>
<string name="duplicateCard">Дублиране</string>
<string name="archive">Архивиране</string>
<string name="unarchive">Изваждане от архива</string>
<string name="archived">Картата е архивирана</string>
<string name="unarchived">Карта е извадена от архива</string>
<string name="archiveList">Архив</string>
<string name="noUnarchivedCardsMessage">Няма карти извън архива</string>
<string name="noGiftCardsGroup">Няма карти. След като добавите ще можете да ги зачислите към списък от тук.</string>
</resources>

View File

@@ -21,6 +21,7 @@
<string name="intent_import_card_from_url_share_text">url শেয়ার টেক্সট থেকে ইন্টেন্ট ইম্পোর্ট কার্ড</string>
<string name="settings_disable_lockscreen_while_viewing_card"> কার্ড দেখা কালিন লকস্ক্রিন নিষ্ক্রিয়</string>
<string name="settings_keep_screen_on">সেটিংস পর্দা খোলা রাখুন</string>
<string name="settings_lock_barcode_orientation"> তালাবদ্ধ বার কোড অভিযোজন</string>
<string name="settings_max_font_size_scale">সর্বোচ্চ হরফ আকার</string>
<string name="settings_light_theme">সাদাটে থিম</string>
<string name="settings_system_theme">যন্ত্রর থিম</string>
@@ -65,6 +66,7 @@
<string name="settings_green_theme">সবুজ থিম</string>
<string name="settings_brown_theme">বাদামী থিম</string>
<string name="sort">সাজান</string>
<string name="toggleMoreInfo">আরও তথ্য টগল করুন</string>
<string name="swipeToSwitchImages">ছবি পরিবর্তন করতে সোয়াইপ করুন</string>
<string name="sort_by_name">নামের দ্বারা সাজান</string>
<string name="sort_by_most_recently_used">সর্বাধিক সম্প্রতি ব্যবহৃত দ্বারা সাজান</string>
@@ -81,6 +83,7 @@
<string name="share">ভাগ</string>
<string name="copy_to_clipboard">নকল করুন ক্লিপবোর্ড এ</string>
<string name="deleteConfirmation">নিশ্চিতকরণ মুছে দিন</string>
<string name="unlockScreen">পর্দা আনলক করুন</string>
<string name="confirm">নিশ্চিত করুন</string>
<string name="delete">মুছে ফেলুন</string>
<string name="edit">সম্পাদনা</string>

View File

@@ -21,6 +21,7 @@
<string name="intent_import_card_from_url_share_text">Želim podijeliti čestitku s tobom</string>
<string name="settings_disable_lockscreen_while_viewing_card">Spriječi zaključavanje ekrana</string>
<string name="settings_keep_screen_on">Zadrži ekran</string>
<string name="settings_lock_barcode_orientation">Zaključaj barcode orjentacija</string>
<string name="settings_max_font_size_scale">Max. veliäťina fonta</string>
<string name="settings_light_theme">Svjetlo</string>
<string name="settings_system_theme">Sistem</string>
@@ -65,6 +66,7 @@
<string name="settings_green_theme">Zeleno</string>
<string name="settings_brown_theme">Braun</string>
<string name="sort">Poništi sortiranje</string>
<string name="toggleMoreInfo">Uključi savjete</string>
<string name="swipeToSwitchImages">Swipe ili long press za prebacivanje slika</string>
<string name="sort_by_name">Ime</string>
<string name="sort_by_most_recently_used">Nedavno Korišten</string>
@@ -81,6 +83,7 @@
<string name="share">Podijeli</string>
<string name="copy_to_clipboard">Kopiraj ID u clipboard</string>
<string name="deleteConfirmation">Izbriši trajno ovu karticu\?</string>
<string name="unlockScreen">Odblokalna Rotacija</string>
<string name="confirm">Potvrdi</string>
<string name="delete">Obriši</string>
<string name="edit">Izmijeni</string>

View File

@@ -1,7 +1,7 @@
<?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="action_add">Přidat</string>
<string name="noGiftCards">Klepnutím na tlačítko + plus přidáte kartu nebo ji nejprve importujete z nabídky ⋮.</string>
<string name="noGiftCards">Klepnutím na tlačítko + plus přidáte kartu nebo ji nejprve importujete z nabídky⋮.</string>
<string name="storeName">Název</string>
<string name="note">Poznámka</string>
<string name="cardId">ID karty</string>
@@ -15,21 +15,21 @@
<string name="sendLabel">Odeslat…</string>
<string name="editCardTitle">Editovat věrnostní kartu</string>
<string name="addCardTitle">Přidat věrnostní kartu</string>
<string name="scanCardBarcode">Skenování čárového kódu</string>
<string name="scanCardBarcode">Skenování Čárový Kód Karty</string>
<string name="noStoreError">Zadáno žádné jméno</string>
<string name="noCardIdError">ID nezadáno</string>
<string name="noCardIdError">Žádné ID karty zadáno</string>
<string name="importExport">Import/Export</string>
<string name="exportName">Export</string>
<string name="importExportHelp">Zálohování dat vám umožní přesunout je do jiného zařízení.</string>
<string name="importExportHelp">Zálohování karet vám umožní přesunout je do jiného zařízení.</string>
<string name="importSuccessfulTitle">Importováno</string>
<string name="importFailedTitle">Import selhal</string>
<string name="importFailed">Nelze provést import</string>
<string name="exportSuccessfulTitle">Exportováno</string>
<string name="importFailed">Nelze importovat karty: <xliff:g>%s</xliff:g></string>
<string name="exportSuccessfulTitle">Exportovat</string>
<string name="exportFailedTitle">Export selhal</string>
<string name="exportFailed">Nelze provést export</string>
<string name="exportFailed">Nelze exportovat karty: <xliff:g>%s</xliff:g></string>
<string name="importing">Importuji…</string>
<string name="exporting">Exportuji…</string>
<string name="noExternalStoragePermissionError">Udělit oprávnění přístupu k externímu úložišti pro import nebo export dat</string>
<string name="noExternalStoragePermissionError">Udělit povolení externího úložiště pro import nebo export karet jako první</string>
<string name="importOptionFilesystemTitle">Import ze souborového systému</string>
<string name="importOptionFilesystemExplanation">Vyberte konkrétní soubor v uložišti.</string>
<string name="importOptionFilesystemButton">Ze souborového systému</string>
@@ -42,7 +42,7 @@
<string name="debug_version_fmt">Verze: <xliff:g id="version">%s</xliff:g></string>
<string name="app_revision_fmt">Informace o revizi: <xliff:g id="app_revision_url">%s</xliff:g></string>
<string name="selectBarcodeTitle">Vyberte čárový kód</string>
<string name="copy_to_clipboard_toast">ID zkopírované do schránky</string>
<string name="copy_to_clipboard_toast">ID karty zkopírované do schránky</string>
<string name="deleteTitle">Smazat kartu</string>
<string name="deleteConfirmation">Opravdu chcete smazat tuto věrnostní kartu?</string>
<string name="moveBarcodeToCenterOfScreen">Střed čárového kódu na obrazovce</string>
@@ -58,19 +58,21 @@
\ncopyright © 20162020 Branden Archer</string>
<string name="exportOptionExplanation">Data budou zapsána na místo podle vašeho výběru.</string>
<string name="failedParsingImportUriError">Nelze analyzovat import URI</string>
<string name="noCardExistsError">Kartu nelze najít</string>
<string name="noCardExistsError">Nelze najít kartu</string>
<string name="noCardsMessage">Nejprve přidejte kartu</string>
<string name="cardShortcut">Zástupce Karty</string>
<string name="share">Podíl</string>
<string name="unlockScreen">Odblokovat Rotaci</string>
<string name="lockScreen">Otáčení Bloku</string>
<string name="unstar">Odebrat z oblíbených</string>
<string name="star">Přidat do oblíbených</string>
<string name="noBarcode">Žádný čárový kód</string>
<string name="barcodeNoBarcode">Tato karta nemá čárový kód</string>
<string name="barcodeType">Typ čárového kódu</string>
<string name="noMatchingGiftCards">Nic nenalezeno. Zkuste změnit vyhledávání.</string>
<string name="noMatchingGiftCards">Nic jsem nenašel. Zkuste změnit vyhledávání.</string>
<string name="action_search">Vyhledávání</string>
<string name="thumbnailDescription">Miniatura</string>
<string name="card_ids_copied">Zkopírované ID</string>
<string name="thumbnailDescription">Miniatura karty</string>
<string name="card_ids_copied">Zkopírované ID karty(karet)</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">Opravdu chcete kartu <xliff:g>%d</xliff:g> trvale odstranit\?</item>
<item quantity="few">Opravdu chcete karty <xliff:g>%d</xliff:g> trvale odstranit\?</item>
@@ -81,10 +83,11 @@
<item quantity="few">Odstranit karty <xliff:g>%d</xliff:g></item>
<item quantity="other">Odstranit karty <xliff:g>%d</xliff:g></item>
</plurals>
<string name="importSuccessful">Data importována</string>
<string name="importSuccessful">Data karty importována</string>
<string name="intent_import_card_from_url_share_text">Chci s Vámi sdílet kartu</string>
<string name="settings_disable_lockscreen_while_viewing_card">Bránit uzamykání obrazovky</string>
<string name="settings_keep_screen_on">Udržovat obrazovku zapnutou</string>
<string name="settings_lock_barcode_orientation">Zamknout orientaci čárového kódu</string>
<string name="settings_max_font_size_scale">Maximální velikost písma</string>
<string name="settings_dark_theme">Tmavý</string>
<string name="settings_light_theme">Světlý</string>
@@ -93,12 +96,13 @@
<string name="settings_category_title_ui">Uživatelské rozhraní</string>
<string name="settings">Nastavení</string>
<string name="card">Karta</string>
<string name="balancePoints"><xliff:g>%s</xliff:g> bodů</string>
<string name="balanceSentence">Zůstatek: <xliff:g>%s</xliff:g></string>
<string name="expiryStateSentenceExpired">Platnost vypršela: <xliff:g>%s</xliff:g></string>
<string name="expiryStateSentence">Platí do: <xliff:g>%s</xliff:g></string>
<string name="moveDown">Přesunout dolů</string>
<string name="moveUp">Přesunout nahoru</string>
<string name="enterBarcodeInstructions">Zadejte ID a níže vyberte typ čárového kódu nebo \"Tato karta nemá čárový kód\".</string>
<string name="enterBarcodeInstructions">Zadejte ID karty a níže vyberte typ čárového kódu nebo \"Tato karta nemá čárový kód\".</string>
<string name="settings_brown_theme">Hnědá</string>
<string name="settings_grey_theme">Šedá</string>
<string name="settings_green_theme">Zelená</string>
@@ -117,22 +121,22 @@
<string name="passwordRequired">Zadejte prosím heslo</string>
<string name="no">Ne</string>
<string name="yes">Ano</string>
<string name="updateBarcodeQuestionText">Změnili jste ID. Chcete také aktualizovat čárový kód, aby používal stejnou hodnotu\?</string>
<string name="updateBarcodeQuestionText">Změnili jste ID karty. Chcete také aktualizovat čárový kód, aby používal stejnou hodnotu\?</string>
<string name="updateBarcodeQuestionTitle">Aktualizovat hodnotu čárového kódu\?</string>
<string name="takePhoto">Pořídit fotku</string>
<string name="removeImage">Odstranit obrázek</string>
<string name="setBackImage">Nastavit obrázek zadní strany</string>
<string name="setFrontImage">Nastavit obrázek přední strany</string>
<string name="photos">Fotky</string>
<string name="backImageDescription">Obrázek zadní strany</string>
<string name="frontImageDescription">Obrázek přední strany</string>
<string name="backImageDescription">Obrázek zadní strany karty</string>
<string name="frontImageDescription">Obrázek přední strany karty</string>
<string name="intent_import_card_from_url_share_multiple_text">Chci s Vámi sdílet kartu</string>
<string name="copy_to_clipboard_multiple_toast">ID zkopírováno do schránky</string>
<string name="copy_to_clipboard_multiple_toast">ID karty zkopírováno do schránky</string>
<string name="wrongValueForBarcodeType">Hodnota není platná pro vybraný typ čárového kódu</string>
<string name="unsupportedBarcodeType">Tento typ čárového kódu zatím nelze zobrazit. Možná bude podporován v pozdější verzi aplikace.</string>
<string name="barcodeId">Hodnota čárového kódu</string>
<string name="setBarcodeId">Nastavení hodnoty čárového kódu</string>
<string name="sameAsCardId">Stejné jako ID</string>
<string name="sameAsCardId">Stejné jako ID karty</string>
<string name="importVoucherVaultMessage">Vyberte svůj <i>vouchervault.json</i> export z Voucher Vault, který chcete importovat.
\nVytvořte jej tak, že nejprve stisknete tlačítko Exportovat v aplikaci Voucher Vault.</string>
<string name="importVoucherVault">Import z Voucher Vault</string>
@@ -154,7 +158,7 @@
\nNejsou shromažďovány žádné údaje, což může potvrdit každý, protože naše aplikace je svobodný software.</string>
<string name="privacy_policy">Zásady soukromí</string>
<string name="app_loyalty_card_keychain">Loyalty Card Keychain</string>
<string name="chooseImportType">Importovat data z</string>
<string name="chooseImportType">Importovat data z\?</string>
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> se nezdá být platným zůstatkem.</string>
<string name="points">Body</string>
<string name="currency">Měna</string>
@@ -163,7 +167,7 @@
<string name="noBarcodeFound">Čarový kód nenalezen</string>
<string name="groupsList">Skupiny: <xliff:g>%s</xliff:g></string>
<string name="addFromImage">Výběr obrázku z galerie</string>
<string name="addManually">Ruční zadání ID</string>
<string name="addManually">Ruční zadání ID karty</string>
<string name="leaveWithoutSaveConfirmation">Ukončit bez uložení\?</string>
<string name="leaveWithoutSaveTitle">Ukončit</string>
<string name="failedOpeningFileManager">Nejprve si nainstalujte správce souborů.</string>
@@ -174,10 +178,10 @@
<item quantity="few"><xliff:g>%d</xliff:g> karty</item>
<item quantity="other"><xliff:g>%d</xliff:g> karet</item>
</plurals>
<string name="noGroups">Kliknutím na tlačítko + plus přidejte skupiny pro kategorizaci.</string>
<string name="noGroups">Kliknutím na tlačítko + plus nejprve přidejte skupiny pro kategorizaci.</string>
<string name="groups">Skupiny</string>
<string name="enter_group_name">Zadejte název skupiny</string>
<string name="exportSuccessful">Data exportována</string>
<string name="exportSuccessful">Data karty exportována</string>
<string name="settings_display_barcode_max_brightness">Rozjasněné zobrazení čárového kódu</string>
<string name="starImage">Oblíbená hvězda</string>
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Copyright © 2019<xliff:g>%d</xliff:g> Sylvia van Os</string>
@@ -187,16 +191,17 @@
<item quantity="other">Vybráno <xliff:g>%d</xliff:g> karet</item>
</plurals>
<string name="app_contributors">Přispěli: <xliff:g id="app_contributors">%s</xliff:g></string>
<string name="noGroupCards">Tato skupina je prázdná</string>
<string name="noGroupCards">Tato skupina neobsahuje žádné karty</string>
<string name="sort_by">Seřadit podle</string>
<string name="reverse">…v obráceném pořadí</string>
<string name="reverse">Obrátit</string>
<string name="sort_by_balance">Zůstatek</string>
<string name="sort_by_expiry">Vypršení</string>
<string name="sort_by_most_recently_used">Naposledy použité</string>
<string name="sort_by_name">Název</string>
<string name="swipeToSwitchImages">Přejetím nebo dlouhým stisknutím přepínáte obrázky</string>
<string name="toggleMoreInfo">Přepnout zobrazení dalších informací</string>
<string name="sort">Seřadit</string>
<string name="barcodeImageDescriptionWithType">Obrázek čárového kódu <xliff:g>%s</xliff:g></string>
<string name="barcodeImageDescriptionWithType">Obrázek čárového kódu karty typu <xliff:g>%s</xliff:g></string>
<string name="version_history">Historie verzí</string>
<string name="rate_this_app">Ohodnoťte tuto aplikaci</string>
<string name="and_data_usage">a využití dat</string>
@@ -217,32 +222,4 @@
<string name="group_updated">Skupina aktualizována</string>
<string name="editGroup">Úprava skupiny: <xliff:g>%s</xliff:g></string>
<string name="noGiftCardsGroup">Zatím nemáte žádné věrnostní karty. Jakmile nějaké přidáte, můžete je přiřadit do skupiny zde.</string>
<string name="shortcutSelectCard">Vybrat kartu</string>
<string name="action_show_details">Zobrazit detaily</string>
<string name="action_hide_details">Skrýt detaily</string>
<string name="translate_platform">na Weblate</string>
<string name="showMoreInfo">Zobrazit podrobnosti</string>
<string name="hideMoreInfo">Skrýt podrobnosti</string>
<string name="starred">S hvězdičkou</string>
<string name="set_scale">Nastavení měřítka</string>
<string name="options">Volby</string>
<plurals name="balancePoints">
<item quantity="one"><xliff:g>%s</xliff:g> bod</item>
<item quantity="few"><xliff:g>%s</xliff:g> body</item>
<item quantity="other"><xliff:g>%s</xliff:g> bodů</item>
</plurals>
<string name="settings_oled_dark">Čistě černé pozadí pro tmavý motiv</string>
<string name="include_if_asking_support">Pokud chcete požádat o podporu, uveďte následující informace:</string>
<string name="settings_follow_system_orientation">Následovat systém</string>
<string name="settings_portrait_orientation">Na výšku</string>
<string name="settings_lock_on_opening_orientation">Zamknout podle orientace použité při otevření karty</string>
<string name="archive">Archivovat</string>
<string name="unarchive">Vrátit z archivu</string>
<string name="archiveList">Archivovat</string>
<string name="noUnarchivedCardsMessage">Nejsou žádné karty vrácené z archivu</string>
<string name="unarchived">Karta vrácena z archivu</string>
<string name="settings_card_orientation">Orientace čárového kódu</string>
<string name="settings_landscape_orientation">Na šířku</string>
<string name="duplicateCard">Duplikovat</string>
<string name="archived">Karta archivována</string>
</resources>

View File

@@ -13,6 +13,8 @@
<item quantity="other">Streichen <xliff:g>%d</xliff:g> korts</item>
</plurals>
<string name="deleteTitle">Karte streichen</string>
<string name="unlockScreen">Afbloker rotation</string>
<string name="lockScreen">Blokrotation</string>
<string name="confirm">Bekræft</string>
<string name="delete">Slet</string>
<string name="edit">Rediger</string>
@@ -39,10 +41,10 @@
<string name="importExportHelp">Hvis du sikkerhedskopierer dine kort, kan du flytte dem til en anden enhed.</string>
<string name="importSuccessfulTitle">Importeret</string>
<string name="importFailedTitle">Import mislykkedes</string>
<string name="importFailed">Kunne ikke importere kort</string>
<string name="importFailed">Kunne ikke importere kort: <xliff:g>%s</xliff:g></string>
<string name="exportSuccessfulTitle">Eksporteret</string>
<string name="exportFailedTitle">Eksport mislykkedes</string>
<string name="exportFailed">Kunne ikke eksportere kort</string>
<string name="exportFailed">Kunne ikke eksportere kort: <xliff:g>%s</xliff:g></string>
<string name="importing">Importere…</string>
<string name="exporting">Eksportere…</string>
<string name="settings_dark_theme">Mørk</string>
@@ -83,6 +85,7 @@
<string name="intent_import_card_from_url_share_text">Jeg vil dele et kort med jer</string>
<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>

View File

@@ -12,6 +12,8 @@
<string name="edit">Bearbeiten</string>
<string name="delete">Löschen</string>
<string name="confirm">Bestätigen</string>
<string name="lockScreen">Rotation sperren</string>
<string name="unlockScreen">Rotation erlauben</string>
<string name="star">Zu den Favoriten hinzufügen</string>
<string name="unstar">Aus den Favoriten entfernen</string>
<string name="ok">OK</string>
@@ -30,10 +32,10 @@
<string name="importExportHelp">Wenn du deine Daten sicherst, kannst du sie auf ein anderes Gerät übertragen.</string>
<string name="importSuccessfulTitle">Importiert</string>
<string name="importFailedTitle">Import fehlgeschlagen</string>
<string name="importFailed">Import konnte nicht durchgeführt werden</string>
<string name="importFailed">Karten konnten nicht importiert werden: <xliff:g>%s</xliff:g></string>
<string name="exportSuccessfulTitle">Exportiert</string>
<string name="exportFailedTitle">Export fehlgeschlagen</string>
<string name="exportFailed">Export konnte nicht durchgeführt werden</string>
<string name="exportFailed">Karten konnten nicht exportiert werden: <xliff:g>%s</xliff:g></string>
<string name="importing">Importiere…</string>
<string name="exporting">Exportiere…</string>
<string name="noExternalStoragePermissionError">Berechtigung für den externen Speicher zum Importieren oder Exportieren von Daten erteilen</string>
@@ -54,6 +56,7 @@
<string name="settings">Einstellungen</string>
<string name="settings_category_title_ui">Benutzeroberfläche</string>
<string name="settings_display_barcode_max_brightness">Barcodeansicht aufhellen</string>
<string name="settings_lock_barcode_orientation">Barcoderotation sperren</string>
<string name="exportSuccessful">Daten exportiert</string>
<string name="importSuccessful">Daten importiert</string>
<string name="intent_import_card_from_url_share_text">Ich würde gerne diese Karte mit dir teilen</string>
@@ -89,7 +92,7 @@
</plurals>
<string name="groupsList">Gruppen: <xliff:g>%s</xliff:g></string>
<string name="app_loyalty_card_keychain">Loyalty Card Keychain</string>
<string name="chooseImportType">Daten importieren aus</string>
<string name="chooseImportType">Daten importieren aus?</string>
<string name="parsingBalanceFailed"><xliff:g>%s</xliff:g> scheint kein gültiges Guthaben zu sein.</string>
<string name="points">Punkte</string>
<string name="currency">Währung</string>
@@ -102,6 +105,7 @@
<string name="editBarcode">Barcode ändern</string>
<string name="barcode">Strichcode</string>
<string name="card">Karte</string>
<string name="balancePoints"><xliff:g>%s</xliff:g> Punkte</string>
<string name="balanceSentence">Guthaben: <xliff:g>%s</xliff:g></string>
<string name="expiryStateSentenceExpired">Abgelaufen: <xliff:g>%s</xliff:g></string>
<string name="expiryStateSentence">Läuft ab: <xliff:g>%s</xliff:g></string>
@@ -184,6 +188,7 @@
<string name="settings_catima_theme">Catima</string>
<string name="settings_theme_color">Designfarbe</string>
<string name="app_contributors">Ermöglicht durch: <xliff:g id="app_contributors">%s</xliff:g></string>
<string name="toggleMoreInfo">Umschalten, um weitere Informationen anzuzeigen</string>
<string name="barcodeImageDescriptionWithType">Bild <xliff:g>%s</xliff:g> Barcode</string>
<string name="swipeToSwitchImages">Wischen oder langes Drücken zum Wechseln der Bilder</string>
<string name="sort_by">Sortieren nach</string>
@@ -217,27 +222,4 @@
<string name="action_hide_details">Details ausblenden</string>
<string name="translate_platform">auf Weblate</string>
<string name="shortcutSelectCard">Wählen Sie eine Karte</string>
<string name="options">Optionen</string>
<string name="hideMoreInfo">Infos ausblenden</string>
<string name="set_scale">Größe festlegen</string>
<string name="showMoreInfo">Infos anzeigen</string>
<string name="starred">als Favorit</string>
<plurals name="balancePoints">
<item quantity="one"><xliff:g>%s</xliff:g> Punkt</item>
<item quantity="other"><xliff:g>%s</xliff:g> Punkte</item>
</plurals>
<string name="settings_oled_dark">Rein schwarzer Hintergrund für dunkles Thema</string>
<string name="include_if_asking_support">Wenn Sie Unterstützung anfordern möchten, geben Sie bitte die folgenden Informationen an:</string>
<string name="settings_follow_system_orientation">System folgen</string>
<string name="settings_landscape_orientation">Landschaft</string>
<string name="archiveList">Archiv</string>
<string name="noUnarchivedCardsMessage">Es gibt keine nicht archivierten Karten</string>
<string name="settings_portrait_orientation">Porträt</string>
<string name="duplicateCard">Duplizieren</string>
<string name="unarchive">Archivierung aufheben</string>
<string name="settings_card_orientation">Barcode-Ausrichtung</string>
<string name="unarchived">Karte nicht archiviert</string>
<string name="archive">Archivieren</string>
<string name="archived">Karte archiviert</string>
<string name="settings_lock_on_opening_orientation">Kartenausrichtung nach dem Öffnen beibehalten</string>
</resources>

View File

@@ -10,6 +10,8 @@
<string name="edit">Επεξεργασία</string>
<string name="delete">Διαγραφή</string>
<string name="confirm">Επιβεβαίωση</string>
<string name="lockScreen">Αποκλεισμός Περιστροφής</string>
<string name="unlockScreen">Περιστροφή</string>
<string name="ok">Εντάξει</string>
<string name="copy_to_clipboard">Αντιγραφή κωδικού στο πρόχειρο</string>
<string name="sendLabel">Αποστολή…</string>
@@ -26,10 +28,10 @@
<string name="importExportHelp">Τα εφεδρικά δεδομένα σας δίνουν την δυνατότητα να μεταφέρετε τις κάρτες σας σε μία άλλη συσκευή.</string>
<string name="importSuccessfulTitle">Εισαγωγή επιτυχής</string>
<string name="importFailedTitle">Εισαγωγή ανεπιτυχής</string>
<string name="importFailed">Δεν εισήχθει</string>
<string name="importFailed">Δεν εισήχθει: <xliff:g>%s</xliff:g></string>
<string name="exportSuccessfulTitle">Εξαγωγή επιτυχής</string>
<string name="exportFailedTitle">Εξαγωγή ανεπιτυχής</string>
<string name="exportFailed">Δεν εξήχθη</string>
<string name="exportFailed">Δεν εξήχθη: <xliff:g>%s</xliff:g></string>
<string name="importing">Γίνεται εισαγωγή του…</string>
<string name="exporting">Γίνεται εξαγωγή του…</string>
<string name="noExternalStoragePermissionError">Δεν είναι δυνατή η εισαγωγή ή εξαγωγή καρτών χωρίς την άδεια πρόσβασης στον εξωτερικό χώρο αποθήκευσης</string>
@@ -55,11 +57,4 @@
<string name="barcode">Γραμμικός κώδικας</string>
<string name="deleteTitle">Αφαίρεση Κάρτας</string>
<string name="deleteConfirmation">Παρακαλώ επιβεβαιώστε ότι θέλετε να διαγράψετε αυτή την κάρτα.</string>
<string name="action_search">Αναζήτηση</string>
<string name="noMatchingGiftCards">Κανένα αποτέλεσμα. Δοκίμασε με διαφορετικές λέξεις.</string>
<plurals name="selectedCardCount">
<item quantity="one"><xliff:g>%d</xliff:g> επιλέγχθηκε</item>
<item quantity="other"><xliff:g>%d</xliff:g> επιλέγχθηκαν</item>
</plurals>
<string name="noGiftCardsGroup">Δημιούργησε κάρτες και βάλτες σε αυτή την ομάδα.</string>
</resources>

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