Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5960f03f9b | ||
|
|
b1df0c0baf | ||
|
|
bfb131c811 | ||
|
|
4580ee8017 | ||
|
|
d76a6d79d7 | ||
|
|
b38e035fb6 | ||
|
|
eeb41376c5 | ||
|
|
89f649e5ef | ||
|
|
4bde8f49b1 | ||
|
|
87c1bbdbf4 | ||
|
|
7029818789 | ||
|
|
b64c29bf96 | ||
|
|
24317f4d99 | ||
|
|
b9d3699038 | ||
|
|
ed3c9ceb50 | ||
|
|
0a938628cb | ||
|
|
5720da1581 | ||
|
|
5393903872 | ||
|
|
8e0a4b978d | ||
|
|
df21c2577d | ||
|
|
a7d5b6fa0c | ||
|
|
b49501e66a | ||
|
|
65d0f57358 | ||
|
|
927ac61912 | ||
|
|
fd2b84f318 | ||
|
|
ed4afed538 | ||
|
|
007427023b | ||
|
|
b4ff68eddb | ||
|
|
151b81daa7 | ||
|
|
c090af1c7d | ||
|
|
54a0f89821 | ||
|
|
f01058d5b8 | ||
|
|
e01c77681b | ||
|
|
c49ecdca56 | ||
|
|
b7672e5247 | ||
|
|
71777a74fd | ||
|
|
bebab039d7 | ||
|
|
588a573878 | ||
|
|
a9bbf8fb65 | ||
|
|
175135d695 | ||
|
|
9f08d07a6a | ||
|
|
07f50b1544 | ||
|
|
584064a4a2 | ||
|
|
484f357a82 | ||
|
|
e32b40a024 | ||
|
|
010b88d477 | ||
|
|
fe0bb7b870 | ||
|
|
925f780599 | ||
|
|
9492d206d9 | ||
|
|
a32415b4d2 | ||
|
|
5965b82251 | ||
|
|
a5650e6382 | ||
|
|
6befc99ccc | ||
|
|
0e124b2550 | ||
|
|
06a7db0e6d | ||
|
|
f2f56b06dd | ||
|
|
518f339c7a | ||
|
|
bbe6ec3741 | ||
|
|
18310fdd25 | ||
|
|
19bd64c48c | ||
|
|
c86819fc74 | ||
|
|
8edc9ce5fd | ||
|
|
a3a5a3a8db | ||
|
|
793247a48c | ||
|
|
2f86de4c1b | ||
|
|
0aa1804258 | ||
|
|
1c8ef34b8a | ||
|
|
3fd45af7d9 | ||
|
|
227af54de7 | ||
|
|
b89c5eb91c | ||
|
|
cecec15762 | ||
|
|
dc4a41088c | ||
|
|
b91d4c934a | ||
|
|
b8d4eaacad | ||
|
|
0a7d5d89cf | ||
|
|
7bbcc52ba6 |
@@ -1,4 +1,5 @@
|
||||
language: android
|
||||
sudo: true
|
||||
android:
|
||||
components:
|
||||
# Uncomment the lines below if you want to
|
||||
@@ -15,10 +16,6 @@ android:
|
||||
# Additional components
|
||||
- extra
|
||||
|
||||
# Specify at least one system image,
|
||||
# if you need to run emulator(s) during your tests
|
||||
- sys-img-x86-android-17
|
||||
|
||||
script: ./gradlew build lint findbugs test
|
||||
|
||||
after_failure:
|
||||
|
||||
69
CHANGELOG.md
Normal file
@@ -0,0 +1,69 @@
|
||||
## v0.8 (2016-11-22)
|
||||
|
||||
New features/improvements:
|
||||
- Screen brightness increased to its maximum when displaying a card, to help barcode scanners successfully capture the barcode. (https://github.com/brarcher/loyalty-card-locker/pull/54)
|
||||
- Add a delete confirmation when deleting a card. (https://github.com/brarcher/loyalty-card-locker/pull/55)
|
||||
- Add translations for German (https://github.com/brarcher/loyalty-card-locker/pull/57) and Czech (https://github.com/brarcher/loyalty-card-locker/pull/58).
|
||||
- Clarification change for Italian translation. (https://github.com/brarcher/loyalty-card-locker/pull/66)
|
||||
|
||||
## v0.7 (2016-07-14)
|
||||
|
||||
New features/improvements:
|
||||
- Long-click of a card brings up option to copy card ID to the clipboard. (https://github.com/brarcher/loyalty-card-locker/issues/49)
|
||||
|
||||
Bug fixes:
|
||||
- Back button on Input/Export view now works, moving user to main view
|
||||
|
||||
## v0.6 (2016-05-23)
|
||||
|
||||
New features/improvements:
|
||||
- Allow user to enter barcode manually. If a user elects to enter a barcode manually, a list of all valid and supported barcode images is displayed. The user then may select the barcode image which matches what the user wants. https://github.com/brarcher/loyalty-card-locker/issues/33, https://github.com/brarcher/loyalty-card-locker/pull/44
|
||||
|
||||
Bug fixes:
|
||||
- Resolve issue where some displayed barcodes were blurry. (https://github.com/brarcher/loyalty-card-locker/issues/37)
|
||||
|
||||
## v0.5 (2016-05-16)
|
||||
|
||||
New features/improvements:
|
||||
- An about dialog can be opened from the main screen, which gives details about the application and project on GitHub (https://github.com/brarcher/loyalty-card-locker/issues/19)
|
||||
- Allow loyalty card information to be imported from/exported to a CSV file in external storage (https://github.com/brarcher/loyalty-card-locker/issues/36 https://github.com/brarcher/loyalty-card-locker/issues/20)
|
||||
|
||||
## v0.4 (2016-04-09)
|
||||
|
||||
New features/improvements:
|
||||
- Dutch translation
|
||||
- Allow name field to be editable after adding loyalty card
|
||||
- Add an optional note field
|
||||
|
||||
Bug fixes:
|
||||
|
||||
- Resolve all issues identified by FindBugs and require all FindBugs issues be resolved prior to pull request acceptance
|
||||
|
||||
## v0.3 (2016-02-11)
|
||||
|
||||
- Now officially supports the following list of 1D and 2D barcodes:
|
||||
* AZTEC
|
||||
* CODABAR
|
||||
* CODE_39
|
||||
* CODE_128
|
||||
* DATA_MATRIX
|
||||
* EAN_8
|
||||
* EAN_13
|
||||
* ITF
|
||||
* PDF_417
|
||||
* QR_CODE
|
||||
* UPC_A
|
||||
- Generated barcodes are larger, easier to scan from a scanning device
|
||||
|
||||
## v0.2 (2016-02-07)
|
||||
|
||||
- Italian translations
|
||||
- Support for all 1D barcode types. (Originally only product 1D barcodes were supported)
|
||||
- Add required camera permission, which was initially missing.
|
||||
|
||||
|
||||
## v0.1 (2016-01-30)
|
||||
|
||||
- Ability to create/edit/delete loyalty cards
|
||||
- Capture barcode of loyalty card using a camera
|
||||
- Display captured barcode, for scanning at a store
|
||||
12
README.md
@@ -1,7 +1,7 @@
|
||||
# Loyalty Card Locker
|
||||
# Loyalty Card Keychain
|
||||
[](https://travis-ci.org/brarcher/loyalty-card-locker)
|
||||
|
||||
[](https://f-droid.org/repository/browse/?fdid=protect.card_locker "Loyalty Card Locker on F-Droid")
|
||||
[](https://f-droid.org/repository/browse/?fdid=protect.card_locker "Loyalty Card Keychain on F-Droid")
|
||||
|
||||
|
||||
Stores all of your store loyalty cards on your phone, removing the need to carry them around. Currently the following barcode types are supported:
|
||||
@@ -21,6 +21,14 @@ Stores all of your store loyalty cards on your phone, removing the need to carry
|
||||
If there is any interest in improving this project, kindly submit a pull request with
|
||||
proposed changes.
|
||||
|
||||
# Screenshots
|
||||
|
||||
[<img src="https://cloud.githubusercontent.com/assets/5264535/18036233/32fae9a6-6d33-11e6-81e4-55ba60e83d9b.png" width=250>](https://cloud.githubusercontent.com/assets/5264535/18036233/32fae9a6-6d33-11e6-81e4-55ba60e83d9b.png)
|
||||
[<img src="https://cloud.githubusercontent.com/assets/5264535/18036246/7ee5c7f0-6d33-11e6-90cf-d2b3ca5a94c7.png" width=250>](https://cloud.githubusercontent.com/assets/5264535/18036246/7ee5c7f0-6d33-11e6-90cf-d2b3ca5a94c7.png)
|
||||
|
||||
[<img src="https://cloud.githubusercontent.com/assets/5264535/18036258/bb19562e-6d33-11e6-856e-740e8785ad71.png" width=250>](https://cloud.githubusercontent.com/assets/5264535/18036258/bb19562e-6d33-11e6-856e-740e8785ad71.png)
|
||||
[<img src="https://cloud.githubusercontent.com/assets/5264535/18036269/0202baf8-6d34-11e6-9c17-449d5b348738.png" width=250>](https://cloud.githubusercontent.com/assets/5264535/18036269/0202baf8-6d34-11e6-9c17-449d5b348738.png)
|
||||
|
||||
# Building
|
||||
|
||||
To build, use the gradle wrapper scripts provided in the top level directory of the project. The following will
|
||||
|
||||
@@ -12,10 +12,10 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "protect.card_locker"
|
||||
minSdkVersion 17
|
||||
minSdkVersion 11
|
||||
targetSdkVersion 23
|
||||
versionCode 5
|
||||
versionName "0.5"
|
||||
versionCode 9
|
||||
versionName "0.9"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
@@ -40,6 +40,7 @@ dependencies {
|
||||
compile 'com.journeyapps:zxing-android-embedded:3.2.0@aar'
|
||||
compile 'com.google.zxing:core:3.2.1'
|
||||
compile 'org.apache.commons:commons-csv:1.2'
|
||||
compile group: 'com.google.guava', name: 'guava', version: '18.0'
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile "org.robolectric:robolectric:3.0"
|
||||
}
|
||||
|
||||
@@ -36,14 +36,18 @@
|
||||
android:name=".LoyaltyCardViewActivity"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:parentActivityName="protect.card_locker.MainActivity"/>
|
||||
android:windowSoftInputMode="stateHidden"/>
|
||||
<activity
|
||||
android:name=".BarcodeSelectorActivity"
|
||||
android:label="@string/selectBarcodeTitle"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:windowSoftInputMode="stateHidden"/>
|
||||
<activity
|
||||
android:name=".ImportExportActivity"
|
||||
android:label="@string/importExport"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:parentActivityName=".MainActivity"/>
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* This task will generate a barcode and load it into an ImageView.
|
||||
* Only a weak reference of the ImageView is kept, so this class will not
|
||||
* prevent the ImageView from being garbage collected.
|
||||
*/
|
||||
class BarcodeImageWriterTask extends AsyncTask<Void, Void, Bitmap>
|
||||
{
|
||||
private static final String TAG = "LoyaltyCardLocker";
|
||||
|
||||
private final WeakReference<ImageView> imageViewReference;
|
||||
private final String cardId;
|
||||
private final BarcodeFormat format;
|
||||
private final int imageHeight;
|
||||
private final int imageWidth;
|
||||
|
||||
public BarcodeImageWriterTask(ImageView imageView, String cardIdString,
|
||||
BarcodeFormat barcodeFormat)
|
||||
{
|
||||
// Use a WeakReference to ensure the ImageView can be garbage collected
|
||||
imageViewReference = new WeakReference<>(imageView);
|
||||
|
||||
cardId = cardIdString;
|
||||
format = barcodeFormat;
|
||||
imageHeight = imageView.getHeight();
|
||||
imageWidth = imageView.getWidth();
|
||||
}
|
||||
|
||||
public Bitmap doInBackground(Void... params)
|
||||
{
|
||||
MultiFormatWriter writer = new MultiFormatWriter();
|
||||
BitMatrix bitMatrix;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
bitMatrix = writer.encode(cardId, format, imageWidth, imageHeight, null);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
// Cast a wider net here and catch any exception, as there are some
|
||||
// cases where an encoder may fail if the data is invalid for the
|
||||
// barcode type. If this happens, we want to fail gracefully.
|
||||
throw new WriterException(e);
|
||||
}
|
||||
|
||||
final int WHITE = 0xFFFFFFFF;
|
||||
final int BLACK = 0xFF000000;
|
||||
|
||||
int bitMatrixWidth = bitMatrix.getWidth();
|
||||
int bitMatrixHeight = bitMatrix.getHeight();
|
||||
|
||||
int[] pixels = new int[bitMatrixWidth * bitMatrixHeight];
|
||||
|
||||
for (int y = 0; y < bitMatrixHeight; y++)
|
||||
{
|
||||
int offset = y * bitMatrixWidth;
|
||||
for (int x = 0; x < bitMatrixWidth; x++)
|
||||
{
|
||||
int color = bitMatrix.get(x, y) ? BLACK : WHITE;
|
||||
pixels[offset + x] = color;
|
||||
}
|
||||
}
|
||||
Bitmap bitmap = Bitmap.createBitmap(bitMatrixWidth, bitMatrixHeight,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
bitmap.setPixels(pixels, 0, bitMatrixWidth, 0, 0, bitMatrixWidth, bitMatrixHeight);
|
||||
|
||||
// Determine if the image needs to be scaled.
|
||||
// This is necessary because the datamatrix barcode generator
|
||||
// ignores the requested size and returns the smallest image necessary
|
||||
// to represent the barcode. If we let the ImageView scale the image
|
||||
// it will use bi-linear filtering, which results in a blurry barcode.
|
||||
// To avoid this, if scaling is needed do so without filtering.
|
||||
|
||||
int heightScale = imageHeight / bitMatrixHeight;
|
||||
int widthScale = imageWidth / bitMatrixHeight;
|
||||
int scalingFactor = Math.min(heightScale, widthScale);
|
||||
|
||||
if(scalingFactor > 1)
|
||||
{
|
||||
bitmap = Bitmap.createScaledBitmap(bitmap, bitMatrixWidth * scalingFactor, bitMatrixHeight * scalingFactor, false);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
catch (WriterException e)
|
||||
{
|
||||
Log.e(TAG, "Failed to generate barcode of type " + format + ": " + cardId, e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onPostExecute(Bitmap result)
|
||||
{
|
||||
Log.i(TAG, "Finished generating barcode image of type " + format + ": " + cardId);
|
||||
ImageView imageView = imageViewReference.get();
|
||||
if(imageView == null)
|
||||
{
|
||||
// The ImageView no longer exists, nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
imageView.setImageBitmap(result);
|
||||
|
||||
if(result != null)
|
||||
{
|
||||
Log.i(TAG, "Displaying barcode");
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.i(TAG, "Barcode generation failed, removing image from display");
|
||||
imageView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This activity is callable and will allow a user to enter
|
||||
* barcode data and generate all barcodes possible for
|
||||
* the data. The user may then select any barcode, where its
|
||||
* data and type will be returned to the caller.
|
||||
*/
|
||||
public class BarcodeSelectorActivity extends AppCompatActivity
|
||||
{
|
||||
private static final String TAG = "LoyaltyCardLocker";
|
||||
|
||||
// Result this activity will return
|
||||
public static final String BARCODE_CONTENTS = "contents";
|
||||
public static final String BARCODE_FORMAT = "format";
|
||||
|
||||
// These are all the barcode types that the zxing library
|
||||
// is able to generate a barcode for, and thus should be
|
||||
// the only barcodes which we should attempt to scan.
|
||||
public static final Collection<String> SUPPORTED_BARCODE_TYPES = Collections.unmodifiableList(
|
||||
Arrays.asList(
|
||||
BarcodeFormat.AZTEC.name(),
|
||||
BarcodeFormat.CODE_39.name(),
|
||||
BarcodeFormat.CODE_128.name(),
|
||||
BarcodeFormat.CODABAR.name(),
|
||||
BarcodeFormat.DATA_MATRIX.name(),
|
||||
BarcodeFormat.EAN_8.name(),
|
||||
BarcodeFormat.EAN_13.name(),
|
||||
BarcodeFormat.ITF.name(),
|
||||
BarcodeFormat.PDF_417.name(),
|
||||
BarcodeFormat.QR_CODE.name(),
|
||||
BarcodeFormat.UPC_A.name()
|
||||
));
|
||||
|
||||
private Map<String, Integer> barcodeViewMap;
|
||||
private LinkedList<AsyncTask> barcodeGeneratorTasks = new LinkedList<>();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.barcode_selector_activity);
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null)
|
||||
{
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
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 = (EditText) findViewById(R.id.cardId);
|
||||
cardId.addTextChangedListener(new TextWatcher()
|
||||
{
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after)
|
||||
{
|
||||
// Noting to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count)
|
||||
{
|
||||
Log.d(TAG, "Entered text: " + s);
|
||||
|
||||
// Stop any async tasks which may not have been started yet
|
||||
for(AsyncTask task : barcodeGeneratorTasks)
|
||||
{
|
||||
task.cancel(false);
|
||||
}
|
||||
barcodeGeneratorTasks.clear();
|
||||
|
||||
// Update barcodes
|
||||
for(String key : barcodeViewMap.keySet())
|
||||
{
|
||||
ImageView image = (ImageView)findViewById(barcodeViewMap.get(key));
|
||||
createBarcodeOption(image, key, s.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s)
|
||||
{
|
||||
// Noting to do
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createBarcodeOption(final ImageView image, final String formatType, final String cardId)
|
||||
{
|
||||
final BarcodeFormat format = BarcodeFormat.valueOf(formatType);
|
||||
if(format == null)
|
||||
{
|
||||
Log.w(TAG, "Unsupported barcode format: " + formatType);
|
||||
return;
|
||||
}
|
||||
|
||||
image.setImageBitmap(null);
|
||||
image.setVisibility(View.GONE);
|
||||
image.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
Log.d(TAG, "Selected barcode type " + formatType);
|
||||
Intent result = new Intent();
|
||||
result.putExtra(BARCODE_FORMAT, formatType);
|
||||
result.putExtra(BARCODE_CONTENTS, cardId);
|
||||
BarcodeSelectorActivity.this.setResult(RESULT_OK, result);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
if(image.getHeight() == 0)
|
||||
{
|
||||
// The size of the ImageView is not yet available as it has not
|
||||
// yet been drawn. Wait for it to be drawn so the size is available.
|
||||
image.getViewTreeObserver().addOnGlobalLayoutListener(
|
||||
new ViewTreeObserver.OnGlobalLayoutListener()
|
||||
{
|
||||
@Override
|
||||
public void onGlobalLayout()
|
||||
{
|
||||
Log.d(TAG, "Global layout finished, type: + " + formatType + ", width: " + image.getWidth());
|
||||
if (Build.VERSION.SDK_INT < 16)
|
||||
{
|
||||
image.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
image.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
}
|
||||
|
||||
Log.d(TAG, "Generating barcode for type " + formatType);
|
||||
BarcodeImageWriterTask task = new BarcodeImageWriterTask(image, cardId, format);
|
||||
barcodeGeneratorTasks.add(task);
|
||||
task.execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "Generating barcode for type " + formatType);
|
||||
BarcodeImageWriterTask task = new BarcodeImageWriterTask(image, cardId, format);
|
||||
barcodeGeneratorTasks.add(task);
|
||||
task.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
if (item.getItemId() == android.R.id.home)
|
||||
{
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,42 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class ImportExportActivity extends AppCompatActivity
|
||||
{
|
||||
private static final int PERMISSIONS_EXTERNAL_STORAGE_IMPORT = 1;
|
||||
private static final int PERMISSIONS_EXTERNAL_STORAGE_EXPORT = 2;
|
||||
private static final String TAG = "LoyaltyCardLocker";
|
||||
|
||||
ImportExportTask importExporter;
|
||||
private static final int PERMISSIONS_EXTERNAL_STORAGE = 1;
|
||||
private static final int CHOOSE_EXPORT_FILE = 2;
|
||||
|
||||
private ImportExportTask importExporter;
|
||||
|
||||
private final File sdcardDir = Environment.getExternalStorageDirectory();
|
||||
private final File exportFile = new File(sdcardDir, "LoyaltyCardLocker.csv");
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
@@ -33,25 +51,20 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
Button importButton = (Button)findViewById(R.id.importButton);
|
||||
importButton.setOnClickListener(new View.OnClickListener()
|
||||
// If the application does not have permissions to external
|
||||
// storage, as for it now
|
||||
|
||||
if (ContextCompat.checkSelfPermission(ImportExportActivity.this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
|
||||
ContextCompat.checkSelfPermission(ImportExportActivity.this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
if (ContextCompat.checkSelfPermission(ImportExportActivity.this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
startImport();
|
||||
}
|
||||
else
|
||||
{
|
||||
ActivityCompat.requestPermissions(ImportExportActivity.this,
|
||||
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||
PERMISSIONS_EXTERNAL_STORAGE_IMPORT);
|
||||
}
|
||||
}
|
||||
});
|
||||
ActivityCompat.requestPermissions(ImportExportActivity.this,
|
||||
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
PERMISSIONS_EXTERNAL_STORAGE);
|
||||
}
|
||||
|
||||
|
||||
Button exportButton = (Button)findViewById(R.id.exportButton);
|
||||
exportButton.setOnClickListener(new View.OnClickListener()
|
||||
@@ -59,56 +72,120 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
if (ContextCompat.checkSelfPermission(ImportExportActivity.this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
startExport();
|
||||
}
|
||||
else
|
||||
{
|
||||
ActivityCompat.requestPermissions(ImportExportActivity.this,
|
||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
PERMISSIONS_EXTERNAL_STORAGE_EXPORT);
|
||||
}
|
||||
startExport();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Check that there is an activity that can bring up a file chooser
|
||||
final Intent intentPickAction = new Intent(Intent.ACTION_PICK);
|
||||
intentPickAction.setData(Uri.parse("file://"));
|
||||
|
||||
Button importFilesystem = (Button) findViewById(R.id.importOptionFilesystemButton);
|
||||
importFilesystem.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
chooseFileWithIntent(intentPickAction);
|
||||
}
|
||||
});
|
||||
|
||||
if(isCallable(getApplicationContext(), intentPickAction) == false)
|
||||
{
|
||||
findViewById(R.id.dividerImportFilesystem).setVisibility(View.GONE);
|
||||
findViewById(R.id.importOptionFilesystemTitle).setVisibility(View.GONE);
|
||||
findViewById(R.id.importOptionFilesystemExplanation).setVisibility(View.GONE);
|
||||
importFilesystem.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
||||
// Check that there is an application that can find content
|
||||
final Intent intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intentGetContentAction.setType("*/*");
|
||||
|
||||
Button importApplication = (Button) findViewById(R.id.importOptionApplicationButton);
|
||||
importApplication.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
chooseFileWithIntent(intentGetContentAction);
|
||||
}
|
||||
});
|
||||
|
||||
if(isCallable(getApplicationContext(), intentGetContentAction) == false)
|
||||
{
|
||||
findViewById(R.id.dividerImportApplication).setVisibility(View.GONE);
|
||||
findViewById(R.id.importOptionApplicationTitle).setVisibility(View.GONE);
|
||||
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 = (Button)findViewById(R.id.importOptionFixedButton);
|
||||
importButton.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
startImport(exportFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void startImport()
|
||||
private void startImport(File target)
|
||||
{
|
||||
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener()
|
||||
{
|
||||
@Override
|
||||
public void onTaskComplete(boolean success, File file)
|
||||
{
|
||||
onImportComplete(success, file);
|
||||
}
|
||||
};
|
||||
|
||||
importExporter = new ImportExportTask(ImportExportActivity.this,
|
||||
true, DataFormat.CSV);
|
||||
true, DataFormat.CSV, target, listener);
|
||||
importExporter.execute();
|
||||
}
|
||||
|
||||
private void startExport()
|
||||
{
|
||||
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener()
|
||||
{
|
||||
@Override
|
||||
public void onTaskComplete(boolean success, File file)
|
||||
{
|
||||
onExportComplete(success, file);
|
||||
}
|
||||
};
|
||||
|
||||
importExporter = new ImportExportTask(ImportExportActivity.this,
|
||||
false, DataFormat.CSV);
|
||||
false, DataFormat.CSV, exportFile, listener);
|
||||
importExporter.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
|
||||
{
|
||||
if(requestCode == PERMISSIONS_EXTERNAL_STORAGE_IMPORT ||
|
||||
requestCode == PERMISSIONS_EXTERNAL_STORAGE_EXPORT)
|
||||
if(requestCode == PERMISSIONS_EXTERNAL_STORAGE)
|
||||
{
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.length > 0 &&
|
||||
grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
||||
boolean success = grantResults.length > 0;
|
||||
|
||||
for(int grant : grantResults)
|
||||
{
|
||||
// permission was granted.
|
||||
if(requestCode == PERMISSIONS_EXTERNAL_STORAGE_IMPORT)
|
||||
if(grant != PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
startImport();
|
||||
}
|
||||
else
|
||||
{
|
||||
startExport();
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if(success == false)
|
||||
{
|
||||
// External storage permission rejected, inform user that
|
||||
// import/export is prevented
|
||||
@@ -128,4 +205,173 @@ public class ImportExportActivity extends AppCompatActivity
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
int id = item.getItemId();
|
||||
|
||||
if(id == android.R.id.home)
|
||||
{
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void onImportComplete(boolean success, File path)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
|
||||
if(success)
|
||||
{
|
||||
builder.setTitle(R.string.importSuccessfulTitle);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.setTitle(R.string.importFailedTitle);
|
||||
}
|
||||
|
||||
int messageId = success ? R.string.importedFrom : R.string.importFailed;
|
||||
|
||||
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()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
private void onExportComplete(boolean success, final File path)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
|
||||
if(success)
|
||||
{
|
||||
builder.setTitle(R.string.exportSuccessfulTitle);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.setTitle(R.string.exportFailedTitle);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
if(success)
|
||||
{
|
||||
final CharSequence sendLabel = ImportExportActivity.this.getResources().getText(R.string.sendLabel);
|
||||
|
||||
builder.setPositiveButton(sendLabel, new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
Uri outputUri = Uri.fromFile(path);
|
||||
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_STREAM, outputUri);
|
||||
sendIntent.setType("text/plain");
|
||||
|
||||
ImportExportActivity.this.startActivity(Intent.createChooser(sendIntent,
|
||||
sendLabel));
|
||||
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if there is at least one activity that can perform the given intent
|
||||
*/
|
||||
private boolean isCallable(Context context, final Intent intent)
|
||||
{
|
||||
PackageManager manager = context.getPackageManager();
|
||||
if(manager == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
List<ResolveInfo> list = manager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
|
||||
for(ResolveInfo info : list)
|
||||
{
|
||||
if(info.activityInfo.exported)
|
||||
{
|
||||
// There is one activity which is available to be called
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void chooseFileWithIntent(Intent intent)
|
||||
{
|
||||
try
|
||||
{
|
||||
startActivityForResult(intent, CHOOSE_EXPORT_FILE);
|
||||
}
|
||||
catch (ActivityNotFoundException e)
|
||||
{
|
||||
Log.e(TAG, "No activity found to handle intent", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (resultCode == RESULT_OK && requestCode == CHOOSE_EXPORT_FILE)
|
||||
{
|
||||
String path = null;
|
||||
|
||||
Uri uri = data.getData();
|
||||
if(uri != null && uri.toString().startsWith("/"))
|
||||
{
|
||||
uri = Uri.parse("file://" + uri.toString());
|
||||
}
|
||||
|
||||
if(uri != null)
|
||||
{
|
||||
path = uri.getPath();
|
||||
}
|
||||
|
||||
if(path != null)
|
||||
{
|
||||
Log.e(TAG, "Starting file import with: " + uri.toString());
|
||||
startImport(new File(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.e(TAG, "Fail to make sense of URI returned from activity: " + (uri != null ? uri.toString() : "null"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.w(TAG, "Failed onActivityResult(), result=" + resultCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,49 +16,31 @@ import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
class ImportExportTask extends AsyncTask<Void, Void, Void>
|
||||
class ImportExportTask extends AsyncTask<Void, Void, Boolean>
|
||||
{
|
||||
private static final String TAG = "BudgetWatch";
|
||||
|
||||
private static final String TARGET_FILE = "LoyaltyCardLocker.csv";
|
||||
private static final String TAG = "LoyaltyCardLocker";
|
||||
|
||||
private Activity activity;
|
||||
private boolean doImport;
|
||||
private DataFormat format;
|
||||
private File target;
|
||||
private TaskCompleteListener listener;
|
||||
|
||||
private ProgressDialog progress;
|
||||
|
||||
public ImportExportTask(Activity activity, boolean doImport, DataFormat format)
|
||||
public ImportExportTask(Activity activity, boolean doImport, DataFormat format, File target,
|
||||
TaskCompleteListener listener)
|
||||
{
|
||||
super();
|
||||
this.activity = activity;
|
||||
this.doImport = doImport;
|
||||
this.format = format;
|
||||
this.target = target;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
private void toastWithArg(int stringId, String argument)
|
||||
private boolean performImport(File importFile, DBHelper db)
|
||||
{
|
||||
final String template = activity.getResources().getString(stringId);
|
||||
final String message = String.format(template, argument);
|
||||
|
||||
activity.runOnUiThread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
Toast.makeText(activity, message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void performImport(File importFile, DBHelper db)
|
||||
{
|
||||
if(importFile.exists() == false)
|
||||
{
|
||||
toastWithArg(R.string.fileMissing, importFile.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
|
||||
boolean result = false;
|
||||
|
||||
try
|
||||
@@ -73,11 +55,12 @@ class ImportExportTask extends AsyncTask<Void, Void, Void>
|
||||
Log.e(TAG, "Unable to import file", e);
|
||||
}
|
||||
|
||||
int messageId = result ? R.string.importedFrom : R.string.importFailed;
|
||||
toastWithArg(messageId, importFile.getAbsolutePath());
|
||||
Log.i(TAG, "Import of '" + importFile.getAbsolutePath() + "' result: " + result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void performExport(File exportFile, DBHelper db)
|
||||
private boolean performExport(File exportFile, DBHelper db)
|
||||
{
|
||||
boolean result = false;
|
||||
|
||||
@@ -93,8 +76,7 @@ class ImportExportTask extends AsyncTask<Void, Void, Void>
|
||||
Log.e(TAG, "Unable to export file", e);
|
||||
}
|
||||
|
||||
int messageId = result ? R.string.exportedTo : R.string.exportFailed;
|
||||
toastWithArg(messageId, exportFile.getAbsolutePath());
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void onPreExecute()
|
||||
@@ -114,26 +96,27 @@ class ImportExportTask extends AsyncTask<Void, Void, Void>
|
||||
progress.show();
|
||||
}
|
||||
|
||||
protected Void doInBackground(Void... nothing)
|
||||
protected Boolean doInBackground(Void... nothing)
|
||||
{
|
||||
final File sdcardDir = Environment.getExternalStorageDirectory();
|
||||
final File importExportFile = new File(sdcardDir, TARGET_FILE);
|
||||
final DBHelper db = new DBHelper(activity);
|
||||
boolean result;
|
||||
|
||||
if(doImport)
|
||||
{
|
||||
performImport(importExportFile, db);
|
||||
result = performImport(target, db);
|
||||
}
|
||||
else
|
||||
{
|
||||
performExport(importExportFile, db);
|
||||
result = performExport(target, db);
|
||||
}
|
||||
|
||||
return null;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void onPostExecute(Void result)
|
||||
protected void onPostExecute(Boolean result)
|
||||
{
|
||||
listener.onTaskComplete(result, target);
|
||||
|
||||
progress.dismiss();
|
||||
Log.i(TAG, (doImport ? "Import" : "Export") + " Complete");
|
||||
}
|
||||
@@ -143,4 +126,9 @@ class ImportExportTask extends AsyncTask<Void, Void, Void>
|
||||
progress.dismiss();
|
||||
Log.i(TAG, (doImport ? "Import" : "Export") + " Cancelled");
|
||||
}
|
||||
|
||||
interface TaskCompleteListener
|
||||
{
|
||||
void onTaskComplete(boolean success, File file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,37 @@
|
||||
package protect.card_locker;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.integration.android.IntentIntegrator;
|
||||
import com.google.zxing.integration.android.IntentResult;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
|
||||
public class LoyaltyCardViewActivity extends AppCompatActivity
|
||||
{
|
||||
private static final String TAG = "CardLocker";
|
||||
|
||||
// These are all the barcode types that the zxing library
|
||||
// is able to generate a barcode for, and thus should be
|
||||
// the only barcodes which we should attempt to scan.
|
||||
Collection<String> supportedBarcodeTypes = Collections.unmodifiableList(Arrays.asList(
|
||||
BarcodeFormat.AZTEC.name(),
|
||||
BarcodeFormat.CODE_39.name(),
|
||||
BarcodeFormat.CODE_128.name(),
|
||||
BarcodeFormat.CODABAR.name(),
|
||||
BarcodeFormat.DATA_MATRIX.name(),
|
||||
BarcodeFormat.EAN_8.name(),
|
||||
BarcodeFormat.EAN_13.name(),
|
||||
BarcodeFormat.ITF.name(),
|
||||
BarcodeFormat.PDF_417.name(),
|
||||
BarcodeFormat.QR_CODE.name(),
|
||||
BarcodeFormat.UPC_A.name()
|
||||
));
|
||||
private static final int SELECT_BARCODE_REQUEST = 1;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
@@ -76,6 +60,20 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
|
||||
|
||||
Log.i(TAG, "To view card: " + loyaltyCardId);
|
||||
|
||||
if(viewLoyaltyCard)
|
||||
{
|
||||
// The brightness value is on a scale from [0, ..., 1], where
|
||||
// '1' is the brightest. We attempt to maximize the brightness
|
||||
// to help barcode readers scan the barcode.
|
||||
Window window = getWindow();
|
||||
if(window != null)
|
||||
{
|
||||
WindowManager.LayoutParams attributes = window.getAttributes();
|
||||
attributes.screenBrightness = 1F;
|
||||
window.setAttributes(attributes);
|
||||
}
|
||||
}
|
||||
|
||||
final EditText storeField = (EditText) findViewById(R.id.storeName);
|
||||
final EditText noteField = (EditText) findViewById(R.id.note);
|
||||
final EditText cardIdField = (EditText) findViewById(R.id.cardId);
|
||||
@@ -87,6 +85,7 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
|
||||
final View barcodeCaptureLayout = findViewById(R.id.barcodeCaptureLayout);
|
||||
|
||||
final Button captureButton = (Button) findViewById(R.id.captureButton);
|
||||
final Button enterButton = (Button) findViewById(R.id.enterButton);
|
||||
final Button saveButton = (Button) findViewById(R.id.saveButton);
|
||||
final Button cancelButton = (Button) findViewById(R.id.cancelButton);
|
||||
|
||||
@@ -149,52 +148,43 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
|
||||
|
||||
if(cardIdField.getText().length() > 0 && barcodeTypeField.getText().length() > 0)
|
||||
{
|
||||
MultiFormatWriter writer = new MultiFormatWriter();
|
||||
BitMatrix result;
|
||||
try
|
||||
String formatString = barcodeTypeField.getText().toString();
|
||||
final BarcodeFormat format = BarcodeFormat.valueOf(formatString);
|
||||
final String cardIdString = cardIdField.getText().toString();
|
||||
|
||||
if(barcodeImage.getHeight() == 0)
|
||||
{
|
||||
String formatString = barcodeTypeField.getText().toString();
|
||||
BarcodeFormat format = BarcodeFormat.valueOf(formatString);
|
||||
if(format == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Unrecognized barcode format: " + formatString);
|
||||
}
|
||||
|
||||
int generateWidth = 100;
|
||||
int generateHeight = 100;
|
||||
|
||||
String cardIdString = cardIdField.getText().toString();
|
||||
|
||||
Log.i(TAG, "Card: " + cardIdString);
|
||||
|
||||
result = writer.encode(cardIdString, format, generateWidth, generateHeight, null);
|
||||
|
||||
final int WHITE = 0xFFFFFFFF;
|
||||
final int BLACK = 0xFF000000;
|
||||
|
||||
int width = result.getWidth();
|
||||
int height = result.getHeight();
|
||||
int[] pixels = new int[width * height];
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
int offset = y * width;
|
||||
for (int x = 0; x < width; x++)
|
||||
Log.d(TAG, "ImageView size is not known known at start, waiting for load");
|
||||
// The size of the ImageView is not yet available as it has not
|
||||
// yet been drawn. Wait for it to be drawn so the size is available.
|
||||
barcodeImage.getViewTreeObserver().addOnGlobalLayoutListener(
|
||||
new ViewTreeObserver.OnGlobalLayoutListener()
|
||||
{
|
||||
pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
|
||||
}
|
||||
}
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||
barcodeImage.setImageBitmap(bitmap);
|
||||
@Override
|
||||
public void onGlobalLayout()
|
||||
{
|
||||
if (Build.VERSION.SDK_INT < 16)
|
||||
{
|
||||
barcodeImage.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
barcodeImage.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
}
|
||||
|
||||
barcodeIdLayout.setVisibility(View.VISIBLE);
|
||||
barcodeImageLayout.setVisibility(View.VISIBLE);
|
||||
Log.d(TAG, "ImageView size now known");
|
||||
new BarcodeImageWriterTask(barcodeImage, cardIdString, format).execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (WriterException | IllegalArgumentException e)
|
||||
else
|
||||
{
|
||||
Log.e(TAG, "Failed to generate barcode", e);
|
||||
Log.d(TAG, "ImageView size known known, creating barcode");
|
||||
new BarcodeImageWriterTask(barcodeImage, cardIdString, format).execute();
|
||||
}
|
||||
|
||||
barcodeIdLayout.setVisibility(View.VISIBLE);
|
||||
barcodeImageLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
View.OnClickListener captureCallback = new View.OnClickListener()
|
||||
@@ -203,7 +193,7 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
|
||||
public void onClick(View v)
|
||||
{
|
||||
IntentIntegrator integrator = new IntentIntegrator(LoyaltyCardViewActivity.this);
|
||||
integrator.setDesiredBarcodeFormats(supportedBarcodeTypes);
|
||||
integrator.setDesiredBarcodeFormats(BarcodeSelectorActivity.SUPPORTED_BARCODE_TYPES);
|
||||
|
||||
String prompt = getResources().getString(R.string.scanCardBarcode);
|
||||
integrator.setPrompt(prompt);
|
||||
@@ -213,6 +203,16 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
|
||||
|
||||
captureButton.setOnClickListener(captureCallback);
|
||||
|
||||
enterButton.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
Intent i = new Intent(getApplicationContext(), BarcodeSelectorActivity.class);
|
||||
startActivityForResult(i, SELECT_BARCODE_REQUEST);
|
||||
}
|
||||
});
|
||||
|
||||
saveButton.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
@@ -288,12 +288,38 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
|
||||
|
||||
switch(id)
|
||||
{
|
||||
case R.id.action_delete:
|
||||
Log.e(TAG, "Deleting card: " + loyaltyCardId);
|
||||
|
||||
DBHelper db = new DBHelper(this);
|
||||
db.deleteLoyaltyCard(loyaltyCardId);
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
break;
|
||||
|
||||
case R.id.action_delete:
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.deleteTitle);
|
||||
builder.setMessage(R.string.deleteConfirmation);
|
||||
builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
Log.e(TAG, "Deleting card: " + loyaltyCardId);
|
||||
|
||||
DBHelper db = new DBHelper(LoyaltyCardViewActivity.this);
|
||||
db.deleteLoyaltyCard(loyaltyCardId);
|
||||
finish();
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
|
||||
return true;
|
||||
case R.id.action_edit:
|
||||
Intent intent = new Intent(getApplicationContext(), LoyaltyCardViewActivity.class);
|
||||
@@ -312,24 +338,37 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent)
|
||||
{
|
||||
String contents = null;
|
||||
String format = null;
|
||||
|
||||
IntentResult result =
|
||||
IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
|
||||
if (result != null)
|
||||
{
|
||||
String contents = result.getContents();
|
||||
String format = result.getFormatName();
|
||||
if(contents != null && contents.isEmpty() == false &&
|
||||
format != null && format.isEmpty() == false)
|
||||
{
|
||||
Log.i(TAG, "Read Contents from scan: " + contents);
|
||||
Log.i(TAG, "Read Format: " + format);
|
||||
Log.i(TAG, "Received barcode information from capture");
|
||||
contents = result.getContents();
|
||||
format = result.getFormatName();
|
||||
}
|
||||
|
||||
final EditText cardIdField = (EditText) findViewById(R.id.cardId);
|
||||
cardIdField.setText(contents);
|
||||
final EditText barcodeTypeField = (EditText) findViewById(R.id.barcodeType);
|
||||
barcodeTypeField.setText(format);
|
||||
onResume();
|
||||
}
|
||||
if(requestCode == SELECT_BARCODE_REQUEST && resultCode == Activity.RESULT_OK)
|
||||
{
|
||||
Log.i(TAG, "Received barcode information from capture");
|
||||
|
||||
contents = intent.getStringExtra(BarcodeSelectorActivity.BARCODE_CONTENTS);
|
||||
format = intent.getStringExtra(BarcodeSelectorActivity.BARCODE_FORMAT);
|
||||
}
|
||||
|
||||
if(contents != null && contents.isEmpty() == false &&
|
||||
format != null && format.isEmpty() == false)
|
||||
{
|
||||
Log.i(TAG, "Read barcode id: " + contents);
|
||||
Log.i(TAG, "Read format: " + format);
|
||||
|
||||
final EditText cardIdField = (EditText) findViewById(R.id.cardId);
|
||||
cardIdField.setText(contents);
|
||||
final EditText barcodeTypeField = (EditText) findViewById(R.id.barcodeType);
|
||||
barcodeTypeField.setText(format);
|
||||
onResume();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
@@ -10,13 +12,16 @@ import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
@@ -65,6 +70,8 @@ public class MainActivity extends AppCompatActivity
|
||||
final LoyaltyCardCursorAdapter adapter = new LoyaltyCardCursorAdapter(this, cardCursor);
|
||||
cardList.setAdapter(adapter);
|
||||
|
||||
registerForContextMenu(cardList);
|
||||
|
||||
cardList.setOnItemClickListener(new AdapterView.OnItemClickListener()
|
||||
{
|
||||
@Override
|
||||
@@ -83,6 +90,39 @@ public class MainActivity extends AppCompatActivity
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)
|
||||
{
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
if (v.getId()==R.id.list)
|
||||
{
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.card_longclick_menu, menu);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item)
|
||||
{
|
||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
|
||||
ListView listView = (ListView) findViewById(R.id.list);
|
||||
|
||||
Cursor cardCursor = (Cursor)listView.getItemAtPosition(info.position);
|
||||
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cardCursor);
|
||||
|
||||
if(card != null && 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;
|
||||
}
|
||||
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
@@ -123,6 +163,7 @@ public class MainActivity extends AppCompatActivity
|
||||
final String[][] USED_LIBRARIES = new String[][]
|
||||
{
|
||||
new String[] {"Commons CSV", "https://commons.apache.org/proper/commons-csv/"},
|
||||
new String[] {"Guava", "https://github.com/google/guava"},
|
||||
new String[] {"ZXing", "https://github.com/zxing/zxing"},
|
||||
new String[] {"ZXing Android Embedded", "https://github.com/journeyapps/zxing-android-embedded"},
|
||||
};
|
||||
|
||||
205
app/src/main/res/layout/barcode_selector_activity.xml
Normal file
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<android.support.v7.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" />
|
||||
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:id="@+id/scrollView">
|
||||
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView android:textSize="20sp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingStart="20.0dip"
|
||||
android:paddingEnd="20.0dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enterBarcodeInstructions" />
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/barcodeIdLayout">
|
||||
<TextView android:textSize="16.0sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingStart="20.0dip"
|
||||
android:paddingEnd="20.0dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:labelFor="@+id/cardId"
|
||||
android:text="@string/cardId" />
|
||||
<EditText android:id="@+id/cardId"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/barcodesLayout"/>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
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"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
|
||||
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
@@ -5,10 +5,6 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:context="protect.card_locker.MainActivity"
|
||||
tools:showIn="@layout/main_activity">
|
||||
|
||||
@@ -19,36 +19,149 @@
|
||||
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="20dp"
|
||||
android:textSize="20sp"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/importExportHelp"/>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<Button
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="8dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/importName"
|
||||
android:layout_weight="1.0"
|
||||
android:id="@+id/importButton"/>
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/exportName"
|
||||
android:layout_weight="1.0"
|
||||
android:id="@+id/exportButton"/>
|
||||
</LinearLayout>
|
||||
android:textSize="@dimen/text_size_medium"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/importExportHelp"/>
|
||||
|
||||
</LinearLayout>
|
||||
<View
|
||||
android:id="@+id/dividerExport"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="16dp"
|
||||
android:background="?android:attr/listDivider"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/exportOptionTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/text_size_large"
|
||||
android:text="@string/exportName"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/exportOptionExplanation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/text_size_medium"
|
||||
android:text="@string/exportOptionExplanation"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/exportButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/exportName" />
|
||||
|
||||
<View
|
||||
android:id="@+id/dividerImportFilesystem"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="16dp"
|
||||
android:background="?android:attr/listDivider"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/importOptionFilesystemTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/text_size_large"
|
||||
android:text="@string/importOptionFilesystemTitle"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/importOptionFilesystemExplanation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/text_size_medium"
|
||||
android:text="@string/importOptionFilesystemExplanation"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/importOptionFilesystemButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/importOptionFilesystemButton" />
|
||||
|
||||
|
||||
<View
|
||||
android:id="@+id/dividerImportApplication"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_margin="16dp"
|
||||
android:background="?android:attr/listDivider"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/importOptionApplicationTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/text_size_large"
|
||||
android:text="@string/importOptionApplicationTitle"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/importOptionApplicationExplanation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/text_size_medium"
|
||||
android:text="@string/importOptionApplicationExplanation"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/importOptionApplicationButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Use external application" />
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:padding="5.0dip"
|
||||
android:padding="10.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="5.0dip"
|
||||
android:padding="5.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="true">
|
||||
@@ -18,7 +18,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="5.0dip"
|
||||
android:padding="5.0dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="true">
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.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.budgetwatch.AccountsActivity">
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -138,6 +136,11 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/capture"
|
||||
android:layout_weight="1.0"/>
|
||||
<Button android:id="@+id/enterButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enterCard"
|
||||
android:layout_weight="1.0"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:padding="10.0dip"
|
||||
|
||||
9
app/src/main/res/menu/card_longclick_menu.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_clipboard"
|
||||
android:title="@string/copy_to_clipboard"
|
||||
app:showAsAction="always"/>
|
||||
</menu>
|
||||
|
Before Width: | Height: | Size: 1012 B After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 676 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 5.6 KiB |
78
app/src/main/res/values-cs/strings.xml
Normal file
@@ -0,0 +1,78 @@
|
||||
<resources
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
|
||||
<string name="app_name">Loyalty Card Keychain</string>
|
||||
<string name="action_add">Přidat</string>
|
||||
|
||||
<string name="noGiftCards">ZAtím némáte žádné věrnostní karty. Klikněte na tlačítko "+" (plus) nahoře a začněte.\n\nLoyalty Card Locker umožňuje nosit své věrnostní karty v telefonu, takže jsou vždy na dosah.</string>
|
||||
|
||||
<string name="storeName">Obchod</string>
|
||||
<string name="note">Poznámka</string>
|
||||
<string name="cardId">ID karty</string>
|
||||
<string name="barcodeType">Typ čárového kódu</string>
|
||||
|
||||
<string name="cancel">Zrušit</string>
|
||||
<string name="save">Uložit</string>
|
||||
<string name="capture">Naskenovat kartu</string>
|
||||
<string name="enterCard">Vložit vlastnoručně</string>
|
||||
<string name="edit">Editovat</string>
|
||||
<string name="delete">Smazat</string>
|
||||
<string name="confirm">Potvrdit</string>
|
||||
<string name="deleteTitle">Odstzranit věrnostní kartu</string>
|
||||
<string name="deleteConfirmation">Opravdu chcete smazat tuto věrnostní kartu?</string>
|
||||
<string name="ok">Ano</string>
|
||||
<string name="copy_to_clipboard">Kopírovat ID do schránky</string>
|
||||
|
||||
<string name="editCardTitle">Editovat věrnostní kartu</string>
|
||||
<string name="addCardTitle">Přidat věrnostní kartu</string>
|
||||
<string name="viewCardTitle">Zobrazit věrnostní kartu</string>
|
||||
<string name="scanCardBarcode">Oskenujte kód karty</string>
|
||||
|
||||
<string name="barcodeImageDescription">Obrázek kódu karty</string>
|
||||
|
||||
<string name="noStoreError">Nebyl zadán Obchod</string>
|
||||
<string name="noCardIdError">Nebylo zadáno ID karty</string>
|
||||
|
||||
<string name="cardIdFormat">%1$s: %2$s</string>
|
||||
|
||||
<string name="importExport">Import/Export</string>
|
||||
<string name="importName">Import</string>
|
||||
<string name="exportName">Export</string>
|
||||
<string name="importedFrom">Importováno z: %1$s</string>
|
||||
<string name="exportedTo">Exportováno do: %1$s</string>
|
||||
<string name="fileMissing">Doubor chybí: %1$s</string>
|
||||
<string name="importFailed">Import selhal: %1$s</string>
|
||||
<string name="exportFailed">Export selhal: %1$s</string>
|
||||
<string name="importing">Importuji…</string>
|
||||
<string name="exporting">Exportuji…</string>
|
||||
<string name="noExternalStoragePermissionError">Nelze importovat nebo exportovat karty bez přístupu k externímu uložišti</string>
|
||||
|
||||
<string name="about">O aplikaci</string>
|
||||
<string name="app_copyright_fmt">Copyright 2016-<xliff:g>%s</xliff:g> Branden Archer</string>
|
||||
<string name="app_license">Licensed under the GPLv3.</string>
|
||||
<string name="about_title_fmt">O aplikaci <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Verze: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Revizní informace: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="app_libraries"><xliff:g id="app_name">%s</xliff:g> používá tyto knihovny třetích stran: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
|
||||
<string name="selectBarcodeTitle">Vyberte čárový kód</string>
|
||||
<string name="enterBarcodeInstructions">Zadejte hodnotu čárového kódu a potm vyberte kód, který představuje čárový kód, který je na kartě.</string>
|
||||
|
||||
<string name="copy_to_clipboard_toast">ID karty zkopírováno do schránky</string>
|
||||
<string name="importExportHelp">Zálohování dat vám umožní přesunout vaše uložené karty na jiné zařízení.</string>
|
||||
<string name="importSuccessfulTitle">Import proběhl úspěšně</string>
|
||||
<string name="importFailedTitle">Import selhal</string>
|
||||
<string name="exportSuccessfulTitle">Export proběhl úspěšně</string>
|
||||
<string name="exportFailedTitle">Export selhal</string>
|
||||
<string name="exportOptionExplanation">Data jsou zapsána do kořenové složky externího uložiště.</string>
|
||||
<string name="importOptionFilesystemTitle">Import ze souborového systému</string>
|
||||
<string name="importOptionFilesystemExplanation">Vyberte konkrétní soubor v uložišti.</string>
|
||||
<string name="importOptionFilesystemButton">Ze souborového systému</string>
|
||||
<string name="importOptionApplicationTitle">Import ze souborového systému</string>
|
||||
<string name="importOptionApplicationExplanation">K otevření souboru použije externí aplikaci jako Dropbox, Google Drive, nebo vámi preferovaný prohlížeč souborů.</string>
|
||||
<string name="importOptionApplicationButton">Použít externí aplikaci</string>
|
||||
<string name="importOptionFixedTitle">Import z umístění exportu</string>
|
||||
<string name="importOptionFixedExplanation">Import ze stejné složky souborového systému do níž se zapisuje při exportu.</string>
|
||||
<string name="importOptionFixedButton">Použít složku exportu</string>
|
||||
<string name="sendLabel">Odeslat…</string>
|
||||
</resources>
|
||||
68
app/src/main/res/values-de/strings.xml
Normal file
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="app_name">Loyalty Card Keychain</string>
|
||||
<string name="about">Über</string>
|
||||
<string name="about_title_fmt">Über <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="action_add">Neu</string>
|
||||
<string name="addCardTitle">Neue Kundenkarte</string>
|
||||
<string name="app_copyright_fmt">Copyright 2016-<xliff:g>%s</xliff:g> Branden Archer</string>
|
||||
<string name="app_license">Lizensiert unter der GPLv3.</string>
|
||||
<string name="app_libraries"><xliff:g id="app_name">%s</xliff:g> benutzt die folgenden Fremdbibliotheken: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="viewCardTitle">Kundenkarte anzeigen</string>
|
||||
<string name="ok">Ok</string>
|
||||
<string name="note">Notiz</string>
|
||||
<string name="save">Speichern</string>
|
||||
<string name="scanCardBarcode">Barcode scannen</string>
|
||||
<string name="selectBarcodeTitle">Barcode auswählen</string>
|
||||
<string name="storeName">Firma</string>
|
||||
<string name="noStoreError">Keine Firma angegeben</string>
|
||||
<string name="exportName">Exportieren</string>
|
||||
<string name="exportedTo">Exportiert nach: %1$s</string>
|
||||
<string name="fileMissing">Datei fehlt: %1$s</string>
|
||||
<string name="importExport">Import/Export</string>
|
||||
<string name="importFailed">Import fehlgeschlagen: %1$s</string>
|
||||
<string name="importName">Import</string>
|
||||
<string name="importedFrom">Importiert von: %1$s</string>
|
||||
<string name="noCardIdError">Keine Kartennummer angegeben</string>
|
||||
<string name="noExternalStoragePermissionError">Ohne die Berechtigung für den externen Speicher kann kein Import oder Export erfolgen.</string>
|
||||
<string name="noGiftCards">Du hast noch keine Kundenkarte angelegt. Über den "+" Button oben rechts, kannst du welche anlegen.\n\nDiese App ermöglicht es dir, deine Kundenkarten immer mit dir zu führen.</string>
|
||||
<string name="cancel">Abrechen</string>
|
||||
<string name="capture">Karte aufnehmen</string>
|
||||
<string name="cardId">Kartennummer</string>
|
||||
<string name="cardIdFormat">%1$s: %2$s</string>
|
||||
<string name="confirm">Bestätigen</string>
|
||||
<string name="copy_to_clipboard">Kopiere die Nummer in die Zwischenablage</string>
|
||||
<string name="delete">Löschen</string>
|
||||
<string name="deleteConfirmation">Bitte bestätige, dass du die Karte löschen möchtest.</string>
|
||||
<string name="deleteTitle">Lösche die Kundenkarte</string>
|
||||
<string name="edit">Bearbeiten</string>
|
||||
<string name="editCardTitle">Kundenkarte bearbeiten</string>
|
||||
<string name="enterCard">Karte einfügen</string>
|
||||
<string name="exportFailed">Export fehlgeschlagen: %1$s</string>
|
||||
<string name="barcodeType">Barcodeart</string>
|
||||
<string name="barcodeImageDescription">Bild des Barcodes</string>
|
||||
<string name="copy_to_clipboard_toast">Nummer in die Zwischenablage kopiert</string>
|
||||
<string name="debug_version_fmt">Version: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="enterBarcodeInstructions">Füge die Kundennummer ein, anschließend wähle die korrekte Barcodeart aus.</string>
|
||||
<string name="app_revision_fmt">Versions Information: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="importing">Importiere…</string>
|
||||
<string name="exporting">Exportiere…</string>
|
||||
|
||||
<string name="importExportHelp">Gesicherte Daten ermöglichen das Verschieben der Kundenkarten auf ein anderes Gerät.</string>
|
||||
<string name="importSuccessfulTitle">Import erfolgreich</string>
|
||||
<string name="importFailedTitle">Import fehlgeschlagen</string>
|
||||
<string name="exportSuccessfulTitle">Export erfolgreich</string>
|
||||
<string name="exportFailedTitle">Export fehlgeschlagen</string>
|
||||
<string name="exportOptionExplanation">Die Datei wird ins Wurzelverzeichnis des externen Speichers geschrieben.</string>
|
||||
<string name="importOptionFilesystemTitle">Importiere vom Dateisystem</string>
|
||||
<string name="importOptionFilesystemExplanation">Wähle eine Datei im Speicher aus.</string>
|
||||
<string name="importOptionFilesystemButton">Vom Dateisystem</string>
|
||||
<string name="importOptionApplicationTitle">Importiere vom Dateisystem</string>
|
||||
<string name="importOptionApplicationExplanation">Wähle eine Datei aus einer App wie Dropbox, Google Drive, oder deinem bevorzugten Dateisystem aus.</string>
|
||||
<string name="importOptionApplicationButton">Nutze eine externe App</string>
|
||||
<string name="importOptionFixedTitle">Importiere vom Export Ort</string>
|
||||
<string name="importOptionFixedExplanation">Importiere von derselben Stelle, wo die exportiere Datei liegen würde.</string>
|
||||
<string name="importOptionFixedButton">Verwende die exportierte Stelle</string>
|
||||
<string name="sendLabel">Senden…</string>
|
||||
|
||||
</resources>
|
||||
79
app/src/main/res/values-fr/strings.xml
Normal file
@@ -0,0 +1,79 @@
|
||||
<resources
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
|
||||
<string name="app_name">Loyalty Card Keychain</string>
|
||||
<string name="action_add">Ajouter</string>
|
||||
|
||||
<string name="noGiftCards">Pas de carte de fidélité enregistrée. Cliquez sur le bouton "+" (plus) pour commencer.\n\nLoyalty Card Locker vous permet d\'enregistrer vos cartes de fidélité sur votre téléphone pour toujours les avoir à portée de main.</string>
|
||||
|
||||
<string name="storeName">Nom</string>
|
||||
<string name="note">Note</string>
|
||||
<string name="cardId">Numéro</string>
|
||||
<string name="barcodeType">Type de code-barres</string>
|
||||
|
||||
<string name="cancel">Annuler</string>
|
||||
<string name="save">Enregistrer</string>
|
||||
<string name="capture">Flasher</string>
|
||||
<string name="enterCard">Mode manuel</string>
|
||||
<string name="edit">Modifier</string>
|
||||
<string name="delete">Supprimer</string>
|
||||
<string name="confirm">Confirmer</string>
|
||||
<string name="deleteTitle">Supprimer la carte de fidélité</string>
|
||||
<string name="deleteConfirmation">Confirmez que vous souhaitez supprimer cette carte</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="copy_to_clipboard">Copier le numéro dans le presse-papier</string>
|
||||
|
||||
<string name="editCardTitle">Modifier la carte de fidélité</string>
|
||||
<string name="addCardTitle">Ajouter une carte de fidélité</string>
|
||||
<string name="viewCardTitle">Voir la carte de fidélité</string>
|
||||
<string name="scanCardBarcode">Flasher le code-barres de la carte</string>
|
||||
|
||||
<string name="barcodeImageDescription">Image du code-barres de la carte</string>
|
||||
|
||||
<string name="noStoreError">Aucun nom n\'a été saisi</string>
|
||||
<string name="noCardIdError">Aucun numéro n\'a été saisi</string>
|
||||
|
||||
<string name="cardIdFormat">%1$s: %2$s</string>
|
||||
|
||||
<string name="importExport">Importer/Exporter</string>
|
||||
<string name="importName">Importer</string>
|
||||
<string name="exportName">Exporter</string>
|
||||
<string name="importedFrom">Importé depuis : %1$s</string>
|
||||
<string name="exportedTo">Exporté vers : %1$s</string>
|
||||
<string name="fileMissing">Fichier manquant : %1$s</string>
|
||||
<string name="importFailed">Échec de l\'import : %1$s</string>
|
||||
<string name="exportFailed">Échec de l\'export : %1$s</string>
|
||||
<string name="importing">Import …</string>
|
||||
<string name="exporting">Export …</string>
|
||||
<string name="noExternalStoragePermissionError">Impossible d\'importer ou d\'exporter les données sans l\'autorisation d\'accès au stockage externe</string>
|
||||
|
||||
<string name="about">À propos</string>
|
||||
<string name="app_copyright_fmt">Copyright 2016-<xliff:g>%s</xliff:g> Branden Archer</string>
|
||||
<string name="app_license">Licence GPLv3.</string>
|
||||
<string name="about_title_fmt">À propos de <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Version : <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Notes sur les versions : <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="app_libraries"><xliff:g id="app_name">%s</xliff:g> utilise les bibliothèques-tierces suivantes : <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
|
||||
<string name="selectBarcodeTitle">Choisissez le code-barre</string>
|
||||
<string name="enterBarcodeInstructions">Saisissez les chiffres du code-barres et sélectionnez l\'image qui le représente</string>
|
||||
|
||||
<string name="copy_to_clipboard_toast">Numéro de carte copié dans le presse-papier</string>
|
||||
|
||||
<string name="importExportHelp">Exporter vos données vous permet de récupérer vos cartes sur un autre appareil.</string>
|
||||
<string name="importSuccessfulTitle">Importé avec succès</string>
|
||||
<string name="importFailedTitle">Échec de l\'import</string>
|
||||
<string name="exportSuccessfulTitle">Exporté avec succès</string>
|
||||
<string name="exportFailedTitle">Échec de l\'export</string>
|
||||
<string name="exportOptionExplanation">Les données sont sauvegardées à la racine du stockage externe.</string>
|
||||
<string name="importOptionFilesystemTitle">Importer depuis le système de fichiers.</string>
|
||||
<string name="importOptionFilesystemExplanation">Choisissez le fichier à importer.</string>
|
||||
<string name="importOptionFilesystemButton">Système de fichiers</string>
|
||||
<string name="importOptionApplicationTitle">Importer depuis le système de fichiers</string>
|
||||
<string name="importOptionApplicationExplanation">Utilisez une application externe comme Dropbox, Google Drive, ou votre gestionnaire de fichiers favori pour ouvrir un fichier.</string>
|
||||
<string name="importOptionApplicationButton">Application externe</string>
|
||||
<string name="importOptionFixedTitle">Importer depuis le même emplacement que pour l\'export</string>
|
||||
<string name="importOptionFixedExplanation">Importe les données depuis le même emplacement que celui défini pour l\'export.</string>
|
||||
<string name="importOptionFixedButton">Utiliser l\'emplacement de l\'export</string>
|
||||
<string name="sendLabel">Envoyer…</string>
|
||||
</resources>
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
<string name="cancel">Annulla</string>
|
||||
<string name="save">Salva</string>
|
||||
<string name="capture">Salva tessera</string>
|
||||
<string name="capture">Scansione carta</string>
|
||||
<string name="edit">Modifica</string>
|
||||
<string name="delete">Elimina</string>
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
<string name="importExport">Importa/Esporta</string>
|
||||
<string name="importName">Importa</string>
|
||||
<string name="exportName">Esporta</string>
|
||||
<string name="importExportHelp">I dati sono stati importati in o esportati dal file LoyaltyCardLocker.csv sulla memoria esterna</string>
|
||||
<string name="importedFrom">Importato da: %1$s</string>
|
||||
<string name="exportedTo">Esportato in: %1$s</string>
|
||||
<string name="fileMissing">File mancante: %1$s</string>
|
||||
@@ -49,4 +48,28 @@
|
||||
<string name="app_revision_fmt">Informazione sulla revisione: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="app_libraries"><xliff:g id="app_name">%s</xliff:g> usa le seguenti librerie di terze parti: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="ok">Ok</string>
|
||||
<string name="enterCard">Inserisci carta</string>
|
||||
<string name="selectBarcodeTitle">Seleziona codice a barre</string>
|
||||
<string name="enterBarcodeInstructions">Digita il valore del codice a barre, quindi seleziona l\'immagine che rappresenta il codice a barre che vuoi usare.</string>
|
||||
<string name="copy_to_clipboard">Copia ID negli appunti</string>
|
||||
<string name="copy_to_clipboard_toast">ID della carta copiato negli appunti</string>
|
||||
<string name="confirm">Conferma</string>
|
||||
<string name="deleteTitle">Rimuovi carta fedeltà</string>
|
||||
<string name="deleteConfirmation">Conferma che vuoi eliminare questa carta.</string>
|
||||
<string name="importExportHelp">Fare il backup dei dati ti permette di spostare le tue tessere da un dispositivo ad un altro.</string>
|
||||
<string name="importSuccessfulTitle">Importazione avvenuta con successo</string>
|
||||
<string name="importFailedTitle">Importazione fallita</string>
|
||||
<string name="exportSuccessfulTitle">Esportazione avvenuta con successo</string>
|
||||
<string name="exportFailedTitle">Esportazione fallita</string>
|
||||
<string name="exportOptionExplanation">I dati sono stati scritti nella cartella principale della memoria esterna.</string>
|
||||
<string name="importOptionFilesystemTitle">Importa dal file system</string>
|
||||
<string name="importOptionFilesystemExplanation">Scegli un file dal file system.</string>
|
||||
<string name="importOptionFilesystemButton">Dal file system</string>
|
||||
<string name="importOptionApplicationTitle">Importa dal file system</string>
|
||||
<string name="importOptionApplicationExplanation">Usa un\'applicazione esterna come Dropbox, Google Drive o il tuo file manager preferito per aprire il file.</string>
|
||||
<string name="importOptionApplicationButton">Usa un\'applicazione esterna</string>
|
||||
<string name="importOptionFixedTitle">Importa da un altro posto</string>
|
||||
<string name="importOptionFixedExplanation">Importa dallo stesso posto del file system dove si è esportato.</string>
|
||||
<string name="importOptionFixedButton">Usa luogo dell\'esportazione</string>
|
||||
<string name="sendLabel">Invia…</string>
|
||||
</resources>
|
||||
|
||||
79
app/src/main/res/values-lt/strings.xml
Normal file
@@ -0,0 +1,79 @@
|
||||
<resources
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
|
||||
<string name="app_name">Loyalty Card Keychain</string>
|
||||
<string name="action_add">Pridėti</string>
|
||||
|
||||
<string name="noGiftCards">Šiuo metu neturite nė vienos įvestos lojalumo kortelės. Paspauskite "+" (pliuso) pliuso mygtuką, kad pradėtumėte.\n\nLoyalty Card Locker leidžia Jums visada nešiotis lojalumo kortelių informaciją savo telefone ar planšetėje, taip jos visada pasiekiamos.</string>
|
||||
|
||||
<string name="storeName">Parduotuvė</string>
|
||||
<string name="note">Užrašas</string>
|
||||
<string name="cardId">Kortelės ID</string>
|
||||
<string name="barcodeType">Brūkšninio kodo tipas</string>
|
||||
|
||||
<string name="cancel">Atšaukti</string>
|
||||
<string name="save">Išsaugoti</string>
|
||||
<string name="capture">Nufotografuoti kortelę</string>
|
||||
<string name="enterCard">Įvesti kortelę</string>
|
||||
<string name="edit">Redaguoti</string>
|
||||
<string name="delete">Ištrinti</string>
|
||||
<string name="confirm">Patvirtinti</string>
|
||||
<string name="deleteTitle">Panaikinti lojalumo kortelę</string>
|
||||
<string name="deleteConfirmation">Prašome patvirtinti jog Jūs norite panaikinti šią lojalumo kortelę.</string>
|
||||
<string name="ok">Gerai</string>
|
||||
<string name="copy_to_clipboard">Nukopijuoti ID į iškarpinę</string>
|
||||
|
||||
<string name="editCardTitle">Redaguoti lojalumo kortelę</string>
|
||||
<string name="addCardTitle">Pridėti lojalumo kortelę</string>
|
||||
<string name="viewCardTitle">Paeržiūrėti lojalumo kortelę</string>
|
||||
<string name="scanCardBarcode">Nuskanuokite kortelės brūkšninį kodą</string>
|
||||
|
||||
<string name="barcodeImageDescription">Kortelės brūkšninio kodo paveikslėlis</string>
|
||||
|
||||
<string name="noStoreError">Parduotuvė neįvesta</string>
|
||||
<string name="noCardIdError">Neįvestas kortelės ID</string>
|
||||
|
||||
<string name="cardIdFormat">%1$s: %2$s</string>
|
||||
|
||||
<string name="importExport">Importuoti/Exportuoti</string>
|
||||
<string name="importName">Importuoti</string>
|
||||
<string name="exportName">Exportuoti</string>
|
||||
<string name="importedFrom">Importuota iš: %1$s</string>
|
||||
<string name="exportedTo">Eksportuota į: %1$s</string>
|
||||
<string name="fileMissing">Failas nerastas: %1$s</string>
|
||||
<string name="importFailed">Nepavyko importuoti: %1$s</string>
|
||||
<string name="exportFailed">Nepavyko eksportuoti: %1$s</string>
|
||||
<string name="importing">Importuoja…</string>
|
||||
<string name="exporting">Eksportuoja…</string>
|
||||
<string name="noExternalStoragePermissionError">Negalima importuoti/eksportuoti kortelių be išorinės atminties leidimo</string>
|
||||
|
||||
<string name="about">Apie</string>
|
||||
<string name="app_copyright_fmt">Visos teisės saugomos 2016-<xliff:g>%s</xliff:g> Branden Archer</string>
|
||||
<string name="app_license">Licenzijuota pagal GPLv3.</string>
|
||||
<string name="about_title_fmt">Apie <xliff:g id="app_name">%s</xliff:g></string>
|
||||
<string name="debug_version_fmt">Versija: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Revizijos informacija: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="app_libraries"><xliff:g id="app_name">%s</xliff:g> naudoja šias trečiosios šalies bibliotekas: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
|
||||
<string name="selectBarcodeTitle">Pasirinkite brūkšninį kodą</string>
|
||||
<string name="enterBarcodeInstructions">Enter the barcode value then select the image which represents the barcode you want to use</string>
|
||||
|
||||
<string name="copy_to_clipboard_toast">Kortelės ID nukopijuota į iškarpinę</string>
|
||||
|
||||
<!-- needs translated --><string name="importExportHelp">Backed up data can allow you to move your cards to another device.</string>
|
||||
<!-- needs translated --><string name="importSuccessfulTitle">Import successful</string>
|
||||
<!-- needs translated --><string name="importFailedTitle">Import failed</string>
|
||||
<!-- needs translated --><string name="exportSuccessfulTitle">Export successful</string>
|
||||
<!-- needs translated --><string name="exportFailedTitle">Export failed</string>
|
||||
<!-- needs translated --><string name="exportOptionExplanation">Data is written to the top directory in external storage.</string>
|
||||
<!-- needs translated --><string name="importOptionFilesystemTitle">Import from filesystem</string>
|
||||
<!-- needs translated --><string name="importOptionFilesystemExplanation">Choose a specific file from the filesystem.</string>
|
||||
<!-- needs translated --><string name="importOptionFilesystemButton">From filesystem</string>
|
||||
<!-- needs translated --><string name="importOptionApplicationTitle">Import from filesystem</string>
|
||||
<!-- needs translated --><string name="importOptionApplicationExplanation">Use an external application like Dropbox, Google Drive, or your favorite file manager to open a file.</string>
|
||||
<!-- needs translated --><string name="importOptionApplicationButton">Use external application</string>
|
||||
<!-- needs translated --><string name="importOptionFixedTitle">Import from export location</string>
|
||||
<!-- needs translated --><string name="importOptionFixedExplanation">Import from the same location on the filesystem that is written to on export.</string>
|
||||
<!-- needs translated --><string name="importOptionFixedButton">Use export location</string>
|
||||
<!-- needs translated --> <string name="sendLabel">Send…</string>
|
||||
</resources>
|
||||
@@ -32,7 +32,6 @@
|
||||
<string name="importExport">Importeer/Exporteer</string>
|
||||
<string name="importName">Importeer</string>
|
||||
<string name="exportName">Exporteer</string>
|
||||
<string name="importExportHelp">Data is geïmporteerd van of geëxporteerd naar LoyaltyCardLocker.csv op externe opslag</string>
|
||||
<string name="importedFrom">Geïmporteerd van: %1$s</string>
|
||||
<string name="exportedTo">Geëxporteerd naar: %1$s</string>
|
||||
<string name="fileMissing">Bestand niet gevonden: %1$s</string>
|
||||
@@ -49,4 +48,29 @@
|
||||
<string name="app_revision_fmt">Revisieïnformatie: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="app_libraries"><xliff:g id="app_name">%s</xliff:g> gebruikt de volgende bibliotheken van derden: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
<string name="ok">Oké</string>
|
||||
<string name="enterCard">Voer kaart in</string>
|
||||
<string name="selectBarcodeTitle">Selecteer barcode</string>
|
||||
<string name="enterBarcodeInstructions">Voer de waarde van de barcode in en kies daarna de afbeelding die de barcode die je wil gebruiken representeert</string>
|
||||
<string name="copy_to_clipboard">Kopieer het ID naar het klembord</string>
|
||||
<string name="copy_to_clipboard_toast">Het ID is naar het klembord gekopieerd</string>
|
||||
<string name="confirm">Bevestig</string>
|
||||
<string name="deleteConfirmation">Bevestig deze kaart te verwijderen.</string>
|
||||
<string name="deleteTitle">Verwijder kaart</string>
|
||||
|
||||
<string name="importExportHelp">Data die is geback-upt maakt het mogelijk om je klantenkaarten naar een ander apparaat te verplaatsen.</string>
|
||||
<string name="importSuccessfulTitle">Importeren succesvol</string>
|
||||
<string name="importFailedTitle">Importeren mislukte</string>
|
||||
<string name="exportSuccessfulTitle">Exporteren succesvol</string>
|
||||
<string name="exportFailedTitle">Exporteren mislukt</string>
|
||||
<string name="exportOptionExplanation">Data is weggeschreven naar de hoogste map in externe opslag.</string>
|
||||
<string name="importOptionFilesystemTitle">Importeer van filesysteem</string>
|
||||
<string name="importOptionFilesystemExplanation">Kies een specifiek bestand van het filesysteem.</string>
|
||||
<string name="importOptionFilesystemButton">Van filesysteem</string>
|
||||
<string name="importOptionApplicationTitle">Importeer van filesysteem</string>
|
||||
<string name="importOptionApplicationExplanation">Gebruik een externe applicatie zoals Dropbox, Google Drive of je favoriete bestandsbeheer om een bestand te openen.</string>
|
||||
<string name="importOptionApplicationButton">Gebruik externe applicatie</string>
|
||||
<string name="importOptionFixedTitle">Importeer van exporteerlocatie</string>
|
||||
<string name="importOptionFixedExplanation">Importeer van zelfde locatie op het filesysteem waar tijdens exporteren naar geschreven is.</string>
|
||||
<string name="importOptionFixedButton">gebruik exporteerlocaite</string>
|
||||
<string name="sendLabel">Verzend…</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,4 +7,8 @@
|
||||
<dimen name="no_data_padding">22dp</dimen>
|
||||
|
||||
<dimen name="barcode_disp_height">200dp</dimen>
|
||||
|
||||
<dimen name="text_size_medium">18sp</dimen>
|
||||
<dimen name="text_size_large">22sp</dimen>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<resources
|
||||
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
|
||||
<string name="app_name">Loyalty Card Locker</string>
|
||||
<string name="app_name">Loyalty Card Keychain</string>
|
||||
<string name="action_add">Add</string>
|
||||
|
||||
<string name="noGiftCards">You don\'t have any loyalty cards at the moment. Click the "+" (plus) button up top to get started.\n\nLoyalty Card Locker lets you carry your loyalty cards on your phone, so they are always within reach.</string>
|
||||
@@ -14,9 +14,15 @@
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="capture">Capture Card</string>
|
||||
<string name="enterCard">Enter Card</string>
|
||||
<string name="edit">Edit</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="confirm">Confirm</string>
|
||||
<string name="deleteTitle">Remove Loyalty Card</string>
|
||||
<string name="deleteConfirmation">Please confirm that you want to delete this card.</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="copy_to_clipboard">Copy ID to clipboard</string>
|
||||
<string name="sendLabel">Send…</string>
|
||||
|
||||
<string name="editCardTitle">Edit Loyalty Card</string>
|
||||
<string name="addCardTitle">Add Loyalty Card</string>
|
||||
@@ -34,15 +40,29 @@
|
||||
<string name="importExport">Import/Export</string>
|
||||
<string name="importName">Import</string>
|
||||
<string name="exportName">Export</string>
|
||||
<string name="importExportHelp">Data is imported to/exported from LoyaltyCardLocker.csv on external storage</string>
|
||||
<string name="importExportHelp">Backed up data can allow you to move your cards to another device.</string>
|
||||
<string name="importedFrom">Imported from: %1$s</string>
|
||||
<string name="exportedTo">Exported to: %1$s</string>
|
||||
<string name="fileMissing">File missing: %1$s</string>
|
||||
<string name="importSuccessfulTitle">Import successful</string>
|
||||
<string name="importFailedTitle">Import failed</string>
|
||||
<string name="importFailed">Failed to import: %1$s</string>
|
||||
<string name="exportSuccessfulTitle">Export successful</string>
|
||||
<string name="exportFailedTitle">Export failed</string>
|
||||
<string name="exportFailed">Failed to export: %1$s</string>
|
||||
<string name="importing">Importing…</string>
|
||||
<string name="exporting">Exporting…</string>
|
||||
<string name="noExternalStoragePermissionError">Unable to import or export cards without the external storage permission</string>
|
||||
<string name="exportOptionExplanation">Data is written to the top directory in external storage.</string>
|
||||
<string name="importOptionFilesystemTitle">Import from filesystem</string>
|
||||
<string name="importOptionFilesystemExplanation">Choose a specific file from the filesystem.</string>
|
||||
<string name="importOptionFilesystemButton">From filesystem</string>
|
||||
<string name="importOptionApplicationTitle">Import from filesystem</string>
|
||||
<string name="importOptionApplicationExplanation">Use an external application like Dropbox, Google Drive, or your favorite file manager to open a file.</string>
|
||||
<string name="importOptionApplicationButton">Use external application</string>
|
||||
<string name="importOptionFixedTitle">Import from export location</string>
|
||||
<string name="importOptionFixedExplanation">Import from the same location on the filesystem that is written to on export.</string>
|
||||
<string name="importOptionFixedButton">Use export location</string>
|
||||
|
||||
<string name="about">About</string>
|
||||
<string name="app_copyright_fmt">Copyright 2016-<xliff:g>%s</xliff:g> Branden Archer</string>
|
||||
@@ -51,4 +71,10 @@
|
||||
<string name="debug_version_fmt">Version: <xliff:g id="version">%s</xliff:g></string>
|
||||
<string name="app_revision_fmt">Revision Information: <xliff:g id="app_revision_url">%s</xliff:g></string>
|
||||
<string name="app_libraries"><xliff:g id="app_name">%s</xliff:g> uses the following third-party libraries: <xliff:g id="app_libraries_list">%s</xliff:g></string>
|
||||
</resources>
|
||||
|
||||
<string name="selectBarcodeTitle">Select Barcode</string>
|
||||
<string name="enterBarcodeInstructions">Enter the barcode value then select the image which represents the barcode you want to use</string>
|
||||
|
||||
<string name="copy_to_clipboard_toast">Card ID copied to clipboard</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricGradleTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.res.builder.RobolectricPackageManager;
|
||||
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(RobolectricGradleTestRunner.class)
|
||||
@Config(constants = BuildConfig.class, sdk = 17)
|
||||
public class ImportExportActivityTest
|
||||
{
|
||||
private void registerIntentHandler(String handler)
|
||||
{
|
||||
// Add something that will 'handle' the given intent type
|
||||
|
||||
RobolectricPackageManager packageManager = (RobolectricPackageManager) shadowOf(
|
||||
RuntimeEnvironment.application).getPackageManager();
|
||||
|
||||
ResolveInfo info = new ResolveInfo();
|
||||
info.isDefault = true;
|
||||
|
||||
ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.packageName = "does.not.matter";
|
||||
info.activityInfo = new ActivityInfo();
|
||||
info.activityInfo.applicationInfo = applicationInfo;
|
||||
info.activityInfo.name = "DoesNotMatter";
|
||||
info.activityInfo.exported = true;
|
||||
|
||||
Intent intent = new Intent(handler);
|
||||
if(handler.equals(Intent.ACTION_PICK))
|
||||
{
|
||||
intent.setData(Uri.parse("file://"));
|
||||
}
|
||||
|
||||
if(handler.equals(Intent.ACTION_GET_CONTENT))
|
||||
{
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("*/*");
|
||||
}
|
||||
|
||||
packageManager.addResolveInfoForIntent(intent, info);
|
||||
}
|
||||
|
||||
private void checkVisibility(Activity activity, int state, int divider, int title, int message, int button)
|
||||
{
|
||||
View dividerView = activity.findViewById(divider);
|
||||
View titleView = activity.findViewById(title);
|
||||
View messageView = activity.findViewById(message);
|
||||
View buttonView = activity.findViewById(button);
|
||||
|
||||
assertEquals(state, dividerView.getVisibility());
|
||||
assertEquals(state, titleView.getVisibility());
|
||||
assertEquals(state, messageView.getVisibility());
|
||||
assertEquals(state, buttonView.getVisibility());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportFilesystemOption()
|
||||
{
|
||||
for(boolean isInstalled : new Boolean[]{false, true})
|
||||
{
|
||||
int visibility = isInstalled ? View.VISIBLE : View.GONE;
|
||||
|
||||
if(isInstalled)
|
||||
{
|
||||
registerIntentHandler(Intent.ACTION_PICK);
|
||||
}
|
||||
|
||||
Activity activity = Robolectric.setupActivity(ImportExportActivity.class);
|
||||
|
||||
checkVisibility(activity, visibility, R.id.dividerImportFilesystem,
|
||||
R.id.importOptionFilesystemTitle, R.id.importOptionFilesystemExplanation,
|
||||
R.id.importOptionFilesystemButton);
|
||||
|
||||
// Should always be gone, as its provider is never installed
|
||||
checkVisibility(activity, View.GONE, R.id.dividerImportApplication,
|
||||
R.id.importOptionApplicationTitle, R.id.importOptionApplicationExplanation,
|
||||
R.id.importOptionApplicationButton);
|
||||
|
||||
// Import from file system should always be present
|
||||
|
||||
checkVisibility(activity, View.VISIBLE, R.id.dividerImportFixed,
|
||||
R.id.importOptionFixedTitle, R.id.importOptionFixedExplanation,
|
||||
R.id.importOptionFixedButton);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportApplicationOption()
|
||||
{
|
||||
for(boolean isInstalled : new Boolean[]{false, true})
|
||||
{
|
||||
int visibility = isInstalled ? View.VISIBLE : View.GONE;
|
||||
|
||||
if(isInstalled)
|
||||
{
|
||||
registerIntentHandler(Intent.ACTION_GET_CONTENT);
|
||||
}
|
||||
|
||||
Activity activity = Robolectric.setupActivity(ImportExportActivity.class);
|
||||
|
||||
checkVisibility(activity, visibility, R.id.dividerImportApplication,
|
||||
R.id.importOptionApplicationTitle, R.id.importOptionApplicationExplanation,
|
||||
R.id.importOptionApplicationButton);
|
||||
|
||||
// Should always be gone, as its provider is never installed
|
||||
checkVisibility(activity, View.GONE, R.id.dividerImportFilesystem,
|
||||
R.id.importOptionFilesystemTitle, R.id.importOptionFilesystemExplanation,
|
||||
R.id.importOptionFilesystemButton);
|
||||
|
||||
// Import from file system should always be present
|
||||
|
||||
checkVisibility(activity, View.VISIBLE, R.id.dividerImportFixed,
|
||||
R.id.importOptionFixedTitle, R.id.importOptionFixedExplanation,
|
||||
R.id.importOptionFixedButton);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllOptionsAvailable()
|
||||
{
|
||||
registerIntentHandler(Intent.ACTION_PICK);
|
||||
registerIntentHandler(Intent.ACTION_GET_CONTENT);
|
||||
|
||||
Activity activity = Robolectric.setupActivity(ImportExportActivity.class);
|
||||
|
||||
checkVisibility(activity, View.VISIBLE, R.id.dividerImportApplication,
|
||||
R.id.importOptionApplicationTitle, R.id.importOptionApplicationExplanation,
|
||||
R.id.importOptionApplicationButton);
|
||||
|
||||
checkVisibility(activity, View.VISIBLE, R.id.dividerImportFilesystem,
|
||||
R.id.importOptionFilesystemTitle, R.id.importOptionFilesystemExplanation,
|
||||
R.id.importOptionFilesystemButton);
|
||||
|
||||
checkVisibility(activity, View.VISIBLE, R.id.dividerImportFixed,
|
||||
R.id.importOptionFixedTitle, R.id.importOptionFixedExplanation,
|
||||
R.id.importOptionFixedButton);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package protect.card_locker;
|
||||
import android.app.Activity;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Environment;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
@@ -15,12 +16,14 @@ import org.robolectric.annotation.Config;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.Calendar;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(RobolectricGradleTestRunner.class)
|
||||
@@ -109,7 +112,7 @@ public class ImportExportTest
|
||||
@Test
|
||||
public void multipleCardsExportImport() throws IOException
|
||||
{
|
||||
final int NUM_CARDS = 1000;
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
for(DataFormat format : DataFormat.values())
|
||||
{
|
||||
@@ -144,7 +147,7 @@ public class ImportExportTest
|
||||
@Test
|
||||
public void importExistingCardsNotReplace() throws IOException
|
||||
{
|
||||
final int NUM_CARDS = 1000;
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
for(DataFormat format : DataFormat.values())
|
||||
{
|
||||
@@ -177,7 +180,7 @@ public class ImportExportTest
|
||||
@Test
|
||||
public void corruptedImportNothingSaved() throws IOException
|
||||
{
|
||||
final int NUM_CARDS = 1000;
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
for(DataFormat format : DataFormat.values())
|
||||
{
|
||||
@@ -205,32 +208,63 @@ public class ImportExportTest
|
||||
}
|
||||
}
|
||||
|
||||
class TestTaskCompleteListener implements ImportExportTask.TaskCompleteListener
|
||||
{
|
||||
Boolean success;
|
||||
File file;
|
||||
|
||||
public void onTaskComplete(boolean success, File file)
|
||||
{
|
||||
this.success = success;
|
||||
this.file = file;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useImportExportTask()
|
||||
{
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
final File sdcardDir = Environment.getExternalStorageDirectory();
|
||||
final File exportFile = new File(sdcardDir, "LoyaltyCardLocker.csv");
|
||||
|
||||
for(DataFormat format : DataFormat.values())
|
||||
{
|
||||
addLoyaltyCards(NUM_CARDS);
|
||||
|
||||
// Export to whatever the default location is
|
||||
ImportExportTask task = new ImportExportTask(activity, false, format);
|
||||
TestTaskCompleteListener listener = new TestTaskCompleteListener();
|
||||
|
||||
// Export to the file
|
||||
ImportExportTask task = new ImportExportTask(activity, false, format, exportFile, listener);
|
||||
task.execute();
|
||||
|
||||
// Actually run the task to completion
|
||||
Robolectric.flushBackgroundThreadScheduler();
|
||||
|
||||
// Check that the listener was executed
|
||||
assertNotNull(listener.success);
|
||||
assertEquals(true, listener.success);
|
||||
assertNotNull(listener.file);
|
||||
assertEquals(exportFile, listener.file);
|
||||
|
||||
clearDatabase();
|
||||
|
||||
// Import everything back from the default location
|
||||
|
||||
task = new ImportExportTask(activity, true, format);
|
||||
listener = new TestTaskCompleteListener();
|
||||
|
||||
task = new ImportExportTask(activity, true, format, exportFile, listener);
|
||||
task.execute();
|
||||
|
||||
// Actually run the task to completion
|
||||
Robolectric.flushBackgroundThreadScheduler();
|
||||
|
||||
// Check that the listener was executed
|
||||
assertNotNull(listener.success);
|
||||
assertEquals(true, listener.success);
|
||||
assertNotNull(listener.file);
|
||||
assertEquals(exportFile, listener.file);
|
||||
|
||||
assertEquals(NUM_CARDS, db.getLoyaltyCardCount());
|
||||
|
||||
checkLoyaltyCards();
|
||||
|
||||
@@ -5,7 +5,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.0.0'
|
||||
classpath 'com.android.tools.build:gradle:2.1.3'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Tue May 03 10:42:45 EDT 2016
|
||||
#Sun Dec 04 15:17:03 EST 2016
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
|
||||