From d5d921a1c8e669f6be1131bda1000db7dc9c0da0 Mon Sep 17 00:00:00 2001 From: Katharine Date: Thu, 28 Oct 2021 01:25:50 +0800 Subject: [PATCH 01/14] Group management POC --- app/src/main/AndroidManifest.xml | 91 ++--- .../java/protect/card_locker/DBHelper.java | 54 +++ .../main/java/protect/card_locker/Group.java | 35 +- .../card_locker/ManageGroupActivity.java | 355 +++++++++++++++++ .../ManageGroupActivityInGroupState.java | 58 +++ .../card_locker/ManageGroupCursorAdapter.java | 365 ++++++++++++++++++ .../card_locker/ManageGroupLoyaltyCard.java | 168 ++++++++ .../card_locker/ManageGroupsActivity.java | 9 +- .../main/res/layout/activity_manage_group.xml | 56 +++ .../main/res/layout/content_manage_group.xml | 49 +++ .../manage_group_loyalty_card_layout.xml | 147 +++++++ app/src/main/res/menu/manage_group_menu.xml | 10 + app/src/main/res/values/strings.xml | 7 +- 13 files changed, 1358 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/protect/card_locker/ManageGroupActivity.java create mode 100644 app/src/main/java/protect/card_locker/ManageGroupActivityInGroupState.java create mode 100644 app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java create mode 100644 app/src/main/java/protect/card_locker/ManageGroupLoyaltyCard.java create mode 100644 app/src/main/res/layout/activity_manage_group.xml create mode 100644 app/src/main/res/layout/content_manage_group.xml create mode 100644 app/src/main/res/layout/manage_group_loyalty_card_layout.xml create mode 100644 app/src/main/res/menu/manage_group_menu.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3602f9e97..4c6e441ce 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,14 +1,13 @@ - + - - - + + + + + - - + + android:theme="@style/Theme.App.Starting"> - + - + - - + android:theme="@style/AppTheme.NoActionBar"> - + android:theme="@style/AppTheme.NoActionBar"> + android:windowSoftInputMode="stateHidden" /> - + android:windowSoftInputMode="stateHidden"> + + - - + - - - + android:theme="@style/AppTheme.NoActionBar" /> + android:windowSoftInputMode="stateHidden" /> + android:theme="@style/AppTheme.NoActionBar" /> + android:theme="@style/AppTheme.NoActionBar" /> + android:theme="@style/AppTheme.NoActionBar"> - - + + + + + android:grantUriPermissions="true"> + android:resource="@xml/file_provider_paths" /> - + \ No newline at end of file diff --git a/app/src/main/java/protect/card_locker/DBHelper.java b/app/src/main/java/protect/card_locker/DBHelper.java index 505f3be52..a55ae71fe 100644 --- a/app/src/main/java/protect/card_locker/DBHelper.java +++ b/app/src/main/java/protect/card_locker/DBHelper.java @@ -613,6 +613,21 @@ public class DBHelper extends SQLiteOpenHelper } } + public void addLoyaltyCardToGroup(int cardId, String groupId){ + SQLiteDatabase db = getWritableDatabase(); + ContentValues contentValues = new ContentValues(); + contentValues.put(LoyaltyCardDbIdsGroups.cardID, cardId); + contentValues.put(LoyaltyCardDbIdsGroups.groupID, groupId); + db.insert(LoyaltyCardDbIdsGroups.TABLE, null, contentValues); + } + + public void removeLoyaltyCardFromGroup(int cardId, String groupId){ + SQLiteDatabase db = getWritableDatabase(); + db.delete(LoyaltyCardDbIdsGroups.TABLE, + whereAttrs(LoyaltyCardDbIdsGroups.cardID, LoyaltyCardDbIdsGroups.groupID), + withArgs(cardId, groupId)); + } + public boolean deleteLoyaltyCard(final int id) { SQLiteDatabase db = getWritableDatabase(); @@ -718,6 +733,45 @@ public class DBHelper extends SQLiteOpenHelper limitString, filter.trim().isEmpty() ? null : new String[] { TextUtils.join("* ", filter.split(" ")) + '*' }, null); } + /** + * Returns a cursor to all loyalty cards with the filter text in either the store and whether card is in the provided group + * + * @param filter + * @param group + * @param order + * @return Cursor + */ + public Cursor getIfLoyaltyCardsAreInGroupCursor(String filter, Group group, LoyaltyCardOrder order, LoyaltyCardOrderDirection direction) { + SQLiteDatabase db = getReadableDatabase(); + + if (group == null) { + throw new IllegalArgumentException("group cannot be null"); + } + String orderField = getFieldForOrder(order); + String[] selectionArgs; + if(filter.trim().isEmpty()) { + selectionArgs = new String[]{ + group._id + }; + }else{ + selectionArgs = new String[]{ + group._id, + TextUtils.join("* ", filter.split(" ")) + '*' + }; + } + return db.rawQuery("SELECT " + "*" + + " FROM " + LoyaltyCardDbIds.TABLE + " LEFT OUTER JOIN " + + " (SELECT " + LoyaltyCardDbIdsGroups.TABLE + ".*" + + " FROM " + LoyaltyCardDbIdsGroups.TABLE + + " WHERE " + LoyaltyCardDbIdsGroups.groupID + " = ? " + + " ) " + " AS " + LoyaltyCardDbIdsGroups.TABLE + + " ON " + LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.ID + " = " + LoyaltyCardDbIdsGroups.TABLE + "." + LoyaltyCardDbIdsGroups.cardID + + (filter.trim().isEmpty() ? "" : " WHERE " + LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.STORE + " MATCH ? ") + + " ORDER BY " + LoyaltyCardDbIds.TABLE + "." + orderField, + selectionArgs, + null); + } + /** * Returns the amount of loyalty cards. * diff --git a/app/src/main/java/protect/card_locker/Group.java b/app/src/main/java/protect/card_locker/Group.java index 1d5de8603..0120dd229 100644 --- a/app/src/main/java/protect/card_locker/Group.java +++ b/app/src/main/java/protect/card_locker/Group.java @@ -1,8 +1,10 @@ package protect.card_locker; import android.database.Cursor; +import android.os.Parcel; +import android.os.Parcelable; -public class Group +public class Group implements Parcelable { public final String _id; public final int order; @@ -12,6 +14,25 @@ public class Group this.order = order; } + protected Group(Parcel in){ + this._id = in.readString(); + this.order = in.readInt(); + } + + + @Override + public void writeToParcel(Parcel parcel, int i){ + parcel.writeString(_id); + parcel.writeInt(order); + } + + + @Override + public int describeContents() { + // group table does not have an integer ID + return 0; + } + public static Group toGroup(Cursor cursor) { String _id = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.ID)); @@ -19,4 +40,16 @@ public class Group return new Group(_id, order); } + + public static final Creator CREATOR = new Creator() { + @Override + public Group createFromParcel(Parcel in) { + return new Group(in); + } + + @Override + public Group[] newArray(int size) { + return new Group[size]; + } + }; } diff --git a/app/src/main/java/protect/card_locker/ManageGroupActivity.java b/app/src/main/java/protect/card_locker/ManageGroupActivity.java new file mode 100644 index 000000000..f993ddfd4 --- /dev/null +++ b/app/src/main/java/protect/card_locker/ManageGroupActivity.java @@ -0,0 +1,355 @@ +package protect.card_locker; + +import android.app.SearchManager; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.CursorIndexOutOfBoundsException; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; +import android.view.GestureDetector; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.android.material.tabs.TabLayout; + +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.view.ActionMode; +import androidx.appcompat.widget.SearchView; +import androidx.appcompat.widget.Toolbar; +import androidx.core.graphics.BlendModeColorFilterCompat; +import androidx.core.graphics.BlendModeCompat; +import androidx.core.splashscreen.SplashScreen; +import androidx.recyclerview.widget.RecyclerView; +import protect.card_locker.preferences.SettingsActivity; + +public class ManageGroupActivity extends CatimaAppCompatActivity implements ManageGroupCursorAdapter.CardAdapterListener +{ + private static final String TAG = "Catima"; + + private final DBHelper mDB = new DBHelper(this); + private ManageGroupCursorAdapter mAdapter; + private ActionMode mCurrentActionMode; + private Menu mMenu; + + // currently unused + protected String mFilter = ""; + protected DBHelper.LoyaltyCardOrderDirection mOrderDirection = DBHelper.LoyaltyCardOrderDirection.Ascending; + protected DBHelper.LoyaltyCardOrder mOrder = DBHelper.LoyaltyCardOrder.Alpha; + + protected Group mGroup = null; + private RecyclerView mCardList; + private View mHelpText; + private View mNoMatchingCardsText; + private View mNoGroupCardsText; + private EditText mGroupNameText; + private TextView mGroupNameLabel; + private ActionBar mActionBar; + + private HashMap mAdapterState; + private String mCurrentGroupName; + + private boolean mGroupNameNotInUse; + + private boolean mDarkMode; + + @Override + protected void onCreate(Bundle inputSavedInstanceState) + { + super.onCreate(inputSavedInstanceState); + setContentView(R.layout.activity_manage_group); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + mHelpText = findViewById(R.id.helpText); + mNoMatchingCardsText = findViewById(R.id.noMatchingCardsText); + mNoGroupCardsText = findViewById(R.id.noGroupCardsText); + mCardList = findViewById(R.id.list); + + mGroupNameText = findViewById(R.id.editTextGroupName); + mGroupNameLabel = findViewById(R.id.textViewEditGroupName); + + mAdapter = new ManageGroupCursorAdapter(this, null, this); + mCardList.setAdapter(mAdapter); + registerForContextMenu(mCardList); + + mGroup = null; + + mDarkMode = Utils.isDarkModeEnabled(getApplicationContext()); + + if (inputSavedInstanceState != null) { + ManageGroupActivityInGroupState adapterState = inputSavedInstanceState.getParcelable("mAdapterState"); + if (adapterState != null) { + mAdapterState = adapterState.getMap(); + } + mCurrentGroupName = inputSavedInstanceState.getString("mCurrentGroupName"); + } + + mActionBar = getSupportActionBar(); + + mActionBar.setDisplayHomeAsUpEnabled(true); + mActionBar.setDisplayShowHomeEnabled(true); + + } + + private void resetGroupNameTextColor() { + if (mDarkMode) { + mGroupNameText.setTextColor(Color.WHITE); + } else{ + mGroupNameText.setTextColor(Color.BLACK); + } + } + + private void checkIfGroupNameIsInUse(){ + mGroupNameNotInUse = false; + String currentGroupName = mGroupNameText.getText().toString(); + if (!mGroup._id.equals(currentGroupName.trim())) { + Group group = mDB.getGroup(currentGroupName.trim()); + if (group != null) { + mGroupNameNotInUse = false; + mGroupNameText.setTextColor(Color.RED); + } else { + mGroupNameNotInUse = true; + } + } + } + + @Override + protected void onResume() + { + super.onResume(); + + Intent intent = getIntent(); + mGroup = intent.getParcelableExtra("group"); + if (mGroup == null){ + throw(new IllegalArgumentException("this activity expects a group loaded into it's intent")); + } + + setTitle(getString(R.string.edit) + ": " + mGroup._id); + + if (mCurrentGroupName == null){ + mGroupNameText.setText(mGroup._id); + }else{ + mGroupNameText.setText(mCurrentGroupName); + checkIfGroupNameIsInUse(); + } + + mGroupNameText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + return; + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + return; + } + + @Override + public void afterTextChanged(Editable s) { + resetGroupNameTextColor(); + checkIfGroupNameIsInUse(); + } + }); + + if (mAdapterState != null){ + mAdapter.importInGroupState(mAdapterState); + } + updateLoyaltyCardList(); + } + + @Override + protected void onSaveInstanceState (Bundle outState){ + super.onSaveInstanceState(outState); + if(mAdapterState != null){ + ManageGroupActivityInGroupState state = new ManageGroupActivityInGroupState(mAdapterState); + outState.putParcelable("mAdapterState", state); + } + if(mCurrentGroupName != null){ + outState.putString("mCurrentGroupName", mCurrentGroupName); + } + + } + + @Override + protected void onPause(){ + super.onPause(); + + mAdapterState = mAdapter.exportInGroupState(); + mCurrentGroupName = mGroupNameText.getText().toString(); + } + + private void updateLoyaltyCardList() { + mAdapter.swapCursor(mDB.getIfLoyaltyCardsAreInGroupCursor(mFilter, mGroup, mOrder, mOrderDirection)); + + if(mAdapter.getCountFromCursor() > 0) + { + // We want the cardList to be visible regardless of the filtered match count + // to ensure that the noMatchingCardsText doesn't end up being shown below + // the keyboard + mHelpText.setVisibility(View.GONE); + mNoGroupCardsText.setVisibility(View.GONE); + if(mAdapter.getItemCount() > 0) + { + mCardList.setVisibility(View.VISIBLE); + mNoMatchingCardsText.setVisibility(View.GONE); + } + else + { + mCardList.setVisibility(View.GONE); + if (!mFilter.isEmpty()) { + // Actual Empty Search Result + mNoMatchingCardsText.setVisibility(View.VISIBLE); + mNoGroupCardsText.setVisibility(View.GONE); + } else { + // Group Tab with no Group Cards + mNoMatchingCardsText.setVisibility(View.GONE); + mNoGroupCardsText.setVisibility(View.VISIBLE); + } + } + } + else + { + mCardList.setVisibility(View.GONE); + mHelpText.setVisibility(View.VISIBLE); + mNoMatchingCardsText.setVisibility(View.GONE); + mNoGroupCardsText.setVisibility(View.GONE); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu inputMenu) + { + this.mMenu = inputMenu; + + getMenuInflater().inflate(R.menu.manage_group_menu, inputMenu); + + MenuItem confirmButton = inputMenu.findItem(R.id.action_confirm); + Drawable icon = confirmButton.getIcon(); + icon.mutate(); + icon.setTint(Color.WHITE); + confirmButton.setIcon(icon); + return super.onCreateOptionsMenu(inputMenu); + } + + private void leaveWithoutSaving(){ + if (hasChanged()){ + AlertDialog.Builder builder = new AlertDialog.Builder(ManageGroupActivity.this); + builder.setTitle(R.string.discard_changes); + builder.setMessage(R.string.discard_changes_confirm); + builder.setPositiveButton(R.string.confirm, (dialog, which) -> finish()); + builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); + AlertDialog dialog = builder.create(); + dialog.show(); + }else{ + finish(); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem inputItem) + { + int id = inputItem.getItemId(); + + if (id == R.id.action_confirm) + { + String currentGroupName = mGroupNameText.getText().toString(); + if(!currentGroupName.trim().equals(mGroup._id)){ + if(!mGroupNameNotInUse) { + Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT); + toast.show(); + return true; + } + if(currentGroupName.trim().length() == 0){ + Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT); + toast.show(); + return true; + } + } + + mAdapter.commitToDatabase(getApplicationContext(), mGroup._id); + Toast toast = Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT); + if(!currentGroupName.trim().equals(mGroup._id)){ + mDB.updateGroup(mGroup._id, currentGroupName.trim()); + } + toast.show(); + finish(); + return true; + } + + return super.onOptionsItemSelected(inputItem); + } + @Override + public void onBackPressed() + { + leaveWithoutSaving(); + } + + @Override + public boolean onSupportNavigateUp() { + onBackPressed(); + return true; + } + + private boolean hasChanged(){ + return mAdapter.hasChanged() || !mGroup._id.equals(mGroupNameText.getText().toString().trim()); + } + + private void setSort(DBHelper.LoyaltyCardOrder order, DBHelper.LoyaltyCardOrderDirection direction) { + // Update values + mOrder = order; + mOrderDirection = direction; + + // Store in Shared Preference to restore next app launch + SharedPreferences sortPref = getApplicationContext().getSharedPreferences( + getString(R.string.sharedpreference_sort), + Context.MODE_PRIVATE); + SharedPreferences.Editor sortPrefEditor = sortPref.edit(); + sortPrefEditor.putString(getString(R.string.sharedpreference_sort_order), order.name()); + sortPrefEditor.putString(getString(R.string.sharedpreference_sort_direction), direction.name()); + sortPrefEditor.apply(); + + // Update card list + updateLoyaltyCardList(); + } + + @Override + public void onRowLongClicked(int inputPosition) + { + // do nothing for now + return; + } + + @Override + public void onRowClicked(int inputPosition) + { + Cursor selected = mAdapter.getCursor(); + mAdapter.toggleSelection(inputPosition); + } +} diff --git a/app/src/main/java/protect/card_locker/ManageGroupActivityInGroupState.java b/app/src/main/java/protect/card_locker/ManageGroupActivityInGroupState.java new file mode 100644 index 000000000..e6c30f793 --- /dev/null +++ b/app/src/main/java/protect/card_locker/ManageGroupActivityInGroupState.java @@ -0,0 +1,58 @@ +package protect.card_locker; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.HashMap; +import java.util.Map; + +public class ManageGroupActivityInGroupState implements Parcelable { + HashMap map; + + + + public ManageGroupActivityInGroupState(HashMap in){ + map = (HashMap)in.clone(); + } + + @Override + public int describeContents(){ + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(map.size()); + + for(Map.Entry entry : map.entrySet()){ + dest.writeInt(entry.getKey()); + dest.writeInt(entry.getValue() ? 1 : 0); + } + } + + protected ManageGroupActivityInGroupState(Parcel in){ + map = new HashMap(); + int length = in.readInt(); + for (int i = 0;i < length; i++){ + int key = in.readInt(); + boolean value = in.readInt() == 1 ? true : false; + map.put(key, value); + } + } + + public static final Creator CREATOR = new Creator() { + @Override + public ManageGroupActivityInGroupState createFromParcel(Parcel in) { + return new ManageGroupActivityInGroupState(in); + } + + @Override + public ManageGroupActivityInGroupState[] newArray(int size) { + return new ManageGroupActivityInGroupState[size]; + } + }; + + public HashMap getMap(){ + return (HashMap)map.clone(); + } +} diff --git a/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java b/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java new file mode 100644 index 000000000..c1a10d6d0 --- /dev/null +++ b/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java @@ -0,0 +1,365 @@ +package protect.card_locker; + +import android.content.Context; +import android.content.res.Resources; +import android.database.Cursor; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.util.SparseBooleanArray; +import android.util.TypedValue; +import android.view.HapticFeedbackConstants; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.google.android.material.card.MaterialCardView; + +import java.math.BigDecimal; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.graphics.BlendModeColorFilterCompat; +import androidx.core.graphics.BlendModeCompat; +import androidx.recyclerview.widget.RecyclerView; + +import protect.card_locker.preferences.Settings; + +public class ManageGroupCursorAdapter extends BaseCursorAdapter { + private 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; + private HashMap mIndexCardMap; + private HashMap mInGroupOverlay; + + + public ManageGroupCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener) { + super(inputCursor); + setHasStableIds(true); + mSettings = new Settings(inputContext); + mContext = inputContext; + mListener = inputListener; + mSelectedItems = new SparseBooleanArray(); + mAnimationItemsIndex = new SparseBooleanArray(); + + mDarkModeEnabled = Utils.isDarkModeEnabled(inputContext); + + + mInGroupOverlay = new HashMap(); + swapCursor(mCursor); + } + + @Override + public void swapCursor(Cursor inputCursor) { + mIndexCardMap = new HashMap(); + + super.swapCursor(inputCursor); + mCursor = inputCursor; + + } + + @Override + public ManageGroupListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType) { + View itemView = LayoutInflater.from(inputParent.getContext()).inflate(R.layout.manage_group_loyalty_card_layout, inputParent, false); + return new ManageGroupListItemViewHolder(itemView, mListener); + } + + public Cursor getCursor() { + return mCursor; + } + + public void onBindViewHolder(ManageGroupListItemViewHolder inputHolder, Cursor inputCursor) { + // Invisible until we want to show something more + inputHolder.mDivider.setVisibility(View.GONE); + + int size = mSettings.getFontSizeMax(mSettings.getSmallFont()); + + if (mDarkModeEnabled) { + inputHolder.mStarIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP)); + } + + ManageGroupLoyaltyCard cardEntry = ManageGroupLoyaltyCard.toCard(inputCursor); + + inputHolder.mStoreField.setText(cardEntry.store); + inputHolder.mStoreField.setTextSize(mSettings.getFontSizeMax(mSettings.getMediumFont())); + if (!cardEntry.note.isEmpty()) { + inputHolder.mNoteField.setVisibility(View.VISIBLE); + inputHolder.mNoteField.setText(cardEntry.note); + inputHolder.mNoteField.setTextSize(size); + } else { + inputHolder.mNoteField.setVisibility(View.GONE); + } + + if (!cardEntry.balance.equals(new BigDecimal("0"))) { + int drawableSize = dpToPx((size*24)/14, mContext); + inputHolder.mDivider.setVisibility(View.VISIBLE); + inputHolder.mBalanceField.setVisibility(View.VISIBLE); + Drawable balanceIcon = inputHolder.mBalanceField.getCompoundDrawables()[0]; + balanceIcon.setBounds(0,0,drawableSize,drawableSize); + inputHolder.mBalanceField.setCompoundDrawablesRelative(balanceIcon, null, null, null); + if (mDarkModeEnabled) { + balanceIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP)); + } + inputHolder.mBalanceField.setText(Utils.formatBalance(mContext, cardEntry.balance, cardEntry.balanceType)); + inputHolder.mBalanceField.setTextSize(size); + } else { + inputHolder.mBalanceField.setVisibility(View.GONE); + } + + if (cardEntry.expiry != null) { + int drawableSize = dpToPx((size*24)/14, mContext); + inputHolder.mDivider.setVisibility(View.VISIBLE); + inputHolder.mExpiryField.setVisibility(View.VISIBLE); + Drawable expiryIcon = inputHolder.mExpiryField.getCompoundDrawables()[0]; + expiryIcon.setBounds(0,0, drawableSize, drawableSize); + inputHolder.mExpiryField.setCompoundDrawablesRelative(expiryIcon, null, null, null); + if (Utils.hasExpired(cardEntry.expiry)) { + expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.RED, BlendModeCompat.SRC_ATOP)); + inputHolder.mExpiryField.setTextColor(Color.RED); + } else if (mDarkModeEnabled) { + expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP)); + } + inputHolder.mExpiryField.setText(DateFormat.getDateInstance(DateFormat.LONG).format(cardEntry.expiry)); + inputHolder.mExpiryField.setTextSize(size); + } else { + inputHolder.mExpiryField.setVisibility(View.GONE); + } + + // inputHolder.mStarIcon.setVisibility(cardEntry.starStatus != 0 ? View.VISIBLE : View.GONE); + inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, cardEntry.store, cardEntry.headerColor).getLetterTile()); + int imageSize = dpToPx( (size*46)/14, mContext); + inputHolder.mCardIcon.getLayoutParams().height = imageSize; + inputHolder.mCardIcon.getLayoutParams().width = imageSize; + inputHolder.mStarIcon.getLayoutParams().height = imageSize; + inputHolder.mStarIcon.getLayoutParams().width = imageSize; + inputHolder.mTickIcon.getLayoutParams().height = imageSize; + inputHolder.mTickIcon.getLayoutParams().width = imageSize; + + /* Changing Padding and Margin of different views according to font size + * Views Included: + * a) InformationContainer padding + * b) Store left padding + * c) Divider Margin + * d) note top margin + * e) row margin + * */ + int marginPaddingSize = dpToPx((size*16)/14, mContext ); + inputHolder.mInformationContainer.setPadding(marginPaddingSize, marginPaddingSize, marginPaddingSize, marginPaddingSize); + inputHolder.mStoreField.setPadding(marginPaddingSize, 0, 0, 0); + LinearLayout.LayoutParams lpDivider = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT ); + lpDivider.setMargins(0, marginPaddingSize, 0, marginPaddingSize); + inputHolder.mDivider.setLayoutParams(lpDivider); + LinearLayout.LayoutParams lpNoteField = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT ); + lpNoteField.setMargins(0, marginPaddingSize/2, 0, 0); + inputHolder.mNoteField.setLayoutParams(lpNoteField); + LinearLayout.LayoutParams lpRow = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT ); + lpRow.setMargins(marginPaddingSize/2, marginPaddingSize/2, marginPaddingSize/2, marginPaddingSize/2); + inputHolder.mRow.setLayoutParams(lpRow); + + inputHolder.itemView.setActivated(mSelectedItems.get(inputCursor.getPosition(), false)); + + Boolean overlayValue = mInGroupOverlay.get(cardEntry.id); + if((overlayValue != null? overlayValue: cardEntry.is_in_group)) { + mAnimationItemsIndex.put(inputCursor.getPosition(), true); + mSelectedItems.put(inputCursor.getPosition(), true); + } + + applyIconAnimation(inputHolder, inputCursor.getPosition()); + applyClickEvents(inputHolder, inputCursor.getPosition()); + + mIndexCardMap.put(inputCursor.getPosition(), cardEntry); + } + + private void applyClickEvents(ManageGroupListItemViewHolder inputHolder, final int inputPosition) { + inputHolder.mRow.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition)); + inputHolder.mInformationContainer.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition)); + + inputHolder.mRow.setOnLongClickListener(inputView -> { + mListener.onRowLongClicked(inputPosition); + inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + return true; + }); + + inputHolder.mInformationContainer.setOnLongClickListener(inputView -> { + mListener.onRowLongClicked(inputPosition); + inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + return true; + }); + } + + private void applyIconAnimation(ManageGroupListItemViewHolder 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(); + } + } else { + inputHolder.mThumbnailBackContainer.setVisibility(View.GONE); + resetIconYAxis(inputHolder.mThumbnailFrontContainer); + inputHolder.mThumbnailFrontContainer.setVisibility(View.VISIBLE); + inputHolder.mThumbnailFrontContainer.setAlpha(1); + if ((mReverseAllAnimations && mAnimationItemsIndex.get(inputPosition, false)) || mCurrentSelectedIndex == inputPosition) { + 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(); + } + + + 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); + } + ManageGroupLoyaltyCard cardEntry = mIndexCardMap.get(inputPosition); + Boolean overlayValue = mInGroupOverlay.get(cardEntry.id); + if (overlayValue == null){ + mInGroupOverlay.put(cardEntry.id, !cardEntry.is_in_group); + }else{ + mInGroupOverlay.put(cardEntry.id, !overlayValue); + } + + notifyDataSetChanged(); + } + + private void resetCurrentIndex() { + mCurrentSelectedIndex = -1; + } + + public interface CardAdapterListener { + void onRowClicked(int inputPosition); + + void onRowLongClicked(int inputPosition); + } + + private HashMap fetchWholeQuery (){ + HashMap res = new HashMap(); + int oldPosition = mCursor.getPosition(); + mCursor.moveToFirst(); + while(!mCursor.isAfterLast()){ + ManageGroupLoyaltyCard cardEntry = ManageGroupLoyaltyCard.toCard(mCursor); + res.put(cardEntry.id, cardEntry); + mCursor.moveToNext(); + } + mCursor.moveToPosition(oldPosition); + return res; + } + + public void commitToDatabase(Context context, String groupId){ + DBHelper dbHelper = new DBHelper(context); + HashMap cache = fetchWholeQuery(); + for(Map.Entry entry : mInGroupOverlay.entrySet()){ + ManageGroupLoyaltyCard cardEntry = cache.get(entry.getKey()); + if (cardEntry == null){ + Log.d("commitToDatabase", "card with id " + entry.getKey() + " was removed from database unexpectedly"); + continue; + } + if (entry.getValue() != cardEntry.is_in_group) { + if (entry.getValue()) { + dbHelper.addLoyaltyCardToGroup(entry.getKey(), groupId); + } else { + dbHelper.removeLoyaltyCardFromGroup(entry.getKey(), groupId); + } + } + } + } + + public boolean hasChanged(){ + HashMap cache = fetchWholeQuery(); + for(Map.Entry entry : mInGroupOverlay.entrySet()){ + ManageGroupLoyaltyCard cardEntry = cache.get(entry.getKey()); + if(cardEntry.is_in_group != entry.getValue()){ + return true; + } + } + return false; + } + + public int getCountFromCursor(){ + return mCursor.getCount(); + } + + public HashMap exportInGroupState(){ + return (HashMap)mInGroupOverlay.clone(); + } + + public void importInGroupState(HashMap cardIdInGroupMap){ + mInGroupOverlay = (HashMap)cardIdInGroupMap.clone(); + } + + + public static class ManageGroupListItemViewHolder extends RecyclerView.ViewHolder { + + public TextView mStoreField, mNoteField, mBalanceField, mExpiryField; + public LinearLayout mInformationContainer; + public ImageView mCardIcon, mStarIcon, mTickIcon; + public MaterialCardView mRow; + public View mDivider; + public RelativeLayout mThumbnailFrontContainer, mThumbnailBackContainer; + + public ManageGroupListItemViewHolder(View inputView, CardAdapterListener inputListener) { + super(inputView); + mRow = inputView.findViewById(R.id.row); + mDivider = inputView.findViewById(R.id.info_divider); + 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); + mTickIcon = inputView.findViewById(R.id.selected_thumbnail); + inputView.setOnLongClickListener(view -> { + inputListener.onRowClicked(getAdapterPosition()); + inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + return true; + }); + } + } + + public int dpToPx(int dp, Context mContext){ + Resources r = mContext.getResources(); + int px = (int)TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()); + return px; + } +} diff --git a/app/src/main/java/protect/card_locker/ManageGroupLoyaltyCard.java b/app/src/main/java/protect/card_locker/ManageGroupLoyaltyCard.java new file mode 100644 index 000000000..0010d1f19 --- /dev/null +++ b/app/src/main/java/protect/card_locker/ManageGroupLoyaltyCard.java @@ -0,0 +1,168 @@ +package protect.card_locker; +// Was thinking about extending LoyaltyCard but this makes things more modular..? +import android.database.Cursor; +import android.os.Parcel; +import android.os.Parcelable; + +import java.math.BigDecimal; +import java.util.Currency; +import java.util.Date; + +import androidx.annotation.Nullable; + +public class ManageGroupLoyaltyCard implements Parcelable { + public final int id; + public final String store; + public final String note; + public final Date expiry; + public final BigDecimal balance; + public final Currency balanceType; + public final String cardId; + + @Nullable + public final String barcodeId; + + @Nullable + public final CatimaBarcode barcodeType; + + @Nullable + public final Integer headerColor; + + public final int starStatus; + public final long lastUsed; + public int zoomLevel; + + public final boolean is_in_group; + + public ManageGroupLoyaltyCard(final int id, final String store, final String note, final Date expiry, + final BigDecimal balance, final Currency balanceType, final String cardId, + @Nullable final String barcodeId, @Nullable final CatimaBarcode barcodeType, + @Nullable final Integer headerColor, final int starStatus, final long lastUsed,final int zoomLevel, + final boolean is_in_group) + { + this.id = id; + this.store = store; + this.note = note; + this.expiry = expiry; + this.balance = balance; + this.balanceType = balanceType; + this.cardId = cardId; + this.barcodeId = barcodeId; + this.barcodeType = barcodeType; + this.headerColor = headerColor; + this.starStatus = starStatus; + this.lastUsed = lastUsed; + this.zoomLevel = zoomLevel; + this.is_in_group = is_in_group; + } + + protected ManageGroupLoyaltyCard(Parcel in) { + id = in.readInt(); + store = in.readString(); + note = in.readString(); + long tmpExpiry = in.readLong(); + expiry = tmpExpiry != -1 ? new Date(tmpExpiry) : null; + balance = (BigDecimal) in.readValue(BigDecimal.class.getClassLoader()); + balanceType = (Currency) in.readValue(Currency.class.getClassLoader()); + cardId = in.readString(); + barcodeId = in.readString(); + String tmpBarcodeType = in.readString(); + barcodeType = !tmpBarcodeType.isEmpty() ? CatimaBarcode.fromName(tmpBarcodeType) : null; + int tmpHeaderColor = in.readInt(); + headerColor = tmpHeaderColor != -1 ? tmpHeaderColor : null; + starStatus = in.readInt(); + lastUsed = in.readLong(); + zoomLevel = in.readInt(); + if (in.readInt() == 1) { + is_in_group = true; + }else{ + is_in_group = false; + } + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeInt(id); + parcel.writeString(store); + parcel.writeString(note); + parcel.writeLong(expiry != null ? expiry.getTime() : -1); + parcel.writeValue(balance); + parcel.writeValue(balanceType); + parcel.writeString(cardId); + parcel.writeString(barcodeId); + parcel.writeString(barcodeType != null ? barcodeType.name() : ""); + parcel.writeInt(headerColor != null ? headerColor : -1); + parcel.writeInt(starStatus); + parcel.writeLong(lastUsed); + parcel.writeInt(zoomLevel); + if (is_in_group) { + parcel.writeInt(1); + }else{ + parcel.writeInt(0); + } + } + + public static ManageGroupLoyaltyCard toCard(Cursor cursor) + { + int id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID)); + String store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE)); + String note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE)); + long expiryLong = cursor.getLong(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.EXPIRY)); + BigDecimal balance = new BigDecimal(cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BALANCE))); + String cardId = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.CARD_ID)); + String barcodeId = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_ID)); + int starred = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STAR_STATUS)); + long lastUsed = cursor.getLong(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.LAST_USED)); + int zoomLevel = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ZOOM_LEVEL)); + + int barcodeTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_TYPE); + int balanceTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BALANCE_TYPE); + int headerColorColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.HEADER_COLOR); + + boolean was_in_group = !cursor.isNull(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIdsGroups.groupID)); + + CatimaBarcode barcodeType = null; + Currency balanceType = null; + Date expiry = null; + Integer headerColor = null; + + if (cursor.isNull(barcodeTypeColumn) == false) + { + barcodeType = CatimaBarcode.fromName(cursor.getString(barcodeTypeColumn)); + } + + if (cursor.isNull(balanceTypeColumn) == false) + { + balanceType = Currency.getInstance(cursor.getString(balanceTypeColumn)); + } + + if(expiryLong > 0) + { + expiry = new Date(expiryLong); + } + + if(cursor.isNull(headerColorColumn) == false) + { + headerColor = cursor.getInt(headerColorColumn); + } + + return new ManageGroupLoyaltyCard(id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starred, lastUsed,zoomLevel,was_in_group); + } + + @Override + public int describeContents() { + return id; + } + + public static final Creator CREATOR = new Creator() { + @Override + public LoyaltyCard createFromParcel(Parcel in) { + return new LoyaltyCard(in); + } + + @Override + public LoyaltyCard[] newArray(int size) { + return new LoyaltyCard[size]; + } + }; +} diff --git a/app/src/main/java/protect/card_locker/ManageGroupsActivity.java b/app/src/main/java/protect/card_locker/ManageGroupsActivity.java index 60e6dd35f..9140ef7de 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupsActivity.java +++ b/app/src/main/java/protect/card_locker/ManageGroupsActivity.java @@ -1,6 +1,7 @@ package protect.card_locker; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.text.InputType; @@ -176,7 +177,12 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro @Override public void onEditButtonClicked(View view) { - final String groupName = getGroupName(view); + Group group = mDb.getGroup(getGroupName(view)); + Intent intent = new Intent(this, ManageGroupActivity.class); + intent.putExtra("group", group); + startActivity(intent); + /* + final String groupName = c; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.enter_group_name); @@ -195,6 +201,7 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro dialog.show(); dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); input.requestFocus(); + */ } @Override diff --git a/app/src/main/res/layout/activity_manage_group.xml b/app/src/main/res/layout/activity_manage_group.xml new file mode 100644 index 000000000..32f696a4c --- /dev/null +++ b/app/src/main/res/layout/activity_manage_group.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/content_manage_group.xml b/app/src/main/res/layout/content_manage_group.xml new file mode 100644 index 000000000..71a305bcb --- /dev/null +++ b/app/src/main/res/layout/content_manage_group.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/manage_group_loyalty_card_layout.xml b/app/src/main/res/layout/manage_group_loyalty_card_layout.xml new file mode 100644 index 000000000..4c3af71d5 --- /dev/null +++ b/app/src/main/res/layout/manage_group_loyalty_card_layout.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/manage_group_menu.xml b/app/src/main/res/menu/manage_group_menu.xml new file mode 100644 index 000000000..ca6a8b551 --- /dev/null +++ b/app/src/main/res/menu/manage_group_menu.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4e14f6b22..b29e5858c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - + Search Add @@ -129,6 +129,9 @@ %d card %d cards + Group name already in use! + Group name cannot be empty! + Group updated! All Delete group? Install a file manager first. @@ -245,4 +248,6 @@ Rate this app on Google Play Report Error + Discard Changes + There are unsaved changes that were made, do you wish to leave without saving? From cc402c39beb5a3cebf106ec0092936a8e121b016 Mon Sep 17 00:00:00 2001 From: Katharine Date: Fri, 29 Oct 2021 19:21:03 +0800 Subject: [PATCH 02/14] fixing errors reported by spotbugs --- .../main/java/protect/card_locker/ManageGroupActivity.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/protect/card_locker/ManageGroupActivity.java b/app/src/main/java/protect/card_locker/ManageGroupActivity.java index f993ddfd4..473c2c5c8 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupActivity.java +++ b/app/src/main/java/protect/card_locker/ManageGroupActivity.java @@ -112,10 +112,11 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana } mActionBar = getSupportActionBar(); - + if (mActionBar == null){ + throw(new RuntimeException("mActionBar is not expected to be null here")); + } mActionBar.setDisplayHomeAsUpEnabled(true); mActionBar.setDisplayShowHomeEnabled(true); - } private void resetGroupNameTextColor() { @@ -349,7 +350,6 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana @Override public void onRowClicked(int inputPosition) { - Cursor selected = mAdapter.getCursor(); mAdapter.toggleSelection(inputPosition); } } From f667fcbebe3ddb01364e4186a65a4cb24b033d40 Mon Sep 17 00:00:00 2001 From: Katharine Date: Sat, 30 Oct 2021 09:25:27 +0800 Subject: [PATCH 03/14] requested manifest changes --- app/src/main/AndroidManifest.xml | 8 ++++---- app/src/main/res/values/strings.xml | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4c6e441ce..1e81afb71 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -23,10 +23,6 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> - + Card data exported Enter group name Groups + Edit Group Click the + plus button to add groups for categorization first. This group does not contain any cards From b4b544e342e988d7baddc5baeda9cc63a6c6e381 Mon Sep 17 00:00:00 2001 From: Katharine Date: Sat, 30 Oct 2021 11:04:21 +0800 Subject: [PATCH 04/14] remove modularity --- .../main/java/protect/card_locker/Group.java | 20 + .../card_locker/LoyaltyCardCursorAdapter.java | 4 +- .../card_locker/ManageGroupActivity.java | 25 +- .../card_locker/ManageGroupCursorAdapter.java | 361 +++--------------- .../card_locker/ManageGroupLoyaltyCard.java | 168 -------- .../card_locker/ManageGroupsActivity.java | 3 +- .../main/res/layout/activity_manage_group.xml | 2 +- .../main/res/layout/content_manage_group.xml | 49 --- .../manage_group_loyalty_card_layout.xml | 147 ------- 9 files changed, 97 insertions(+), 682 deletions(-) delete mode 100644 app/src/main/java/protect/card_locker/ManageGroupLoyaltyCard.java delete mode 100644 app/src/main/res/layout/content_manage_group.xml delete mode 100644 app/src/main/res/layout/manage_group_loyalty_card_layout.xml diff --git a/app/src/main/java/protect/card_locker/Group.java b/app/src/main/java/protect/card_locker/Group.java index 0120dd229..fab064cda 100644 --- a/app/src/main/java/protect/card_locker/Group.java +++ b/app/src/main/java/protect/card_locker/Group.java @@ -4,6 +4,8 @@ import android.database.Cursor; import android.os.Parcel; import android.os.Parcelable; +import androidx.annotation.Nullable; + public class Group implements Parcelable { public final String _id; @@ -52,4 +54,22 @@ public class Group implements Parcelable return new Group[size]; } }; + + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null){ + return false; + } + if (!(obj instanceof Group)){ + return false; + } + Group anotherGroup = (Group)obj; + return _id.equals(anotherGroup._id) && order == anotherGroup.order; + } + + @Override + public int hashCode(){ + String combined = _id + "_" + order; + return combined.hashCode(); + } } diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java b/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java index 8572fe152..f259768c1 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java @@ -35,8 +35,8 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter 0) { @@ -294,7 +296,7 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana } } - mAdapter.commitToDatabase(getApplicationContext(), mGroup._id); + mAdapter.commitToDatabase(getApplicationContext()); Toast toast = Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT); if(!currentGroupName.trim().equals(mGroup._id)){ mDB.updateGroup(mGroup._id, currentGroupName.trim()); @@ -351,5 +353,6 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana public void onRowClicked(int inputPosition) { mAdapter.toggleSelection(inputPosition); + } } diff --git a/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java b/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java index c1a10d6d0..a88083474 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java +++ b/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java @@ -24,6 +24,8 @@ import java.text.DateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; @@ -35,331 +37,86 @@ import androidx.recyclerview.widget.RecyclerView; import protect.card_locker.preferences.Settings; -public class ManageGroupCursorAdapter extends BaseCursorAdapter { - private 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; - private HashMap mIndexCardMap; +public class ManageGroupCursorAdapter extends LoyaltyCardCursorAdapter { + private HashMap mIndexCardMap; private HashMap mInGroupOverlay; - - - public ManageGroupCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener) { - super(inputCursor); - setHasStableIds(true); - mSettings = new Settings(inputContext); - mContext = inputContext; - mListener = inputListener; - mSelectedItems = new SparseBooleanArray(); - mAnimationItemsIndex = new SparseBooleanArray(); - - mDarkModeEnabled = Utils.isDarkModeEnabled(inputContext); - - + private Group mGroup; + private DBHelper mDb; + public ManageGroupCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener, Group group){ + super(inputContext, inputCursor, inputListener); + mGroup = new Group(group._id, group.order); mInGroupOverlay = new HashMap(); - swapCursor(mCursor); + mDb = new DBHelper(inputContext); } @Override public void swapCursor(Cursor inputCursor) { - mIndexCardMap = new HashMap(); - super.swapCursor(inputCursor); - mCursor = inputCursor; - + mIndexCardMap = new HashMap(); } @Override - public ManageGroupListItemViewHolder onCreateViewHolder(ViewGroup inputParent, int inputViewType) { - View itemView = LayoutInflater.from(inputParent.getContext()).inflate(R.layout.manage_group_loyalty_card_layout, inputParent, false); - return new ManageGroupListItemViewHolder(itemView, mListener); - } - - public Cursor getCursor() { - return mCursor; - } - - public void onBindViewHolder(ManageGroupListItemViewHolder inputHolder, Cursor inputCursor) { - // Invisible until we want to show something more - inputHolder.mDivider.setVisibility(View.GONE); - - int size = mSettings.getFontSizeMax(mSettings.getSmallFont()); - - if (mDarkModeEnabled) { - inputHolder.mStarIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP)); - } - - ManageGroupLoyaltyCard cardEntry = ManageGroupLoyaltyCard.toCard(inputCursor); - - inputHolder.mStoreField.setText(cardEntry.store); - inputHolder.mStoreField.setTextSize(mSettings.getFontSizeMax(mSettings.getMediumFont())); - if (!cardEntry.note.isEmpty()) { - inputHolder.mNoteField.setVisibility(View.VISIBLE); - inputHolder.mNoteField.setText(cardEntry.note); - inputHolder.mNoteField.setTextSize(size); - } else { - inputHolder.mNoteField.setVisibility(View.GONE); - } - - if (!cardEntry.balance.equals(new BigDecimal("0"))) { - int drawableSize = dpToPx((size*24)/14, mContext); - inputHolder.mDivider.setVisibility(View.VISIBLE); - inputHolder.mBalanceField.setVisibility(View.VISIBLE); - Drawable balanceIcon = inputHolder.mBalanceField.getCompoundDrawables()[0]; - balanceIcon.setBounds(0,0,drawableSize,drawableSize); - inputHolder.mBalanceField.setCompoundDrawablesRelative(balanceIcon, null, null, null); - if (mDarkModeEnabled) { - balanceIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP)); - } - inputHolder.mBalanceField.setText(Utils.formatBalance(mContext, cardEntry.balance, cardEntry.balanceType)); - inputHolder.mBalanceField.setTextSize(size); - } else { - inputHolder.mBalanceField.setVisibility(View.GONE); - } - - if (cardEntry.expiry != null) { - int drawableSize = dpToPx((size*24)/14, mContext); - inputHolder.mDivider.setVisibility(View.VISIBLE); - inputHolder.mExpiryField.setVisibility(View.VISIBLE); - Drawable expiryIcon = inputHolder.mExpiryField.getCompoundDrawables()[0]; - expiryIcon.setBounds(0,0, drawableSize, drawableSize); - inputHolder.mExpiryField.setCompoundDrawablesRelative(expiryIcon, null, null, null); - if (Utils.hasExpired(cardEntry.expiry)) { - expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.RED, BlendModeCompat.SRC_ATOP)); - inputHolder.mExpiryField.setTextColor(Color.RED); - } else if (mDarkModeEnabled) { - expiryIcon.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.WHITE, BlendModeCompat.SRC_ATOP)); - } - inputHolder.mExpiryField.setText(DateFormat.getDateInstance(DateFormat.LONG).format(cardEntry.expiry)); - inputHolder.mExpiryField.setTextSize(size); - } else { - inputHolder.mExpiryField.setVisibility(View.GONE); - } - - // inputHolder.mStarIcon.setVisibility(cardEntry.starStatus != 0 ? View.VISIBLE : View.GONE); - inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, cardEntry.store, cardEntry.headerColor).getLetterTile()); - int imageSize = dpToPx( (size*46)/14, mContext); - inputHolder.mCardIcon.getLayoutParams().height = imageSize; - inputHolder.mCardIcon.getLayoutParams().width = imageSize; - inputHolder.mStarIcon.getLayoutParams().height = imageSize; - inputHolder.mStarIcon.getLayoutParams().width = imageSize; - inputHolder.mTickIcon.getLayoutParams().height = imageSize; - inputHolder.mTickIcon.getLayoutParams().width = imageSize; - - /* Changing Padding and Margin of different views according to font size - * Views Included: - * a) InformationContainer padding - * b) Store left padding - * c) Divider Margin - * d) note top margin - * e) row margin - * */ - int marginPaddingSize = dpToPx((size*16)/14, mContext ); - inputHolder.mInformationContainer.setPadding(marginPaddingSize, marginPaddingSize, marginPaddingSize, marginPaddingSize); - inputHolder.mStoreField.setPadding(marginPaddingSize, 0, 0, 0); - LinearLayout.LayoutParams lpDivider = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT ); - lpDivider.setMargins(0, marginPaddingSize, 0, marginPaddingSize); - inputHolder.mDivider.setLayoutParams(lpDivider); - LinearLayout.LayoutParams lpNoteField = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT ); - lpNoteField.setMargins(0, marginPaddingSize/2, 0, 0); - inputHolder.mNoteField.setLayoutParams(lpNoteField); - LinearLayout.LayoutParams lpRow = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.WRAP_CONTENT ); - lpRow.setMargins(marginPaddingSize/2, marginPaddingSize/2, marginPaddingSize/2, marginPaddingSize/2); - inputHolder.mRow.setLayoutParams(lpRow); - - inputHolder.itemView.setActivated(mSelectedItems.get(inputCursor.getPosition(), false)); - - Boolean overlayValue = mInGroupOverlay.get(cardEntry.id); - if((overlayValue != null? overlayValue: cardEntry.is_in_group)) { + public void onBindViewHolder(LoyaltyCardListItemViewHolder inputHolder, Cursor inputCursor){ + LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(inputCursor); + Boolean overlayValue = mInGroupOverlay.get(loyaltyCard.id); + if((overlayValue != null? overlayValue: isLoyaltyCardInGroup(loyaltyCard.id))) { mAnimationItemsIndex.put(inputCursor.getPosition(), true); mSelectedItems.put(inputCursor.getPosition(), true); } - - applyIconAnimation(inputHolder, inputCursor.getPosition()); - applyClickEvents(inputHolder, inputCursor.getPosition()); - - mIndexCardMap.put(inputCursor.getPosition(), cardEntry); + mIndexCardMap.put(inputCursor.getPosition(), loyaltyCard.id); + super.onBindViewHolder(inputHolder, inputCursor); } - private void applyClickEvents(ManageGroupListItemViewHolder inputHolder, final int inputPosition) { - inputHolder.mRow.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition)); - inputHolder.mInformationContainer.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition)); - - inputHolder.mRow.setOnLongClickListener(inputView -> { - mListener.onRowLongClicked(inputPosition); - inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - return true; - }); - - inputHolder.mInformationContainer.setOnLongClickListener(inputView -> { - mListener.onRowLongClicked(inputPosition); - inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - return true; - }); - } - - private void applyIconAnimation(ManageGroupListItemViewHolder 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(); - } - } else { - inputHolder.mThumbnailBackContainer.setVisibility(View.GONE); - resetIconYAxis(inputHolder.mThumbnailFrontContainer); - inputHolder.mThumbnailFrontContainer.setVisibility(View.VISIBLE); - inputHolder.mThumbnailFrontContainer.setAlpha(1); - if ((mReverseAllAnimations && mAnimationItemsIndex.get(inputPosition, false)) || mCurrentSelectedIndex == inputPosition) { - 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(); - } - - - 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); - } - ManageGroupLoyaltyCard cardEntry = mIndexCardMap.get(inputPosition); - Boolean overlayValue = mInGroupOverlay.get(cardEntry.id); - if (overlayValue == null){ - mInGroupOverlay.put(cardEntry.id, !cardEntry.is_in_group); - }else{ - mInGroupOverlay.put(cardEntry.id, !overlayValue); - } - - notifyDataSetChanged(); - } - - private void resetCurrentIndex() { - mCurrentSelectedIndex = -1; - } - - public interface CardAdapterListener { - void onRowClicked(int inputPosition); - - void onRowLongClicked(int inputPosition); - } - - private HashMap fetchWholeQuery (){ - HashMap res = new HashMap(); - int oldPosition = mCursor.getPosition(); - mCursor.moveToFirst(); - while(!mCursor.isAfterLast()){ - ManageGroupLoyaltyCard cardEntry = ManageGroupLoyaltyCard.toCard(mCursor); - res.put(cardEntry.id, cardEntry); - mCursor.moveToNext(); - } - mCursor.moveToPosition(oldPosition); - return res; - } - - public void commitToDatabase(Context context, String groupId){ - DBHelper dbHelper = new DBHelper(context); - HashMap cache = fetchWholeQuery(); - for(Map.Entry entry : mInGroupOverlay.entrySet()){ - ManageGroupLoyaltyCard cardEntry = cache.get(entry.getKey()); - if (cardEntry == null){ - Log.d("commitToDatabase", "card with id " + entry.getKey() + " was removed from database unexpectedly"); - continue; - } - if (entry.getValue() != cardEntry.is_in_group) { - if (entry.getValue()) { - dbHelper.addLoyaltyCardToGroup(entry.getKey(), groupId); - } else { - dbHelper.removeLoyaltyCardFromGroup(entry.getKey(), groupId); - } - } - } - } - - public boolean hasChanged(){ - HashMap cache = fetchWholeQuery(); - for(Map.Entry entry : mInGroupOverlay.entrySet()){ - ManageGroupLoyaltyCard cardEntry = cache.get(entry.getKey()); - if(cardEntry.is_in_group != entry.getValue()){ + private boolean isLoyaltyCardInGroup(int cardId){ + List groups = mDb.getLoyaltyCardGroups(cardId); + Iterator groupItr = groups.listIterator(); + while(groupItr.hasNext()){ + if (groupItr.next().equals(mGroup)){ return true; } } return false; } - public int getCountFromCursor(){ - return mCursor.getCount(); - } - - public HashMap exportInGroupState(){ - return (HashMap)mInGroupOverlay.clone(); - } - - public void importInGroupState(HashMap cardIdInGroupMap){ - mInGroupOverlay = (HashMap)cardIdInGroupMap.clone(); - } - - - public static class ManageGroupListItemViewHolder extends RecyclerView.ViewHolder { - - public TextView mStoreField, mNoteField, mBalanceField, mExpiryField; - public LinearLayout mInformationContainer; - public ImageView mCardIcon, mStarIcon, mTickIcon; - public MaterialCardView mRow; - public View mDivider; - public RelativeLayout mThumbnailFrontContainer, mThumbnailBackContainer; - - public ManageGroupListItemViewHolder(View inputView, CardAdapterListener inputListener) { - super(inputView); - mRow = inputView.findViewById(R.id.row); - mDivider = inputView.findViewById(R.id.info_divider); - 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); - mTickIcon = inputView.findViewById(R.id.selected_thumbnail); - inputView.setOnLongClickListener(view -> { - inputListener.onRowClicked(getAdapterPosition()); - inputView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - return true; - }); + @Override + public void toggleSelection(int inputPosition){ + super.toggleSelection(inputPosition); + int cardId = mIndexCardMap.get(inputPosition); + Boolean overlayValue = mInGroupOverlay.get(cardId); + if (overlayValue == null){ + mInGroupOverlay.put(cardId, !isLoyaltyCardInGroup(cardId)); + }else{ + mInGroupOverlay.remove(cardId); } } - public int dpToPx(int dp, Context mContext){ - Resources r = mContext.getResources(); - int px = (int)TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()); - return px; + public boolean hasChanged() { + return mInGroupOverlay.size() > 0; + } + + public void commitToDatabase(Context context){ + // this is very inefficient but done to keep the size of DBHelper low + for(Map.Entry entry: mInGroupOverlay.entrySet()){ + int cardId = entry.getKey(); + List groups = mDb.getLoyaltyCardGroups(cardId); + if(entry.getValue()){ + groups.add(mGroup); + }else{ + groups.remove(mGroup); + } + mDb.setLoyaltyCardGroups(cardId, groups); + } + } + + public void importInGroupState(HashMap cardIdInGroupMap) { + mInGroupOverlay = (HashMap) cardIdInGroupMap.clone(); + } + + public HashMap exportInGroupState(){ + return (HashMap)mInGroupOverlay.clone(); + } + + public int getCountFromCursor() { + return super.getCursor().getCount(); } } diff --git a/app/src/main/java/protect/card_locker/ManageGroupLoyaltyCard.java b/app/src/main/java/protect/card_locker/ManageGroupLoyaltyCard.java deleted file mode 100644 index 0010d1f19..000000000 --- a/app/src/main/java/protect/card_locker/ManageGroupLoyaltyCard.java +++ /dev/null @@ -1,168 +0,0 @@ -package protect.card_locker; -// Was thinking about extending LoyaltyCard but this makes things more modular..? -import android.database.Cursor; -import android.os.Parcel; -import android.os.Parcelable; - -import java.math.BigDecimal; -import java.util.Currency; -import java.util.Date; - -import androidx.annotation.Nullable; - -public class ManageGroupLoyaltyCard implements Parcelable { - public final int id; - public final String store; - public final String note; - public final Date expiry; - public final BigDecimal balance; - public final Currency balanceType; - public final String cardId; - - @Nullable - public final String barcodeId; - - @Nullable - public final CatimaBarcode barcodeType; - - @Nullable - public final Integer headerColor; - - public final int starStatus; - public final long lastUsed; - public int zoomLevel; - - public final boolean is_in_group; - - public ManageGroupLoyaltyCard(final int id, final String store, final String note, final Date expiry, - final BigDecimal balance, final Currency balanceType, final String cardId, - @Nullable final String barcodeId, @Nullable final CatimaBarcode barcodeType, - @Nullable final Integer headerColor, final int starStatus, final long lastUsed,final int zoomLevel, - final boolean is_in_group) - { - this.id = id; - this.store = store; - this.note = note; - this.expiry = expiry; - this.balance = balance; - this.balanceType = balanceType; - this.cardId = cardId; - this.barcodeId = barcodeId; - this.barcodeType = barcodeType; - this.headerColor = headerColor; - this.starStatus = starStatus; - this.lastUsed = lastUsed; - this.zoomLevel = zoomLevel; - this.is_in_group = is_in_group; - } - - protected ManageGroupLoyaltyCard(Parcel in) { - id = in.readInt(); - store = in.readString(); - note = in.readString(); - long tmpExpiry = in.readLong(); - expiry = tmpExpiry != -1 ? new Date(tmpExpiry) : null; - balance = (BigDecimal) in.readValue(BigDecimal.class.getClassLoader()); - balanceType = (Currency) in.readValue(Currency.class.getClassLoader()); - cardId = in.readString(); - barcodeId = in.readString(); - String tmpBarcodeType = in.readString(); - barcodeType = !tmpBarcodeType.isEmpty() ? CatimaBarcode.fromName(tmpBarcodeType) : null; - int tmpHeaderColor = in.readInt(); - headerColor = tmpHeaderColor != -1 ? tmpHeaderColor : null; - starStatus = in.readInt(); - lastUsed = in.readLong(); - zoomLevel = in.readInt(); - if (in.readInt() == 1) { - is_in_group = true; - }else{ - is_in_group = false; - } - } - - @Override - public void writeToParcel(Parcel parcel, int i) { - parcel.writeInt(id); - parcel.writeString(store); - parcel.writeString(note); - parcel.writeLong(expiry != null ? expiry.getTime() : -1); - parcel.writeValue(balance); - parcel.writeValue(balanceType); - parcel.writeString(cardId); - parcel.writeString(barcodeId); - parcel.writeString(barcodeType != null ? barcodeType.name() : ""); - parcel.writeInt(headerColor != null ? headerColor : -1); - parcel.writeInt(starStatus); - parcel.writeLong(lastUsed); - parcel.writeInt(zoomLevel); - if (is_in_group) { - parcel.writeInt(1); - }else{ - parcel.writeInt(0); - } - } - - public static ManageGroupLoyaltyCard toCard(Cursor cursor) - { - int id = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ID)); - String store = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STORE)); - String note = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.NOTE)); - long expiryLong = cursor.getLong(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.EXPIRY)); - BigDecimal balance = new BigDecimal(cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BALANCE))); - String cardId = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.CARD_ID)); - String barcodeId = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_ID)); - int starred = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.STAR_STATUS)); - long lastUsed = cursor.getLong(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.LAST_USED)); - int zoomLevel = cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ZOOM_LEVEL)); - - int barcodeTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_TYPE); - int balanceTypeColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BALANCE_TYPE); - int headerColorColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.HEADER_COLOR); - - boolean was_in_group = !cursor.isNull(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIdsGroups.groupID)); - - CatimaBarcode barcodeType = null; - Currency balanceType = null; - Date expiry = null; - Integer headerColor = null; - - if (cursor.isNull(barcodeTypeColumn) == false) - { - barcodeType = CatimaBarcode.fromName(cursor.getString(barcodeTypeColumn)); - } - - if (cursor.isNull(balanceTypeColumn) == false) - { - balanceType = Currency.getInstance(cursor.getString(balanceTypeColumn)); - } - - if(expiryLong > 0) - { - expiry = new Date(expiryLong); - } - - if(cursor.isNull(headerColorColumn) == false) - { - headerColor = cursor.getInt(headerColorColumn); - } - - return new ManageGroupLoyaltyCard(id, store, note, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starred, lastUsed,zoomLevel,was_in_group); - } - - @Override - public int describeContents() { - return id; - } - - public static final Creator CREATOR = new Creator() { - @Override - public LoyaltyCard createFromParcel(Parcel in) { - return new LoyaltyCard(in); - } - - @Override - public LoyaltyCard[] newArray(int size) { - return new LoyaltyCard[size]; - } - }; -} diff --git a/app/src/main/java/protect/card_locker/ManageGroupsActivity.java b/app/src/main/java/protect/card_locker/ManageGroupsActivity.java index 9140ef7de..60127bd24 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupsActivity.java +++ b/app/src/main/java/protect/card_locker/ManageGroupsActivity.java @@ -177,9 +177,8 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro @Override public void onEditButtonClicked(View view) { - Group group = mDb.getGroup(getGroupName(view)); Intent intent = new Intent(this, ManageGroupActivity.class); - intent.putExtra("group", group); + intent.putExtra("group", getGroupName(view)); startActivity(intent); /* final String groupName = c; diff --git a/app/src/main/res/layout/activity_manage_group.xml b/app/src/main/res/layout/activity_manage_group.xml index 32f696a4c..75031e891 100644 --- a/app/src/main/res/layout/activity_manage_group.xml +++ b/app/src/main/res/layout/activity_manage_group.xml @@ -49,7 +49,7 @@ + layout="@layout/content_main" /> diff --git a/app/src/main/res/layout/content_manage_group.xml b/app/src/main/res/layout/content_manage_group.xml deleted file mode 100644 index 71a305bcb..000000000 --- a/app/src/main/res/layout/content_manage_group.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/layout/manage_group_loyalty_card_layout.xml b/app/src/main/res/layout/manage_group_loyalty_card_layout.xml deleted file mode 100644 index 4c3af71d5..000000000 --- a/app/src/main/res/layout/manage_group_loyalty_card_layout.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 9252c01aa7fdb4d87fa4a73a114e90d66b3b9975 Mon Sep 17 00:00:00 2001 From: Katharine Date: Sat, 30 Oct 2021 13:04:03 +0800 Subject: [PATCH 05/14] Group does not need to be a Parcelable anymore --- .../main/java/protect/card_locker/Group.java | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/app/src/main/java/protect/card_locker/Group.java b/app/src/main/java/protect/card_locker/Group.java index fab064cda..d1b6a0495 100644 --- a/app/src/main/java/protect/card_locker/Group.java +++ b/app/src/main/java/protect/card_locker/Group.java @@ -6,7 +6,7 @@ import android.os.Parcelable; import androidx.annotation.Nullable; -public class Group implements Parcelable +public class Group { public final String _id; public final int order; @@ -21,20 +21,6 @@ public class Group implements Parcelable this.order = in.readInt(); } - - @Override - public void writeToParcel(Parcel parcel, int i){ - parcel.writeString(_id); - parcel.writeInt(order); - } - - - @Override - public int describeContents() { - // group table does not have an integer ID - return 0; - } - public static Group toGroup(Cursor cursor) { String _id = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.ID)); @@ -43,18 +29,6 @@ public class Group implements Parcelable return new Group(_id, order); } - public static final Creator CREATOR = new Creator() { - @Override - public Group createFromParcel(Parcel in) { - return new Group(in); - } - - @Override - public Group[] newArray(int size) { - return new Group[size]; - } - }; - @Override public boolean equals(@Nullable Object obj) { if (obj == null){ From cb8275771fb335d9500b97e2b1b865973653c4bd Mon Sep 17 00:00:00 2001 From: Katharine Date: Sat, 30 Oct 2021 13:08:37 +0800 Subject: [PATCH 06/14] remove database shortcuts --- .../java/protect/card_locker/DBHelper.java | 54 ------------------- 1 file changed, 54 deletions(-) diff --git a/app/src/main/java/protect/card_locker/DBHelper.java b/app/src/main/java/protect/card_locker/DBHelper.java index a55ae71fe..505f3be52 100644 --- a/app/src/main/java/protect/card_locker/DBHelper.java +++ b/app/src/main/java/protect/card_locker/DBHelper.java @@ -613,21 +613,6 @@ public class DBHelper extends SQLiteOpenHelper } } - public void addLoyaltyCardToGroup(int cardId, String groupId){ - SQLiteDatabase db = getWritableDatabase(); - ContentValues contentValues = new ContentValues(); - contentValues.put(LoyaltyCardDbIdsGroups.cardID, cardId); - contentValues.put(LoyaltyCardDbIdsGroups.groupID, groupId); - db.insert(LoyaltyCardDbIdsGroups.TABLE, null, contentValues); - } - - public void removeLoyaltyCardFromGroup(int cardId, String groupId){ - SQLiteDatabase db = getWritableDatabase(); - db.delete(LoyaltyCardDbIdsGroups.TABLE, - whereAttrs(LoyaltyCardDbIdsGroups.cardID, LoyaltyCardDbIdsGroups.groupID), - withArgs(cardId, groupId)); - } - public boolean deleteLoyaltyCard(final int id) { SQLiteDatabase db = getWritableDatabase(); @@ -733,45 +718,6 @@ public class DBHelper extends SQLiteOpenHelper limitString, filter.trim().isEmpty() ? null : new String[] { TextUtils.join("* ", filter.split(" ")) + '*' }, null); } - /** - * Returns a cursor to all loyalty cards with the filter text in either the store and whether card is in the provided group - * - * @param filter - * @param group - * @param order - * @return Cursor - */ - public Cursor getIfLoyaltyCardsAreInGroupCursor(String filter, Group group, LoyaltyCardOrder order, LoyaltyCardOrderDirection direction) { - SQLiteDatabase db = getReadableDatabase(); - - if (group == null) { - throw new IllegalArgumentException("group cannot be null"); - } - String orderField = getFieldForOrder(order); - String[] selectionArgs; - if(filter.trim().isEmpty()) { - selectionArgs = new String[]{ - group._id - }; - }else{ - selectionArgs = new String[]{ - group._id, - TextUtils.join("* ", filter.split(" ")) + '*' - }; - } - return db.rawQuery("SELECT " + "*" + - " FROM " + LoyaltyCardDbIds.TABLE + " LEFT OUTER JOIN " + - " (SELECT " + LoyaltyCardDbIdsGroups.TABLE + ".*" + - " FROM " + LoyaltyCardDbIdsGroups.TABLE + - " WHERE " + LoyaltyCardDbIdsGroups.groupID + " = ? " + - " ) " + " AS " + LoyaltyCardDbIdsGroups.TABLE + - " ON " + LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.ID + " = " + LoyaltyCardDbIdsGroups.TABLE + "." + LoyaltyCardDbIdsGroups.cardID + - (filter.trim().isEmpty() ? "" : " WHERE " + LoyaltyCardDbIds.TABLE + "." + LoyaltyCardDbIds.STORE + " MATCH ? ") + - " ORDER BY " + LoyaltyCardDbIds.TABLE + "." + orderField, - selectionArgs, - null); - } - /** * Returns the amount of loyalty cards. * From d6eccd11a5e4d89f5d3ac03cd466e2b8302ad813 Mon Sep 17 00:00:00 2001 From: Katharine Date: Sat, 30 Oct 2021 13:41:05 +0800 Subject: [PATCH 07/14] UI touch ups --- .../card_locker/ManageGroupActivity.java | 93 +++++++------------ .../main/res/layout/activity_manage_group.xml | 29 ++++-- app/src/main/res/menu/manage_group_menu.xml | 10 -- app/src/main/res/values/strings.xml | 8 +- 4 files changed, 56 insertions(+), 84 deletions(-) delete mode 100644 app/src/main/res/menu/manage_group_menu.xml diff --git a/app/src/main/java/protect/card_locker/ManageGroupActivity.java b/app/src/main/java/protect/card_locker/ManageGroupActivity.java index da26a5438..bed43944c 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupActivity.java +++ b/app/src/main/java/protect/card_locker/ManageGroupActivity.java @@ -71,13 +71,14 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana private EditText mGroupNameText; private TextView mGroupNameLabel; private ActionBar mActionBar; + private FloatingActionButton mSaveButton; private HashMap mAdapterState; private String mCurrentGroupName; private boolean mGroupNameNotInUse; - private boolean mDarkMode; + private int mGroupNameInputTextColor; @Override protected void onCreate(Bundle inputSavedInstanceState) @@ -91,9 +92,10 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana mNoMatchingCardsText = findViewById(R.id.noMatchingCardsText); mNoGroupCardsText = findViewById(R.id.noGroupCardsText); mCardList = findViewById(R.id.list); + mSaveButton = findViewById(R.id.fabSave); mGroupNameText = findViewById(R.id.editTextGroupName); - mGroupNameLabel = findViewById(R.id.textViewEditGroupName); + mGroupNameInputTextColor = mGroupNameText.getCurrentTextColor(); Intent intent = getIntent(); String groupId = intent.getStringExtra("group"); @@ -109,8 +111,6 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana mCardList.setAdapter(mAdapter); registerForContextMenu(mCardList); - mDarkMode = Utils.isDarkModeEnabled(getApplicationContext()); - if (inputSavedInstanceState != null) { ManageGroupActivityInGroupState adapterState = inputSavedInstanceState.getParcelable("mAdapterState"); if (adapterState != null) { @@ -125,14 +125,37 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana } mActionBar.setDisplayHomeAsUpEnabled(true); mActionBar.setDisplayShowHomeEnabled(true); + + mSaveButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String currentGroupName = mGroupNameText.getText().toString(); + if(!currentGroupName.trim().equals(mGroup._id)){ + if(!mGroupNameNotInUse) { + Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT); + toast.show(); + return; + } + if(currentGroupName.trim().length() == 0){ + Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT); + toast.show(); + return; + } + } + + mAdapter.commitToDatabase(getApplicationContext()); + Toast toast = Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT); + if(!currentGroupName.trim().equals(mGroup._id)){ + mDB.updateGroup(mGroup._id, currentGroupName.trim()); + } + toast.show(); + finish(); + } + }); } private void resetGroupNameTextColor() { - if (mDarkMode) { - mGroupNameText.setTextColor(Color.WHITE); - } else{ - mGroupNameText.setTextColor(Color.BLACK); - } + mGroupNameText.setTextColor(mGroupNameInputTextColor); } private void checkIfGroupNameIsInUse(){ @@ -246,26 +269,11 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana } } - @Override - public boolean onCreateOptionsMenu(Menu inputMenu) - { - this.mMenu = inputMenu; - - getMenuInflater().inflate(R.menu.manage_group_menu, inputMenu); - - MenuItem confirmButton = inputMenu.findItem(R.id.action_confirm); - Drawable icon = confirmButton.getIcon(); - icon.mutate(); - icon.setTint(Color.WHITE); - confirmButton.setIcon(icon); - return super.onCreateOptionsMenu(inputMenu); - } - private void leaveWithoutSaving(){ if (hasChanged()){ AlertDialog.Builder builder = new AlertDialog.Builder(ManageGroupActivity.this); - builder.setTitle(R.string.discard_changes); - builder.setMessage(R.string.discard_changes_confirm); + builder.setTitle(R.string.leaveWithoutSaveTitle); + builder.setMessage(R.string.leaveWithoutSaveConfirmation); builder.setPositiveButton(R.string.confirm, (dialog, which) -> finish()); builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); AlertDialog dialog = builder.create(); @@ -275,39 +283,6 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana } } - @Override - public boolean onOptionsItemSelected(MenuItem inputItem) - { - int id = inputItem.getItemId(); - - if (id == R.id.action_confirm) - { - String currentGroupName = mGroupNameText.getText().toString(); - if(!currentGroupName.trim().equals(mGroup._id)){ - if(!mGroupNameNotInUse) { - Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT); - toast.show(); - return true; - } - if(currentGroupName.trim().length() == 0){ - Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT); - toast.show(); - return true; - } - } - - mAdapter.commitToDatabase(getApplicationContext()); - Toast toast = Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT); - if(!currentGroupName.trim().equals(mGroup._id)){ - mDB.updateGroup(mGroup._id, currentGroupName.trim()); - } - toast.show(); - finish(); - return true; - } - - return super.onOptionsItemSelected(inputItem); - } @Override public void onBackPressed() { diff --git a/app/src/main/res/layout/activity_manage_group.xml b/app/src/main/res/layout/activity_manage_group.xml index 75031e891..4a1855f48 100644 --- a/app/src/main/res/layout/activity_manage_group.xml +++ b/app/src/main/res/layout/activity_manage_group.xml @@ -7,7 +7,14 @@ android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="protect.card_locker.ManageGroupActivity"> - + - - + android:hint="@string/storeName"> + + + - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 37697ef05..90a3d7c7b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -130,9 +130,9 @@ %d card %d cards - Group name already in use! - Group name cannot be empty! - Group updated! + Group name already in use + Group name cannot be empty + Group updated All Delete group? Install a file manager first. @@ -249,6 +249,4 @@ Rate this app on Google Play Report Error - Discard Changes - There are unsaved changes that were made, do you wish to leave without saving? From 426acc701eb2179da4616452ee3509ea2131a58d Mon Sep 17 00:00:00 2001 From: Katharine Date: Sat, 30 Oct 2021 13:43:50 +0800 Subject: [PATCH 08/14] remove setSort which will likely not be implemented in here --- .../card_locker/ManageGroupActivity.java | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/app/src/main/java/protect/card_locker/ManageGroupActivity.java b/app/src/main/java/protect/card_locker/ManageGroupActivity.java index bed43944c..80a83d96f 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupActivity.java +++ b/app/src/main/java/protect/card_locker/ManageGroupActivity.java @@ -299,24 +299,6 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana return mAdapter.hasChanged() || !mGroup._id.equals(mGroupNameText.getText().toString().trim()); } - private void setSort(DBHelper.LoyaltyCardOrder order, DBHelper.LoyaltyCardOrderDirection direction) { - // Update values - mOrder = order; - mOrderDirection = direction; - - // Store in Shared Preference to restore next app launch - SharedPreferences sortPref = getApplicationContext().getSharedPreferences( - getString(R.string.sharedpreference_sort), - Context.MODE_PRIVATE); - SharedPreferences.Editor sortPrefEditor = sortPref.edit(); - sortPrefEditor.putString(getString(R.string.sharedpreference_sort_order), order.name()); - sortPrefEditor.putString(getString(R.string.sharedpreference_sort_direction), direction.name()); - sortPrefEditor.apply(); - - // Update card list - updateLoyaltyCardList(); - } - @Override public void onRowLongClicked(int inputPosition) { From a00a69e0c004fa7fc558ff8e174ad3944f42293b Mon Sep 17 00:00:00 2001 From: Katharine Chui Date: Mon, 1 Nov 2021 01:02:17 +0800 Subject: [PATCH 09/14] UI changes, group cache, code cleanup hash maps are cloned manually to make android studio and spotbug happy --- .../card_locker/ManageGroupActivity.java | 191 +++++++----------- .../ManageGroupActivityInGroupState.java | 58 ------ .../card_locker/ManageGroupCursorAdapter.java | 90 ++++----- app/src/main/res/values/strings.xml | 2 + 4 files changed, 115 insertions(+), 226 deletions(-) delete mode 100644 app/src/main/java/protect/card_locker/ManageGroupActivityInGroupState.java diff --git a/app/src/main/java/protect/card_locker/ManageGroupActivity.java b/app/src/main/java/protect/card_locker/ManageGroupActivity.java index 80a83d96f..eb7e3ca68 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupActivity.java +++ b/app/src/main/java/protect/card_locker/ManageGroupActivity.java @@ -1,85 +1,45 @@ package protect.card_locker; -import android.app.SearchManager; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; + import android.content.Intent; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.database.CursorIndexOutOfBoundsException; -import android.graphics.Color; -import android.graphics.drawable.Drawable; + import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; -import android.view.GestureDetector; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; import android.view.View; -import android.widget.CheckBox; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.google.android.material.floatingactionbutton.FloatingActionButton; -import com.google.android.material.tabs.TabLayout; -import java.io.UnsupportedEncodingException; -import java.util.Arrays; +import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import androidx.annotation.Nullable; +import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.view.ActionMode; -import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.Toolbar; -import androidx.core.graphics.BlendModeColorFilterCompat; -import androidx.core.graphics.BlendModeCompat; -import androidx.core.splashscreen.SplashScreen; import androidx.recyclerview.widget.RecyclerView; -import protect.card_locker.preferences.SettingsActivity; public class ManageGroupActivity extends CatimaAppCompatActivity implements ManageGroupCursorAdapter.CardAdapterListener { - private static final String TAG = "Catima"; private final DBHelper mDB = new DBHelper(this); private ManageGroupCursorAdapter mAdapter; - private ActionMode mCurrentActionMode; - private Menu mMenu; - - // currently unused - protected String mFilter = ""; - protected DBHelper.LoyaltyCardOrderDirection mOrderDirection = DBHelper.LoyaltyCardOrderDirection.Ascending; - protected DBHelper.LoyaltyCardOrder mOrder = DBHelper.LoyaltyCardOrder.Alpha; protected Group mGroup = null; private RecyclerView mCardList; - private View mHelpText; - private View mNoMatchingCardsText; - private View mNoGroupCardsText; + private TextView mHelpText; private EditText mGroupNameText; - private TextView mGroupNameLabel; - private ActionBar mActionBar; - private FloatingActionButton mSaveButton; private HashMap mAdapterState; private String mCurrentGroupName; private boolean mGroupNameNotInUse; - private int mGroupNameInputTextColor; - @Override protected void onCreate(Bundle inputSavedInstanceState) { @@ -89,20 +49,17 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana setSupportActionBar(toolbar); mHelpText = findViewById(R.id.helpText); - mNoMatchingCardsText = findViewById(R.id.noMatchingCardsText); - mNoGroupCardsText = findViewById(R.id.noGroupCardsText); mCardList = findViewById(R.id.list); - mSaveButton = findViewById(R.id.fabSave); + FloatingActionButton saveButton = findViewById(R.id.fabSave); mGroupNameText = findViewById(R.id.editTextGroupName); - mGroupNameInputTextColor = mGroupNameText.getCurrentTextColor(); Intent intent = getIntent(); String groupId = intent.getStringExtra("group"); if (groupId == null){ throw(new IllegalArgumentException("this activity expects a group loaded into it's intent")); } - Log.d("groupId", "gropuId: " + groupId); + Log.d("groupId", "groupId: " + groupId); mGroup = mDB.getGroup(groupId); if (mGroup == null){ throw(new IllegalArgumentException("cannot load group " + groupId + " from database")); @@ -112,50 +69,44 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana registerForContextMenu(mCardList); if (inputSavedInstanceState != null) { - ManageGroupActivityInGroupState adapterState = inputSavedInstanceState.getParcelable("mAdapterState"); + ArrayList adapterState = inputSavedInstanceState.getIntegerArrayList("mAdapterState"); if (adapterState != null) { - mAdapterState = adapterState.getMap(); + integerArrayToAdapterState(adapterState); } mCurrentGroupName = inputSavedInstanceState.getString("mCurrentGroupName"); } - mActionBar = getSupportActionBar(); - if (mActionBar == null){ + ActionBar actionBar = getSupportActionBar(); + if (actionBar == null){ throw(new RuntimeException("mActionBar is not expected to be null here")); } - mActionBar.setDisplayHomeAsUpEnabled(true); - mActionBar.setDisplayShowHomeEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowHomeEnabled(true); - mSaveButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - String currentGroupName = mGroupNameText.getText().toString(); - if(!currentGroupName.trim().equals(mGroup._id)){ - if(!mGroupNameNotInUse) { - Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT); - toast.show(); - return; - } - if(currentGroupName.trim().length() == 0){ - Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT); - toast.show(); - return; - } + saveButton.setOnClickListener(v -> { + String currentGroupName = mGroupNameText.getText().toString(); + if(!currentGroupName.trim().equals(mGroup._id)){ + if(!mGroupNameNotInUse) { + Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT); + toast.show(); + return; } - - mAdapter.commitToDatabase(getApplicationContext()); - Toast toast = Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT); - if(!currentGroupName.trim().equals(mGroup._id)){ - mDB.updateGroup(mGroup._id, currentGroupName.trim()); + if(currentGroupName.trim().length() == 0){ + Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT); + toast.show(); + return; } - toast.show(); - finish(); } - }); - } - private void resetGroupNameTextColor() { - mGroupNameText.setTextColor(mGroupNameInputTextColor); + mAdapter.commitToDatabase(); + Toast toast = Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT); + if(!currentGroupName.trim().equals(mGroup._id)){ + mDB.updateGroup(mGroup._id, currentGroupName.trim()); + } + toast.show(); + finish(); + }); + mHelpText.setText(getResources().getText(R.string.noGiftCardsGroup)); } private void checkIfGroupNameIsInUse(){ @@ -165,7 +116,7 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana Group group = mDB.getGroup(currentGroupName.trim()); if (group != null) { mGroupNameNotInUse = false; - mGroupNameText.setTextColor(Color.RED); + mGroupNameText.setError(getResources().getText(R.string.group_name_already_in_use)); } else { mGroupNameNotInUse = true; } @@ -177,7 +128,7 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana { super.onResume(); - setTitle(getString(R.string.edit) + ": " + mGroup._id); + setTitle(getString(R.string.editGroup, mGroup._id)); if (mCurrentGroupName == null){ mGroupNameText.setText(mGroup._id); @@ -189,17 +140,15 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana mGroupNameText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { - return; } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - return; } @Override public void afterTextChanged(Editable s) { - resetGroupNameTextColor(); + mGroupNameText.setError(null); checkIfGroupNameIsInUse(); } }); @@ -210,12 +159,38 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana updateLoyaltyCardList(); } + private ArrayList adapterStateToIntegerArray(){ + ArrayList ret = new ArrayList<>(mAdapterState.size() * 2); + for (Map.Entry entry : mAdapterState.entrySet()) { + ret.add(entry.getKey()); + ret.add(entry.getValue()?1:0); + } + return ret; + } + + private void integerArrayToAdapterState(ArrayList in) { + boolean isKey = true; + int cardId = 0; + mAdapterState = new HashMap<>(); + for (int value : in) { + if (isKey) { + cardId = value; + } else { + mAdapterState.put(cardId, value == 1); + } + isKey = !isKey; + } + if(!isKey){ + throw(new RuntimeException("failed restoring mAdapterState from integer array list")); + } + } + + @Override - protected void onSaveInstanceState (Bundle outState){ + protected void onSaveInstanceState (@NonNull Bundle outState){ super.onSaveInstanceState(outState); if(mAdapterState != null){ - ManageGroupActivityInGroupState state = new ManageGroupActivityInGroupState(mAdapterState); - outState.putParcelable("mAdapterState", state); + outState.putIntegerArrayList("mAdapterState", adapterStateToIntegerArray()); } if(mCurrentGroupName != null){ outState.putString("mCurrentGroupName", mCurrentGroupName); @@ -232,40 +207,15 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana } private void updateLoyaltyCardList() { - mAdapter.swapCursor(mDB.getLoyaltyCardCursor(mFilter, null, mOrder, mOrderDirection)); + mAdapter.swapCursor(mDB.getLoyaltyCardCursor("", null, DBHelper.LoyaltyCardOrder.Alpha, DBHelper.LoyaltyCardOrderDirection.Ascending)); - if(mAdapter.getCountFromCursor() > 0) - { - // We want the cardList to be visible regardless of the filtered match count - // to ensure that the noMatchingCardsText doesn't end up being shown below - // the keyboard - mHelpText.setVisibility(View.GONE); - mNoGroupCardsText.setVisibility(View.GONE); - if(mAdapter.getItemCount() > 0) - { - mCardList.setVisibility(View.VISIBLE); - mNoMatchingCardsText.setVisibility(View.GONE); - } - else - { - mCardList.setVisibility(View.GONE); - if (!mFilter.isEmpty()) { - // Actual Empty Search Result - mNoMatchingCardsText.setVisibility(View.VISIBLE); - mNoGroupCardsText.setVisibility(View.GONE); - } else { - // Group Tab with no Group Cards - mNoMatchingCardsText.setVisibility(View.GONE); - mNoGroupCardsText.setVisibility(View.VISIBLE); - } - } - } - else + if(mAdapter.getCountFromCursor() == 0) { mCardList.setVisibility(View.GONE); mHelpText.setVisibility(View.VISIBLE); - mNoMatchingCardsText.setVisibility(View.GONE); - mNoGroupCardsText.setVisibility(View.GONE); + }else { + mCardList.setVisibility(View.VISIBLE); + mHelpText.setVisibility(View.GONE); } } @@ -303,7 +253,6 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana public void onRowLongClicked(int inputPosition) { // do nothing for now - return; } @Override diff --git a/app/src/main/java/protect/card_locker/ManageGroupActivityInGroupState.java b/app/src/main/java/protect/card_locker/ManageGroupActivityInGroupState.java deleted file mode 100644 index e6c30f793..000000000 --- a/app/src/main/java/protect/card_locker/ManageGroupActivityInGroupState.java +++ /dev/null @@ -1,58 +0,0 @@ -package protect.card_locker; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.HashMap; -import java.util.Map; - -public class ManageGroupActivityInGroupState implements Parcelable { - HashMap map; - - - - public ManageGroupActivityInGroupState(HashMap in){ - map = (HashMap)in.clone(); - } - - @Override - public int describeContents(){ - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(map.size()); - - for(Map.Entry entry : map.entrySet()){ - dest.writeInt(entry.getKey()); - dest.writeInt(entry.getValue() ? 1 : 0); - } - } - - protected ManageGroupActivityInGroupState(Parcel in){ - map = new HashMap(); - int length = in.readInt(); - for (int i = 0;i < length; i++){ - int key = in.readInt(); - boolean value = in.readInt() == 1 ? true : false; - map.put(key, value); - } - } - - public static final Creator CREATOR = new Creator() { - @Override - public ManageGroupActivityInGroupState createFromParcel(Parcel in) { - return new ManageGroupActivityInGroupState(in); - } - - @Override - public ManageGroupActivityInGroupState[] newArray(int size) { - return new ManageGroupActivityInGroupState[size]; - } - }; - - public HashMap getMap(){ - return (HashMap)map.clone(); - } -} diff --git a/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java b/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java index a88083474..d3d0b476c 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java +++ b/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java @@ -1,58 +1,32 @@ package protect.card_locker; import android.content.Context; -import android.content.res.Resources; import android.database.Cursor; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.util.Log; -import android.util.SparseBooleanArray; -import android.util.TypedValue; -import android.view.HapticFeedbackConstants; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.TextView; -import com.google.android.material.card.MaterialCardView; - -import java.math.BigDecimal; -import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.graphics.BlendModeColorFilterCompat; -import androidx.core.graphics.BlendModeCompat; -import androidx.recyclerview.widget.RecyclerView; - -import protect.card_locker.preferences.Settings; public class ManageGroupCursorAdapter extends LoyaltyCardCursorAdapter { private HashMap mIndexCardMap; private HashMap mInGroupOverlay; - private Group mGroup; - private DBHelper mDb; + private HashMap mIsLoyaltyCardInGroupCache; + private HashMap> mGetGroupCache; + final private Group mGroup; + final private DBHelper mDb; public ManageGroupCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener, Group group){ super(inputContext, inputCursor, inputListener); mGroup = new Group(group._id, group.order); - mInGroupOverlay = new HashMap(); + mInGroupOverlay = new HashMap<>(); mDb = new DBHelper(inputContext); } @Override public void swapCursor(Cursor inputCursor) { super.swapCursor(inputCursor); - mIndexCardMap = new HashMap(); + mIndexCardMap = new HashMap<>(); + mIsLoyaltyCardInGroupCache = new HashMap<>(); + mGetGroupCache = new HashMap<>(); } @Override @@ -67,21 +41,37 @@ public class ManageGroupCursorAdapter extends LoyaltyCardCursorAdapter { super.onBindViewHolder(inputHolder, inputCursor); } - private boolean isLoyaltyCardInGroup(int cardId){ - List groups = mDb.getLoyaltyCardGroups(cardId); - Iterator groupItr = groups.listIterator(); - while(groupItr.hasNext()){ - if (groupItr.next().equals(mGroup)){ - return true; - } + private List getGroups(int cardId){ + List cache = mGetGroupCache.get(cardId); + if(cache != null){ + return cache; } + List groups = mDb.getLoyaltyCardGroups(cardId); + mGetGroupCache.put(cardId, groups); + return groups; + } + + private boolean isLoyaltyCardInGroup(int cardId){ + Boolean cache = mIsLoyaltyCardInGroupCache.get(cardId); + if(cache != null){ + return cache; + } + List groups = getGroups(cardId); + if (groups.contains(mGroup)){ + mIsLoyaltyCardInGroupCache.put(cardId, true); + return true; + } + mIsLoyaltyCardInGroupCache.put(cardId, false); return false; } @Override public void toggleSelection(int inputPosition){ super.toggleSelection(inputPosition); - int cardId = mIndexCardMap.get(inputPosition); + Integer cardId = mIndexCardMap.get(inputPosition); + if (cardId == null){ + throw(new RuntimeException("cardId should not be null here")); + } Boolean overlayValue = mInGroupOverlay.get(cardId); if (overlayValue == null){ mInGroupOverlay.put(cardId, !isLoyaltyCardInGroup(cardId)); @@ -94,11 +84,10 @@ public class ManageGroupCursorAdapter extends LoyaltyCardCursorAdapter { return mInGroupOverlay.size() > 0; } - public void commitToDatabase(Context context){ - // this is very inefficient but done to keep the size of DBHelper low + public void commitToDatabase(){ for(Map.Entry entry: mInGroupOverlay.entrySet()){ int cardId = entry.getKey(); - List groups = mDb.getLoyaltyCardGroups(cardId); + List groups = getGroups(cardId); if(entry.getValue()){ groups.add(mGroup); }else{ @@ -109,11 +98,18 @@ public class ManageGroupCursorAdapter extends LoyaltyCardCursorAdapter { } public void importInGroupState(HashMap cardIdInGroupMap) { - mInGroupOverlay = (HashMap) cardIdInGroupMap.clone(); + mInGroupOverlay = new HashMap<>(); + for (Map.Entry entry: cardIdInGroupMap.entrySet()){ + mInGroupOverlay.put(entry.getKey(), entry.getValue()); + } } public HashMap exportInGroupState(){ - return (HashMap)mInGroupOverlay.clone(); + HashMap ret = new HashMap<>(); + for (Map.Entry entry: mInGroupOverlay.entrySet()){ + ret.put(entry.getKey(), entry.getValue()); + } + return ret; } public int getCountFromCursor() { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 90a3d7c7b..6c88f4f91 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7,6 +7,7 @@ %d cards selected Click the + plus button to add a card, or import some from the ⋮ menu first. + Looks like you have not added any loyalty cards yet. They can be added to this group from here once you have some ^w^ Didn\'t find anything. Try changing your search. Name Note @@ -143,6 +144,7 @@ Manually enter card ID Select image from gallery Groups: %s + Editing Group: %s Expires: %s Expired: %s Balance: %s From cfc901855bb155a72c214af386724f239dfee0a2 Mon Sep 17 00:00:00 2001 From: Katharine Date: Mon, 1 Nov 2021 10:29:02 +0800 Subject: [PATCH 10/14] update help text in group edit activity --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6c88f4f91..3e5e9621c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7,7 +7,7 @@ %d cards selected Click the + plus button to add a card, or import some from the ⋮ menu first. - Looks like you have not added any loyalty cards yet. They can be added to this group from here once you have some ^w^ + You don\'t have any loyalty cards yet. Once you\'ve added some you can add them to the group here. Didn\'t find anything. Try changing your search. Name Note From 9e831924c6d3848c319da0bd8865c0e4f1b91143 Mon Sep 17 00:00:00 2001 From: Katharine Date: Mon, 1 Nov 2021 13:27:42 +0800 Subject: [PATCH 11/14] remove Parcel in Group, remove onResume/onPause in ManageGroupActivity and clean ups --- .../main/java/protect/card_locker/Group.java | 7 - .../card_locker/ManageGroupActivity.java | 148 ++++++------------ 2 files changed, 52 insertions(+), 103 deletions(-) diff --git a/app/src/main/java/protect/card_locker/Group.java b/app/src/main/java/protect/card_locker/Group.java index d1b6a0495..f39de2b50 100644 --- a/app/src/main/java/protect/card_locker/Group.java +++ b/app/src/main/java/protect/card_locker/Group.java @@ -1,8 +1,6 @@ package protect.card_locker; import android.database.Cursor; -import android.os.Parcel; -import android.os.Parcelable; import androidx.annotation.Nullable; @@ -16,11 +14,6 @@ public class Group this.order = order; } - protected Group(Parcel in){ - this._id = in.readString(); - this.order = in.readInt(); - } - public static Group toGroup(Cursor cursor) { String _id = cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbGroups.ID)); diff --git a/app/src/main/java/protect/card_locker/ManageGroupActivity.java b/app/src/main/java/protect/card_locker/ManageGroupActivity.java index eb7e3ca68..45df64b57 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupActivity.java +++ b/app/src/main/java/protect/card_locker/ManageGroupActivity.java @@ -35,9 +35,6 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana private TextView mHelpText; private EditText mGroupNameText; - private HashMap mAdapterState; - private String mCurrentGroupName; - private boolean mGroupNameNotInUse; @Override @@ -54,6 +51,36 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana mGroupNameText = findViewById(R.id.editTextGroupName); + mGroupNameText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + mGroupNameNotInUse = true; + mGroupNameText.setError(null); + String currentGroupName = mGroupNameText.getText().toString(); + if(currentGroupName.trim().length() == 0){ + mGroupNameText.setError(getResources().getText(R.string.group_name_is_empty)); + return; + } + if (!mGroup._id.equals(currentGroupName.trim())) { + Group group = mDB.getGroup(currentGroupName.trim()); + if (group != null) { + mGroupNameNotInUse = false; + mGroupNameText.setError(getResources().getText(R.string.group_name_already_in_use)); + } else { + mGroupNameNotInUse = true; + } + } + } + }); + Intent intent = getIntent(); String groupId = intent.getStringExtra("group"); if (groupId == null){ @@ -64,16 +91,15 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana if (mGroup == null){ throw(new IllegalArgumentException("cannot load group " + groupId + " from database")); } + mGroupNameText.setText(mGroup._id); + setTitle(getString(R.string.editGroup, mGroup._id)); mAdapter = new ManageGroupCursorAdapter(this, null, this, mGroup); mCardList.setAdapter(mAdapter); registerForContextMenu(mCardList); if (inputSavedInstanceState != null) { - ArrayList adapterState = inputSavedInstanceState.getIntegerArrayList("mAdapterState"); - if (adapterState != null) { - integerArrayToAdapterState(adapterState); - } - mCurrentGroupName = inputSavedInstanceState.getString("mCurrentGroupName"); + mAdapter.importInGroupState(integerArrayToAdapterState(inputSavedInstanceState.getIntegerArrayList("adapterState"))); + mGroupNameText.setText(inputSavedInstanceState.getString("currentGroupName")); } ActionBar actionBar = getSupportActionBar(); @@ -86,128 +112,58 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana saveButton.setOnClickListener(v -> { String currentGroupName = mGroupNameText.getText().toString(); if(!currentGroupName.trim().equals(mGroup._id)){ - if(!mGroupNameNotInUse) { - Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT); - toast.show(); + if(currentGroupName.trim().length() == 0){ + Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT).show(); return; } - if(currentGroupName.trim().length() == 0){ - Toast toast = Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT); - toast.show(); + if(!mGroupNameNotInUse) { + Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT).show(); return; } } mAdapter.commitToDatabase(); - Toast toast = Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT); if(!currentGroupName.trim().equals(mGroup._id)){ mDB.updateGroup(mGroup._id, currentGroupName.trim()); } - toast.show(); + Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT).show(); finish(); }); mHelpText.setText(getResources().getText(R.string.noGiftCardsGroup)); - } - - private void checkIfGroupNameIsInUse(){ - mGroupNameNotInUse = false; - String currentGroupName = mGroupNameText.getText().toString(); - if (!mGroup._id.equals(currentGroupName.trim())) { - Group group = mDB.getGroup(currentGroupName.trim()); - if (group != null) { - mGroupNameNotInUse = false; - mGroupNameText.setError(getResources().getText(R.string.group_name_already_in_use)); - } else { - mGroupNameNotInUse = true; - } - } - } - - @Override - protected void onResume() - { - super.onResume(); - - setTitle(getString(R.string.editGroup, mGroup._id)); - - if (mCurrentGroupName == null){ - mGroupNameText.setText(mGroup._id); - }else{ - mGroupNameText.setText(mCurrentGroupName); - checkIfGroupNameIsInUse(); - } - - mGroupNameText.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - @Override - public void afterTextChanged(Editable s) { - mGroupNameText.setError(null); - checkIfGroupNameIsInUse(); - } - }); - - if (mAdapterState != null){ - mAdapter.importInGroupState(mAdapterState); - } updateLoyaltyCardList(); } - private ArrayList adapterStateToIntegerArray(){ - ArrayList ret = new ArrayList<>(mAdapterState.size() * 2); - for (Map.Entry entry : mAdapterState.entrySet()) { + private ArrayList adapterStateToIntegerArray(HashMap adapterState){ + ArrayList ret = new ArrayList<>(adapterState.size() * 2); + for (Map.Entry entry : adapterState.entrySet()) { ret.add(entry.getKey()); ret.add(entry.getValue()?1:0); } return ret; } - private void integerArrayToAdapterState(ArrayList in) { - boolean isKey = true; - int cardId = 0; - mAdapterState = new HashMap<>(); - for (int value : in) { - if (isKey) { - cardId = value; - } else { - mAdapterState.put(cardId, value == 1); - } - isKey = !isKey; + private HashMap integerArrayToAdapterState(ArrayList in) { + HashMap ret = new HashMap<>(); + if (in.size() % 2 != 0){ + throw(new RuntimeException("failed restoring adapterState from integer array list")); } - if(!isKey){ - throw(new RuntimeException("failed restoring mAdapterState from integer array list")); + for(int i = 0;i < in.size(); i += 2){ + ret.put(in.get(i), in.get(i+1) == 1); } + return ret; } @Override protected void onSaveInstanceState (@NonNull Bundle outState){ super.onSaveInstanceState(outState); - if(mAdapterState != null){ - outState.putIntegerArrayList("mAdapterState", adapterStateToIntegerArray()); - } - if(mCurrentGroupName != null){ - outState.putString("mCurrentGroupName", mCurrentGroupName); - } - } - - @Override - protected void onPause(){ - super.onPause(); - - mAdapterState = mAdapter.exportInGroupState(); - mCurrentGroupName = mGroupNameText.getText().toString(); + outState.putIntegerArrayList("adapterState", adapterStateToIntegerArray(mAdapter.exportInGroupState())); + outState.putString("currentGroupName", mGroupNameText.getText().toString()); } private void updateLoyaltyCardList() { - mAdapter.swapCursor(mDB.getLoyaltyCardCursor("", null, DBHelper.LoyaltyCardOrder.Alpha, DBHelper.LoyaltyCardOrderDirection.Ascending)); + mAdapter.swapCursor(mDB.getLoyaltyCardCursor()); if(mAdapter.getCountFromCursor() == 0) { From c815c3908fdb227cc365a4b1c57bf6b3a51dee83 Mon Sep 17 00:00:00 2001 From: Katharine Date: Tue, 2 Nov 2021 08:14:30 +0800 Subject: [PATCH 12/14] added a comment explaining why setText is used there --- app/src/main/java/protect/card_locker/ManageGroupActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/protect/card_locker/ManageGroupActivity.java b/app/src/main/java/protect/card_locker/ManageGroupActivity.java index 45df64b57..6219dea30 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupActivity.java +++ b/app/src/main/java/protect/card_locker/ManageGroupActivity.java @@ -129,6 +129,7 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT).show(); finish(); }); + // this setText is here because content_main.xml is reused from main activity mHelpText.setText(getResources().getText(R.string.noGiftCardsGroup)); updateLoyaltyCardList(); } From 2cdeb1af9c92975fbea2aaa05833513c5773aac4 Mon Sep 17 00:00:00 2001 From: Katharine Date: Tue, 2 Nov 2021 08:20:24 +0800 Subject: [PATCH 13/14] use HashMap<> constructor to clone HashMap in LoyaltyCardCursorAdapter --- .../protect/card_locker/ManageGroupCursorAdapter.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java b/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java index d3d0b476c..96f62fdfa 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java +++ b/app/src/main/java/protect/card_locker/ManageGroupCursorAdapter.java @@ -98,18 +98,11 @@ public class ManageGroupCursorAdapter extends LoyaltyCardCursorAdapter { } public void importInGroupState(HashMap cardIdInGroupMap) { - mInGroupOverlay = new HashMap<>(); - for (Map.Entry entry: cardIdInGroupMap.entrySet()){ - mInGroupOverlay.put(entry.getKey(), entry.getValue()); - } + mInGroupOverlay = new HashMap<>(cardIdInGroupMap); } public HashMap exportInGroupState(){ - HashMap ret = new HashMap<>(); - for (Map.Entry entry: mInGroupOverlay.entrySet()){ - ret.put(entry.getKey(), entry.getValue()); - } - return ret; + return new HashMap<>(mInGroupOverlay); } public int getCountFromCursor() { From 88a91de63b8bc57c83939fe4d9a26f0f4b75ff84 Mon Sep 17 00:00:00 2001 From: Katharine Date: Wed, 3 Nov 2021 10:12:09 +0800 Subject: [PATCH 14/14] removed commented code, input check for group add, input check and minor revisions --- .../card_locker/ManageGroupActivity.java | 30 +++++++++-------- .../card_locker/ManageGroupsActivity.java | 33 +++++++------------ 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/protect/card_locker/ManageGroupActivity.java b/app/src/main/java/protect/card_locker/ManageGroupActivity.java index 6219dea30..ec3c2ccb8 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupActivity.java +++ b/app/src/main/java/protect/card_locker/ManageGroupActivity.java @@ -30,6 +30,9 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana private final DBHelper mDB = new DBHelper(this); private ManageGroupCursorAdapter mAdapter; + private final String SAVE_INSTANCE_ADAPTER_STATE = "adapterState"; + private final String SAVE_INSTANCE_CURRENT_GROUP_NAME = "currentGroupName"; + protected Group mGroup = null; private RecyclerView mCardList; private TextView mHelpText; @@ -64,14 +67,13 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana public void afterTextChanged(Editable s) { mGroupNameNotInUse = true; mGroupNameText.setError(null); - String currentGroupName = mGroupNameText.getText().toString(); - if(currentGroupName.trim().length() == 0){ + String currentGroupName = mGroupNameText.getText().toString().trim(); + if(currentGroupName.length() == 0){ mGroupNameText.setError(getResources().getText(R.string.group_name_is_empty)); return; } - if (!mGroup._id.equals(currentGroupName.trim())) { - Group group = mDB.getGroup(currentGroupName.trim()); - if (group != null) { + if (!mGroup._id.equals(currentGroupName)) { + if (mDB.getGroup(currentGroupName) != null) { mGroupNameNotInUse = false; mGroupNameText.setError(getResources().getText(R.string.group_name_already_in_use)); } else { @@ -98,8 +100,8 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana registerForContextMenu(mCardList); if (inputSavedInstanceState != null) { - mAdapter.importInGroupState(integerArrayToAdapterState(inputSavedInstanceState.getIntegerArrayList("adapterState"))); - mGroupNameText.setText(inputSavedInstanceState.getString("currentGroupName")); + mAdapter.importInGroupState(integerArrayToAdapterState(inputSavedInstanceState.getIntegerArrayList(SAVE_INSTANCE_ADAPTER_STATE))); + mGroupNameText.setText(inputSavedInstanceState.getString(SAVE_INSTANCE_CURRENT_GROUP_NAME)); } ActionBar actionBar = getSupportActionBar(); @@ -110,9 +112,9 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana actionBar.setDisplayShowHomeEnabled(true); saveButton.setOnClickListener(v -> { - String currentGroupName = mGroupNameText.getText().toString(); - if(!currentGroupName.trim().equals(mGroup._id)){ - if(currentGroupName.trim().length() == 0){ + String currentGroupName = mGroupNameText.getText().toString().trim(); + if(!currentGroupName.equals(mGroup._id)){ + if(currentGroupName.length() == 0){ Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT).show(); return; } @@ -123,8 +125,8 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana } mAdapter.commitToDatabase(); - if(!currentGroupName.trim().equals(mGroup._id)){ - mDB.updateGroup(mGroup._id, currentGroupName.trim()); + if(!currentGroupName.equals(mGroup._id)){ + mDB.updateGroup(mGroup._id, currentGroupName); } Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT).show(); finish(); @@ -159,8 +161,8 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana protected void onSaveInstanceState (@NonNull Bundle outState){ super.onSaveInstanceState(outState); - outState.putIntegerArrayList("adapterState", adapterStateToIntegerArray(mAdapter.exportInGroupState())); - outState.putString("currentGroupName", mGroupNameText.getText().toString()); + outState.putIntegerArrayList(SAVE_INSTANCE_ADAPTER_STATE, adapterStateToIntegerArray(mAdapter.exportInGroupState())); + outState.putString(SAVE_INSTANCE_CURRENT_GROUP_NAME, mGroupNameText.getText().toString()); } private void updateLoyaltyCardList() { diff --git a/app/src/main/java/protect/card_locker/ManageGroupsActivity.java b/app/src/main/java/protect/card_locker/ManageGroupsActivity.java index 60127bd24..116dc7a1c 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupsActivity.java +++ b/app/src/main/java/protect/card_locker/ManageGroupsActivity.java @@ -10,6 +10,7 @@ import android.view.View; import android.view.WindowManager; import android.widget.EditText; import android.widget.TextView; +import android.widget.Toast; import com.google.android.material.floatingactionbutton.FloatingActionButton; @@ -118,7 +119,16 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro builder.setView(input); builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> { - mDb.insertGroup(input.getText().toString()); + String inputString = input.getText().toString().trim(); + if(inputString.length() == 0){ + Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT).show(); + return; + } + if (mDb.getGroup(inputString) != null) { + Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT).show(); + return; + } + mDb.insertGroup(inputString); updateGroupList(); }); builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel()); @@ -180,27 +190,6 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro Intent intent = new Intent(this, ManageGroupActivity.class); intent.putExtra("group", getGroupName(view)); startActivity(intent); - /* - final String groupName = c; - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.enter_group_name); - final EditText input = new EditText(this); - input.setInputType(InputType.TYPE_CLASS_TEXT); - input.setText(groupName); - builder.setView(input); - - builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> { - String newGroupName = input.getText().toString(); - mDb.updateGroup(groupName, newGroupName); - updateGroupList(); - }); - builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel()); - AlertDialog dialog = builder.create(); - dialog.show(); - dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); - input.requestFocus(); - */ } @Override