Merge pull request #205 from TheLastProject/feature/multiselect

Support multi-selection
This commit is contained in:
Sylvia van Os
2021-04-26 20:18:06 +02:00
committed by GitHub
52 changed files with 1217 additions and 562 deletions

View File

@@ -4,9 +4,6 @@ import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
@@ -28,6 +25,10 @@ import java.util.Collections;
import java.util.LinkedList;
import java.util.Map;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
/**
* This activity is callable and will allow a user to enter
* barcode data and generate all barcodes possible for

View File

@@ -0,0 +1,87 @@
package protect.card_locker;
import android.database.Cursor;
import androidx.recyclerview.widget.RecyclerView;
public abstract class BaseCursorAdapter<V extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<V>
{
private Cursor mCursor;
private boolean mDataValid;
private int mRowIDColumn;
public BaseCursorAdapter(Cursor inputCursor)
{
setHasStableIds(true);
swapCursor(inputCursor);
}
public abstract void onBindViewHolder(V inputHolder, Cursor inputCursor);
@Override
public void onBindViewHolder(V inputHolder, int inputPosition)
{
if (!mDataValid)
{
throw new IllegalStateException("Cannot bind view holder when cursor is in invalid state.");
}
if (!mCursor.moveToPosition(inputPosition))
{
throw new IllegalStateException("Could not move cursor to position " + inputPosition + " when trying to bind view holder");
}
onBindViewHolder(inputHolder, mCursor);
}
@Override
public int getItemCount()
{
if (mDataValid)
{
return mCursor.getCount();
}
else
{
return 0;
}
}
@Override
public long getItemId(int inputPosition)
{
if (!mDataValid)
{
throw new IllegalStateException("Cannot lookup item id when cursor is in invalid state.");
}
if (!mCursor.moveToPosition(inputPosition))
{
throw new IllegalStateException("Could not move cursor to position " + inputPosition + " when trying to get an item id");
}
return mCursor.getLong(mRowIDColumn);
}
public void swapCursor(Cursor inputCursor)
{
if (inputCursor == mCursor)
{
return;
}
if (inputCursor != null)
{
mCursor = inputCursor;
mDataValid = true;
notifyDataSetChanged();
}
else
{
notifyItemRangeRemoved(0, getItemCount());
mCursor = null;
mRowIDColumn = -1;
mDataValid = false;
}
}
}

View File

@@ -2,32 +2,28 @@ package protect.card_locker;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;
import android.os.Parcelable;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.RecyclerView;
/**
* The configuration screen for creating a shortcut.
*/
public class CardShortcutConfigure extends AppCompatActivity
public class CardShortcutConfigure extends AppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener
{
static final String TAG = "Catima";
final DBHelper mDb = new DBHelper(this);
@Override
public void onCreate(Bundle bundle)
{
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
// Set the result to CANCELED. This will cause nothing to happen if the
@@ -45,53 +41,59 @@ public class CardShortcutConfigure extends AppCompatActivity
final DBHelper db = new DBHelper(this);
// If there are no cards, bail
if(db.getLoyaltyCardCount() == 0)
{
if (db.getLoyaltyCardCount() == 0) {
Toast.makeText(this, R.string.noCardsMessage, Toast.LENGTH_LONG).show();
finish();
}
final ListView cardList = findViewById(R.id.list);
final RecyclerView cardList = findViewById(R.id.list);
cardList.setVisibility(View.VISIBLE);
Cursor cardCursor = db.getLoyaltyCardCursor();
final LoyaltyCardCursorAdapter adapter = new LoyaltyCardCursorAdapter(this, cardCursor);
final LoyaltyCardCursorAdapter adapter = new LoyaltyCardCursorAdapter(this, cardCursor, this);
cardList.setAdapter(adapter);
}
cardList.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Cursor selected = (Cursor) parent.getItemAtPosition(position);
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
private void onClickAction(int position) {
Cursor selected = mDb.getLoyaltyCardCursor();
selected.moveToPosition(position);
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
Log.d(TAG, "Creating shortcut for card " + loyaltyCard.store + "," + loyaltyCard.id);
Log.d(TAG, "Creating shortcut for card " + loyaltyCard.store + "," + loyaltyCard.id);
Intent shortcutIntent = new Intent(CardShortcutConfigure.this, LoyaltyCardViewActivity.class);
shortcutIntent.setAction(Intent.ACTION_MAIN);
// Prevent instances of the view activity from piling up; if one exists let this
// one replace it.
shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
Bundle bundle = new Bundle();
bundle.putInt("id", loyaltyCard.id);
bundle.putBoolean("view", true);
shortcutIntent.putExtras(bundle);
Intent shortcutIntent = new Intent(CardShortcutConfigure.this, LoyaltyCardViewActivity.class);
shortcutIntent.setAction(Intent.ACTION_MAIN);
// Prevent instances of the view activity from piling up; if one exists let this
// one replace it.
shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
Bundle bundle = new Bundle();
bundle.putInt("id", loyaltyCard.id);
bundle.putBoolean("view", true);
shortcutIntent.putExtras(bundle);
Bitmap icon = Utils.generateIcon(CardShortcutConfigure.this, loyaltyCard.store, loyaltyCard.headerColor, true).getLetterTile();
Parcelable icon = Intent.ShortcutIconResource.fromContext(CardShortcutConfigure.this, R.mipmap.ic_launcher);
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, loyaltyCard.store);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon);
setResult(RESULT_OK, intent);
ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(CardShortcutConfigure.this, String.valueOf(loyaltyCard.id))
.setIntent(shortcutIntent)
.setIcon(IconCompat.createWithAdaptiveBitmap(icon))
.setShortLabel(loyaltyCard.store)
.build();
finish();
}
Intent intent = ShortcutManagerCompat.createShortcutResultIntent(CardShortcutConfigure.this, shortcutInfo);
setResult(RESULT_OK, intent);
@Override
public void onIconClicked(int inputPosition) {
onClickAction(inputPosition);
}
finish();
}
});
@Override
public void onRowClicked(int inputPosition) {
onClickAction(inputPosition);
}
@Override
public void onRowLongClicked(int inputPosition) {
// do nothing
}
}

View File

@@ -6,14 +6,13 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Color;
import com.google.zxing.BarcodeFormat;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Currency;
import java.util.Date;
import java.util.ArrayList;
import java.util.List;
public class DBHelper extends SQLiteOpenHelper

View File

@@ -8,15 +8,6 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
@@ -29,7 +20,13 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class ImportExportActivity extends AppCompatActivity
{

View File

@@ -8,7 +8,6 @@ import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;

View File

@@ -10,6 +10,7 @@ import java.io.InvalidObjectException;
import java.math.BigDecimal;
import java.util.Currency;
import java.util.Date;
import java.util.List;
public class ImportURIHelper {
private static final String STORE = DBHelper.LoyaltyCardDbIds.STORE;
@@ -29,6 +30,7 @@ public class ImportURIHelper {
private final String oldHost;
private final String oldPath;
private final String shareText;
private final String shareMultipleText;
public ImportURIHelper(Context context) {
this.context = context;
@@ -37,6 +39,7 @@ public class ImportURIHelper {
oldHost = "brarcher.github.io";
oldPath = "/loyalty-card-locker/share";
shareText = context.getResources().getString(R.string.intent_import_card_from_url_share_text);
shareMultipleText = context.getResources().getString(R.string.intent_import_card_from_url_share_multiple_text);
}
private boolean isImportUri(Uri uri) {
@@ -126,17 +129,33 @@ public class ImportURIHelper {
return uriBuilder.build();
}
private void startShareIntent(Uri uri) {
public void startShareIntent(List<LoyaltyCard> loyaltyCards) {
int loyaltyCardCount = loyaltyCards.size();
StringBuilder text = new StringBuilder();
if (loyaltyCardCount == 1) {
text.append(shareText);
} else {
text.append(shareMultipleText);
}
text.append("\n\n");
for (int i = 0; i < loyaltyCardCount; i++) {
LoyaltyCard loyaltyCard = loyaltyCards.get(i);
text.append(loyaltyCard.store + ": " + toUri(loyaltyCard));
if (i < (loyaltyCardCount - 1)) {
text.append("\n\n");
}
}
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, shareText + "\n" + uri.toString());
sendIntent.putExtra(Intent.EXTRA_TEXT, text.toString());
sendIntent.setType("text/plain");
Intent shareIntent = Intent.createChooser(sendIntent, null);
context.startActivity(shareIntent);
}
public void startShareIntent(LoyaltyCard loyaltyCard) {
startShareIntent(toUri(loyaltyCard));
}
}

View File

@@ -0,0 +1,37 @@
package protect.card_locker;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.content.Context;
import android.view.View;
public class LoyaltyCardAnimator {
private static AnimatorSet selectedViewIn, defaultViewOut, selectedViewOut, defaultViewIn;
public static void flipView(Context inputContext, final View inputSelectedView, final View inputDefaultView, boolean inputItemSelected) {
selectedViewIn = (AnimatorSet) AnimatorInflater.loadAnimator(inputContext, R.animator.flip_left_in);
defaultViewOut = (AnimatorSet) AnimatorInflater.loadAnimator(inputContext, R.animator.flip_right_out);
selectedViewOut = (AnimatorSet) AnimatorInflater.loadAnimator(inputContext, R.animator.flip_left_out);
defaultViewIn = (AnimatorSet) AnimatorInflater.loadAnimator(inputContext, R.animator.flip_right_in);
final AnimatorSet showFrontAnim = new AnimatorSet();
final AnimatorSet showBackAnim = new AnimatorSet();
selectedViewIn.setTarget(inputSelectedView);
defaultViewOut.setTarget(inputDefaultView);
showFrontAnim.playTogether(selectedViewIn, defaultViewOut);
selectedViewOut.setTarget(inputSelectedView);
defaultViewIn.setTarget(inputDefaultView);
showBackAnim.playTogether(defaultViewIn, selectedViewOut);
if (inputItemSelected) {
showFrontAnim.start();
} else {
showBackAnim.start();
}
}
}

View File

@@ -2,98 +2,296 @@ package protect.card_locker;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.util.SparseBooleanArray;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.Date;
import java.util.ArrayList;
import androidx.cardview.widget.CardView;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import protect.card_locker.preferences.Settings;
class LoyaltyCardCursorAdapter extends CursorAdapter
public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder>
{
Settings settings;
private static int mCurrentSelectedIndex = -1;
private Cursor mCursor;
Settings mSettings;
boolean mDarkModeEnabled;
private Context mContext;
private CardAdapterListener mListener;
private SparseBooleanArray mSelectedItems;
private SparseBooleanArray mAnimationItemsIndex;
private boolean mReverseAllAnimations = false;
public LoyaltyCardCursorAdapter(Context context, Cursor cursor)
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener)
{
super(context, cursor, 0);
settings = new Settings(context);
super(inputCursor);
mSettings = new Settings(inputContext);
mCursor = inputCursor;
mContext = inputContext;
mListener = inputListener;
mSelectedItems = new SparseBooleanArray();
mAnimationItemsIndex = new SparseBooleanArray();
mDarkModeEnabled = MainActivity.isDarkModeEnabled(inputContext);
}
// The newView method is used to inflate a new view and return it,
// you don't bind any data to the view at this point.
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent)
public LoyaltyCardListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType)
{
return LayoutInflater.from(context).inflate(R.layout.loyalty_card_layout, parent, false);
View itemView = LayoutInflater.from(inputParent.getContext()).inflate(R.layout.loyalty_card_layout, inputParent, false);
return new LoyaltyCardListItemViewHolder(itemView);
}
// The bindView method is used to bind all data to a given view
// such as setting the text on a TextView.
@Override
public void bindView(View view, Context context, Cursor cursor)
public Cursor getCursor()
{
// Find fields to populate in inflated template
ImageView thumbnail = view.findViewById(R.id.thumbnail);
TextView storeField = view.findViewById(R.id.store);
TextView noteField = view.findViewById(R.id.note);
TextView balanceField = view.findViewById(R.id.balance);
TextView expiryField = view.findViewById(R.id.expiry);
ImageView star = view.findViewById(R.id.star);
return mCursor;
}
// Extract properties from cursor
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(cursor);
// Populate fields with extracted properties
storeField.setText(loyaltyCard.store);
storeField.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
if(!loyaltyCard.note.isEmpty())
{
noteField.setVisibility(View.VISIBLE);
noteField.setText(loyaltyCard.note);
noteField.setTextSize(settings.getFontSizeMax(settings.getSmallFont()));
}
else
{
noteField.setVisibility(View.GONE);
public void onBindViewHolder(LoyaltyCardListItemViewHolder inputHolder, Cursor inputCursor) {
if (mDarkModeEnabled) {
inputHolder.mStarIcon.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
}
if(!loyaltyCard.balance.equals(new BigDecimal("0"))) {
balanceField.setVisibility(View.VISIBLE);
balanceField.setText(context.getString(R.string.balanceSentence, Utils.formatBalance(context, loyaltyCard.balance, loyaltyCard.balanceType)));
balanceField.setTextSize(settings.getFontSizeMax(settings.getSmallFont()));
}
else
{
balanceField.setVisibility(View.GONE);
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(inputCursor);
inputHolder.mStoreField.setText(loyaltyCard.store);
inputHolder.mStoreField.setTextSize(mSettings.getFontSizeMax(mSettings.getMediumFont()));
if (!loyaltyCard.note.isEmpty()) {
inputHolder.mNoteField.setVisibility(View.VISIBLE);
inputHolder.mNoteField.setText(loyaltyCard.note);
inputHolder.mNoteField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
} else {
inputHolder.mNoteField.setVisibility(View.GONE);
}
if(loyaltyCard.expiry != null)
if (!loyaltyCard.balance.equals(new BigDecimal("0"))) {
inputHolder.mBalanceField.setVisibility(View.VISIBLE);
inputHolder.mBalanceField.setText(mContext.getString(R.string.balanceSentence, Utils.formatBalance(mContext, loyaltyCard.balance, loyaltyCard.balanceType)));
inputHolder.mBalanceField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
} else {
inputHolder.mBalanceField.setVisibility(View.GONE);
}
if (loyaltyCard.expiry != null)
{
expiryField.setVisibility(View.VISIBLE);
inputHolder.mExpiryField.setVisibility(View.VISIBLE);
int expiryString = R.string.expiryStateSentence;
if(Utils.hasExpired(loyaltyCard.expiry)) {
expiryString = R.string.expiryStateSentenceExpired;
expiryField.setTextColor(context.getResources().getColor(R.color.alert));
inputHolder.mExpiryField.setTextColor(mContext.getResources().getColor(R.color.alert));
}
inputHolder.mExpiryField.setText(mContext.getString(expiryString, DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.expiry)));
inputHolder.mExpiryField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
} else {
inputHolder.mExpiryField.setVisibility(View.GONE);
}
inputHolder.mStarIcon.setVisibility((loyaltyCard.starStatus != 0) ? View.VISIBLE : View.GONE);
inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, loyaltyCard.store, loyaltyCard.headerColor).getLetterTile());
inputHolder.itemView.setActivated(mSelectedItems.get(inputCursor.getPosition(), false));
applyIconAnimation(inputHolder, inputCursor.getPosition());
applyClickEvents(inputHolder, inputCursor.getPosition());
}
private void applyClickEvents(LoyaltyCardListItemViewHolder inputHolder, final int inputPosition)
{
inputHolder.mThumbnailContainer.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View inputView)
{
mListener.onIconClicked(inputPosition);
}
});
inputHolder.mRow.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View inputView)
{
mListener.onRowClicked(inputPosition);
}
});
inputHolder.mInformationContainer.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View inputView)
{
mListener.onRowClicked(inputPosition);
}
});
inputHolder.mRow.setOnLongClickListener(new View.OnLongClickListener()
{
@Override
public boolean onLongClick(View inputView)
{
mListener.onRowLongClicked(inputPosition);
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
}
});
inputHolder.mInformationContainer.setOnLongClickListener(new View.OnLongClickListener()
{
@Override
public boolean onLongClick(View inputView)
{
mListener.onRowLongClicked(inputPosition);
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
}
});
}
private void applyIconAnimation(LoyaltyCardListItemViewHolder inputHolder, int inputPosition)
{
if (mSelectedItems.get(inputPosition, false))
{
inputHolder.mThumbnailFrontContainer.setVisibility(View.GONE);
resetIconYAxis(inputHolder.mThumbnailBackContainer);
inputHolder.mThumbnailBackContainer.setVisibility(View.VISIBLE);
inputHolder.mThumbnailBackContainer.setAlpha(1);
if (mCurrentSelectedIndex == inputPosition)
{
LoyaltyCardAnimator.flipView(mContext, inputHolder.mThumbnailBackContainer, inputHolder.mThumbnailFrontContainer, true);
resetCurrentIndex();
}
expiryField.setText(context.getString(expiryString, DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.expiry)));
expiryField.setTextSize(settings.getFontSizeMax(settings.getSmallFont()));
}
else
{
expiryField.setVisibility(View.GONE);
inputHolder.mThumbnailBackContainer.setVisibility(View.GONE);
resetIconYAxis(inputHolder.mThumbnailFrontContainer);
inputHolder.mThumbnailFrontContainer.setVisibility(View.VISIBLE);
inputHolder.mThumbnailFrontContainer.setAlpha(1);
if ((mReverseAllAnimations && mAnimationItemsIndex.get(inputPosition, false)) || mCurrentSelectedIndex == inputPosition)
{
LoyaltyCardAnimator.flipView(mContext, inputHolder.mThumbnailBackContainer, inputHolder.mThumbnailFrontContainer, false);
resetCurrentIndex();
}
}
}
private void resetIconYAxis(View inputView)
{
if (inputView.getRotationY() != 0)
{
inputView.setRotationY(0);
}
}
public void resetAnimationIndex()
{
mReverseAllAnimations = false;
mAnimationItemsIndex.clear();
}
@SuppressFBWarnings("ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD")
public void toggleSelection(int inputPosition)
{
mCurrentSelectedIndex = inputPosition;
if (mSelectedItems.get(inputPosition, false))
{
mSelectedItems.delete(inputPosition);
mAnimationItemsIndex.delete(inputPosition);
}
else
{
mSelectedItems.put(inputPosition, true);
mAnimationItemsIndex.put(inputPosition, true);
}
notifyItemChanged(inputPosition);
}
public void clearSelections()
{
mReverseAllAnimations = true;
mSelectedItems.clear();
notifyDataSetChanged();
}
public int getSelectedItemCount()
{
return mSelectedItems.size();
}
public ArrayList<LoyaltyCard> getSelectedItems()
{
ArrayList<LoyaltyCard> result = new ArrayList<>();
int i;
for(i = 0; i < mSelectedItems.size(); i++)
{
mCursor.moveToPosition(mSelectedItems.keyAt(i));
result.add(LoyaltyCard.toLoyaltyCard(mCursor));
}
if (loyaltyCard.starStatus!=0) star.setVisibility(View.VISIBLE);
else star.setVisibility(View.GONE);
thumbnail.setImageBitmap(Utils.generateIcon(context, loyaltyCard.store, loyaltyCard.headerColor).getLetterTile());
return result;
}
}
private void resetCurrentIndex()
{
mCurrentSelectedIndex = -1;
}
public interface CardAdapterListener
{
void onIconClicked(int inputPosition);
void onRowClicked(int inputPosition);
void onRowLongClicked(int inputPosition);
}
public class LoyaltyCardListItemViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener
{
public TextView mStoreField, mNoteField, mBalanceField, mExpiryField;
public LinearLayout mInformationContainer;
public ImageView mCardIcon, mStarIcon;
public CardView mThumbnailContainer;
public ConstraintLayout mRow;
public RelativeLayout mThumbnailFrontContainer, mThumbnailBackContainer;
public LoyaltyCardListItemViewHolder(View inputView)
{
super(inputView);
mThumbnailContainer = inputView.findViewById(R.id.thumbnail_container);
mRow = inputView.findViewById(R.id.row);
mThumbnailFrontContainer = inputView.findViewById(R.id.thumbnail_front);
mThumbnailBackContainer = inputView.findViewById(R.id.thumbnail_back);
mInformationContainer = inputView.findViewById(R.id.information_container);
mStoreField = inputView.findViewById(R.id.store);
mNoteField = inputView.findViewById(R.id.note);
mBalanceField = inputView.findViewById(R.id.balance);
mExpiryField = inputView.findViewById(R.id.expiry);
mCardIcon = inputView.findViewById(R.id.thumbnail);
mStarIcon = inputView.findViewById(R.id.star);
inputView.setOnLongClickListener(this);
}
@Override
public boolean onLongClick(View inputView)
{
mListener.onRowLongClicked(getAdapterPosition());
inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
}
}
}

View File

@@ -6,22 +6,10 @@ import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.DialogFragment;
import android.os.LocaleList;
import android.text.Editable;
import android.text.InputType;
@@ -29,7 +17,6 @@ import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
@@ -42,6 +29,10 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
import com.google.zxing.BarcodeFormat;
import com.jaredrummler.android.colorpicker.ColorPickerDialog;
@@ -50,7 +41,6 @@ import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;
import java.io.InvalidObjectException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
@@ -60,6 +50,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.DialogFragment;
public class LoyaltyCardEditActivity extends AppCompatActivity
{
private static final String TAG = "Catima";

View File

@@ -1,8 +1,8 @@
package protect.card_locker;
import android.app.Application;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.app.AppCompatDelegate;
import protect.card_locker.preferences.Settings;
public class LoyaltyCardLockerApplication extends Application {

View File

@@ -7,24 +7,12 @@ import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Guideline;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.widget.TextViewCompat;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.Toolbar;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
@@ -41,8 +29,17 @@ import com.google.zxing.BarcodeFormat;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.Guideline;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.widget.TextViewCompat;
import protect.card_locker.preferences.Settings;
public class LoyaltyCardViewActivity extends AppCompatActivity
@@ -491,7 +488,7 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
break;
case R.id.action_share:
importURIHelper.startShareIntent(loyaltyCard);
importURIHelper.startShareIntent(Arrays.asList(loyaltyCard));
return true;
case R.id.action_lock_unlock:

View File

@@ -1,63 +1,157 @@
package protect.card_locker;
import android.app.AlertDialog;
import android.app.SearchManager;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.view.ContextMenu;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.tabs.TabLayout;
import java.util.List;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import protect.card_locker.preferences.SettingsActivity;
public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener
public class MainActivity extends AppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener, GestureDetector.OnGestureListener
{
private static final String TAG = "Catima";
private Menu menu;
private GestureDetector gestureDetector;
protected String filter = "";
private final DBHelper mDB = new DBHelper(this);
private LoyaltyCardCursorAdapter mAdapter;
private ActionMode mCurrentActionMode;
private Menu mMenu;
private GestureDetector mGestureDetector;
protected String mFilter = "";
protected int selectedTab = 0;
private RecyclerView mCardList;
private ActionMode.Callback mCurrentActionModeCallback = new ActionMode.Callback()
{
@Override
public boolean onCreateActionMode(ActionMode inputMode, Menu inputMenu)
{
inputMode.getMenuInflater().inflate(R.menu.card_longclick_menu, inputMenu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode inputMode, Menu inputMenu)
{
return false;
}
@Override
public boolean onActionItemClicked(ActionMode inputMode, MenuItem inputItem)
{
if (inputItem.getItemId() == R.id.action_copy_to_clipboard)
{
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
String clipboardData;
int cardCount = mAdapter.getSelectedItemCount();
if (cardCount == 1) {
clipboardData = mAdapter.getSelectedItems().get(0).cardId;
} else {
StringBuilder cardIds = new StringBuilder();
for (int i = 0; i < cardCount; i++) {
LoyaltyCard loyaltyCard = mAdapter.getSelectedItems().get(i);
cardIds.append(loyaltyCard.store + ": " + loyaltyCard.cardId);
if (i < (cardCount - 1)) {
cardIds.append("\n");
}
}
clipboardData = cardIds.toString();
}
ClipData clip = ClipData.newPlainText(getString(R.string.card_ids_copied), clipboardData);
clipboard.setPrimaryClip(clip);
Toast.makeText(MainActivity.this, cardCount > 1 ? R.string.copy_to_clipboard_multiple_toast : R.string.copy_to_clipboard_toast, Toast.LENGTH_LONG).show();
inputMode.finish();
return true;
}
else if (inputItem.getItemId() == R.id.action_share)
{
final ImportURIHelper importURIHelper = new ImportURIHelper(MainActivity.this);
importURIHelper.startShareIntent(mAdapter.getSelectedItems());
inputMode.finish();
return true;
}
else if(inputItem.getItemId() == R.id.action_edit)
{
if (mAdapter.getSelectedItemCount() != 1) {
throw new IllegalArgumentException("Cannot edit more than 1 card at a time");
}
Intent intent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("id", mAdapter.getSelectedItems().get(0).id);
bundle.putBoolean("update", true);
intent.putExtras(bundle);
startActivity(intent);
inputMode.finish();
return true;
}
return false;
}
@Override
public void onDestroyActionMode(ActionMode inputMode)
{
mAdapter.clearSelections();
mCurrentActionMode = null;
mCardList.post(new Runnable()
{
@Override
public void run()
{
mAdapter.resetAnimationIndex();
}
});
}
};
@Override
protected void onCreate(Bundle savedInstanceState)
protected void onCreate(Bundle inputSavedInstanceState)
{
super.onCreate(savedInstanceState);
super.onCreate(inputSavedInstanceState);
setContentView(R.layout.main_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
updateLoyaltyCardList(filter, null);
updateLoyaltyCardList(mFilter, null);
TabLayout groupsTabLayout = findViewById(R.id.groups);
groupsTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
selectedTab = tab.getPosition();
updateLoyaltyCardList(filter, tab.getTag());
updateLoyaltyCardList(mFilter, tab.getTag());
// Store active tab in Shared Preference to restore next app launch
SharedPreferences activeTabPref = getApplicationContext().getSharedPreferences(
@@ -79,12 +173,12 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
}
});
gestureDetector = new GestureDetector(this, this);
mGestureDetector = new GestureDetector(this, this);
View.OnTouchListener gestureTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(final View v, final MotionEvent event){
return gestureDetector.onTouchEvent(event);
return mGestureDetector.onTouchEvent(event);
}
};
@@ -129,15 +223,23 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
}
@Override
protected void onResume() {
protected void onResume()
{
super.onResume();
if (menu != null)
if(mCurrentActionMode != null)
{
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
mAdapter.clearSelections();
mCurrentActionMode.finish();
}
if (!searchView.isIconified()) {
filter = searchView.getQuery().toString();
if (mMenu != null)
{
SearchView searchView = (SearchView) mMenu.findItem(R.id.action_search).getActionView();
if (!searchView.isIconified())
{
mFilter = searchView.getQuery().toString();
}
}
@@ -163,11 +265,12 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
assert tab != null;
group = tab.getTag();
}
updateLoyaltyCardList(filter, group);
updateLoyaltyCardList(mFilter, group);
// End of active tab logic
FloatingActionButton addButton = findViewById(R.id.fabAdd);
addButton.setOnClickListener(new View.OnClickListener() {
addButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(), ScanActivity.class);
@@ -183,14 +286,12 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
if (requestCode == Utils.MAIN_REQUEST) {
// We're coming back from another view so clear the search
// We only do this now to prevent a flash of all entries right after picking one
filter = "";
if (menu != null)
mFilter = "";
if (mMenu != null)
{
MenuItem searchItem = menu.findItem(R.id.action_search);
MenuItem searchItem = mMenu.findItem(R.id.action_search);
searchItem.collapseActionView();
}
// In case the theme changed
recreate();
return;
@@ -209,16 +310,18 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
}
@Override
public void onBackPressed() {
if (menu == null)
public void onBackPressed()
{
if (mMenu == null)
{
super.onBackPressed();
return;
}
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
SearchView searchView = (SearchView) mMenu.findItem(R.id.action_search).getActionView();
if (!searchView.isIconified()) {
if (!searchView.isIconified())
{
searchView.setIconified(true);
} else {
TabLayout groupsTabLayout = findViewById(R.id.groups);
@@ -239,21 +342,29 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
group = (Group) tag;
}
final ListView cardList = findViewById(R.id.list);
mCardList = findViewById(R.id.list);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
mCardList.setLayoutManager(mLayoutManager);
mCardList.setItemAnimator(new DefaultItemAnimator());
final TextView helpText = findViewById(R.id.helpText);
final TextView noMatchingCardsText = findViewById(R.id.noMatchingCardsText);
final DBHelper db = new DBHelper(this);
Cursor cardCursor = db.getLoyaltyCardCursor(filterText, group);
Cursor cardCursor = mDB.getLoyaltyCardCursor(filterText, group);
if(db.getLoyaltyCardCount() > 0)
mAdapter = new LoyaltyCardCursorAdapter(this, cardCursor, this);
mCardList.setAdapter(mAdapter);
registerForContextMenu(mCardList);
if(mDB.getLoyaltyCardCount() > 0)
{
// We want the cardList to be visible regardless of the filtered match count
// to ensure that the noMatchingCardsText doesn't end up being shown below
// the keyboard
cardList.setVisibility(View.VISIBLE);
mCardList.setVisibility(View.VISIBLE);
helpText.setVisibility(View.GONE);
if(cardCursor.getCount() > 0)
if(mAdapter.getItemCount() > 0)
{
noMatchingCardsText.setVisibility(View.GONE);
}
@@ -264,35 +375,14 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
}
else
{
cardList.setVisibility(View.GONE);
mCardList.setVisibility(View.GONE);
helpText.setVisibility(View.VISIBLE);
noMatchingCardsText.setVisibility(View.GONE);
}
final LoyaltyCardCursorAdapter adapter = new LoyaltyCardCursorAdapter(this, cardCursor);
cardList.setAdapter(adapter);
registerForContextMenu(cardList);
cardList.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Cursor selected = (Cursor) parent.getItemAtPosition(position);
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
Intent i = new Intent(view.getContext(), LoyaltyCardViewActivity.class);
i.setAction("");
final Bundle b = new Bundle();
b.putInt("id", loyaltyCard.id);
i.putExtras(b);
ShortcutHelper.updateShortcuts(MainActivity.this, loyaltyCard, i);
startActivityForResult(i, Utils.MAIN_REQUEST);
}
});
if (mCurrentActionMode != null) {
mCurrentActionMode.finish();
}
}
public void updateTabGroups(TabLayout groupsTabLayout)
@@ -333,80 +423,47 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)
public boolean onCreateOptionsMenu(Menu inputMenu)
{
super.onCreateContextMenu(menu, v, menuInfo);
if (v.getId()==R.id.list)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.card_longclick_menu, menu);
}
}
this.mMenu = inputMenu;
@Override
public boolean onContextItemSelected(MenuItem item)
{
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
ListView listView = findViewById(R.id.list);
Cursor cardCursor = (Cursor)listView.getItemAtPosition(info.position);
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cardCursor);
if(item.getItemId() == R.id.action_clipboard)
{
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(card.store, card.cardId);
clipboard.setPrimaryClip(clip);
Toast.makeText(this, R.string.copy_to_clipboard_toast, Toast.LENGTH_LONG).show();
return true;
}
else if(item.getItemId() == R.id.action_share)
{
final ImportURIHelper importURIHelper = new ImportURIHelper(this);
importURIHelper.startShareIntent(card);
return true;
}
return super.onContextItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
this.menu = menu;
getMenuInflater().inflate(R.menu.main_menu, menu);
getMenuInflater().inflate(R.menu.main_menu, inputMenu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
if (searchManager != null) {
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
if (searchManager != null)
{
SearchView searchView = (SearchView) inputMenu.findItem(R.id.action_search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setSubmitButtonEnabled(false);
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
searchView.setOnCloseListener(new SearchView.OnCloseListener()
{
@Override
public boolean onClose() {
public boolean onClose()
{
invalidateOptionsMenu();
return false;
}
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener()
{
@Override
public boolean onQueryTextSubmit(String query) {
public boolean onQueryTextSubmit(String query)
{
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
filter = newText;
public boolean onQueryTextChange(String newText)
{
mFilter = newText;
TabLayout groupsTabLayout = findViewById(R.id.groups);
TabLayout.Tab currentTab = groupsTabLayout.getTabAt(groupsTabLayout.getSelectedTabPosition());
updateLoyaltyCardList(
newText,
mFilter,
currentTab != null ? currentTab.getTag() : null
);
@@ -414,14 +471,13 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
}
});
}
return super.onCreateOptionsMenu(menu);
return super.onCreateOptionsMenu(inputMenu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
public boolean onOptionsItemSelected(MenuItem inputItem)
{
int id = item.getItemId();
int id = inputItem.getItemId();
if (id == R.id.action_manage_groups)
{
@@ -430,14 +486,14 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
return true;
}
if(id == R.id.action_import_export)
if (id == R.id.action_import_export)
{
Intent i = new Intent(getApplicationContext(), ImportExportActivity.class);
startActivityForResult(i, Utils.MAIN_REQUEST);
return true;
}
if(id == R.id.action_settings)
if (id == R.id.action_settings)
{
Intent i = new Intent(getApplicationContext(), SettingsActivity.class);
startActivityForResult(i, Utils.MAIN_REQUEST);
@@ -450,14 +506,14 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
return true;
}
if(id == R.id.action_about)
if (id == R.id.action_about)
{
Intent i = new Intent(getApplicationContext(), AboutActivity.class);
startActivityForResult(i, Utils.MAIN_REQUEST);
return true;
}
return super.onOptionsItemSelected(item);
return super.onOptionsItemSelected(inputItem);
}
protected static boolean isDarkModeEnabled(Context inputContext)
@@ -536,4 +592,79 @@ public class MainActivity extends AppCompatActivity implements GestureDetector.O
return false;
}
@Override
public void onRowLongClicked(int inputPosition)
{
enableActionMode(inputPosition);
}
private void enableActionMode(int inputPosition)
{
if (mCurrentActionMode == null)
{
mCurrentActionMode = startSupportActionMode(mCurrentActionModeCallback);
}
toggleSelection(inputPosition);
}
private void toggleSelection(int inputPosition)
{
mAdapter.toggleSelection(inputPosition);
int count = mAdapter.getSelectedItemCount();
if (count == 0) {
mCurrentActionMode.finish();
} else {
mCurrentActionMode.setTitle("Selected: " + count + " Cards");
MenuItem editItem = mCurrentActionMode.getMenu().findItem(R.id.action_edit);
if (count == 1) {
editItem.setVisible(true);
editItem.setEnabled(true);
} else {
editItem.setVisible(false);
editItem.setEnabled(false);
}
mCurrentActionMode.invalidate();
}
}
@Override
public void onIconClicked(int inputPosition)
{
if (mCurrentActionMode == null)
{
mCurrentActionMode = startSupportActionMode(mCurrentActionModeCallback);
}
toggleSelection(inputPosition);
}
@Override
public void onRowClicked(int inputPosition)
{
if (mAdapter.getSelectedItemCount() > 0)
{
enableActionMode(inputPosition);
}
else
{
Cursor selected = mAdapter.getCursor();
selected.moveToPosition(inputPosition);
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(selected);
Intent i = new Intent(this, LoyaltyCardViewActivity.class);
i.setAction("");
final Bundle b = new Bundle();
b.putInt("id", loyaltyCard.id);
i.putExtras(b);
ShortcutHelper.updateShortcuts(MainActivity.this, loyaltyCard, i);
startActivityForResult(i, Utils.MAIN_REQUEST);
}
}
}

View File

@@ -9,6 +9,14 @@ import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.NumberFormat;
@@ -19,15 +27,6 @@ import java.util.GregorianCalendar;
import androidx.core.graphics.ColorUtils;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
public class Utils {
private static final String TAG = "Catima";

View File

@@ -7,23 +7,17 @@ import com.google.zxing.BarcodeFormat;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.json.JSONException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.Currency;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipFile;
import protect.card_locker.DBHelper;
import protect.card_locker.FormatException;

View File

@@ -2,10 +2,8 @@ package protect.card_locker.importexport;
import org.json.JSONException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import protect.card_locker.DBHelper;

View File

@@ -1,33 +1,21 @@
package protect.card_locker.importexport;
import android.annotation.SuppressLint;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import com.google.zxing.BarcodeFormat;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Currency;
import java.util.Date;
import java.util.TimeZone;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import protect.card_locker.DBHelper;

View File

@@ -7,8 +7,6 @@ import java.io.OutputStreamWriter;
import protect.card_locker.DBHelper;
import protect.card_locker.DataFormat;
import protect.card_locker.importexport.CsvDatabaseExporter;
import protect.card_locker.importexport.DatabaseExporter;
public class MultiFormatExporter
{

View File

@@ -6,14 +6,11 @@ import org.json.JSONException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import protect.card_locker.DBHelper;
import protect.card_locker.DataFormat;
import protect.card_locker.FormatException;
import protect.card_locker.importexport.CsvDatabaseImporter;
import protect.card_locker.importexport.DatabaseImporter;
public class MultiFormatImporter
{

View File

@@ -2,11 +2,11 @@ package protect.card_locker.preferences;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.preference.PreferenceManager;
import androidx.annotation.IntegerRes;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
import protect.card_locker.R;
public class Settings

View File

@@ -1,15 +1,15 @@
package protect.card_locker.preferences;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import android.view.MenuItem;
import nl.invissvenska.numberpickerpreference.NumberDialogPreference;
import nl.invissvenska.numberpickerpreference.NumberPickerPreferenceDialogFragment;
import protect.card_locker.R;

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="0"
android:propertyName="alpha"
android:valueFrom="1.0"
android:valueTo="0.0" />
<objectAnimator
android:duration="@integer/full_rotation_duration"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:propertyName="rotationY"
android:valueFrom="-180"
android:valueTo="0" />
<objectAnimator
android:duration="1"
android:propertyName="alpha"
android:startOffset="@integer/half_rotation_duration"
android:valueFrom="0.0"
android:valueTo="1.0" />
</set>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@integer/full_rotation_duration"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:propertyName="rotationY"
android:valueFrom="0"
android:valueTo="180" />
<objectAnimator
android:duration="1"
android:propertyName="alpha"
android:startOffset="@integer/half_rotation_duration"
android:valueFrom="1.0"
android:valueTo="0.0" />
</set>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="0"
android:propertyName="alpha"
android:valueFrom="1.0"
android:valueTo="0.0" />
<objectAnimator
android:duration="@integer/full_rotation_duration"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:propertyName="rotationY"
android:valueFrom="180"
android:valueTo="0" />
<objectAnimator
android:duration="1"
android:propertyName="alpha"
android:startOffset="@integer/half_rotation_duration"
android:valueFrom="0.0"
android:valueTo="1.0" />
</set>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@integer/full_rotation_duration"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:propertyName="rotationY"
android:valueFrom="0"
android:valueTo="-180" />
<objectAnimator
android:duration="1"
android:propertyName="alpha"
android:startOffset="@integer/half_rotation_duration"
android:valueFrom="1.0"
android:valueTo="0.0" />
</set>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
</vector>

View File

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

View File

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

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
</vector>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/darker_gray"/>
<size android:height="1dp"/>
</shape>

View File

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

View File

@@ -27,9 +27,11 @@
android:text="@string/noMatchingGiftCards"
android:visibility="gone"/>
<ListView
android:layout_width="wrap_content"
android:layout_height="match_parent"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:visibility="gone"/>
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:visibility="gone" />
</RelativeLayout>

View File

@@ -1,80 +1,118 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/row"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:baselineAligned="false"
android:layout_height="wrap_content"
android:layout_marginBottom="0.5dp"
android:background="@drawable/list_row"
android:clickable="true"
android:focusable="true"
android:padding="@dimen/activity_margin">
<androidx.cardview.widget.CardView
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_marginEnd="@dimen/activity_margin"
app:cardCornerRadius="4dp"
app:cardElevation="0dp">
<ImageView
android:id="@+id/thumbnail"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:contentDescription="@string/thumbnailDescription"
android:src="@mipmap/ic_launcher"/>
</androidx.cardview.widget.CardView>
<LinearLayout
android:orientation="vertical"
android:layout_width="0dip"
android:id="@+id/information_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
android:layout_marginStart="@dimen/activity_margin"
android:layout_marginLeft="@dimen/activity_margin"
android:layout_toEndOf="@+id/thumbnail_container"
android:layout_toRightOf="@+id/thumbnail_container"
android:layout_weight="1"
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@+id/thumbnail_container"
app:layout_constraintEnd_toStartOf="@+id/star"
app:layout_constraintStart_toEndOf="@+id/thumbnail_container"
app:layout_constraintTop_toTopOf="@+id/thumbnail_container">
<LinearLayout
android:id="@+id/valueLayout"
<TextView
android:id="@+id/store"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible" >
<TextView
android:id="@+id/store"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/storeNameTextSize"
android:textStyle="bold"/>
</LinearLayout>
android:textSize="@dimen/storeNameTextSize"
android:textStyle="bold" />
<TextView
android:id="@+id/note"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textSize="@dimen/noteTextSize"/>
android:lines="1"
android:textSize="@dimen/noteTextSize" />
<TextView
android:id="@+id/balance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textSize="@dimen/noteTextSize"/>
android:lines="1"
android:textSize="@dimen/noteTextSize" />
<TextView
android:id="@+id/expiry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textSize="@dimen/noteTextSize"/>
android:lines="1"
android:textSize="@dimen/noteTextSize" />
</LinearLayout>
<androidx.cardview.widget.CardView
android:id="@+id/thumbnail_container"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
app:cardCornerRadius="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<RelativeLayout
android:id="@+id/thumbnail_front"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize">
<ImageView
android:id="@+id/thumbnail"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:contentDescription="@string/thumbnailDescription"
android:src="@mipmap/ic_launcher" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/thumbnail_back"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize">
<ImageView
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_centerHorizontal="true"
android:contentDescription="@string/thumbnailDescription"
app:srcCompat="@drawable/ic_done" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
<ImageView
android:id="@+id/star"
android:layout_width="@dimen/cardThumbnailSize"
android:layout_height="@dimen/cardThumbnailSize"
android:layout_marginStart="@dimen/activity_margin"
android:layout_marginLeft="@dimen/activity_margin"
app:srcCompat="@drawable/ic_starred_white"
app:tint="@color/iconColor"
android:contentDescription="@string/starImage"/>
</LinearLayout>
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginStart="@dimen/activity_margin"
android:contentDescription="@string/starImage"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@android:color/black" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,4 +1,3 @@
<?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">
<menu>
</menu>

View File

@@ -3,11 +3,24 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_clipboard"
android:id="@+id/action_copy_to_clipboard"
android:title="@string/copy_to_clipboard"
android:icon="@drawable/ic_copy"
android:titleCondensed="@string/copy_to_clipboard"
app:showAsAction="always"/>
<item
android:id="@+id/action_share"
android:title="@string/share"
android:icon="@drawable/ic_share"
android:titleCondensed="@string/share"
app:showAsAction="always"/>
<item
android:id="@+id/action_edit"
android:icon="@drawable/ic_edit"
android:title="@string/editCardTitle"
android:titleCondensed="@string/editCardTitle"
app:showAsAction="always"/>
</menu>

View File

@@ -11,6 +11,8 @@
<color name="colorPrimaryText">#000000</color>
<color name="colorSecondaryText">#ffffff</color>
<color name="listItemHighlight">#88000000</color>
<color name="inputContrastBackground">#070707</color>
<color name="inputBackground">#000000</color>
<color name="inputBorder">#222222</color>

View File

@@ -1,8 +1,9 @@
<resources>>
<resources>
<style name="AppTheme.NoActionBar" parent="AppTheme">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
</resources>

View File

@@ -10,6 +10,8 @@
<color name="colorPrimaryText">#ffffff</color>
<color name="colorSecondaryText">#000000</color>
<color name="listItemHighlight">#44000000</color>
<color name="inputContrastBackground">#F8F8F8</color>
<color name="inputBackground">#FFFFFF</color>
<color name="inputBorder">#DDDDDD</color>

View File

@@ -2,4 +2,6 @@
<resources>
<string name="app_revision_url" translatable="false">https://github.com/TheLastProject/Catima/releases</string>
<string name="app_webpage_url" translatable="false">https://github.com/TheLastProject/Catima</string>
<integer name="full_rotation_duration">100</integer>
<integer name="half_rotation_duration">50</integer>
</resources>

View File

@@ -4,6 +4,7 @@
<string name="action_search">Search</string>
<string name="action_add">Add</string>
<string name="card_selected">Selected:\u0020</string>
<string name="noGiftCards">Click the + plus button to add a card, or import some from the ⋮ menu first.</string>
<string name="noMatchingGiftCards">Didn\'t find anything. Try changing your search.</string>
@@ -36,6 +37,7 @@
<string name="scanCardBarcode">Scan Card Barcode</string>
<string name="cardShortcut">Card Shortcut</string>
<string name="noCardsMessage">Add a card first</string>
<string name="card_ids_copied">Copied Card ID(s)</string>
<string name="barcodeImageDescription">Image of card barcode</string>
@@ -76,7 +78,7 @@
<string name="selectBarcodeTitle">Select Barcode</string>
<string name="enterBarcodeInstructions">Enter the card ID, and either pick its barcode type below, or &#8220;This card has no barcode&#8221;.</string>
<string name="copy_to_clipboard_toast">Card ID copied to clipboard</string>
<string name="copy_to_clipboard_toast">Card ID(s) copied to clipboard</string>
<string name="thumbnailDescription">Thumbnail for card</string>
<string name="starImage">Favorite star</string>
@@ -173,4 +175,6 @@
<string name="setBarcodeId">Set barcode value</string>
<string name="unsupportedBarcodeType">This barcode type can\'t yet be displayed. It may be supported in a newer version of the app.</string>
<string name="wrongValueForBarcodeType">The value is not valid for the selected barcode type</string>
<string name="copy_to_clipboard_multiple_toast">Copied card IDs to clipboard</string>
<string name="intent_import_card_from_url_share_multiple_text">I want to share some cards with you</string>
</resources>

View File

@@ -7,6 +7,9 @@
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorSecondary">@color/colorSecondary</item>
<item name="colorAccent">@color/colorSecondary</item>
<item name="actionModeBackground">@color/colorPrimary</item>
<item name="windowActionModeOverlay">true</item>
<item name="actionModeCloseDrawable">@drawable/ic_close</item>
</style>
<style name="AppTheme.NoActionBar" parent="AppTheme">

View File

@@ -38,7 +38,7 @@ public class DatabaseTest
public void setUp()
{
Activity activity = Robolectric.setupActivity(MainActivity.class);
db = new DBHelper(activity);
db = TestHelpers.getEmptyDb(activity);
}
@Test

View File

@@ -1,8 +1,5 @@
package protect.card_locker;
import static org.junit.Assert.assertEquals;
import static org.robolectric.Shadows.shadowOf;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -10,6 +7,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.view.View;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
@@ -17,6 +15,9 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import static org.junit.Assert.assertEquals;
import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class ImportExportActivityTest

View File

@@ -17,7 +17,6 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -25,13 +24,12 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Currency;
import java.util.Date;
@@ -62,7 +60,7 @@ public class ImportExportTest
public void setUp()
{
activity = Robolectric.setupActivity(MainActivity.class);
db = new DBHelper(activity);
db = TestHelpers.getEmptyDb(activity);
nowMs = System.currentTimeMillis();
Calendar lastYear = Calendar.getInstance();
@@ -314,20 +312,6 @@ public class ImportExportTest
cursor.close();
}
/**
* Delete the contents of the database
*/
private void clearDatabase()
{
SQLiteDatabase database = db.getWritableDatabase();
database.execSQL("delete from " + DBHelper.LoyaltyCardDbIds.TABLE);
database.execSQL("delete from " + DBHelper.LoyaltyCardDbGroups.TABLE);
database.execSQL("delete from " + DBHelper.LoyaltyCardDbIdsGroups.TABLE);
database.close();
assertEquals(0, db.getLoyaltyCardCount());
}
@Test
public void multipleCardsExportImport() throws IOException
{
@@ -343,7 +327,7 @@ public class ImportExportTest
assertTrue(result);
outStream.close();
clearDatabase();
TestHelpers.getEmptyDb(activity);
ByteArrayInputStream inData = new ByteArrayInputStream(outData.toByteArray());
@@ -356,7 +340,7 @@ public class ImportExportTest
checkLoyaltyCards();
// Clear the database for the next format under test
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -374,7 +358,7 @@ public class ImportExportTest
assertTrue(result);
outStream.close();
clearDatabase();
TestHelpers.getEmptyDb(activity);
ByteArrayInputStream inData = new ByteArrayInputStream(outData.toByteArray());
@@ -387,7 +371,7 @@ public class ImportExportTest
checkLoyaltyCardsFiveStarred();
// Clear the database for the next format under test
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
private List<String> groupsToGroupNames(List<Group> groups)
@@ -447,7 +431,7 @@ public class ImportExportTest
assertTrue(result);
outStream.close();
clearDatabase();
TestHelpers.getEmptyDb(activity);
ByteArrayInputStream inData = new ByteArrayInputStream(outData.toByteArray());
@@ -473,7 +457,7 @@ public class ImportExportTest
assertEquals(emptyGroup, db.getLoyaltyCardGroups(10));
// Clear the database for the next format under test
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -502,7 +486,7 @@ public class ImportExportTest
checkLoyaltyCards();
// Clear the database for the next format under test
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -521,7 +505,7 @@ public class ImportExportTest
boolean result = MultiFormatExporter.exportData(db, outStream, DataFormat.Catima);
assertTrue(result);
clearDatabase();
TestHelpers.getEmptyDb(activity);
// commons-csv would throw a RuntimeException if an entry was quotes but had
// content after. For example:
@@ -537,7 +521,7 @@ public class ImportExportTest
assertEquals(0, db.getLoyaltyCardCount());
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
}
@@ -576,7 +560,7 @@ public class ImportExportTest
assertNotNull(listener.success);
assertEquals(true, listener.success);
clearDatabase();
TestHelpers.getEmptyDb(activity);
// Import everything back from the default location
@@ -599,7 +583,7 @@ public class ImportExportTest
checkLoyaltyCards();
// Clear the database for the next format under test
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -635,7 +619,7 @@ public class ImportExportTest
assertNull(card.headerColor);
assertEquals(0, card.starStatus);
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -673,7 +657,7 @@ public class ImportExportTest
assertNull(card.headerColor);
assertEquals(0, card.starStatus);
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -698,7 +682,7 @@ public class ImportExportTest
assertEquals(false, result);
assertEquals(0, db.getLoyaltyCardCount());
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -736,7 +720,7 @@ public class ImportExportTest
assertEquals(1, (long) card.headerColor);
assertEquals(0, card.starStatus);
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -774,7 +758,7 @@ public class ImportExportTest
assertEquals(1, (long) card.headerColor);
assertEquals(1, card.starStatus);
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -812,7 +796,7 @@ public class ImportExportTest
assertEquals(1, (long) card.headerColor);
assertEquals(0, card.starStatus);
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -869,7 +853,7 @@ public class ImportExportTest
assertEquals(1, (long) card.headerColor);
assertEquals(0, card.starStatus);
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -1026,7 +1010,7 @@ public class ImportExportTest
assertEquals(null, card6.headerColor);
assertEquals(0, card6.starStatus);
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
@Test
@@ -1087,6 +1071,6 @@ public class ImportExportTest
assertEquals(Color.rgb(128, 0, 128), (long) card.headerColor);
assertEquals(0, card.starStatus);
clearDatabase();
TestHelpers.getEmptyDb(activity);
}
}

View File

@@ -3,13 +3,16 @@ package protect.card_locker;
import android.app.Activity;
import android.graphics.Color;
import android.net.Uri;
import com.google.zxing.BarcodeFormat;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.io.InvalidObjectException;
import java.math.BigDecimal;
import java.util.Currency;
@@ -18,7 +21,6 @@ import java.util.Date;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static protect.card_locker.DBHelper.LoyaltyCardDbIds;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
@@ -31,7 +33,7 @@ public class ImportURITest {
{
Activity activity = Robolectric.setupActivity(MainActivity.class);
importURIHelper = new ImportURIHelper(activity);
db = new DBHelper(activity);
db = TestHelpers.getEmptyDb(activity);
}
@Test

View File

@@ -4,11 +4,8 @@ import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import androidx.preference.PreferenceManager;
import androidx.test.core.app.ApplicationProvider;
import protect.card_locker.preferences.Settings;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
@@ -21,13 +18,22 @@ import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.Currency;
import java.util.Date;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView;
import protect.card_locker.preferences.Settings;
import static android.os.Looper.getMainLooper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
@@ -40,8 +46,10 @@ public class LoyaltyCardCursorAdapterTest
@Before
public void setUp()
{
ShadowLog.stream = System.out;
activity = Robolectric.setupActivity(MainActivity.class);
db = new DBHelper(activity);
db = TestHelpers.getEmptyDb(activity);
settings = PreferenceManager.getDefaultSharedPreferences(activity);
}
@@ -54,12 +62,12 @@ public class LoyaltyCardCursorAdapterTest
private View createView(Cursor cursor)
{
LoyaltyCardCursorAdapter adapter = new LoyaltyCardCursorAdapter(activity.getApplicationContext(), cursor);
LoyaltyCardCursorAdapter adapter = new LoyaltyCardCursorAdapter(activity.getApplicationContext(), cursor, (MainActivity) activity);
View view = adapter.newView(activity.getApplicationContext(), cursor, null);
adapter.bindView(view, activity.getApplicationContext(), cursor);
RecyclerView.ViewHolder viewHolder = adapter.createViewHolder(activity.findViewById(R.id.list), 0);
adapter.bindViewHolder((LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder) viewHolder, cursor.getPosition());
return view;
return viewHolder.itemView;
}
private void checkView(final View view, final String store, final String note, final String expiry, final String balance, boolean checkFontSizes)
@@ -148,7 +156,7 @@ public class LoyaltyCardCursorAdapterTest
@Test
public void TestCursorAdapterFontSizes()
{
final Context context = ApplicationProvider.getApplicationContext();
final Context context = activity.getApplicationContext();
Date expiryDate = new Date();
String dateString = context.getString(R.string.expiryStateSentence, DateFormat.getDateInstance(DateFormat.LONG).format(expiryDate));
@@ -173,22 +181,39 @@ public class LoyaltyCardCursorAdapterTest
@Test
public void TestCursorAdapterStarring()
{
db.insertLoyaltyCard("storeA", "note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 0);
db.insertLoyaltyCard("storeB", "note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 1);
db.insertLoyaltyCard("storeC", "note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 1);
assertNotEquals(-1, db.insertLoyaltyCard("storeA", "note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 0));
assertNotEquals(-1, db.insertLoyaltyCard("storeB", "note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 1));
assertNotEquals(-1, db.insertLoyaltyCard("storeC", "note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 1));
assertEquals(3, db.getLoyaltyCardCount());
Cursor cursor = db.getLoyaltyCardCursor();
assertEquals(3, cursor.getCount());
cursor.moveToFirst();
System.out.println(LoyaltyCard.toLoyaltyCard(cursor).store);
cursor.moveToNext();
System.out.println(LoyaltyCard.toLoyaltyCard(cursor).store);
cursor.moveToNext();
System.out.println(LoyaltyCard.toLoyaltyCard(cursor).store);
assertTrue(cursor.moveToFirst());
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(cursor);
assertEquals("storeB", loyaltyCard.store);
View view = createView(cursor);
ImageView star = view.findViewById(R.id.star);
assertEquals(View.VISIBLE, star.getVisibility());
cursor.moveToNext();
assertTrue(cursor.moveToNext());
loyaltyCard = LoyaltyCard.toLoyaltyCard(cursor);
assertEquals("storeC", loyaltyCard.store);
view = createView(cursor);
star = view.findViewById(R.id.star);
assertEquals(View.VISIBLE, star.getVisibility());
cursor.moveToNext();
assertTrue(cursor.moveToNext());
loyaltyCard = LoyaltyCard.toLoyaltyCard(cursor);
assertEquals("storeA", loyaltyCard.store);
view = createView(cursor);
star = view.findViewById(R.id.star);
assertEquals(View.GONE, star.getVisibility());

View File

@@ -1,26 +1,18 @@
package protect.card_locker;
import static android.os.Looper.getMainLooper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.robolectric.Shadows.shadowOf;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import androidx.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -30,20 +22,13 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.core.widget.TextViewCompat;
import androidx.test.core.app.ApplicationProvider;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.textfield.MaterialAutoCompleteTextView;
import com.google.android.material.textfield.TextInputLayout;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.android.Intents;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Currency;
import java.util.Date;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,10 +38,26 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowActivity;
import org.robolectric.shadows.ShadowAlertDialog;
import org.robolectric.shadows.ShadowDialog;
import org.robolectric.shadows.ShadowLog;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Currency;
import java.util.Date;
import androidx.core.widget.TextViewCompat;
import androidx.preference.PreferenceManager;
import static android.os.Looper.getMainLooper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)
public class LoyaltyCardViewActivityTest
@@ -328,7 +329,7 @@ public class LoyaltyCardViewActivityTest
activityController.resume();
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
final Context context = activity.getApplicationContext();
checkAllFields(activity, ViewMode.ADD_CARD, "", "", context.getString(R.string.never) , "0", context.getString(R.string.points), "", context.getString(R.string.sameAsCardId),"");
}
@@ -343,7 +344,7 @@ public class LoyaltyCardViewActivityTest
Activity activity = (Activity)activityController.get();
DBHelper db = new DBHelper(activity);
DBHelper db = TestHelpers.getEmptyDb(activity);
assertEquals(0, db.getLoyaltyCardCount());
final EditText storeField = activity.findViewById(R.id.storeNameEdit);
@@ -388,7 +389,7 @@ public class LoyaltyCardViewActivityTest
activityController.resume();
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
final Context context = activity.getApplicationContext();
checkAllFields(activity, ViewMode.ADD_CARD, "", "", context.getString(R.string.never), "0", context.getString(R.string.points), "", context.getString(R.string.sameAsCardId),"");
@@ -412,7 +413,7 @@ public class LoyaltyCardViewActivityTest
activityController.resume();
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
final Context context = activity.getApplicationContext();
checkAllFields(activity, ViewMode.ADD_CARD, "", "", context.getString(R.string.never), "0", context.getString(R.string.points), "", context.getString(R.string.sameAsCardId), "");
@@ -431,7 +432,7 @@ public class LoyaltyCardViewActivityTest
activityController.resume();
LoyaltyCardEditActivity activity = (LoyaltyCardEditActivity) activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
final Context context = activity.getApplicationContext();
checkAllFields(activity, ViewMode.ADD_CARD, "", "", context.getString(R.string.never), "0", context.getString(R.string.points), "", context.getString(R.string.sameAsCardId),"");
@@ -485,8 +486,8 @@ public class LoyaltyCardViewActivityTest
{
ActivityController activityController = createActivityWithLoyaltyCard(true);
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
DBHelper db = new DBHelper(activity);
final Context context = activity.getApplicationContext();
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, Color.BLACK, 0);
@@ -504,8 +505,8 @@ public class LoyaltyCardViewActivityTest
{
ActivityController activityController = createActivityWithLoyaltyCard(false);
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
DBHelper db = new DBHelper(activity);
final Context context = activity.getApplicationContext();
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, Color.BLACK, 0);
@@ -523,8 +524,8 @@ public class LoyaltyCardViewActivityTest
{
ActivityController activityController = createActivityWithLoyaltyCard(true);
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
DBHelper db = new DBHelper(activity);
final Context context = activity.getApplicationContext();
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, EAN_BARCODE_DATA, null, EAN_BARCODE_TYPE, Color.BLACK, 0);
@@ -547,8 +548,8 @@ public class LoyaltyCardViewActivityTest
{
ActivityController activityController = createActivityWithLoyaltyCard(true);
LoyaltyCardEditActivity activity = (LoyaltyCardEditActivity) activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
DBHelper db = new DBHelper(activity);
final Context context = activity.getApplicationContext();
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, EAN_BARCODE_DATA, null, EAN_BARCODE_TYPE, Color.BLACK, 0);
@@ -585,8 +586,8 @@ public class LoyaltyCardViewActivityTest
{
ActivityController activityController = createActivityWithLoyaltyCard(true);
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
DBHelper db = new DBHelper(activity);
final Context context = activity.getApplicationContext();
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, EAN_BARCODE_DATA, null, EAN_BARCODE_TYPE, Color.BLACK, 0);
@@ -618,8 +619,8 @@ public class LoyaltyCardViewActivityTest
{
ActivityController activityController = createActivityWithLoyaltyCard(true);
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
DBHelper db = new DBHelper(activity);
final Context context = activity.getApplicationContext();
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", new Date(), new BigDecimal("0"), null, EAN_BARCODE_DATA, null, EAN_BARCODE_TYPE, Color.BLACK, 0);
@@ -643,8 +644,8 @@ public class LoyaltyCardViewActivityTest
{
ActivityController activityController = createActivityWithLoyaltyCard(true);
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
DBHelper db = new DBHelper(activity);
final Context context = activity.getApplicationContext();
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, EAN_BARCODE_DATA, null, EAN_BARCODE_TYPE, Color.BLACK, 0);
@@ -694,8 +695,8 @@ public class LoyaltyCardViewActivityTest
{
ActivityController activityController = createActivityWithLoyaltyCard(true);
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
DBHelper db = new DBHelper(activity);
final Context context = activity.getApplicationContext();
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("10.00"), Currency.getInstance("USD"), EAN_BARCODE_DATA, null, EAN_BARCODE_TYPE, Color.BLACK, 0);
@@ -735,7 +736,7 @@ public class LoyaltyCardViewActivityTest
{
ActivityController activityController = createActivityWithLoyaltyCard(false);
Activity activity = (Activity)activityController.get();
DBHelper db = new DBHelper(activity);
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, Color.BLACK, 0);
@@ -784,7 +785,7 @@ public class LoyaltyCardViewActivityTest
ActivityController activityController = createActivityWithLoyaltyCard(false);
Activity activity = (Activity)activityController.get();
DBHelper db = new DBHelper(activity);
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, Color.BLACK, 0);
activityController.start();
@@ -804,7 +805,7 @@ public class LoyaltyCardViewActivityTest
ActivityController activityController = createActivityWithLoyaltyCard(false);
Activity activity = (Activity)activityController.get();
DBHelper db = new DBHelper(activity);
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, null, 0);
activityController.start();
@@ -823,7 +824,7 @@ public class LoyaltyCardViewActivityTest
ActivityController activityController = createActivityWithLoyaltyCard(true);
Activity activity = (Activity)activityController.get();
DBHelper db = new DBHelper(activity);
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, null, 0);
activityController.start();
@@ -841,7 +842,7 @@ public class LoyaltyCardViewActivityTest
ActivityController activityController = createActivityWithLoyaltyCard(true);
Activity activity = (Activity)activityController.get();
DBHelper db = new DBHelper(activity);
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, null, Color.BLACK, 0);
activityController.start();
@@ -858,8 +859,8 @@ public class LoyaltyCardViewActivityTest
public void removeBarcodeFromLoyaltyCard() throws IOException, ParseException {
ActivityController activityController = createActivityWithLoyaltyCard(true);
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
DBHelper db = new DBHelper(activity);
final Context context = activity.getApplicationContext();
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, Color.BLACK, 0);
@@ -889,7 +890,7 @@ public class LoyaltyCardViewActivityTest
ActivityController activityController = createActivityWithLoyaltyCard(false);
Activity activity = (Activity)activityController.get();
DBHelper db = new DBHelper(activity);
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, Color.BLACK, 0);
final int LARGE_FONT_SIZE = 40;
@@ -964,7 +965,7 @@ public class LoyaltyCardViewActivityTest
ActivityController activityController = createActivityWithLoyaltyCard(false);
Activity activity = (Activity) activityController.get();
DBHelper db = new DBHelper(activity);
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, Color.BLACK,0);
activityController.start();
activityController.visible();
@@ -999,7 +1000,7 @@ public class LoyaltyCardViewActivityTest
ActivityController activityController = createActivityWithLoyaltyCard(false);
Activity activity = (Activity)activityController.get();
DBHelper db = new DBHelper(activity);
DBHelper db = TestHelpers.getEmptyDb(activity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, Color.BLACK, 0);
activityController.start();
@@ -1110,7 +1111,7 @@ public class LoyaltyCardViewActivityTest
activityController.resume();
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
final Context context = activity.getApplicationContext();
shadowOf(getMainLooper()).idle();
@@ -1133,7 +1134,7 @@ public class LoyaltyCardViewActivityTest
activityController.resume();
Activity activity = (Activity)activityController.get();
final Context context = ApplicationProvider.getApplicationContext();
final Context context = activity.getApplicationContext();
checkAllFields(activity, ViewMode.ADD_CARD, "Example Store", "", context.getString(R.string.never), "0", context.getString(R.string.points), "123456", null, "AZTEC");
assertEquals(-416706, ((ColorDrawable) activity.findViewById(R.id.thumbnail).getBackground()).getColor());

View File

@@ -17,17 +17,20 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowActivity;
import org.w3c.dom.Text;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import androidx.recyclerview.widget.RecyclerView;
import static android.os.Looper.getMainLooper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.robolectric.Shadows.shadowOf;
@RunWith(RobolectricTestRunner.class)
@@ -37,10 +40,9 @@ public class MainActivityTest
private SharedPreferences prefs;
@Test
public void initiallyNoLoyaltyCards() throws Exception
{
public void initiallyNoLoyaltyCards() {
Activity activity = Robolectric.setupActivity(MainActivity.class);
assertTrue(activity != null);
assertNotNull(activity);
TextView helpText = activity.findViewById(R.id.helpText);
assertEquals(View.VISIBLE, helpText.getVisibility());
@@ -48,17 +50,16 @@ public class MainActivityTest
TextView noMatchingCardsText = activity.findViewById(R.id.noMatchingCardsText);
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
ListView list = activity.findViewById(R.id.list);
RecyclerView list = activity.findViewById(R.id.list);
assertEquals(View.GONE, list.getVisibility());
}
@Test
public void onCreateShouldInflateLayout() throws Exception
{
public void onCreateShouldInflateLayout() {
final MainActivity activity = Robolectric.setupActivity(MainActivity.class);
final Menu menu = shadowOf(activity).getOptionsMenu();
assertTrue(menu != null);
assertNotNull(menu);
// The settings, import/export, groups, search and add button should be present
assertEquals(menu.size(), 6);
@@ -92,11 +93,11 @@ public class MainActivityTest
TextView helpText = mainActivity.findViewById(R.id.helpText);
TextView noMatchingCardsText = mainActivity.findViewById(R.id.noMatchingCardsText);
ListView list = mainActivity.findViewById(R.id.list);
RecyclerView list = mainActivity.findViewById(R.id.list);
assertEquals(0, list.getCount());
assertEquals(0, list.getAdapter().getItemCount());
DBHelper db = new DBHelper(mainActivity);
DBHelper db = TestHelpers.getEmptyDb(mainActivity);
db.insertLoyaltyCard("store", "note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 0);
assertEquals(View.VISIBLE, helpText.getVisibility());
@@ -110,9 +111,7 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getAdapter().getCount());
Cursor cursor = (Cursor)list.getAdapter().getItem(0);
assertNotNull(cursor);
assertEquals(1, list.getAdapter().getItemCount());
db.close();
}
@@ -125,14 +124,15 @@ public class MainActivityTest
Activity mainActivity = (Activity)activityController.get();
activityController.start();
activityController.resume();
activityController.visible();
TextView helpText = mainActivity.findViewById(R.id.helpText);
TextView noMatchingCardsText = mainActivity.findViewById(R.id.noMatchingCardsText);
ListView list = mainActivity.findViewById(R.id.list);
RecyclerView list = mainActivity.findViewById(R.id.list);
assertEquals(0, list.getCount());
assertEquals(0, list.getAdapter().getItemCount());
DBHelper db = new DBHelper(mainActivity);
DBHelper db = TestHelpers.getEmptyDb(mainActivity);
db.insertLoyaltyCard("storeB", "note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 0);
db.insertLoyaltyCard("storeA", "note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 0);
db.insertLoyaltyCard("storeD", "note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 1);
@@ -144,27 +144,17 @@ public class MainActivityTest
activityController.pause();
activityController.resume();
activityController.visible();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(4, list.getAdapter().getCount());
Cursor cursor = (Cursor)list.getAdapter().getItem(0);
assertNotNull(cursor);
assertEquals("storeC",cursor.getString(cursor.getColumnIndex("store")));
cursor = (Cursor)list.getAdapter().getItem(1);
assertNotNull(cursor);
assertEquals("storeD",cursor.getString(cursor.getColumnIndex("store")));
cursor = (Cursor)list.getAdapter().getItem(2);
assertNotNull(cursor);
assertEquals("storeA",cursor.getString(cursor.getColumnIndex("store")));
cursor = (Cursor)list.getAdapter().getItem(3);
assertNotNull(cursor);
assertEquals("storeB",cursor.getString(cursor.getColumnIndex("store")));
assertEquals(4, list.getAdapter().getItemCount());
assertEquals("storeC", ((TextView) list.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.store)).getText());
assertEquals("storeD", ((TextView) list.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.store)).getText());
assertEquals("storeA", ((TextView) list.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.store)).getText());
assertEquals("storeB", ((TextView) list.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.store)).getText());
db.close();
}
@@ -178,7 +168,7 @@ public class MainActivityTest
activityController.start();
activityController.resume();
DBHelper db = new DBHelper(mainActivity);
DBHelper db = TestHelpers.getEmptyDb(mainActivity);
TabLayout groupTabs = mainActivity.findViewById(R.id.groups);
@@ -230,10 +220,10 @@ public class MainActivityTest
TextView helpText = mainActivity.findViewById(R.id.helpText);
TextView noMatchingCardsText = mainActivity.findViewById(R.id.noMatchingCardsText);
ListView list = mainActivity.findViewById(R.id.list);
RecyclerView list = mainActivity.findViewById(R.id.list);
TabLayout groupTabs = mainActivity.findViewById(R.id.groups);
DBHelper db = new DBHelper(mainActivity);
DBHelper db = TestHelpers.getEmptyDb(mainActivity);
db.insertLoyaltyCard("The First Store", "Initial note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 0);
db.insertLoyaltyCard("The Second Store", "Secondary note", null, new BigDecimal("0"), null, "cardId", null, BarcodeFormat.UPC_A, Color.BLACK, 0);
@@ -249,9 +239,9 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(2, list.getCount());
assertEquals(2, list.getAdapter().getItemCount());
mainActivity.filter = "store";
mainActivity.mFilter = "store";
activityController.pause();
activityController.resume();
@@ -260,7 +250,7 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(2, list.getCount());
assertEquals(2, list.getAdapter().getItemCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
@@ -272,7 +262,7 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
assertEquals(1, list.getAdapter().getItemCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
@@ -281,9 +271,9 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(2, list.getCount());
assertEquals(2, list.getAdapter().getItemCount());
mainActivity.filter = "first";
mainActivity.mFilter = "first";
activityController.pause();
activityController.resume();
@@ -292,7 +282,7 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
assertEquals(1, list.getAdapter().getItemCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
@@ -304,7 +294,7 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
assertEquals(1, list.getAdapter().getItemCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
@@ -313,9 +303,9 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
assertEquals(1, list.getAdapter().getItemCount());
mainActivity.filter = "initial";
mainActivity.mFilter = "initial";
activityController.pause();
activityController.resume();
@@ -324,7 +314,7 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
assertEquals(1, list.getAdapter().getItemCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
@@ -336,7 +326,7 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
assertEquals(1, list.getAdapter().getItemCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
@@ -345,9 +335,9 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
assertEquals(1, list.getAdapter().getItemCount());
mainActivity.filter = "second";
mainActivity.mFilter = "second";
activityController.pause();
activityController.resume();
@@ -356,7 +346,7 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
assertEquals(1, list.getAdapter().getItemCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
@@ -364,11 +354,13 @@ public class MainActivityTest
activityController.pause();
activityController.resume();
shadowOf(getMainLooper()).idle();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.VISIBLE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(0, list.getCount());
assertEquals(0, list.getAdapter().getItemCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
@@ -377,18 +369,20 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
assertEquals(1, list.getAdapter().getItemCount());
mainActivity.filter = "company";
mainActivity.mFilter = "company";
activityController.pause();
activityController.resume();
shadowOf(getMainLooper()).idle();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.VISIBLE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(0, list.getCount());
assertEquals(0, list.getAdapter().getItemCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
@@ -396,11 +390,13 @@ public class MainActivityTest
activityController.pause();
activityController.resume();
shadowOf(getMainLooper()).idle();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.VISIBLE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(0, list.getCount());
assertEquals(0, list.getAdapter().getItemCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
@@ -409,18 +405,20 @@ public class MainActivityTest
assertEquals(View.VISIBLE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(0, list.getCount());
assertEquals(0, list.getAdapter().getItemCount());
mainActivity.filter = "";
mainActivity.mFilter = "";
activityController.pause();
activityController.resume();
shadowOf(getMainLooper()).idle();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(2, list.getCount());
assertEquals(2, list.getAdapter().getItemCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
@@ -428,11 +426,13 @@ public class MainActivityTest
activityController.pause();
activityController.resume();
shadowOf(getMainLooper()).idle();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
assertEquals(1, list.getAdapter().getItemCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
@@ -441,7 +441,7 @@ public class MainActivityTest
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(2, list.getCount());
assertEquals(2, list.getAdapter().getItemCount());
db.close();
}

View File

@@ -0,0 +1,18 @@
package protect.card_locker;
import android.app.Activity;
import android.database.sqlite.SQLiteDatabase;
public class TestHelpers {
static public DBHelper getEmptyDb(Activity activity) {
DBHelper db = new DBHelper(activity);
// Make sure DB is empty
SQLiteDatabase database = db.getWritableDatabase();
database.execSQL("delete from " + DBHelper.LoyaltyCardDbIds.TABLE);
database.execSQL("delete from " + DBHelper.LoyaltyCardDbGroups.TABLE);
database.execSQL("delete from " + DBHelper.LoyaltyCardDbIdsGroups.TABLE);
database.close();
return db;
}
}

View File

@@ -1,17 +1,14 @@
package protect.card_locker;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.util.Util;
import java.math.BigDecimal;
import java.util.Currency;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)

View File

@@ -1,19 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="192"
height="192"
viewBox="0 0 50.799999 50.799999"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="Catima v1.svg">
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="192" height="192" viewBox="0 0 50.799999 50.799999"
version="1.1" id="svg8" inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)" sodipodi:docname="Catima v1.svg">
<defs
id="defs2" />
<sodipodi:namedview

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB