Compare commits

..

17 Commits

Author SHA1 Message Date
Sylvia van Os
0547fb9949 Fix typo in merge 2020-02-21 16:22:24 +01:00
Sylvia van Os
d092cbe930 Merge branch 'master' into feature/multiple-barcodes 2020-02-21 15:29:26 +01:00
Sylvia van Os
67383a7f10 More tabs into header to save some space 2020-01-06 21:54:52 +01:00
Sylvia van Os
5b5ade0edc Merge branch 'feature/multiple-barcodes' of ssh://github.com/TheLastProject/loyalty-card-locker into feature/multiple-barcodes 2020-01-05 16:09:49 +01:00
Sylvia van Os
efd0f4ef39 Fix tab state loss on rotation 2020-01-05 16:09:21 +01:00
Sylvia van Os
67ada5c027 Merge branch 'master' into feature/multiple-barcodes 2020-01-05 14:47:58 +01:00
Sylvia van Os
520f0da983 Sanitize long and multiline notes 2020-01-05 14:22:15 +01:00
Sylvia van Os
343d710b2a Swipe between different cards from store 2020-01-05 14:16:13 +01:00
Sylvia van Os
1c71dc964f Rename barcodecount to card count because barcodeless card support 2020-01-05 00:50:08 +01:00
Sylvia van Os
524d649523 Add new tests 2020-01-05 00:36:44 +01:00
Sylvia van Os
e39593228d Fix tests 2020-01-05 00:12:12 +01:00
Sylvia van Os
27d718b461 Also add FAB to edit screen 2020-01-05 00:04:50 +01:00
Sylvia van Os
490281bff9 Fix note not reappearing 2020-01-05 00:00:37 +01:00
Sylvia van Os
5030e4c67a Also add FAB button to main activity 2020-01-04 23:52:36 +01:00
Sylvia van Os
29eac68e3f Group together multiple barcodes of same store 2020-01-04 23:45:28 +01:00
Sylvia van Os
422501da3e Make it easy to add extra barcodes 2020-01-04 23:00:23 +01:00
Sylvia van Os
23bd60b476 Add tab to switch between multiple barcodes of same store 2020-01-04 22:26:00 +01:00
194 changed files with 1823 additions and 3586 deletions

View File

@@ -1,27 +0,0 @@
name: Android CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build
run: ./gradlew assembleRelease
- name: Check lint
run: ./gradlew lintRelease
- name: Run unit tests
run: ./gradlew testReleaseUnitTest
- name: FindBugs
run: ./gradlew findbugs

View File

@@ -1,31 +0,0 @@
name: Compress Images on Push to Master
on:
push:
branches:
- master
paths:
- '**.jpg'
- '**.jpeg'
- '**.png'
- '**.webp'
jobs:
build:
name: calibreapp/image-actions
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@master
- name: Compress Images
id: calibre
uses: calibreapp/image-actions@master
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
compressOnly: true
- name: Create New Pull Request If Needed
if: steps.calibre.outputs.markdown != ''
uses: peter-evans/create-pull-request@master
with:
title: Compressed Images
branch-suffix: timestamp
commit-message: Compressed Images
body: ${{ steps.calibre.outputs.markdown }}

16
.travis.yml Normal file
View File

@@ -0,0 +1,16 @@
language: android
sudo: true
install:
- echo y | android update sdk -u -a -t tools
- echo y | android update sdk -u -a -t platform-tools
- echo y | android update sdk -u -a -t build-tools-26.0.2
- yes | sdkmanager "platforms;android-27"
- echo y | android update sdk -u -a -t extra-google-m2repository
- echo y | android update sdk -u -a -t extra-android-m2repository
script: ./gradlew assembleRelease testReleaseUnitTest lintRelease findbugs
after_failure:
- cat app/build/reports/findbugs/findbugs.html
- cat app/build/reports/tests/debug/index.html

10
.tx/config Normal file
View File

@@ -0,0 +1,10 @@
[main]
host = https://www.transifex.com
[loyalty-card-locker.stringsxml]
file_filter = app/src/main/res/values-<lang>/strings.xml
minimum_perc = 0
source_file = app/src/main/res/values/strings.xml
source_lang = en
type = ANDROID

View File

@@ -1,31 +1,3 @@
## v1.0.1 (2020-11-07)
Changes:
- Fix crash in search with no groups
## v1.0 (2020-11-06)
Changes:
- Added rounded edges to card icons on main overview
- Added support for grouping entries
## v0.29 (2020-10-29)
Changes:
- Rebrand to Catima
- Removed intro
- Add floating action buttons
- Fix Android 5 crash when opening About screen
- Add favourites support
- Fix disabled auto-rotate being ignored
## v0.28 (2020-03-09)
Changes:
- Fix barcode centering when exiting full screen ([#351](https://github.com/brarcher/loyalty-card-locker/pull/351))
- Allow backup export location to be selected ([#352](https://github.com/brarcher/loyalty-card-locker/pull/352))
- Update translations ([#357](https://github.com/brarcher/loyalty-card-locker/pull/357)) & ([#362](https://github.com/brarcher/loyalty-card-locker/pull/362))
## v0.27 (2020-01-26)
Changes:

View File

@@ -1,3 +0,0 @@
source "https://rubygems.org"
gem "fastlane"

View File

@@ -1,180 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.2)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
atomos (0.1.3)
aws-eventstream (1.1.0)
aws-partitions (1.388.0)
aws-sdk-core (3.109.1)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.39.0)
aws-sdk-core (~> 3, >= 3.109.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.83.1)
aws-sdk-core (~> 3, >= 3.109.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.2.2)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.0.3)
colored (1.2)
colored2 (3.1.2)
commander-fastlane (4.4.6)
highline (~> 1.7.2)
declarative (0.0.20)
declarative-option (0.1.0)
digest-crc (0.6.1)
rake (~> 13.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
emoji_regex (3.2.0)
excon (0.78.0)
faraday (1.1.0)
multipart-post (>= 1.2, < 3)
ruby2_keywords
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
faraday_middleware (1.0.0)
faraday (~> 1.0)
fastimage (2.2.0)
fastlane (2.165.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
colored
commander-fastlane (>= 4.4.6, < 5.0.0)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
excon (>= 0.71.0, < 1.0.0)
faraday (~> 1.0)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 1.0)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-api-client (>= 0.37.0, < 0.39.0)
google-cloud-storage (>= 1.15.0, < 2.0.0)
highline (>= 1.7.2, < 2.0.0)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (~> 2.0.0)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.3)
simctl (~> 1.6.3)
slack-notifier (>= 2.0.0, < 3.0.0)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
google-api-client (0.38.0)
addressable (~> 2.5, >= 2.5.1)
googleauth (~> 0.9)
httpclient (>= 2.8.1, < 3.0)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
signet (~> 0.12)
google-cloud-core (1.5.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.4.0)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.0.1)
google-cloud-storage (1.29.1)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-api-client (~> 0.33)
google-cloud-core (~> 1.2)
googleauth (~> 0.9)
mini_mime (~> 1.0)
googleauth (0.14.0)
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.14)
highline (1.7.10)
http-cookie (1.0.3)
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.4.0)
json (2.3.1)
jwt (2.2.2)
memoist (0.16.2)
mini_magick (4.10.1)
mini_mime (1.0.2)
multi_json (1.15.0)
multipart-post (2.0.0)
nanaimo (0.3.0)
naturally (2.2.0)
os (1.1.1)
plist (3.5.0)
public_suffix (4.0.6)
rake (13.0.1)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rouge (2.0.7)
ruby2_keywords (0.0.2)
rubyzip (2.3.0)
security (0.1.3)
signet (0.14.0)
addressable (~> 2.3)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.8)
CFPropertyList
naturally
slack-notifier (2.3.2)
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
tty-cursor (0.7.1)
tty-screen (0.8.1)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
word_wrap (1.0.0)
xcodeproj (1.19.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
xcpretty (0.3.0)
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.0)
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
ruby
DEPENDENCIES
fastlane
BUNDLED WITH
2.1.4

View File

@@ -10,20 +10,17 @@ android {
compileSdkVersion 29
defaultConfig {
applicationId "me.hackerchick.catima"
applicationId "protect.card_locker"
minSdkVersion 16
targetSdkVersion 29
versionCode 42
versionName "1.0.1"
versionCode 38
versionName "0.27"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
applicationIdSuffix ".debug"
}
}
lintOptions {
disable "GoogleAppIndexingWarning"
@@ -44,8 +41,8 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'androidx.appcompat:appcompat:1.2.0'
compile 'com.google.android.material:material:1.2.1'
compile 'androidx.appcompat:appcompat:1.2.0-alpha01'
compile 'com.google.android.material:material:1.2.0-alpha03'
compile 'androidx.legacy:legacy-support-v4:1.0.0'
compile 'com.journeyapps:zxing-android-embedded:3.5.0@aar'
compile 'com.google.zxing:core:3.3.0'
@@ -55,7 +52,6 @@ dependencies {
compile group: 'com.google.guava', name: 'guava', version: '20.0'
compile 'com.github.apl-devs:appintro:v4.2.0'
compile "com.vanniktech:vntnumberpickerpreference:1.0.0"
implementation 'androidx.cardview:cardview:1.0.0'
testCompile 'junit:junit:4.12'
testCompile "org.robolectric:robolectric:4.0.2"
}

View File

Binary file not shown.

View File

@@ -1 +0,0 @@
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":41,"versionName":"1.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]

View File

@@ -12,4 +12,4 @@ public class ApplicationTest extends ApplicationTestCase<Application>
{
super(Application.class);
}
}
}

View File

@@ -33,11 +33,6 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".ManageGroupsActivity"
android:label="@string/groups"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".LoyaltyCardViewActivity"
android:theme="@style/AppTheme.NoActionBar"
@@ -47,9 +42,10 @@
<activity
android:name=".LoyaltyCardEditActivity"
android:theme="@style/AppTheme.NoActionBar"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateHidden"
android:exported="true">
<intent-filter android:label="@string/app_name">
<intent-filter android:label="@string/intent_import_card_from_url">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -57,26 +53,32 @@
<data android:scheme="https"
android:host="@string/intent_import_card_from_url_host"
android:pathPrefix="@string/intent_import_card_from_url_path_prefix" />
<data android:scheme="https"
android:host="@string/intent_import_card_from_url_host_old"
android:pathPrefix="@string/intent_import_card_from_url_path_prefix_old" />
</intent-filter>
</activity>
<activity
android:name=".BarcodeSelectorActivity"
android:label="@string/selectBarcodeTitle"
android:theme="@style/AppTheme.NoActionBar"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateHidden"/>
<activity
android:name=".preferences.SettingsActivity"
android:label="@string/settings"/>
android:label="@string/settings"
android:configChanges="orientation|screenSize"/>
<activity
android:name=".ImportExportActivity"
android:label="@string/importExport"
android:configChanges="orientation|screenSize"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name=".intro.IntroActivity"
android:label=""
android:configChanges="orientation|screenSize"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name=".CardShortcutConfigure"
android:label="@string/cardShortcut"
android:configChanges="orientation|screenSize"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT"/>

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -5,7 +5,6 @@ import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
@@ -21,7 +20,7 @@ import java.lang.ref.WeakReference;
*/
class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
{
private static final String TAG = "Catima";
private static final String TAG = "LoyaltyCardLocker";
// When drawn in a smaller window 1D barcodes for some reason end up
// squished, whereas 2D barcodes look fine.
@@ -29,18 +28,16 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
private static final int MAX_WIDTH_2D = 500;
private final WeakReference<ImageView> imageViewReference;
private final WeakReference<TextView> textViewReference;
private final String cardId;
private final BarcodeFormat format;
private final int imageHeight;
private final int imageWidth;
BarcodeImageWriterTask(ImageView imageView, String cardIdString,
BarcodeFormat barcodeFormat, TextView textView)
BarcodeFormat barcodeFormat)
{
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<>(imageView);
textViewReference = new WeakReference<>(textView);
cardId = cardIdString;
format = barcodeFormat;
@@ -61,11 +58,6 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
}
}
BarcodeImageWriterTask(ImageView imageView, String cardIdString, BarcodeFormat barcodeFormat)
{
this(imageView, cardIdString, barcodeFormat, null);
}
private int getMaxWidth(BarcodeFormat format)
{
switch(format)
@@ -183,25 +175,16 @@ class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
}
imageView.setImageBitmap(result);
TextView textView = textViewReference.get();
if(result != null)
{
Log.i(TAG, "Displaying barcode");
imageView.setVisibility(View.VISIBLE);
if (textView != null) {
textView.setVisibility(View.VISIBLE);
textView.setText(format.name());
}
}
else
{
Log.i(TAG, "Barcode generation failed, removing image from display");
imageView.setVisibility(View.GONE);
if (textView != null) {
textView.setVisibility(View.GONE);
}
}
}
}

View File

@@ -11,13 +11,11 @@ import androidx.appcompat.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.util.Pair;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.common.collect.ImmutableMap;
import com.google.zxing.BarcodeFormat;
@@ -36,7 +34,7 @@ import java.util.Map;
*/
public class BarcodeSelectorActivity extends AppCompatActivity
{
private static final String TAG = "Catima";
private static final String TAG = "LoyaltyCardLocker";
// Result this activity will return
public static final String BARCODE_CONTENTS = "contents";
@@ -60,7 +58,7 @@ public class BarcodeSelectorActivity extends AppCompatActivity
BarcodeFormat.UPC_A.name()
));
private Map<String, Pair<Integer, Integer>> barcodeViewMap;
private Map<String, Integer> barcodeViewMap;
private LinkedList<AsyncTask> barcodeGeneratorTasks = new LinkedList<>();
@Override
@@ -77,18 +75,18 @@ public class BarcodeSelectorActivity extends AppCompatActivity
actionBar.setDisplayHomeAsUpEnabled(true);
}
barcodeViewMap = ImmutableMap.<String, Pair<Integer, Integer>>builder()
.put(BarcodeFormat.AZTEC.name(), new Pair<>(R.id.aztecBarcode, R.id.aztecBarcodeText))
.put(BarcodeFormat.CODE_39.name(), new Pair<>(R.id.code39Barcode, R.id.code39BarcodeText))
.put(BarcodeFormat.CODE_128.name(), new Pair<>(R.id.code128Barcode, R.id.code128BarcodeText))
.put(BarcodeFormat.CODABAR.name(), new Pair<>(R.id.codabarBarcode, R.id.codabarBarcodeText))
.put(BarcodeFormat.DATA_MATRIX.name(), new Pair<>(R.id.datamatrixBarcode, R.id.datamatrixBarcodeText))
.put(BarcodeFormat.EAN_8.name(), new Pair<>(R.id.ean8Barcode, R.id.ean8BarcodeText))
.put(BarcodeFormat.EAN_13.name(), new Pair<>(R.id.ean13Barcode, R.id.ean13BarcodeText))
.put(BarcodeFormat.ITF.name(), new Pair<>(R.id.itfBarcode, R.id.itfBarcodeText))
.put(BarcodeFormat.PDF_417.name(), new Pair<>(R.id.pdf417Barcode, R.id.pdf417BarcodeText))
.put(BarcodeFormat.QR_CODE.name(), new Pair<>(R.id.qrcodeBarcode, R.id.qrcodeBarcodeText))
.put(BarcodeFormat.UPC_A.name(), new Pair<>(R.id.upcaBarcode, R.id.upcaBarcodeText))
barcodeViewMap = ImmutableMap.<String, Integer>builder()
.put(BarcodeFormat.AZTEC.name(), R.id.aztecBarcode)
.put(BarcodeFormat.CODE_39.name(), R.id.code39Barcode)
.put(BarcodeFormat.CODE_128.name(), R.id.code128Barcode)
.put(BarcodeFormat.CODABAR.name(), R.id.codabarBarcode)
.put(BarcodeFormat.DATA_MATRIX.name(), R.id.datamatrixBarcode)
.put(BarcodeFormat.EAN_8.name(), R.id.ean8Barcode)
.put(BarcodeFormat.EAN_13.name(), R.id.ean13Barcode)
.put(BarcodeFormat.ITF.name(), R.id.itfBarcode)
.put(BarcodeFormat.PDF_417.name(), R.id.pdf417Barcode)
.put(BarcodeFormat.QR_CODE.name(), R.id.qrcodeBarcode)
.put(BarcodeFormat.UPC_A.name(), R.id.upcaBarcode)
.build();
EditText cardId = findViewById(R.id.cardId);
@@ -115,9 +113,8 @@ public class BarcodeSelectorActivity extends AppCompatActivity
// Update barcodes
for(String key : barcodeViewMap.keySet())
{
ImageView image = findViewById(barcodeViewMap.get(key).first);
TextView text = findViewById(barcodeViewMap.get(key).second);
createBarcodeOption(image, key, s.toString(), text);
ImageView image = findViewById(barcodeViewMap.get(key));
createBarcodeOption(image, key, s.toString());
}
View noBarcodeButtonView = findViewById(R.id.noBarcode);
@@ -156,7 +153,7 @@ public class BarcodeSelectorActivity extends AppCompatActivity
});
}
private void createBarcodeOption(final ImageView image, final String formatType, final String cardId, final TextView text)
private void createBarcodeOption(final ImageView image, final String formatType, final String cardId)
{
final BarcodeFormat format = BarcodeFormat.valueOf(formatType);
if(format == null)
@@ -201,7 +198,7 @@ public class BarcodeSelectorActivity extends AppCompatActivity
}
Log.d(TAG, "Generating barcode for type " + formatType);
BarcodeImageWriterTask task = new BarcodeImageWriterTask(image, cardId, format, text);
BarcodeImageWriterTask task = new BarcodeImageWriterTask(image, cardId, format);
barcodeGeneratorTasks.add(task);
task.execute();
}
@@ -210,7 +207,7 @@ public class BarcodeSelectorActivity extends AppCompatActivity
else
{
Log.d(TAG, "Generating barcode for type " + formatType);
BarcodeImageWriterTask task = new BarcodeImageWriterTask(image, cardId, format, text);
BarcodeImageWriterTask task = new BarcodeImageWriterTask(image, cardId, format);
barcodeGeneratorTasks.add(task);
task.execute();
}

View File

@@ -17,7 +17,7 @@ import android.widget.Toast;
*/
public class CardShortcutConfigure extends AppCompatActivity
{
static final String TAG = "Catima";
static final String TAG = "LoyaltyCardLocker";
@Override
public void onCreate(Bundle bundle)

View File

@@ -18,48 +18,20 @@ public class CsvDatabaseExporter implements DatabaseExporter
{
CSVPrinter printer = new CSVPrinter(output, CSVFormat.RFC4180);
// Print the version
printer.printRecord("2");
printer.println();
// Print the header for groups
printer.printRecord(DBHelper.LoyaltyCardDbGroups.ID);
Cursor groupCursor = db.getGroupCursor();
while(groupCursor.moveToNext())
{
Group group = Group.toGroup(groupCursor);
printer.printRecord(group._id);
if(Thread.currentThread().isInterrupted())
{
throw new InterruptedException();
}
}
groupCursor.close();
// Print an empty line
printer.println();
// Print the header for cards
// Print the header
printer.printRecord(DBHelper.LoyaltyCardDbIds.ID,
DBHelper.LoyaltyCardDbIds.STORE,
DBHelper.LoyaltyCardDbIds.NOTE,
DBHelper.LoyaltyCardDbIds.CARD_ID,
DBHelper.LoyaltyCardDbIds.HEADER_COLOR,
DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR,
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE,
DBHelper.LoyaltyCardDbIds.STAR_STATUS);
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE);
Cursor cardCursor = db.getLoyaltyCardCursor();
Cursor cursor = db.getLoyaltyCardCursor();
while(cardCursor.moveToNext())
while(cursor.moveToNext())
{
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cardCursor);
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cursor);
printer.printRecord(card.id,
card.store,
@@ -67,8 +39,7 @@ public class CsvDatabaseExporter implements DatabaseExporter
card.cardId,
card.headerColor,
card.headerTextColor,
card.barcodeType,
card.starStatus);
card.barcodeType);
if(Thread.currentThread().isInterrupted())
{
@@ -76,32 +47,7 @@ public class CsvDatabaseExporter implements DatabaseExporter
}
}
cardCursor.close();
// Print an empty line
printer.println();
// Print the header for card group mappings
printer.printRecord(DBHelper.LoyaltyCardDbIdsGroups.cardID,
DBHelper.LoyaltyCardDbIdsGroups.groupID);
Cursor cardCursor2 = db.getLoyaltyCardCursor();
while(cardCursor2.moveToNext())
{
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cardCursor2);
for (Group group : db.getLoyaltyCardGroups(card.id)) {
printer.printRecord(card.id, group._id);
}
if(Thread.currentThread().isInterrupted())
{
throw new InterruptedException();
}
}
cardCursor2.close();
cursor.close();
printer.close();
}

View File

@@ -6,11 +6,8 @@ import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.List;
/**
* Class for importing a database from CSV (Comma Separate Values)
@@ -22,34 +19,6 @@ import java.util.List;
public class CsvDatabaseImporter implements DatabaseImporter
{
public void importData(DBHelper db, InputStreamReader input) throws IOException, FormatException, InterruptedException
{
BufferedReader bufferedReader = new BufferedReader(input);
bufferedReader.mark(100);
Integer version = 1;
try {
version = Integer.parseInt(bufferedReader.readLine());
} catch (NumberFormatException _e) {
// Assume version 1
}
bufferedReader.reset();
switch (version) {
case 1:
parseV1(db, bufferedReader);
break;
case 2:
parseV2(db, bufferedReader);
break;
default:
throw new FormatException(String.format("No code to parse version %s", version));
}
}
public void parseV1(DBHelper db, BufferedReader input) throws IOException, FormatException, InterruptedException
{
final CSVParser parser = new CSVParser(input, CSVFormat.RFC4180.withHeader());
@@ -82,116 +51,6 @@ public class CsvDatabaseImporter implements DatabaseImporter
}
}
public void parseV2(DBHelper db, BufferedReader input) throws IOException, FormatException, InterruptedException
{
SQLiteDatabase database = db.getWritableDatabase();
database.beginTransaction();
Integer part = 0;
String stringPart = "";
try {
while (true) {
String tmp = input.readLine();
if (tmp == null || tmp.isEmpty()) {
switch (part) {
case 0:
// This is the version info, ignore
break;
case 1:
parseV2Groups(db, database, stringPart);
break;
case 2:
parseV2Cards(db, database, stringPart);
break;
case 3:
parseV2CardGroups(db, database, stringPart);
break;
default:
throw new FormatException("Issue parsing CSV data, too many parts for v2 parsing");
}
if (tmp == null) {
break;
}
part += 1;
stringPart = "";
} else {
stringPart += tmp + "\n";
}
}
database.setTransactionSuccessful();
} catch (FormatException e) {
throw new FormatException("Issue parsing CSV data", e);
} finally {
database.endTransaction();
database.close();
}
}
public void parseV2Groups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
{
// Parse groups
final CSVParser groupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
try {
for (CSVRecord record : groupParser) {
importGroup(database, db, record);
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
}
groupParser.close();
} catch (IllegalArgumentException | IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e);
}
}
public void parseV2Cards(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
{
// Parse cards
final CSVParser cardParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
try {
for (CSVRecord record : cardParser) {
importLoyaltyCard(database, db, record);
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
}
cardParser.close();
} catch (IllegalArgumentException | IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e);
}
}
public void parseV2CardGroups(DBHelper db, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException
{
// Parse card group mappings
final CSVParser cardGroupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.withHeader());
try {
for (CSVRecord record : cardGroupParser) {
importCardGroupMapping(database, db, record);
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
}
cardGroupParser.close();
} catch (IllegalArgumentException | IllegalStateException e) {
throw new FormatException("Issue parsing CSV data", e);
}
}
/**
* Extract a string from the items array. The index into the array
* is determined by looking up the index in the fields map using the
@@ -283,41 +142,6 @@ public class CsvDatabaseImporter implements DatabaseImporter
headerTextColor = extractInt(DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR, record, true);
}
int starStatus = 0;
try {
starStatus = extractInt(DBHelper.LoyaltyCardDbIds.STAR_STATUS, record, false);
} catch (FormatException _e ) {
// This field did not exist in versions 0.28 and before
// We catch this exception so we can still import old backups
}
if (starStatus != 1) starStatus = 0;
helper.insertLoyaltyCard(database, id, store, note, cardId, barcodeType, headerColor, headerTextColor, starStatus);
helper.insertLoyaltyCard(database, id, store, note, cardId, barcodeType, headerColor, headerTextColor);
}
/**
* Import a single group into the database using the given
* session.
*/
private void importGroup(SQLiteDatabase database, DBHelper helper, CSVRecord record)
throws IOException, FormatException
{
String id = extractString(DBHelper.LoyaltyCardDbGroups.ID, record, null);
helper.insertGroup(database, id);
}
/**
* Import a single card to group mapping into the database using the given
* session.
*/
private void importCardGroupMapping(SQLiteDatabase database, DBHelper helper, CSVRecord record)
throws IOException, FormatException
{
Integer cardId = extractInt(DBHelper.LoyaltyCardDbIdsGroups.cardID, record, false);
String groupId = extractString(DBHelper.LoyaltyCardDbIdsGroups.groupID, record, null);
List<Group> cardGroups = helper.getLoyaltyCardGroups(cardId);
cardGroups.add(helper.getGroup(groupId));
helper.setLoyaltyCardGroups(database, cardId, cardGroups);
}
}
}

View File

@@ -1,5 +1,6 @@
package protect.card_locker;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -11,15 +12,9 @@ import java.util.List;
public class DBHelper extends SQLiteOpenHelper
{
public static final String DATABASE_NAME = "Catima.db";
public static final String DATABASE_NAME = "LoyaltyCards.db";
public static final int ORIGINAL_DATABASE_VERSION = 1;
public static final int DATABASE_VERSION = 5;
static class LoyaltyCardDbGroups
{
public static final String TABLE = "groups";
public static final String ID = "_id";
}
public static final int DATABASE_VERSION = 3;
static class LoyaltyCardDbIds
{
@@ -31,14 +26,6 @@ public class DBHelper extends SQLiteOpenHelper
public static final String HEADER_TEXT_COLOR = "headertextcolor";
public static final String CARD_ID = "cardid";
public static final String BARCODE_TYPE = "barcodetype";
public static final String STAR_STATUS = "starstatus";
}
static class LoyaltyCardDbIdsGroups
{
public static final String TABLE = "cardsGroups";
public static final String cardID = "cardId";
public static final String groupID = "groupId";
}
public DBHelper(Context context)
@@ -49,11 +36,7 @@ public class DBHelper extends SQLiteOpenHelper
@Override
public void onCreate(SQLiteDatabase db)
{
// create table for card groups
db.execSQL("create table " + LoyaltyCardDbGroups.TABLE + "(" +
LoyaltyCardDbGroups.ID + " TEXT primary key not null)");
// create table for cards
// create table for gift cards
db.execSQL("create table " + LoyaltyCardDbIds.TABLE + "(" +
LoyaltyCardDbIds.ID + " INTEGER primary key autoincrement," +
LoyaltyCardDbIds.STORE + " TEXT not null," +
@@ -61,14 +44,7 @@ public class DBHelper extends SQLiteOpenHelper
LoyaltyCardDbIds.HEADER_COLOR + " INTEGER," +
LoyaltyCardDbIds.HEADER_TEXT_COLOR + " INTEGER," +
LoyaltyCardDbIds.CARD_ID + " TEXT not null," +
LoyaltyCardDbIds.BARCODE_TYPE + " TEXT not null," +
LoyaltyCardDbIds.STAR_STATUS + " INTEGER DEFAULT '0' )");
// create associative table for cards in groups
db.execSQL("create table " + LoyaltyCardDbIdsGroups.TABLE + "(" +
LoyaltyCardDbIdsGroups.cardID + " INTEGER," +
LoyaltyCardDbIdsGroups.groupID + " TEXT," +
"primary key (" + LoyaltyCardDbIdsGroups.cardID + "," + LoyaltyCardDbIdsGroups.groupID +"))");
LoyaltyCardDbIds.BARCODE_TYPE + " TEXT not null)");
}
@Override
@@ -89,30 +65,11 @@ public class DBHelper extends SQLiteOpenHelper
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
+ " ADD COLUMN " + LoyaltyCardDbIds.HEADER_TEXT_COLOR + " INTEGER");
}
// Upgrade from version 3 to version 4
if(oldVersion < 4 && newVersion >= 4)
{
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
+ " ADD COLUMN " + LoyaltyCardDbIds.STAR_STATUS + " INTEGER DEFAULT '0'");
}
// Upgrade from version 4 to version 5
if(oldVersion < 5 && newVersion >= 5)
{
db.execSQL("create table " + LoyaltyCardDbGroups.TABLE + "(" +
LoyaltyCardDbGroups.ID + " TEXT primary key not null)");
db.execSQL("create table " + LoyaltyCardDbIdsGroups.TABLE + "(" +
LoyaltyCardDbIdsGroups.cardID + " INTEGER," +
LoyaltyCardDbIdsGroups.groupID + " TEXT," +
"primary key (" + LoyaltyCardDbIdsGroups.cardID + "," + LoyaltyCardDbIdsGroups.groupID +"))");
}
}
public long insertLoyaltyCard(final String store, final String note, final String cardId,
final String barcodeType, final Integer headerColor,
final Integer headerTextColor, final int starStatus)
final Integer headerTextColor)
{
SQLiteDatabase db = getWritableDatabase();
ContentValues contentValues = new ContentValues();
@@ -122,15 +79,14 @@ public class DBHelper extends SQLiteOpenHelper
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType);
contentValues.put(LoyaltyCardDbIds.HEADER_COLOR, headerColor);
contentValues.put(LoyaltyCardDbIds.HEADER_TEXT_COLOR, headerTextColor);
contentValues.put(LoyaltyCardDbIds.STAR_STATUS, starStatus);
final long newId = db.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
return newId;
}
public boolean insertLoyaltyCard(final SQLiteDatabase db, final int id, final String store,
final String note, final String cardId,
public boolean insertLoyaltyCard(final SQLiteDatabase db, final int id,
final String store, final String note, final String cardId,
final String barcodeType, final Integer headerColor,
final Integer headerTextColor, final int starStatus)
final Integer headerTextColor)
{
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbIds.ID, id);
@@ -140,11 +96,11 @@ public class DBHelper extends SQLiteOpenHelper
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType);
contentValues.put(LoyaltyCardDbIds.HEADER_COLOR, headerColor);
contentValues.put(LoyaltyCardDbIds.HEADER_TEXT_COLOR, headerTextColor);
contentValues.put(LoyaltyCardDbIds.STAR_STATUS,starStatus);
final long newId = db.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
return (newId != -1);
}
public boolean updateLoyaltyCard(final int id, final String store, final String note,
final String cardId, final String barcodeType,
final Integer headerColor, final Integer headerTextColor)
@@ -163,17 +119,6 @@ public class DBHelper extends SQLiteOpenHelper
return (rowsUpdated == 1);
}
public boolean updateLoyaltyCardStarStatus(final int id, final int starStatus)
{
SQLiteDatabase db = getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbIds.STAR_STATUS,starStatus);
int rowsUpdated = db.update(LoyaltyCardDbIds.TABLE, contentValues,
LoyaltyCardDbIds.ID + "=?",
new String[]{Integer.toString(id)});
return (rowsUpdated == 1);
}
public LoyaltyCard getLoyaltyCard(final int id)
{
SQLiteDatabase db = getReadableDatabase();
@@ -185,7 +130,6 @@ public class DBHelper extends SQLiteOpenHelper
if(data.getCount() == 1)
{
data.moveToFirst();
card = LoyaltyCard.toLoyaltyCard(data);
}
@@ -194,76 +138,12 @@ public class DBHelper extends SQLiteOpenHelper
return card;
}
public List<Group> getLoyaltyCardGroups(final int id)
{
SQLiteDatabase db = getReadableDatabase();
Cursor data = db.rawQuery("select * from " + LoyaltyCardDbGroups.TABLE + " g " +
" LEFT JOIN " + LoyaltyCardDbIdsGroups.TABLE + " ig ON ig." + LoyaltyCardDbIdsGroups.groupID + " = g." + LoyaltyCardDbGroups.ID +
" where " + LoyaltyCardDbIdsGroups.cardID + "=?" +
" ORDER BY " + LoyaltyCardDbIdsGroups.groupID, new String[]{String.format("%d", id)});
List<Group> groups = new ArrayList<>();
if (!data.moveToFirst()) {
return groups;
}
groups.add(Group.toGroup(data));
while (data.moveToNext()) {
groups.add(Group.toGroup(data));
}
return groups;
}
public void setLoyaltyCardGroups(final int id, List<Group> groups)
{
SQLiteDatabase db = getWritableDatabase();
// First delete lookup table entries associated with this card
db.delete(LoyaltyCardDbIdsGroups.TABLE,
LoyaltyCardDbIdsGroups.cardID + " = ? ",
new String[]{String.format("%d", id)});
// Then create entries for selected values
for (Group group : groups) {
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbIdsGroups.cardID, id);
contentValues.put(LoyaltyCardDbIdsGroups.groupID, group._id);
db.insert(LoyaltyCardDbIdsGroups.TABLE, null, contentValues);
}
}
public void setLoyaltyCardGroups(final SQLiteDatabase db, final int id, List<Group> groups)
{
// First delete lookup table entries associated with this card
db.delete(LoyaltyCardDbIdsGroups.TABLE,
LoyaltyCardDbIdsGroups.cardID + " = ? ",
new String[]{String.format("%d", id)});
// Then create entries for selected values
for (Group group : groups) {
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbIdsGroups.cardID, id);
contentValues.put(LoyaltyCardDbIdsGroups.groupID, group._id);
db.insert(LoyaltyCardDbIdsGroups.TABLE, null, contentValues);
}
}
public boolean deleteLoyaltyCard (final int id)
{
SQLiteDatabase db = getWritableDatabase();
// Delete card
int rowsDeleted = db.delete(LoyaltyCardDbIds.TABLE,
int rowsDeleted = db.delete(LoyaltyCardDbIds.TABLE,
LoyaltyCardDbIds.ID + " = ? ",
new String[]{String.format("%d", id)});
// And delete lookup table entries associated with this card
db.delete(LoyaltyCardDbIdsGroups.TABLE,
LoyaltyCardDbIdsGroups.cardID + " = ? ",
new String[]{String.format("%d", id)});
return (rowsDeleted == 1);
}
@@ -280,55 +160,70 @@ public class DBHelper extends SQLiteOpenHelper
* @return Cursor
*/
public Cursor getLoyaltyCardCursor(final String filter)
{
return getLoyaltyCardCursor(filter, null);
}
/**
* Returns a cursor to all loyalty cards with the filter text in either the store or note in a certain group.
*
* @param filter
* @param group
* @return Cursor
*/
public Cursor getLoyaltyCardCursor(final String filter, Group group)
{
String actualFilter = String.format("%%%s%%", filter);
String[] selectionArgs = { actualFilter, actualFilter };
StringBuilder groupFilter = new StringBuilder();
String limitString = "";
SQLiteDatabase db = getReadableDatabase();
if (group != null) {
List<Integer> allowedIds = getGroupCardIds(group._id);
Cursor res = db.rawQuery("select * from " + LoyaltyCardDbIds.TABLE +
" WHERE " + LoyaltyCardDbIds.STORE + " LIKE ? " +
" OR " + LoyaltyCardDbIds.NOTE + " LIKE ? " +
" ORDER BY " + LoyaltyCardDbIds.STORE + " COLLATE NOCASE ASC", selectionArgs, null);
return res;
}
// Empty group
if (allowedIds.size() > 0) {
groupFilter.append("AND (");
/**
* Returns a cursor only containing the first loyalty card of the given store.
*
* @param filter
* @return Cursor
*/
public Cursor getOneLoyaltyCardPerStoreCursor(final String filter)
{
String actualFilter = String.format("%%%s%%", filter);
String[] selectionArgs = { actualFilter, actualFilter };
for (int i = 0; i < allowedIds.size(); i++) {
groupFilter.append(LoyaltyCardDbIds.ID + " = " + allowedIds.get(i));
if (i != allowedIds.size() - 1) {
groupFilter.append(" OR ");
}
}
groupFilter.append(") ");
} else {
limitString = "LIMIT 0";
}
}
SQLiteDatabase db = getReadableDatabase();
Cursor res = db.rawQuery("select * from " + LoyaltyCardDbIds.TABLE +
" WHERE (" + LoyaltyCardDbIds.STORE + " LIKE ? " +
" OR " + LoyaltyCardDbIds.NOTE + " LIKE ? )" +
groupFilter.toString() +
" ORDER BY " + LoyaltyCardDbIds.STAR_STATUS + " DESC," + LoyaltyCardDbIds.STORE + " COLLATE NOCASE ASC " +
limitString, selectionArgs, null);
" WHERE " + LoyaltyCardDbIds.STORE + " LIKE ? " +
" OR " + LoyaltyCardDbIds.NOTE + " LIKE ? " +
" GROUP BY " + LoyaltyCardDbIds.STORE +
" HAVING MIN(" + LoyaltyCardDbIds.ID + ")" +
" ORDER BY " + LoyaltyCardDbIds.STORE + " COLLATE NOCASE ASC", selectionArgs, null);
return res;
}
/**
* Returns a list of all loyalty cards of the given store.
*
* @param store
* @return List<LoyaltyCard>
*/
public List<LoyaltyCard> getLoyaltyCardsForStore(String store)
{
List<LoyaltyCard> loyaltyCards = new ArrayList<>();
SQLiteDatabase db = getReadableDatabase();
String[] selectionArgs = { store };
Cursor res = db.rawQuery("select * from " + LoyaltyCardDbIds.TABLE +
" WHERE " + LoyaltyCardDbIds.STORE + " IS ? " +
" ORDER BY " + LoyaltyCardDbIds.STORE + " COLLATE NOCASE ASC", selectionArgs, null);
try
{
while (res.moveToNext()) {
loyaltyCards.add(LoyaltyCard.toLoyaltyCard(res));
}
} finally {
res.close();
}
return loyaltyCards;
}
public int getLoyaltyCardCount()
{
// An empty string will match everything
@@ -364,172 +259,5 @@ public class DBHelper extends SQLiteOpenHelper
return numItems;
}
/**
* Returns a cursor to all groups.
*
* @return Cursor
*/
public Cursor getGroupCursor()
{
SQLiteDatabase db = getReadableDatabase();
Cursor res = db.rawQuery("select * from " + LoyaltyCardDbGroups.TABLE +
" ORDER BY " + LoyaltyCardDbGroups.ID + " COLLATE NOCASE ASC", null, null);
return res;
}
public List<Group> getGroups() {
Cursor data = getGroupCursor();
List<Group> groups = new ArrayList<>();
if (!data.moveToFirst()) {
return groups;
}
groups.add(Group.toGroup(data));
while (data.moveToNext()) {
groups.add(Group.toGroup(data));
}
return groups;
}
public Group getGroup(final String groupName)
{
SQLiteDatabase db = getReadableDatabase();
Cursor data = db.rawQuery("select * from " + LoyaltyCardDbGroups.TABLE +
" where " + LoyaltyCardDbGroups.ID + "=?", new String[]{groupName});
Group group = null;
if(data.getCount() == 1)
{
data.moveToFirst();
group = Group.toGroup(data);
}
data.close();
return group;
}
public int getGroupCount()
{
SQLiteDatabase db = getReadableDatabase();
Cursor data = db.rawQuery("SELECT Count(*) FROM " + LoyaltyCardDbGroups.TABLE, null);
int numItems = 0;
if(data.getCount() == 1)
{
data.moveToFirst();
numItems = data.getInt(0);
}
data.close();
return numItems;
}
public List<Integer> getGroupCardIds(final String groupName)
{
SQLiteDatabase db = getReadableDatabase();
Cursor data = db.rawQuery("SELECT " + LoyaltyCardDbIdsGroups.cardID +
" FROM " + LoyaltyCardDbIdsGroups.TABLE +
" WHERE " + LoyaltyCardDbIdsGroups.groupID + " =? ", new String[]{groupName});
List<Integer> cardIds = new ArrayList<>();
if (!data.moveToFirst()) {
return cardIds;
}
cardIds.add(data.getInt(0));
while (data.moveToNext()) {
cardIds.add(data.getInt(0));
}
data.close();
return cardIds;
}
public long insertGroup(final String name)
{
if (name.isEmpty()) return -1;
SQLiteDatabase db = getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbGroups.ID, name);
final long newId = db.insert(LoyaltyCardDbGroups.TABLE, null, contentValues);
return newId;
}
public boolean insertGroup(final SQLiteDatabase db, final String name)
{
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbGroups.ID, name);
final long newId = db.insert(LoyaltyCardDbGroups.TABLE, null, contentValues);
return (newId != -1);
}
public boolean updateGroup(final String groupName, final String newName)
{
if (newName.isEmpty()) return false;
SQLiteDatabase db = getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(LoyaltyCardDbGroups.ID, newName);
try {
int rowsUpdated = db.update(LoyaltyCardDbGroups.TABLE, contentValues,
LoyaltyCardDbGroups.ID + "=?",
new String[]{groupName});
return (rowsUpdated == 1);
} catch (android.database.sqlite.SQLiteConstraintException _e) {
return false;
}
}
public boolean deleteGroup(final String groupName)
{
SQLiteDatabase db = getWritableDatabase();
// Delete group
int rowsDeleted = db.delete(LoyaltyCardDbGroups.TABLE,
LoyaltyCardDbGroups.ID + " = ? ",
new String[]{groupName});
// And delete lookup table entries associated with this group
db.delete(LoyaltyCardDbIdsGroups.TABLE,
LoyaltyCardDbIdsGroups.groupID + " = ? ",
new String[]{groupName});
return (rowsDeleted == 1);
}
public int getGroupCardCount(final String groupName)
{
SQLiteDatabase db = getReadableDatabase();
Cursor data = db.rawQuery("SELECT Count(*) FROM " + LoyaltyCardDbIdsGroups.TABLE +
" where " + LoyaltyCardDbIdsGroups.groupID + "=?",
new String[]{groupName});
int numItems = 0;
if(data.getCount() == 1)
{
data.moveToFirst();
numItems = data.getInt(0);
}
data.close();
return numItems;
}
}

View File

@@ -1,20 +0,0 @@
package protect.card_locker;
import android.database.Cursor;
public class Group
{
public final String _id;
public Group(final String _id)
{
this._id = _id;
}
public static Group toGroup(Cursor cursor)
{
String _id = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.ID));
return new Group(_id);
}
}

View File

@@ -1,53 +0,0 @@
package protect.card_locker;
import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.TextView;
import protect.card_locker.preferences.Settings;
class GroupCursorAdapter extends CursorAdapter
{
Settings settings;
DBHelper db;
public GroupCursorAdapter(Context context, Cursor cursor)
{
super(context, cursor, 0);
settings = new Settings(context);
db = new DBHelper(context);
}
// The newView method is used to inflate a new view and return it,
// you don't bind any data to the view at this point.
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent)
{
return LayoutInflater.from(context).inflate(R.layout.group_layout, parent, false);
}
// The bindView method is used to bind all data to a given view
// such as setting the text on a TextView.
@Override
public void bindView(View view, Context context, Cursor cursor)
{
// Find fields to populate in inflated template
TextView nameField = (TextView) view.findViewById(R.id.name);
TextView countField = (TextView) view.findViewById(R.id.cardCount);
// Extract properties from cursor
Group group = Group.toGroup(cursor);
// Populate fields with extracted properties
nameField.setText(group._id);
countField.setText(String.format(context.getString(R.string.groupCardCount), db.getGroupCardCount(group._id)));
nameField.setTextSize(settings.getCardTitleListFontSize());
countField.setTextSize(settings.getCardNoteListFontSize());
}
}

View File

@@ -10,14 +10,15 @@ import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
@@ -27,21 +28,21 @@ import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
public class ImportExportActivity extends AppCompatActivity
{
private static final String TAG = "Catima";
private static final String TAG = "LoyaltyCardLocker";
private static final int PERMISSIONS_EXTERNAL_STORAGE = 1;
private static final int CHOOSE_EXPORT_LOCATION = 2;
private static final int CHOOSE_EXPORTED_FILE = 3;
private static final int CHOOSE_EXPORT_FILE = 2;
private ImportExportTask importExporter;
private final File sdcardDir = Environment.getExternalStorageDirectory();
private final File exportFile = new File(sdcardDir, "LoyaltyCardKeychain.csv");
@Override
protected void onCreate(Bundle savedInstanceState)
{
@@ -69,11 +70,6 @@ public class ImportExportActivity extends AppCompatActivity
PERMISSIONS_EXTERNAL_STORAGE);
}
// Check that there is a file manager available
final Intent intentCreateDocumentAction = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intentCreateDocumentAction.addCategory(Intent.CATEGORY_OPENABLE);
intentCreateDocumentAction.setType("text/csv");
intentCreateDocumentAction.putExtra(Intent.EXTRA_TITLE, "Catima.csv");
Button exportButton = findViewById(R.id.exportButton);
exportButton.setOnClickListener(new View.OnClickListener()
@@ -81,7 +77,7 @@ public class ImportExportActivity extends AppCompatActivity
@Override
public void onClick(View v)
{
chooseFileWithIntent(intentCreateDocumentAction, CHOOSE_EXPORT_LOCATION);
startExport();
}
});
@@ -90,13 +86,14 @@ public class ImportExportActivity extends AppCompatActivity
intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE);
intentGetContentAction.setType("*/*");
Button importFilesystem = findViewById(R.id.importOptionFilesystemButton);
importFilesystem.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
chooseFileWithIntent(intentGetContentAction, CHOOSE_EXPORTED_FILE);
chooseFileWithIntent(intentGetContentAction);
}
});
@@ -117,7 +114,7 @@ public class ImportExportActivity extends AppCompatActivity
@Override
public void onClick(View v)
{
chooseFileWithIntent(intentPickAction, CHOOSE_EXPORTED_FILE);
chooseFileWithIntent(intentPickAction);
}
});
@@ -128,6 +125,28 @@ public class ImportExportActivity extends AppCompatActivity
findViewById(R.id.importOptionApplicationExplanation).setVisibility(View.GONE);
importApplication.setVisibility(View.GONE);
}
// This option, to import from the fixed location, should always be present
Button importButton = findViewById(R.id.importOptionFixedButton);
importButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Uri uri = Uri.fromFile(exportFile);
try
{
FileInputStream stream = new FileInputStream(exportFile);
startImport(stream, uri);
}
catch(FileNotFoundException e)
{
Log.e(TAG, "Could not import file " + exportFile.getAbsolutePath(), e);
onImportComplete(false, uri);
}
}
});
}
private void startImport(final InputStream target, final Uri targetUri)
@@ -146,19 +165,19 @@ public class ImportExportActivity extends AppCompatActivity
importExporter.execute();
}
private void startExport(final OutputStream target, final Uri targetUri)
private void startExport()
{
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener()
{
@Override
public void onTaskComplete(boolean success)
{
onExportComplete(success, targetUri);
onExportComplete(success, exportFile);
}
};
importExporter = new ImportExportTask(ImportExportActivity.this,
DataFormat.CSV, target, listener);
DataFormat.CSV, exportFile, listener);
importExporter.execute();
}
@@ -226,9 +245,13 @@ public class ImportExportActivity extends AppCompatActivity
builder.setTitle(R.string.importFailedTitle);
}
int messageId = success ? R.string.importSuccessful : R.string.importFailed;
final String message = getResources().getString(messageId);
int messageId = success ? R.string.importedFrom : R.string.importFailed;
final String template = getResources().getString(messageId);
// Get the filename of the file being imported
String filename = path.toString();
final String message = String.format(template, filename);
builder.setMessage(message);
builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener()
{
@@ -242,7 +265,7 @@ public class ImportExportActivity extends AppCompatActivity
builder.create().show();
}
private void onExportComplete(boolean success, final Uri path)
private void onExportComplete(boolean success, final File path)
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
@@ -255,9 +278,10 @@ public class ImportExportActivity extends AppCompatActivity
builder.setTitle(R.string.exportFailedTitle);
}
int messageId = success ? R.string.exportSuccessful : R.string.exportFailed;
final String message = getResources().getString(messageId);
int messageId = success ? R.string.exportedTo : R.string.exportFailed;
final String template = getResources().getString(messageId);
final String message = String.format(template, path.getAbsolutePath());
builder.setMessage(message);
builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener()
{
@@ -277,8 +301,9 @@ public class ImportExportActivity extends AppCompatActivity
@Override
public void onClick(DialogInterface dialog, int which)
{
Uri outputUri = FileProvider.getUriForFile(ImportExportActivity.this, BuildConfig.APPLICATION_ID, path);
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, path);
sendIntent.putExtra(Intent.EXTRA_STREAM, outputUri);
sendIntent.setType("text/csv");
// set flag to give temporary permission to external app to use the FileProvider
@@ -320,11 +345,11 @@ public class ImportExportActivity extends AppCompatActivity
return false;
}
private void chooseFileWithIntent(Intent intent, int requestCode)
private void chooseFileWithIntent(Intent intent)
{
try
{
startActivityForResult(intent, requestCode);
startActivityForResult(intent, CHOOSE_EXPORT_FILE);
}
catch (ActivityNotFoundException e)
{
@@ -337,7 +362,7 @@ public class ImportExportActivity extends AppCompatActivity
{
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK || (requestCode != CHOOSE_EXPORT_LOCATION && requestCode != CHOOSE_EXPORTED_FILE))
if (resultCode != RESULT_OK || requestCode != CHOOSE_EXPORT_FILE)
{
Log.w(TAG, "Failed onActivityResult(), result=" + resultCode);
return;
@@ -352,48 +377,24 @@ public class ImportExportActivity extends AppCompatActivity
try
{
if (requestCode == CHOOSE_EXPORT_LOCATION)
{
OutputStream writer;
if (uri.getScheme() != null)
{
writer = getContentResolver().openOutputStream(uri);
}
else
{
writer = new FileOutputStream(new File(uri.toString()));
}
InputStream reader;
Log.e(TAG, "Starting file export with: " + uri.toString());
startExport(writer, uri);
if(uri.getScheme() != null)
{
reader = getContentResolver().openInputStream(uri);
}
else
{
InputStream reader;
if(uri.getScheme() != null)
{
reader = getContentResolver().openInputStream(uri);
}
else
{
reader = new FileInputStream(new File(uri.toString()));
}
Log.e(TAG, "Starting file export with: " + uri.toString());
startImport(reader, uri);
reader = new FileInputStream(new File(uri.toString()));
}
Log.e(TAG, "Starting file import with: " + uri.toString());
startImport(reader, uri);
}
catch(FileNotFoundException e)
{
Log.e(TAG, "Failed to import/export file: " + uri.toString(), e);
if (requestCode == CHOOSE_EXPORT_LOCATION)
{
onExportComplete(false, uri);
}
else
{
onImportComplete(false, uri);
}
Log.e(TAG, "Failed to import file: " + uri.toString(), e);
onImportComplete(false, uri);
}
}
}

View File

@@ -4,23 +4,27 @@ import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
class ImportExportTask extends AsyncTask<Void, Void, Boolean>
{
private static final String TAG = "Catima";
private static final String TAG = "LoyaltyCardLocker";
private Activity activity;
private boolean doImport;
private DataFormat format;
private OutputStream outputStream;
private File target;
private InputStream inputStream;
private TaskCompleteListener listener;
@@ -29,14 +33,14 @@ class ImportExportTask extends AsyncTask<Void, Void, Boolean>
/**
* Constructor which will setup a task for exporting to the given file
*/
ImportExportTask(Activity activity, DataFormat format, OutputStream output,
ImportExportTask(Activity activity, DataFormat format, File target,
TaskCompleteListener listener)
{
super();
this.activity = activity;
this.doImport = false;
this.format = format;
this.outputStream = output;
this.target = target;
this.listener = listener;
}
@@ -74,13 +78,14 @@ class ImportExportTask extends AsyncTask<Void, Void, Boolean>
return result;
}
private boolean performExport(OutputStream stream, DBHelper db)
private boolean performExport(File exportFile, DBHelper db)
{
boolean result = false;
try
{
OutputStreamWriter writer = new OutputStreamWriter(stream, Charset.forName("UTF-8"));
FileOutputStream fileWriter = new FileOutputStream(exportFile);
OutputStreamWriter writer = new OutputStreamWriter(fileWriter, Charset.forName("UTF-8"));
result = MultiFormatExporter.exportData(db, writer, format);
writer.close();
}
@@ -89,7 +94,7 @@ class ImportExportTask extends AsyncTask<Void, Void, Boolean>
Log.e(TAG, "Unable to export file", e);
}
Log.i(TAG, "Export result: " + result);
Log.i(TAG, "Export of '" + exportFile.getAbsolutePath() + "' result: " + result);
return result;
}
@@ -122,7 +127,7 @@ class ImportExportTask extends AsyncTask<Void, Void, Boolean>
}
else
{
result = performExport(outputStream, db);
result = performExport(target, db);
}
return result;

View File

@@ -10,30 +10,23 @@ public class ImportURIHelper {
private static final String NOTE = DBHelper.LoyaltyCardDbIds.NOTE;
private static final String CARD_ID = DBHelper.LoyaltyCardDbIds.CARD_ID;
private static final String BARCODE_TYPE = DBHelper.LoyaltyCardDbIds.BARCODE_TYPE;
private static final String HEADER_COLOR = DBHelper.LoyaltyCardDbIds.HEADER_COLOR;
private static final String HEADER_TEXT_COLOR = DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR;
private final Context context;
private final String host;
private final String path;
private final String oldHost;
private final String oldPath;
private final String shareText;
public ImportURIHelper(Context context) {
this.context = context;
host = context.getResources().getString(R.string.intent_import_card_from_url_host);
path = context.getResources().getString(R.string.intent_import_card_from_url_path_prefix);
oldHost = "brarcher.github.io";
oldPath = "/loyalty-card-locker/share";
shareText = context.getResources().getString(R.string.intent_import_card_from_url_share_text);
}
private boolean isImportUri(Uri uri) {
return (uri.getHost().equals(host) && uri.getPath().equals(path)) || (uri.getHost().equals(oldHost) && uri.getPath().equals(oldPath));
return uri.getHost().equals(host) && uri.getPath().equals(path);
}
public LoyaltyCard parse(Uri uri) throws InvalidObjectException {
@@ -50,8 +43,6 @@ public class ImportURIHelper {
String note = uri.getQueryParameter(NOTE);
String cardId = uri.getQueryParameter(CARD_ID);
String barcodeType = uri.getQueryParameter(BARCODE_TYPE);
if (store == null || note == null || cardId == null || barcodeType == null) throw new InvalidObjectException("Not a valid import URI");
String unparsedHeaderColor = uri.getQueryParameter(HEADER_COLOR);
if(unparsedHeaderColor != null)
{
@@ -62,8 +53,7 @@ public class ImportURIHelper {
{
headerTextColor = Integer.parseInt(unparsedHeaderTextColor);
}
return new LoyaltyCard(-1, store, note, cardId, barcodeType, headerColor, headerTextColor, 0);
return new LoyaltyCard(-1, store, note, cardId, barcodeType, headerColor, headerTextColor);
} catch (NullPointerException | NumberFormatException ex) {
throw new InvalidObjectException("Not a valid import URI");
}
@@ -87,7 +77,7 @@ public class ImportURIHelper {
{
uriBuilder.appendQueryParameter(HEADER_TEXT_COLOR, loyaltyCard.headerTextColor.toString());
}
//StarStatus will not be exported
return uriBuilder.build();
}

View File

@@ -1,7 +1,6 @@
package protect.card_locker;
import android.database.Cursor;
import androidx.annotation.Nullable;
public class LoyaltyCard
@@ -18,11 +17,8 @@ public class LoyaltyCard
@Nullable
public final Integer headerTextColor;
public final int starStatus;
public LoyaltyCard(final int id, final String store, final String note, final String cardId,
final String barcodeType, final Integer headerColor, final Integer headerTextColor,
final int starStatus)
final String barcodeType, final Integer headerColor, final Integer headerTextColor)
{
this.id = id;
this.store = store;
@@ -31,7 +27,6 @@ public class LoyaltyCard
this.barcodeType = barcodeType;
this.headerColor = headerColor;
this.headerTextColor = headerTextColor;
this.starStatus = starStatus;
}
public static LoyaltyCard toLoyaltyCard(Cursor cursor)
@@ -41,8 +36,6 @@ public class LoyaltyCard
String note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE));
String cardId = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.CARD_ID));
String barcodeType = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_TYPE));
int starred = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STAR_STATUS));
int headerColorColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.HEADER_COLOR);
int headerTextColorColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR);
@@ -60,6 +53,6 @@ public class LoyaltyCard
headerTextColor = cursor.getInt(headerTextColorColumn);
}
return new LoyaltyCard(id, store, note, cardId, barcodeType, headerColor, headerTextColor, starred);
return new LoyaltyCard(id, store, note, cardId, barcodeType, headerColor, headerTextColor);
}
}

View File

@@ -2,27 +2,25 @@ package protect.card_locker;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import protect.card_locker.preferences.Settings;
class LoyaltyCardCursorAdapter extends CursorAdapter
{
Settings settings;
boolean darkModeEnabled;
DBHelper dbHelper;
public LoyaltyCardCursorAdapter(Context context, Cursor cursor)
{
super(context, cursor, 0);
settings = new Settings(context);
darkModeEnabled= MainActivity.isDarkModeEnabled(context);
dbHelper = new DBHelper(context);
}
// The newView method is used to inflate a new view and return it,
@@ -40,27 +38,31 @@ class LoyaltyCardCursorAdapter extends CursorAdapter
{
// Find fields to populate in inflated template
ImageView thumbnail = view.findViewById(R.id.thumbnail);
TextView storeField = view.findViewById(R.id.store);
TextView noteField = view.findViewById(R.id.note);
ImageView star = view.findViewById(R.id.star);
if(darkModeEnabled)
{
star.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
}
TextView storeField = (TextView) view.findViewById(R.id.store);
TextView noteField = (TextView) view.findViewById(R.id.note);
// Extract properties from cursor
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(cursor);
// Get amount of cards for this store
int cardCount = dbHelper.getLoyaltyCardsForStore(loyaltyCard.store).size();
// Populate fields with extracted properties
storeField.setText(loyaltyCard.store);
storeField.setTextSize(settings.getCardTitleListFontSize());
if(!loyaltyCard.note.isEmpty())
if(cardCount > 1 || !loyaltyCard.note.isEmpty())
{
noteField.setVisibility(View.VISIBLE);
noteField.setText(loyaltyCard.note);
if(cardCount > 1)
{
noteField.setText(context.getResources().getString(R.string.cardCount, cardCount));
}
else
{
noteField.setText(loyaltyCard.note);
}
noteField.setTextSize(settings.getCardNoteListFontSize());
}
else
@@ -68,9 +70,6 @@ class LoyaltyCardCursorAdapter extends CursorAdapter
noteField.setVisibility(View.GONE);
}
if (loyaltyCard.starStatus!=0) star.setVisibility(View.VISIBLE);
else star.setVisibility(View.GONE);
int tileLetterFontSize = context.getResources().getDimensionPixelSize(R.dimen.tileLetterFontSize);
int pixelSize = context.getResources().getDimensionPixelSize(R.dimen.cardThumbnailSize);

View File

@@ -9,8 +9,6 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import androidx.appcompat.app.ActionBar;
@@ -35,19 +33,17 @@ import com.jaredrummler.android.colorpicker.ColorPickerDialog;
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;
import java.io.InvalidObjectException;
import java.util.ArrayList;
import java.util.List;
public class LoyaltyCardEditActivity extends AppCompatActivity
{
private static final String TAG = "Catima";
private static final String TAG = "CardLocker";
protected static final String NO_BARCODE = "_NO_BARCODE_";
protected static final int SELECT_BARCODE_REQUEST = 1;
FloatingActionButton fabSave;
EditText storeFieldEdit;
EditText noteFieldEdit;
ChipGroup groupsChips;
ImageView headingColorSample;
Button headingColorSelectButton;
ImageView headingStoreTextColorSample;
@@ -65,6 +61,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
int loyaltyCardId;
boolean updateLoyaltyCard;
String loyaltyCardStorePrefill = "";
Uri importLoyaltyCardUri = null;
Integer headingColorValue = null;
Integer headingStoreTextColorValue = null;
@@ -77,6 +74,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
final Bundle b = intent.getExtras();
loyaltyCardId = b != null ? b.getInt("id") : 0;
updateLoyaltyCard = b != null && b.getBoolean("update", false);
loyaltyCardStorePrefill = b != null ? b.getString("store", "") : "";
importLoyaltyCardUri = intent.getData();
Log.d(TAG, "View activity: id=" + loyaltyCardId
@@ -102,9 +100,9 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
db = new DBHelper(this);
importUriHelper = new ImportURIHelper(this);
fabSave = findViewById(R.id.fabSave);
storeFieldEdit = findViewById(R.id.storeNameEdit);
noteFieldEdit = findViewById(R.id.noteEdit);
groupsChips = findViewById(R.id.groupChips);
headingColorSample = findViewById(R.id.headingColorSample);
headingColorSelectButton = findViewById(R.id.headingColorSelectButton);
headingStoreTextColorSample = findViewById(R.id.headingStoreTextColorSample);
@@ -112,7 +110,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
cardIdFieldView = findViewById(R.id.cardIdView);
cardIdDivider = findViewById(R.id.cardIdDivider);
cardIdTableRow = findViewById(R.id.cardIdTableRow);
barcodeTypeField = findViewById(R.id.barcodeTypeView);
barcodeTypeField = findViewById(R.id.barcodeType);
barcodeImage = findViewById(R.id.barcode);
barcodeImageLayout = findViewById(R.id.barcodeLayout);
barcodeCaptureLayout = findViewById(R.id.barcodeCaptureLayout);
@@ -143,6 +141,14 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
Log.i(TAG, "To view card: " + loyaltyCardId);
fabSave.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view) {
doSave();
}
});
if(updateLoyaltyCard)
{
final LoyaltyCard loyaltyCard = db.getLoyaltyCard(loyaltyCardId);
@@ -171,7 +177,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
if(barcodeTypeField.getText().length() == 0)
{
barcodeTypeField.setText(loyaltyCard.barcodeType.isEmpty() ? LoyaltyCardEditActivity.NO_BARCODE : loyaltyCard.barcodeType);
barcodeTypeField.setText(loyaltyCard.barcodeType);
}
if(headingColorValue == null)
@@ -216,41 +222,12 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
else
{
setTitle(R.string.addCardTitle);
hideBarcode();
}
if(groupsChips.getChildCount() == 0)
// Set prefill values if nothing is set
if(storeFieldEdit.getText().length() == 0 && !loyaltyCardStorePrefill.isEmpty())
{
List<Group> existingGroups = db.getGroups();
List<Group> loyaltyCardGroups = db.getLoyaltyCardGroups(loyaltyCardId);
View groupsView = findViewById(R.id.groupsView);
View groupsTableRow = findViewById(R.id.groupsTableRow);
if (existingGroups.isEmpty()) {
groupsView.setVisibility(View.GONE);
groupsTableRow.setVisibility(View.GONE);
} else {
groupsView.setVisibility(View.VISIBLE);
groupsTableRow.setVisibility(View.VISIBLE);
}
for (Group group : db.getGroups()) {
Chip chip = (Chip) getLayoutInflater().inflate(R.layout.layout_chip_choice, groupsChips, false);
chip.setText(group._id);
chip.setTag(group);
chip.setChecked(false);
for (Group loyaltyCardGroup : loyaltyCardGroups) {
if (loyaltyCardGroup._id.equals(group._id)) {
chip.setChecked(true);
break;
}
}
groupsChips.addView(chip);
}
storeFieldEdit.setText(loyaltyCardStorePrefill);
}
if(headingColorValue == null)
@@ -273,9 +250,9 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
if(cardIdFieldView.getText().length() > 0 && barcodeTypeField.getText().length() > 0)
{
if(barcodeTypeField.getText().toString().equals(NO_BARCODE))
if(barcodeTypeField.getText().equals(NO_BARCODE))
{
hideBarcode();
barcodeImageLayout.setVisibility(View.GONE);
}
else
{
@@ -314,7 +291,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
new BarcodeImageWriterTask(barcodeImage, cardIdString, format).execute();
}
showBarcode();
barcodeImageLayout.setVisibility(View.VISIBLE);
}
}
@@ -366,14 +343,6 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
cardIdTableRow.setVisibility(View.GONE);
enterButton.setText(R.string.enterCard);
}
FloatingActionButton saveButton = findViewById(R.id.fabSave);
saveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doSave();
}
});
}
class ColorSelectListener implements View.OnClickListener
@@ -444,25 +413,16 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
return;
}
List<Group> selectedGroups = new ArrayList<>();
for (Integer chipId : groupsChips.getCheckedChipIds()) {
Chip chip = groupsChips.findViewById(chipId);
selectedGroups.add((Group) chip.getTag());
}
if(updateLoyaltyCard)
{ //update of "starStatus" not necessary, since it cannot be changed in this activity (only in ViewActivity)
{
db.updateLoyaltyCard(loyaltyCardId, store, note, cardId, barcodeType, headingColorValue, headingStoreTextColorValue);
Log.i(TAG, "Updated " + loyaltyCardId + " to " + cardId);
}
else
{
loyaltyCardId = (int)db.insertLoyaltyCard(store, note, cardId, barcodeType, headingColorValue, headingStoreTextColorValue, 0);
loyaltyCardId = (int)db.insertLoyaltyCard(store, note, cardId, barcodeType, headingColorValue, headingStoreTextColorValue);
}
db.setLoyaltyCardGroups(loyaltyCardId, selectedGroups);
finish();
}
@@ -473,10 +433,6 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
{
getMenuInflater().inflate(R.menu.card_update_menu, menu);
}
else
{
getMenuInflater().inflate(R.menu.card_add_menu, menu);
}
return super.onCreateOptionsMenu(menu);
}
@@ -563,21 +519,10 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
TextView cardIdView = findViewById(R.id.cardIdView);
cardIdView.setText(contents);
final TextView barcodeTypeField = findViewById(R.id.barcodeType);
// Set special NO_BARCODE value to prevent onResume from overwriting it
barcodeTypeField.setText(format.isEmpty() ? LoyaltyCardEditActivity.NO_BARCODE : format);
onResume();
}
}
private void showBarcode() {
barcodeImageLayout.setVisibility(View.VISIBLE);
findViewById(R.id.barcodeTypeDivider).setVisibility(View.VISIBLE);
findViewById(R.id.barcodeTypeTableRow).setVisibility(View.VISIBLE);
}
private void hideBarcode() {
barcodeImageLayout.setVisibility(View.GONE);
findViewById(R.id.barcodeTypeDivider).setVisibility(View.GONE);
findViewById(R.id.barcodeTypeTableRow).setVisibility(View.GONE);
}
}

View File

@@ -1,5 +1,6 @@
package protect.card_locker;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
@@ -10,6 +11,8 @@ import android.os.Bundle;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.graphics.ColorUtils;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.view.GestureDetectorCompat;
import androidx.core.view.MotionEventCompat;
import androidx.core.widget.TextViewCompat;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
@@ -17,8 +20,10 @@ import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -29,15 +34,22 @@ import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.tabs.TabLayout;
import com.google.zxing.BarcodeFormat;
import java.util.List;
import protect.card_locker.preferences.Settings;
public class LoyaltyCardViewActivity extends AppCompatActivity
public class LoyaltyCardViewActivity extends AppCompatActivity implements GestureDetector.OnGestureListener
{
private static final String TAG = "Catima";
private static final String TAG = "CardLocker";
private static final double LUMINANCE_MIDPOINT = 0.5;
FloatingActionButton FabAdd;
TabLayout tabLayout;
TabLayout.OnTabSelectedListener onTabSelectedListener;
TextView cardIdFieldView;
TextView noteView;
View noteViewDivider;
@@ -46,6 +58,8 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
View collapsingToolbarLayout;
int loyaltyCardId;
LoyaltyCard loyaltyCard;
List<LoyaltyCard> storeCards;
GestureDetectorCompat gestureDetector;
boolean rotationEnabled;
DBHelper db;
ImportURIHelper importURIHelper;
@@ -54,7 +68,6 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
String cardIdString;
BarcodeFormat format;
boolean starred;
boolean backgroundNeedsDarkIcons;
boolean barcodeIsFullscreen = false;
ViewGroup.LayoutParams barcodeImageState;
@@ -104,6 +117,33 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
db = new DBHelper(this);
importURIHelper = new ImportURIHelper(this);
FabAdd = findViewById(R.id.fabAdd);
FabAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
Intent intent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle bundle = new Bundle();
bundle.putString("store", loyaltyCard.store);
intent.putExtras(bundle);
startActivity(intent);
finish();
}
});
tabLayout = findViewById(R.id.tabLayout);
onTabSelectedListener = new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
loyaltyCardId = storeCards.get(tab.getPosition()).id;
onResume();
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {}
@Override
public void onTabReselected(TabLayout.Tab tab) {}
};
cardIdFieldView = findViewById(R.id.cardIdView);
noteView = findViewById(R.id.noteView);
noteViewDivider = findViewById(R.id.noteViewDivider);
@@ -113,6 +153,23 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
rotationEnabled = true;
gestureDetector = new GestureDetectorCompat(this, this);
// Restore active card id after rotation
if(savedInstanceState != null)
{
loyaltyCardId = savedInstanceState.getInt("id");
onResume();
}
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save active card id before rotation
savedInstanceState.putInt("id", loyaltyCardId);
super.onSaveInstanceState(savedInstanceState);
// Allow making barcode fullscreen on tap
barcodeImage.setOnClickListener(new View.OnClickListener() {
@Override
@@ -174,6 +231,38 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
return;
}
storeCards = db.getLoyaltyCardsForStore(loyaltyCard.store);
tabLayout.removeOnTabSelectedListener(onTabSelectedListener);
tabLayout.removeAllTabs();
for(int i = 0; i < storeCards.size(); i++)
{
LoyaltyCard storeCard = storeCards.get(i);
// Use only first line of note
String loyaltyCardText = storeCard.note.split("\\r?\\n")[0].trim();
if(loyaltyCardText.isEmpty())
{
loyaltyCardText = String.valueOf(i + 1);
}
else if(loyaltyCardText.length() > 15)
{
// Shorten long notes
loyaltyCardText = loyaltyCardText.substring(0, 15).trim() + "";
}
tabLayout.addTab(tabLayout.newTab().setText(loyaltyCardText));
if(storeCard.id == loyaltyCardId)
{
tabLayout.getTabAt(i).select();
}
}
tabLayout.addOnTabSelectedListener(onTabSelectedListener);
if(tabLayout.getTabCount() > 1)
{
tabLayout.setVisibility(View.VISIBLE);
}
String formatString = loyaltyCard.barcodeType;
format = !formatString.isEmpty() ? BarcodeFormat.valueOf(formatString) : null;
cardIdString = loyaltyCard.cardId;
@@ -189,6 +278,8 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(noteView,
getResources().getInteger(R.integer.settings_card_note_min_font_size_sp)-1,
settings.getCardNoteFontSize(), 1, TypedValue.COMPLEX_UNIT_SP);
noteView.setVisibility(View.VISIBLE);
noteViewDivider.setVisibility(View.VISIBLE);
}
else
{
@@ -272,22 +363,8 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
}
else
{
findViewById(R.id.barcode).setVisibility(View.GONE);
findViewById(R.id.barcode).setVisibility(View.INVISIBLE);
}
FloatingActionButton editButton = findViewById(R.id.fabEdit);
editButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("id", loyaltyCardId);
bundle.putBoolean("update", true);
intent.putExtras(bundle);
startActivity(intent);
finish();
}
});
}
@Override
@@ -316,29 +393,12 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
item.setVisible(false);
}
loyaltyCard = db.getLoyaltyCard(loyaltyCardId);
starred = loyaltyCard.starStatus != 0;
menu.findItem(R.id.action_share).setIcon(getIcon(R.drawable.ic_share_white, backgroundNeedsDarkIcons));
menu.findItem(R.id.action_edit).setIcon(getIcon(R.drawable.ic_mode_edit_white_24dp, backgroundNeedsDarkIcons));
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
if (starred) {
menu.findItem(R.id.action_star_unstar).setIcon(getIcon(R.drawable.ic_starred_white, backgroundNeedsDarkIcons));
menu.findItem(R.id.action_star_unstar).setTitle(R.string.unstar);
}
else {
menu.findItem(R.id.action_star_unstar).setIcon(getIcon(R.drawable.ic_unstarred_white, backgroundNeedsDarkIcons));
menu.findItem(R.id.action_star_unstar).setTitle(R.string.star);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
@@ -354,6 +414,16 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
importURIHelper.startShareIntent(loyaltyCard);
return true;
case R.id.action_edit:
Intent intent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("id", loyaltyCardId);
bundle.putBoolean("update", true);
intent.putExtras(bundle);
startActivity(intent);
finish();
return true;
case R.id.action_lock_unlock:
if(rotationEnabled)
{
@@ -365,18 +435,11 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
}
rotationEnabled = !rotationEnabled;
return true;
case R.id.action_star_unstar:
starred = !starred;
db.updateLoyaltyCardStarStatus(loyaltyCardId, starred ? 1 : 0);
invalidateOptionsMenu();
return true;
}
return super.onOptionsItemSelected(item);
}
private void setOrientatonLock(MenuItem item, boolean lock)
{
if(lock)
@@ -390,10 +453,59 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
{
item.setIcon(getIcon(R.drawable.ic_lock_open_white_24dp, backgroundNeedsDarkIcons));
item.setTitle(R.string.lockScreen);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
}
// Gesture detection
@Override
public boolean onDown(MotionEvent motionEvent) {
return false;
}
@Override
public void onShowPress(MotionEvent motionEvent) {}
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
return false;
}
@Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
return false;
}
@Override
public void onLongPress(MotionEvent motionEvent) { }
@Override
public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
int currentTab = tabLayout.getSelectedTabPosition();
if (motionEvent1.getX() > motionEvent.getX())
{
// Swipe left
int nextTab = currentTab == 0 ? tabLayout.getTabCount() - 1 : currentTab - 1;
tabLayout.getTabAt(nextTab).select();
}
else
{
// Swipe right
int nextTab = currentTab < (tabLayout.getTabCount() - 1) ? currentTab + 1 : 0;
tabLayout.getTabAt(nextTab).select();
}
return true;
}
@Override
public boolean onTouchEvent(MotionEvent motionEvent)
{
gestureDetector.onTouchEvent(motionEvent);
return super.onTouchEvent(motionEvent);
}
/**
* When enabled, hides the status bar and moves the barcode to the top of the screen.
*
@@ -433,9 +545,6 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
// Move barcode to top
barcodeImage.setScaleType(ImageView.ScaleType.FIT_START);
// Prevent centering
barcodeImage.setAdjustViewBounds(false);
// Set current state
barcodeIsFullscreen = true;
}
@@ -460,9 +569,6 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
// Turn barcode back to normal
barcodeImage.setLayoutParams(barcodeImageState);
// Fix barcode centering
barcodeImage.setAdjustViewBounds(true);
// Set current state
barcodeIsFullscreen = false;
}

View File

@@ -2,10 +2,11 @@ package protect.card_locker;
import android.app.SearchManager;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ClipboardManager;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
@@ -13,6 +14,7 @@ import android.database.Cursor;
import android.os.Bundle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import android.util.Log;
@@ -26,23 +28,24 @@ import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.tabs.TabLayout;
import com.google.common.collect.ImmutableMap;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import protect.card_locker.intro.IntroActivity;
import protect.card_locker.preferences.SettingsActivity;
public class MainActivity extends AppCompatActivity
{
private static final String TAG = "Catima";
private static final String TAG = "LoyaltyCardLocker";
private static final int MAIN_REQUEST_CODE = 1;
private Menu menu;
private FloatingActionButton fabAdd;
protected String filter = "";
protected int selectedTab = 0;
@Override
protected void onCreate(Bundle savedInstanceState)
@@ -52,26 +55,22 @@ public class MainActivity extends AppCompatActivity
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
updateLoyaltyCardList(filter, null);
TabLayout groupsTabLayout = findViewById(R.id.groups);
groupsTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
fabAdd = findViewById(R.id.fabAdd);
fabAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
selectedTab = tab.getPosition();
updateLoyaltyCardList(filter, tab.getTag());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
public void onClick(View view) {
Intent i = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
startActivityForResult(i, MAIN_REQUEST_CODE);
}
});
updateLoyaltyCardList("");
SharedPreferences prefs = getSharedPreferences("protect.card_locker", MODE_PRIVATE);
if (prefs.getBoolean("firstrun", true)) {
startIntro();
prefs.edit().putBoolean("firstrun", false).commit();
}
}
@Override
@@ -87,31 +86,7 @@ public class MainActivity extends AppCompatActivity
}
}
TabLayout groupsTabLayout = findViewById(R.id.groups);
boolean hasReset = updateTabGroups(groupsTabLayout);
Object group = null;
if (groupsTabLayout.getTabCount() != 0) {
TabLayout.Tab tab = groupsTabLayout.getTabAt(0);
if (!hasReset) {
tab = groupsTabLayout.getTabAt(selectedTab);
}
groupsTabLayout.selectTab(tab);
group = tab.getTag();
}
updateLoyaltyCardList(filter, group);
FloatingActionButton addButton = findViewById(R.id.fabAdd);
addButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
startActivityForResult(i, MAIN_REQUEST_CODE);
}
});
updateLoyaltyCardList(filter);
}
@Override
@@ -147,31 +122,17 @@ public class MainActivity extends AppCompatActivity
if (!searchView.isIconified()) {
searchView.setIconified(true);
} else {
TabLayout groupsTabLayout = findViewById(R.id.groups);
if (groupsTabLayout.getVisibility() == View.VISIBLE && selectedTab != 0) {
selectedTab = 0;
groupsTabLayout.selectTab(groupsTabLayout.getTabAt(0));
} else {
super.onBackPressed();
}
super.onBackPressed();
}
}
private void updateLoyaltyCardList(String filterText, Object tag)
private void updateLoyaltyCardList(String filterText)
{
Group group = null;
if (tag != null) {
group = (Group) tag;
}
final ListView cardList = findViewById(R.id.list);
final TextView helpText = findViewById(R.id.helpText);
final TextView noMatchingCardsText = findViewById(R.id.noMatchingCardsText);
final DBHelper db = new DBHelper(this);
Cursor cardCursor = db.getLoyaltyCardCursor(filterText, group);
if(db.getLoyaltyCardCount() > 0)
{
// We want the cardList to be visible regardless of the filtered match count
@@ -179,7 +140,7 @@ public class MainActivity extends AppCompatActivity
// the keyboard
cardList.setVisibility(View.VISIBLE);
helpText.setVisibility(View.GONE);
if(cardCursor.getCount() > 0)
if(db.getLoyaltyCardCount(filterText) > 0)
{
noMatchingCardsText.setVisibility(View.GONE);
}
@@ -195,6 +156,8 @@ public class MainActivity extends AppCompatActivity
noMatchingCardsText.setVisibility(View.GONE);
}
Cursor cardCursor = db.getOneLoyaltyCardPerStoreCursor(filterText);
final LoyaltyCardCursorAdapter adapter = new LoyaltyCardCursorAdapter(this, cardCursor);
cardList.setAdapter(adapter);
@@ -221,53 +184,6 @@ public class MainActivity extends AppCompatActivity
});
}
public boolean updateTabGroups(TabLayout groupsTabLayout)
{
final DBHelper db = new DBHelper(this);
List<Group> newGroups = db.getGroups();
if (newGroups.size() == 0) {
groupsTabLayout.removeAllTabs();
groupsTabLayout.setVisibility(View.GONE);
return true;
}
// -1 because there is an "All" tab
boolean isChanged = groupsTabLayout.getTabCount() - 1 != newGroups.size();
if (!isChanged) {
for (int i = 0; i < newGroups.size(); i++) {
if (!((Group) groupsTabLayout.getTabAt(i + 1).getTag())._id.equals(newGroups.get(i)._id)) {
isChanged = true;
break;
}
}
}
if (isChanged) {
groupsTabLayout.removeAllTabs();
TabLayout.Tab allTab = groupsTabLayout.newTab();
allTab.setText(R.string.all);
allTab.setTag(null);
groupsTabLayout.addTab(allTab);
for (Group group : newGroups) {
TabLayout.Tab tab = groupsTabLayout.newTab();
tab.setText(group._id);
tab.setTag(group);
groupsTabLayout.addTab(tab);
}
groupsTabLayout.setVisibility(View.VISIBLE);
return true;
}
return false;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)
{
@@ -288,20 +204,23 @@ public class MainActivity extends AppCompatActivity
Cursor cardCursor = (Cursor)listView.getItemAtPosition(info.position);
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cardCursor);
if(item.getItemId() == R.id.action_clipboard)
if(card != null)
{
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(card.store, card.cardId);
clipboard.setPrimaryClip(clip);
if(item.getItemId() == R.id.action_clipboard)
{
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(card.store, card.cardId);
clipboard.setPrimaryClip(clip);
Toast.makeText(this, R.string.copy_to_clipboard_toast, Toast.LENGTH_LONG).show();
return true;
}
else if(item.getItemId() == R.id.action_share)
{
final ImportURIHelper importURIHelper = new ImportURIHelper(this);
importURIHelper.startShareIntent(card);
return true;
Toast.makeText(this, R.string.copy_to_clipboard_toast, Toast.LENGTH_LONG).show();
return true;
}
else if(item.getItemId() == R.id.action_share)
{
final ImportURIHelper importURIHelper = new ImportURIHelper(this);
importURIHelper.startShareIntent(card);
return true;
}
}
return super.onContextItemSelected(item);
@@ -337,10 +256,7 @@ public class MainActivity extends AppCompatActivity
@Override
public boolean onQueryTextChange(String newText) {
filter = newText;
TabLayout groupsTabLayout = findViewById(R.id.groups);
updateLoyaltyCardList(newText, groupsTabLayout.getTabCount() > 0 ? groupsTabLayout.getTabAt(groupsTabLayout.getSelectedTabPosition()).getTag() : null);
updateLoyaltyCardList(newText);
return true;
}
});
@@ -354,13 +270,6 @@ public class MainActivity extends AppCompatActivity
{
int id = item.getItemId();
if (id == R.id.action_manage_groups)
{
Intent i = new Intent(getApplicationContext(), ManageGroupsActivity.class);
startActivityForResult(i, MAIN_REQUEST_CODE);
return true;
}
if(id == R.id.action_import_export)
{
Intent i = new Intent(getApplicationContext(), ImportExportActivity.class);
@@ -375,6 +284,12 @@ public class MainActivity extends AppCompatActivity
return true;
}
if(id == R.id.action_intro)
{
startIntro();
return true;
}
if(id == R.id.action_about)
{
displayAboutDialog();
@@ -433,7 +348,9 @@ public class MainActivity extends AppCompatActivity
// Set CSS for dark mode if dark mode
String css = "";
if(isDarkModeEnabled(this))
Configuration config = getResources().getConfiguration();
int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
if(currentNightMode == Configuration.UI_MODE_NIGHT_YES)
{
css = "<style>body {color:white; background-color:black;}</style>";
}
@@ -441,6 +358,7 @@ public class MainActivity extends AppCompatActivity
String html =
"<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />" +
css +
"<img src=\"file:///android_res/mipmap/ic_launcher.png\" alt=\"" + appName + "\"/>" +
"<h1>" +
String.format(getString(R.string.about_title_fmt),
"<a href=\"" + getString(R.string.app_webpage_url)) + "\">" +
@@ -453,12 +371,10 @@ public class MainActivity extends AppCompatActivity
"</p><p>" +
String.format(getString(R.string.app_revision_fmt),
"<a href=\"" + getString(R.string.app_revision_url) + "\">" +
"GitHub" +
getString(R.string.app_revision_url) +
"</a>") +
"</p><hr/><p>" +
String.format(getString(R.string.app_copyright_fmt), year) +
"</p><p>" +
getString(R.string.app_copyright_old) +
"</p><hr/><p>" +
getString(R.string.app_license) +
"</p><hr/><p>" +
@@ -480,11 +396,9 @@ public class MainActivity extends AppCompatActivity
.show();
}
protected static boolean isDarkModeEnabled(Context inputContext)
private void startIntro()
{
Configuration config = inputContext.getResources().getConfiguration();
int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
return (currentNightMode == Configuration.UI_MODE_NIGHT_YES);
Intent intent = new Intent(this, IntroActivity.class);
startActivityForResult(intent, MAIN_REQUEST_CODE);
}
}

View File

@@ -1,186 +0,0 @@
package protect.card_locker;
import android.content.DialogInterface;
import android.database.Cursor;
import android.os.Bundle;
import android.text.InputType;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
public class ManageGroupsActivity extends AppCompatActivity
{
private static final String TAG = "Catima";
private AlertDialog newGroupDialog;
private final DBHelper db = new DBHelper(this);
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.manage_groups_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null)
{
actionBar.setDisplayHomeAsUpEnabled(true);
}
newGroupDialog = createNewGroupDialog();
updateGroupList();
}
@Override
protected void onResume() {
super.onResume();
updateGroupList();
FloatingActionButton addButton = findViewById(R.id.fabAdd);
addButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
newGroupDialog.show();
}
});
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
private void updateGroupList()
{
final ListView groupList = findViewById(R.id.list);
final TextView helpText = findViewById(R.id.helpText);
final DBHelper db = new DBHelper(this);
if(db.getGroupCount() > 0)
{
groupList.setVisibility(View.VISIBLE);
helpText.setVisibility(View.GONE);
}
else
{
groupList.setVisibility(View.GONE);
helpText.setVisibility(View.VISIBLE);
}
Cursor groupCursor = db.getGroupCursor();
final GroupCursorAdapter adapter = new GroupCursorAdapter(this, groupCursor);
groupList.setAdapter(adapter);
registerForContextMenu(groupList);
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
int id = item.getItemId();
if (id == android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
public void editGroup(View view) {
LinearLayout parentRow = (LinearLayout) view.getParent();
TextView groupNameTextView = (TextView) parentRow.findViewById(R.id.name);
final String groupName = (String) groupNameTextView.getText();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.enter_group_name);
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setText(groupName);
builder.setView(input);
builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
db.updateGroup(groupName, input.getText().toString());
updateGroupList();
}
});
builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
public void deleteGroup(View view) {
LinearLayout parentRow = (LinearLayout) view.getParent();
TextView groupNameTextView = (TextView) parentRow.findViewById(R.id.name);
final String groupName = (String) groupNameTextView.getText();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.deleteConfirmationGroup);
builder.setMessage(groupName);
builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
db.deleteGroup(groupName);
updateGroupList();
}
});
builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
private AlertDialog createNewGroupDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.enter_group_name);
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);
builder.setView(input);
builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
db.insertGroup(input.getText().toString());
updateGroupList();
}
});
builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog dialog = builder.create();
return dialog;
}
}

View File

@@ -7,7 +7,7 @@ import java.io.OutputStreamWriter;
public class MultiFormatExporter
{
private static final String TAG = "Catima";
private static final String TAG = "LoyaltyCardLocker";
/**
* Attempts to export data to the output stream in the

View File

@@ -7,7 +7,7 @@ import java.io.InputStreamReader;
public class MultiFormatImporter
{
private static final String TAG = "Catima";
private static final String TAG = "LoyaltyCardLocker";
/**
* Attempts to import data from the input stream of the

View File

@@ -0,0 +1,33 @@
package protect.card_locker.intro;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import com.github.paolorotolo.appintro.AppIntro;
public class IntroActivity extends AppIntro
{
@Override
public void init(Bundle savedInstanceState)
{
addSlide(new IntroSlide1());
addSlide(new IntroSlide2());
addSlide(new IntroSlide3());
addSlide(new IntroSlide4());
addSlide(new IntroSlide5());
addSlide(new IntroSlide6());
}
@Override
public void onSkipPressed(Fragment fragment) {
finish();
}
@Override
public void onDonePressed(Fragment fragment) {
finish();
}
}

View File

@@ -0,0 +1,19 @@
package protect.card_locker.intro;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import protect.card_locker.R;
public class IntroSlide1 extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.intro1_layout, container, false);
return v;
}
}

View File

@@ -0,0 +1,20 @@
package protect.card_locker.intro;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import protect.card_locker.R;
public class IntroSlide2 extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.intro2_layout, container, false);
return v;
}
}

View File

@@ -0,0 +1,19 @@
package protect.card_locker.intro;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import protect.card_locker.R;
public class IntroSlide3 extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.intro3_layout, container, false);
return v;
}
}

View File

@@ -0,0 +1,19 @@
package protect.card_locker.intro;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import protect.card_locker.R;
public class IntroSlide4 extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.intro4_layout, container, false);
return v;
}
}

View File

@@ -0,0 +1,19 @@
package protect.card_locker.intro;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import protect.card_locker.R;
public class IntroSlide5 extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.intro5_layout, container, false);
return v;
}
}

View File

@@ -0,0 +1,19 @@
package protect.card_locker.intro;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import protect.card_locker.R;
public class IntroSlide6 extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.intro6_layout, container, false);
return v;
}
}

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 439 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 B

After

Width:  |  Height:  |  Size: 519 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 406 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 421 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 564 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 466 B

After

Width:  |  Height:  |  Size: 651 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 829 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 809 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 B

After

Width:  |  Height:  |  Size: 853 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 758 B

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,66 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="192dp"
android:height="192dp"
android:viewportWidth="50.8"
android:viewportHeight="50.8">
<path
android:pathData="M14.3354,20.1954l20.7318,-9.2304l5.7612,12.9398l-20.7318,9.2304z"
android:strokeLineJoin="miter"
android:strokeWidth="0.529167"
android:fillColor="#f0f0f0"
android:strokeColor="#c80000"/>
<path
android:pathData="M14.8755,10.9648l23.2041,10.3311l-6.8874,15.4694l-23.2041,-10.3311z"
android:strokeLineJoin="miter"
android:strokeWidth="0.529167"
android:fillColor="#f0f0f0"
android:strokeColor="#c80000"/>
<path
android:pathData="M16.5599,16.1348l26.5459,7.6119l-4.5489,15.8639l-26.5459,-7.6119z"
android:strokeLineJoin="round"
android:strokeWidth="1.5875"
android:fillColor="#c80000"
android:strokeColor="#c80000"
android:fillType="evenOdd"/>
<path
android:pathData="M12.011,15.4955h27.6157v16.5032h-27.6157z"
android:strokeLineJoin="round"
android:strokeWidth="1.5875"
android:fillColor="#ff0000"
android:strokeColor="#ff0000"
android:fillType="evenOdd"/>
<path
android:pathData="M7.8471,23.7471a4.3659,8.5899 0,1 0,8.7317 0a4.3659,8.5899 0,1 0,-8.7317 0z"
android:strokeLineJoin="round"
android:strokeWidth="0.91078"
android:fillColor="#ff0000"
android:strokeColor="#ff0000"/>
<path
android:pathData="m24.4983,25.781a1.6711,1.6711 0,0 1,-1.3809 1.6457,1.6711 1.6711,0 0,1 -1.8605,-1.0741"
android:strokeLineJoin="round"
android:strokeWidth="0.529167"
android:fillColor="#00000000"
android:strokeColor="#f0f0f0"
android:strokeLineCap="round"/>
<path
android:pathData="m27.7991,26.333a1.6711,1.6711 0,0 1,-1.8605 1.0741,1.6711 1.6711,0 0,1 -1.3809,-1.6457"
android:strokeLineJoin="round"
android:strokeWidth="0.529167"
android:fillColor="#00000000"
android:strokeColor="#f0f0f0"
android:strokeLineCap="round"/>
<path
android:pathData="m16.0606,22.271 l2.6458,-2.6458 2.6458,2.6458"
android:strokeLineJoin="miter"
android:strokeWidth="0.529167"
android:fillColor="#00000000"
android:strokeColor="#f0f0f0"
android:strokeLineCap="butt"/>
<path
android:pathData="m27.7023,22.271 l2.6458,-2.6458 2.6458,2.6458"
android:strokeLineJoin="miter"
android:strokeWidth="0.529167"
android:fillColor="#00000000"
android:strokeColor="#f0f0f0"
android:strokeLineCap="butt"/>
</vector>

View File

@@ -1,71 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="1.5307087"
android:scaleY="1.5307087"
android:translateX="15.12"
android:translateY="15.12">
<path
android:pathData="M14.3354,20.1954l20.7318,-9.2304l5.7612,12.9398l-20.7318,9.2304z"
android:strokeLineJoin="miter"
android:strokeWidth="0.529167"
android:fillColor="#f0f0f0"
android:strokeColor="#c80000"/>
<path
android:pathData="M14.8755,10.9648l23.2041,10.3311l-6.8874,15.4694l-23.2041,-10.3311z"
android:strokeLineJoin="miter"
android:strokeWidth="0.529167"
android:fillColor="#f0f0f0"
android:strokeColor="#c80000"/>
<path
android:pathData="M16.5599,16.1348l26.5459,7.6119l-4.5489,15.8639l-26.5459,-7.6119z"
android:strokeLineJoin="round"
android:strokeWidth="1.5875"
android:fillColor="#c80000"
android:strokeColor="#c80000"
android:fillType="evenOdd"/>
<path
android:pathData="M12.011,15.4955h27.6157v16.5032h-27.6157z"
android:strokeLineJoin="round"
android:strokeWidth="1.5875"
android:fillColor="#ff0000"
android:strokeColor="#ff0000"
android:fillType="evenOdd"/>
<path
android:pathData="M7.8471,23.7471a4.3659,8.5899 0,1 0,8.7317 0a4.3659,8.5899 0,1 0,-8.7317 0z"
android:strokeLineJoin="round"
android:strokeWidth="0.91078"
android:fillColor="#ff0000"
android:strokeColor="#ff0000"/>
<path
android:pathData="m24.4983,25.781a1.6711,1.6711 0,0 1,-1.3809 1.6457,1.6711 1.6711,0 0,1 -1.8605,-1.0741"
android:strokeLineJoin="round"
android:strokeWidth="0.529167"
android:fillColor="#00000000"
android:strokeColor="#f0f0f0"
android:strokeLineCap="round"/>
<path
android:pathData="m27.7991,26.333a1.6711,1.6711 0,0 1,-1.8605 1.0741,1.6711 1.6711,0 0,1 -1.3809,-1.6457"
android:strokeLineJoin="round"
android:strokeWidth="0.529167"
android:fillColor="#00000000"
android:strokeColor="#f0f0f0"
android:strokeLineCap="round"/>
<path
android:pathData="m16.0606,22.271 l2.6458,-2.6458 2.6458,2.6458"
android:strokeLineJoin="miter"
android:strokeWidth="0.529167"
android:fillColor="#00000000"
android:strokeColor="#f0f0f0"
android:strokeLineCap="butt"/>
<path
android:pathData="m27.7023,22.271 l2.6458,-2.6458 2.6458,2.6458"
android:strokeLineJoin="miter"
android:strokeWidth="0.529167"
android:fillColor="#00000000"
android:strokeColor="#f0f0f0"
android:strokeLineCap="butt"/>
</group>
</vector>

View File

@@ -70,236 +70,137 @@
android:layout_height="wrap_content"
android:text="@string/barcodeNoBarcode"
android:enabled="false" />
<LinearLayout android:orientation="vertical"
<LinearLayout android:orientation="horizontal"
android:padding="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/aztecBarcode"
android:contentDescription="@string/barcodeImageDescription"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/aztecBarcodeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10.0dip"
android:gravity="center"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:layout_weight="1.0" />
</LinearLayout>
<LinearLayout android:orientation="vertical"
<LinearLayout android:orientation="horizontal"
android:padding="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/code39Barcode"
android:contentDescription="@string/barcodeImageDescription"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/code39BarcodeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10.0dip"
android:gravity="center"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:layout_weight="1.0" />
</LinearLayout>
<LinearLayout android:orientation="vertical"
<LinearLayout android:orientation="horizontal"
android:padding="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/code128Barcode"
android:contentDescription="@string/barcodeImageDescription"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/code128BarcodeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10.0dip"
android:gravity="center"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:layout_weight="1.0" />
</LinearLayout>
<LinearLayout android:orientation="vertical"
<LinearLayout android:orientation="horizontal"
android:padding="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/codabarBarcode"
android:contentDescription="@string/barcodeImageDescription"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/codabarBarcodeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10.0dip"
android:gravity="center"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:layout_weight="1.0" />
</LinearLayout>
<LinearLayout android:orientation="vertical"
<LinearLayout android:orientation="horizontal"
android:padding="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/datamatrixBarcode"
android:contentDescription="@string/barcodeImageDescription"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/datamatrixBarcodeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10.0dip"
android:gravity="center"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:layout_weight="1.0" />
</LinearLayout>
<LinearLayout android:orientation="vertical"
<LinearLayout android:orientation="horizontal"
android:padding="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/ean8Barcode"
android:contentDescription="@string/barcodeImageDescription"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/ean8BarcodeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10.0dip"
android:gravity="center"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:layout_weight="1.0" />
</LinearLayout>
<LinearLayout android:orientation="vertical"
<LinearLayout android:orientation="horizontal"
android:padding="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/ean13Barcode"
android:contentDescription="@string/barcodeImageDescription"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/ean13BarcodeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10.0dip"
android:gravity="center"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:layout_weight="1.0" />
</LinearLayout>
<LinearLayout android:orientation="vertical"
<LinearLayout android:orientation="horizontal"
android:padding="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/itfBarcode"
android:contentDescription="@string/barcodeImageDescription"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/itfBarcodeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10.0dip"
android:gravity="center"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:layout_weight="1.0" />
</LinearLayout>
<LinearLayout android:orientation="vertical"
<LinearLayout android:orientation="horizontal"
android:padding="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/pdf417Barcode"
android:contentDescription="@string/barcodeImageDescription"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/pdf417BarcodeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10.0dip"
android:gravity="center"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:layout_weight="1.0" />
</LinearLayout>
<LinearLayout android:orientation="vertical"
<LinearLayout android:orientation="horizontal"
android:padding="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/qrcodeBarcode"
android:contentDescription="@string/barcodeImageDescription"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/qrcodeBarcodeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10.0dip"
android:gravity="center"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:layout_weight="1.0" />
</LinearLayout>
<LinearLayout android:orientation="vertical"
<LinearLayout android:orientation="horizontal"
android:padding="10.0dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="@dimen/barcode_disp_height"
android:layout_gravity="center_horizontal"
android:id="@+id/upcaBarcode"
android:contentDescription="@string/barcodeImageDescription"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/upcaBarcodeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10.0dip"
android:gravity="center"
android:textSize="@dimen/text_size_medium"
android:textStyle="bold"
android:layout_weight="1.0" />
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@@ -1,68 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:baselineAligned="false"
android:padding="@dimen/activity_margin">
<LinearLayout
android:orientation="vertical"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<LinearLayout
android:id="@+id/valueLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/storeNameTextSize"
android:textStyle="bold"/>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/cardCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textSize="@dimen/noteTextSize"/>
</LinearLayout>
<ImageButton
android:id="@+id/edit"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_marginLeft="@dimen/activity_margin"
android:src="@drawable/ic_mode_edit_white_24dp"
android:contentDescription="@string/edit"
app:tint="#000000"
android:onClick="editGroup" />
<ImageButton
android:id="@+id/delete"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_marginLeft="@dimen/activity_margin"
android:src="@drawable/ic_delete_white_24dp"
android:contentDescription="@string/delete"
app:tint="#000000"
android:onClick="deleteGroup"/>
</LinearLayout>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="protect.card_locker.MainActivity"
tools:showIn="@layout/main_activity">
<TextView
style="@style/AppTheme.TextView.NoData"
android:id="@+id/helpText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/noGroups"
android:visibility="gone"/>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/list"
android:visibility="gone"/>
</RelativeLayout>

View File

@@ -99,6 +99,7 @@
android:layout_marginTop="8dp"
android:text="@string/importOptionFilesystemButton" />
<View
android:id="@+id/dividerImportApplication"
android:layout_width="fill_parent"
@@ -128,6 +129,36 @@
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:text="@string/importOptionApplicationButton" />
<View
android:id="@+id/dividerImportFixed"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:layout_margin="16dp"
android:background="?android:attr/listDivider"/>
<TextView
android:id="@+id/importOptionFixedTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/text_size_large"
android:text="@string/importOptionFixedTitle"/>
<TextView
android:id="@+id/importOptionFixedExplanation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textSize="@dimen/text_size_medium"
android:text="@string/importOptionFixedExplanation"/>
<Button
android:id="@+id/importOptionFixedButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:text="@string/importOptionFixedButton" />
</LinearLayout>
</ScrollView>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#222222"
android:layout_weight="10"
android:id="@+id/main">
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:gravity="center"
android:paddingLeft="32dp"
android:layout_weight="3"
android:fontFamily="sans-serif-thin"
android:textColor="#ffffff"
android:paddingRight="32dp"
android:textSize="28sp"
android:text="@string/intro1Title"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:gravity="center"
android:layout_weight="5">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:src="@drawable/app_icon_intro"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="3"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#ffffff"
android:paddingLeft="64dp"
android:paddingRight="64dp"
android:textSize="16sp"
android:text="@string/intro1Description"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="64dp" />
</LinearLayout>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#222222"
android:layout_weight="10"
android:id="@+id/main">
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:gravity="center"
android:paddingLeft="32dp"
android:layout_weight="3"
android:fontFamily="sans-serif-thin"
android:textColor="#ffffff"
android:paddingRight="32dp"
android:textSize="28sp"
android:text="@string/intro2Title"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:gravity="center"
android:layout_weight="5">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:src="@drawable/intro2_image"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="3"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#ffffff"
android:paddingLeft="64dp"
android:paddingRight="64dp"
android:textSize="16sp"
android:text="@string/intro2Description"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="64dp" />
</LinearLayout>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#222222"
android:layout_weight="10"
android:id="@+id/main">
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:gravity="center"
android:paddingLeft="32dp"
android:layout_weight="3"
android:fontFamily="sans-serif-thin"
android:textColor="#ffffff"
android:paddingRight="32dp"
android:textSize="28sp"
android:text="@string/intro3Title"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:gravity="center"
android:layout_weight="5">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:src="@drawable/intro3_image"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="3"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#ffffff"
android:paddingLeft="64dp"
android:paddingRight="64dp"
android:textSize="16sp"
android:text="@string/intro3Description"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="64dp" />
</LinearLayout>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#222222"
android:layout_weight="10"
android:id="@+id/main">
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:gravity="center"
android:paddingLeft="32dp"
android:layout_weight="3"
android:fontFamily="sans-serif-thin"
android:textColor="#ffffff"
android:paddingRight="32dp"
android:textSize="28sp"
android:text="@string/intro4Title"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:gravity="center"
android:layout_weight="5">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:src="@drawable/intro4_image"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="3"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#ffffff"
android:paddingLeft="64dp"
android:paddingRight="64dp"
android:textSize="16sp"
android:text="@string/intro4Description"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="64dp" />
</LinearLayout>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#222222"
android:layout_weight="10"
android:id="@+id/main">
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:gravity="center"
android:paddingLeft="32dp"
android:layout_weight="3"
android:fontFamily="sans-serif-thin"
android:textColor="#ffffff"
android:paddingRight="32dp"
android:textSize="28sp"
android:text="@string/intro5Title"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:gravity="center"
android:layout_weight="5">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:src="@drawable/intro5_image"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="3"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#ffffff"
android:paddingLeft="64dp"
android:paddingRight="64dp"
android:textSize="16sp"
android:text="@string/intro5Description"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="64dp" />
</LinearLayout>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#222222"
android:layout_weight="10"
android:id="@+id/main">
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:gravity="center"
android:paddingLeft="32dp"
android:layout_weight="3"
android:fontFamily="sans-serif-thin"
android:textColor="#ffffff"
android:paddingRight="32dp"
android:textSize="28sp"
android:text="@string/intro6Title"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:gravity="center"
android:layout_weight="5">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:src="@drawable/app_icon_intro"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="3"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#ffffff"
android:paddingLeft="64dp"
android:paddingRight="64dp"
android:textSize="16sp"
android:text="@string/intro6Description"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="64dp" />
</LinearLayout>

View File

@@ -1,9 +0,0 @@
<com.google.android.material.chip.Chip xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingRight="8dp"
style="@style/Widget.MaterialComponents.Chip.Choice"
app:checkedIconVisible="true"
android:textAppearance="?android:attr/textAppearance" />

View File

@@ -145,62 +145,6 @@
android:background="@color/inputBorder" />
</TableRow>
<!-- Groups -->
<View
android:id="@+id/groupsView"
android:layout_height="@dimen/inputBorderThickness"
android:layout_width="match_parent"
android:background="@color/inputBorder"
android:visibility="gone"/>
<TableRow
android:id="@+id/groupsTableRow"
android:background="@color/inputBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
<View
android:gravity="start"
android:layout_height="match_parent"
android:layout_width="@dimen/inputBorderThickness"
android:background="@color/inputBorder" />
<RelativeLayout
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingRight="@dimen/inputPadding"
android:paddingEnd="@dimen/inputPadding">
<TextView
android:id="@+id/groupsField"
android:text="@string/groups"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:textSize="@dimen/inputSize"
android:padding="@dimen/inputPadding"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
/>
<com.google.android.material.chip.ChipGroup
android:id="@+id/groupChips"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:padding="@dimen/inputPadding"
android:textSize="@dimen/inputSize"
android:layout_toEndOf="@id/groupsField"
android:layout_toRightOf="@id/groupsField"
/>
</RelativeLayout>
<View
android:gravity="end"
android:layout_height="match_parent"
android:layout_width="@dimen/inputBorderThickness"
android:background="@color/inputBorder" />
</TableRow>
<!-- Store Header Background Color -->
<View
android:layout_height="@dimen/inputBorderThickness"
@@ -400,66 +344,16 @@
android:background="@color/inputBorder" />
</TableRow>
<!-- Barcode Type -->
<View
android:id="@+id/barcodeTypeDivider"
android:layout_height="@dimen/inputBorderThickness"
android:layout_width="match_parent"
android:background="@color/inputBorder" />
<TableRow
android:id="@+id/barcodeTypeTableRow"
android:background="@color/inputBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:gravity="start"
android:layout_height="match_parent"
android:layout_width="@dimen/inputBorderThickness"
android:background="@color/inputBorder" />
<RelativeLayout
android:orientation="horizontal"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingRight="@dimen/inputPadding"
android:paddingEnd="@dimen/inputPadding">
<TextView
android:id="@+id/barcodeTypeField"
android:text="@string/barcodeType"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:textSize="@dimen/inputSize"
android:padding="@dimen/inputPadding"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
/>
<TextView
android:id="@+id/barcodeTypeView"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:padding="@dimen/inputPadding"
android:textSize="@dimen/inputSize"
android:textIsSelectable="true"
android:layout_toEndOf="@id/barcodeTypeField"
android:layout_toRightOf="@id/barcodeTypeField"
/>
</RelativeLayout>
<View
android:gravity="end"
android:layout_height="match_parent"
android:layout_width="@dimen/inputBorderThickness"
android:background="@color/inputBorder" />
</TableRow>
<View
android:layout_height="@dimen/inputBorderThickness"
android:layout_width="match_parent"
android:background="@color/inputBorder" />
<TextView android:id="@+id/barcodeType"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone"/>
<LinearLayout android:orientation="horizontal"
android:padding="10.0dip"
android:layout_width="fill_parent"
@@ -488,13 +382,11 @@
android:layout_height="wrap_content"
android:id="@+id/barcodeCaptureLayout">
<Button android:id="@+id/captureButton"
android:layout_margin="@dimen/inputMargin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/capture"
android:layout_weight="1.0"/>
<Button android:id="@+id/enterButton"
android:layout_margin="@dimen/inputMargin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/enterCard"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -8,22 +8,14 @@
android:baselineAligned="false"
android:padding="@dimen/activity_margin">
<androidx.cardview.widget.CardView
<ImageView
android:id="@+id/thumbnail"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_marginEnd="@dimen/activity_margin"
android:layout_marginRight="@dimen/activity_margin"
app:cardCornerRadius="4dp"
app:cardElevation="0dp">
<ImageView
android:id="@+id/thumbnail"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:contentDescription="@string/thumbnailDescription"
android:src="@mipmap/ic_launcher"/>
</androidx.cardview.widget.CardView>
android:src="@mipmap/ic_launcher"
android:contentDescription="@string/thumbnailDescription"/>
<LinearLayout
android:orientation="vertical"
@@ -60,12 +52,5 @@
android:ellipsize="end"
android:textSize="@dimen/noteTextSize"/>
</LinearLayout>
<ImageView
android:id="@+id/star"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_marginLeft="@dimen/activity_margin"
android:src="@drawable/ic_starred_white"
android:tint="#000000"
android:contentDescription="@string/starImage"/>
</LinearLayout>

View File

@@ -9,12 +9,12 @@
>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabEdit"
android:id="@+id/fabAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:src="@drawable/ic_mode_edit_white_24dp"
android:contentDescription="@string/edit"
android:src="@drawable/ic_add_white_24dp"
android:contentDescription="@string/action_add"
android:layout_margin="16dp" />
<FrameLayout
@@ -44,12 +44,12 @@
android:layout_marginBottom="10.0dip"
android:layout_marginStart="15.0dip"
android:layout_marginEnd="15.0dip"
app:layout_constraintTop_toTopOf="parent"
android:padding="10.0dp"
android:background="#ffffff"
app:layout_constraintBottom_toTopOf="@+id/centerGuideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="@string/barcodeImageDescription"/>
<TextView
@@ -150,6 +150,15 @@
android:layout_height="?actionBarSize"
app:contentInsetStart="72.0dip"
app:layout_collapseMode="pin" />
<com.google.android.material.tabs.TabLayout
android:visibility="gone"
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:tabGravity="fill"
app:tabIndicatorAnimationDuration="0"
app:tabMode="scrollable"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -29,13 +29,6 @@
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
<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"/>

View File

@@ -1,36 +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.floatingactionbutton.FloatingActionButton
android:id="@+id/fabAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:src="@drawable/ic_add_white_24dp"
android:contentDescription="@string/action_add"
android:layout_margin="16dp" />
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
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"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/group_main"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

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