Support selecting exactly which details to view in main view

This commit is contained in:
Sylvia van Os
2023-06-04 01:38:59 +02:00
parent 7a4c9ce84f
commit 2a6fe92b1b
13 changed files with 144 additions and 63 deletions

View File

@@ -1,5 +1,9 @@
# Changelog
## Unreleased - 124
- Support selecting exactly which details to view in card overview
## v2.23.3 - 123
- Minor UI improvements

View File

@@ -81,7 +81,7 @@ public class CardShortcutConfigure extends CatimaAppCompatActivity implements Lo
@Override
public boolean onCreateOptionsMenu(Menu inputMenu) {
getMenuInflater().inflate(R.menu.card_details_menu, inputMenu);
Utils.updateMenuCardDetailsButtonState(inputMenu.findItem(R.id.action_unfold), mAdapter.showingDetails());
return super.onCreateOptionsMenu(inputMenu);
}
@@ -89,8 +89,8 @@ public class CardShortcutConfigure extends CatimaAppCompatActivity implements Lo
public boolean onOptionsItemSelected(MenuItem inputItem) {
int id = inputItem.getItemId();
if (id == R.id.action_unfold) {
mAdapter.showDetails(!mAdapter.showingDetails());
if (id == R.id.action_shown_details) {
mAdapter.showSelectDetailDisplayDialog();
invalidateOptionsMenu();
return true;

View File

@@ -4,7 +4,6 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.SparseBooleanArray;
@@ -18,12 +17,14 @@ import android.widget.TextView;
import com.google.android.material.card.MaterialCardView;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.ArrayList;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.BlendModeColorFilterCompat;
@@ -31,7 +32,6 @@ import androidx.core.graphics.BlendModeCompat;
import androidx.recyclerview.widget.RecyclerView;
import protect.card_locker.databinding.LoyaltyCardLayoutBinding;
import protect.card_locker.preferences.Settings;
public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder> {
private int mCurrentSelectedIndex = -1;
@@ -41,7 +41,10 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
protected SparseBooleanArray mSelectedItems;
protected SparseBooleanArray mAnimationItemsIndex;
private boolean mReverseAllAnimations = false;
private boolean mShowDetails;
private boolean mAlwaysShowName;
private boolean mShowNote;
private boolean mShowBalance;
private boolean mShowValidity;
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener) {
super(inputCursor, DBHelper.LoyaltyCardDbIds.ID);
@@ -58,29 +61,104 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
swapCursor(inputCursor);
}
private void saveDetailState(int stateId, boolean value) {
SharedPreferences cardDetailsPref = mContext.getSharedPreferences(
mContext.getString(R.string.sharedpreference_card_details),
Context.MODE_PRIVATE);
SharedPreferences.Editor cardDetailsPrefEditor = cardDetailsPref.edit();
cardDetailsPrefEditor.putBoolean(mContext.getString(stateId), value);
cardDetailsPrefEditor.apply();
}
public void refreshState() {
// Retrieve user details preference
SharedPreferences cardDetailsPref = mContext.getSharedPreferences(
mContext.getString(R.string.sharedpreference_card_details),
Context.MODE_PRIVATE);
mShowDetails = cardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_show), true);
mAlwaysShowName = cardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_always_show_name), false);
mShowNote = cardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_show_note), true);
mShowBalance = cardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_show_balance), true);
mShowValidity = cardDetailsPref.getBoolean(mContext.getString(R.string.sharedpreference_card_details_show_validity), true);
}
public void showDetails(boolean show) {
mShowDetails = show;
public void alwaysShowName(boolean show) {
mAlwaysShowName = show;
notifyDataSetChanged();
// Store in Shared Preference to restore next adapter launch
SharedPreferences cardDetailsPref = mContext.getSharedPreferences(
mContext.getString(R.string.sharedpreference_card_details),
Context.MODE_PRIVATE);
SharedPreferences.Editor cardDetailsPrefEditor = cardDetailsPref.edit();
cardDetailsPrefEditor.putBoolean(mContext.getString(R.string.sharedpreference_card_details_show), show);
cardDetailsPrefEditor.apply();
saveDetailState(R.string.sharedpreference_card_details_always_show_name, show);
}
public boolean showingDetails() {
return mShowDetails;
public boolean alwaysShowingName() {
return mAlwaysShowName;
}
public void showNote(boolean show) {
mShowNote = show;
notifyDataSetChanged();
saveDetailState(R.string.sharedpreference_card_details_show_note, show);
}
public boolean showingNote() {
return mShowNote;
}
public void showBalance(boolean show) {
mShowBalance = show;
notifyDataSetChanged();
saveDetailState(R.string.sharedpreference_card_details_show_balance, show);
}
public boolean showingBalance() {
return mShowBalance;
}
public void showValidity(boolean show) {
mShowValidity = show;
notifyDataSetChanged();
saveDetailState(R.string.sharedpreference_card_details_show_validity, show);
}
public boolean showingValidity() {
return mShowValidity;
}
public void showSelectDetailDisplayDialog() {
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(mContext);
builder.setTitle(R.string.action_show_details);
builder.setMultiChoiceItems(
new String[]{
mContext.getString(R.string.always_show_name),
mContext.getString(R.string.show_note),
mContext.getString(R.string.show_balance),
mContext.getString(R.string.show_validity)
},
new boolean[]{
alwaysShowingName(),
showingNote(),
showingBalance(),
showingValidity()
},
(dialogInterface, i, b) -> {
if (i == 0) {
alwaysShowName(b);
} else if (i == 1) {
showNote(b);
} else if (i == 2) {
showBalance(b);
} else if (i == 3) {
showValidity(b);
} else {
throw new IndexOutOfBoundsException("No such index exists in LoyaltyCardCursorAdapter show details view");
}
}
);
builder.setPositiveButton(R.string.ok, (dialog, i) -> dialog.dismiss());
AlertDialog dialog = builder.create();
dialog.show();
}
@NonNull
@@ -105,32 +183,32 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(inputCursor);
if (mShowDetails && !loyaltyCard.note.isEmpty()) {
if (mShowNote && !loyaltyCard.note.isEmpty()) {
inputHolder.setNoteField(loyaltyCard.note);
} else {
inputHolder.setNoteField(null);
}
if (mShowDetails && !loyaltyCard.balance.equals(new BigDecimal("0"))) {
if (mShowBalance && !loyaltyCard.balance.equals(new BigDecimal("0"))) {
inputHolder.setExtraField(inputHolder.mBalanceField, Utils.formatBalance(mContext, loyaltyCard.balance, loyaltyCard.balanceType), null);
} else {
inputHolder.setExtraField(inputHolder.mBalanceField, null, null);
}
if (mShowDetails && loyaltyCard.validFrom != null) {
if (mShowValidity && loyaltyCard.validFrom != null) {
inputHolder.setExtraField(inputHolder.mValidFromField, DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.validFrom), Utils.isNotYetValid(loyaltyCard.validFrom) ? Color.RED : null);
} else {
inputHolder.setExtraField(inputHolder.mValidFromField, null, null);
}
if (mShowDetails && loyaltyCard.expiry != null) {
if (mShowValidity && loyaltyCard.expiry != null) {
inputHolder.setExtraField(inputHolder.mExpiryField, DateFormat.getDateInstance(DateFormat.LONG).format(loyaltyCard.expiry), Utils.hasExpired(loyaltyCard.expiry) ? Color.RED : null);
} else {
inputHolder.setExtraField(inputHolder.mExpiryField, null, null);
}
inputHolder.mCardIcon.setContentDescription(loyaltyCard.store);
Utils.setIconOrTextWithBackground(mContext, loyaltyCard, inputHolder.mCardIcon, inputHolder.mCardText);
Utils.setIconOrTextWithBackground(mContext, loyaltyCard, inputHolder.mCardIcon, inputHolder.mCardText, mAlwaysShowName);
inputHolder.setIconBackgroundColor(loyaltyCard.headerColor != null ? loyaltyCard.headerColor : androidx.appcompat.R.attr.colorPrimary);
inputHolder.toggleCardStateIcon(loyaltyCard.starStatus != 0, loyaltyCard.archiveStatus != 0, itemSelected(inputCursor.getPosition()));

View File

@@ -630,7 +630,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
editButtonIcon.setTint(Utils.needsDarkForeground(complementaryColor) ? Color.BLACK : Color.WHITE);
binding.fabEdit.setImageDrawable(editButtonIcon);
Utils.setIconOrTextWithBackground(this, loyaltyCard, binding.iconImage, binding.iconText);
Utils.setIconOrTextWithBackground(this, loyaltyCard, binding.iconImage, binding.iconText, false);
// If the background is very bright, we should use dark icons
backgroundNeedsDarkIcons = Utils.needsDarkForeground(backgroundHeaderColor);

View File

@@ -15,18 +15,15 @@ import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.CheckBox;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.SearchView;
@@ -435,7 +432,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
private void displayCardSetupOptions(Menu menu, boolean shouldShow) {
for (int id : new int[]{R.id.action_search, R.id.action_unfold, R.id.action_sort}) {
for (int id : new int[]{R.id.action_search, R.id.action_shown_details, R.id.action_sort}) {
menu.findItem(id).setVisible(shouldShow);
}
}
@@ -600,7 +597,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
getMenuInflater().inflate(R.menu.archive_menu, inputMenu);
}
Utils.updateMenuCardDetailsButtonState(inputMenu.findItem(R.id.action_unfold), mAdapter.showingDetails());
displayCardSetupOptions(inputMenu, mLoyaltyCardCount > 0);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
@@ -653,8 +649,8 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
onBackPressed();
}
if (id == R.id.action_unfold) {
mAdapter.showDetails(!mAdapter.showingDetails());
if (id == R.id.action_shown_details) {
mAdapter.showSelectDetailDisplayDialog();
invalidateOptionsMenu();
return true;

View File

@@ -21,7 +21,6 @@ import java.util.HashMap;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.RecyclerView;
@@ -160,7 +159,7 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana
@Override
public boolean onCreateOptionsMenu(Menu inputMenu) {
getMenuInflater().inflate(R.menu.card_details_menu, inputMenu);
Utils.updateMenuCardDetailsButtonState(inputMenu.findItem(R.id.action_unfold), mAdapter.showingDetails());
return super.onCreateOptionsMenu(inputMenu);
}
@@ -168,8 +167,8 @@ public class ManageGroupActivity extends CatimaAppCompatActivity implements Mana
public boolean onOptionsItemSelected(MenuItem inputItem) {
int id = inputItem.getItemId();
if (id == R.id.action_unfold) {
mAdapter.showDetails(!mAdapter.showingDetails());
if (id == R.id.action_shown_details) {
mAdapter.showSelectDetailDisplayDialog();
invalidateOptionsMenu();
return true;

View File

@@ -560,16 +560,6 @@ public class Utils {
activity.findViewById(android.R.id.content).setBackgroundColor(typedValue.data);
}
public static void updateMenuCardDetailsButtonState(MenuItem item, boolean currentlyExpanded) {
if (currentlyExpanded) {
item.setIcon(R.drawable.ic_baseline_unfold_less_24);
item.setTitle(R.string.action_hide_details);
} else {
item.setIcon(R.drawable.ic_baseline_unfold_more_24);
item.setTitle(R.string.action_show_details);
}
}
public static int getHeaderColorFromImage(Bitmap image, int fallback) {
if (image == null) {
return fallback;
@@ -603,23 +593,25 @@ public class Utils {
return result.toString();
}
public static void setIconOrTextWithBackground(Context context, LoyaltyCard loyaltyCard, ImageView backgroundOrIcon, TextView textWhenNoImage) {
public static void setIconOrTextWithBackground(Context context, LoyaltyCard loyaltyCard, ImageView backgroundOrIcon, TextView textWhenNoImage, boolean alwaysShowTextView) {
Bitmap icon = Utils.retrieveCardImage(context, loyaltyCard.id, ImageLocationType.icon);
int headerColor = loyaltyCard.headerColor != null ? loyaltyCard.headerColor : LetterBitmap.getDefaultColor(context, loyaltyCard.store);
if (icon != null) {
Log.d("onResume", "setting icon image");
textWhenNoImage.setVisibility(View.GONE);
backgroundOrIcon.setImageBitmap(icon);
backgroundOrIcon.setBackgroundColor(Color.TRANSPARENT);
} else {
textWhenNoImage.setVisibility(View.VISIBLE);
int headerColor = loyaltyCard.headerColor != null ? loyaltyCard.headerColor : LetterBitmap.getDefaultColor(context, loyaltyCard.store);
backgroundOrIcon.setImageBitmap(null);
backgroundOrIcon.setBackgroundColor(headerColor);
}
if (icon == null || alwaysShowTextView) {
textWhenNoImage.setVisibility(View.VISIBLE);
textWhenNoImage.setText(loyaltyCard.store);
textWhenNoImage.setTextColor(Utils.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE);
} else {
textWhenNoImage.setVisibility(View.GONE);
}
}

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="?attr/colorControlNormal"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>

View File

@@ -10,9 +10,9 @@
app:showAsAction="always|collapseActionView"
android:visible="false"/>
<item
android:id="@+id/action_unfold"
android:title="@string/action_hide_details"
android:icon="@drawable/ic_baseline_unfold_less_24"
android:id="@+id/action_shown_details"
android:title="@string/action_show_details"
android:icon="@drawable/baseline_visibility_24"
app:showAsAction="always"
android:visible="false"/>
<item

View File

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

View File

@@ -10,9 +10,9 @@
app:showAsAction="always|collapseActionView"
android:visible="false"/>
<item
android:id="@+id/action_unfold"
android:title="@string/action_hide_details"
android:icon="@drawable/ic_baseline_unfold_less_24"
android:id="@+id/action_shown_details"
android:title="@string/action_show_details"
android:icon="@drawable/baseline_visibility_24"
app:showAsAction="always"
android:visible="false"/>
<item

View File

@@ -123,7 +123,6 @@
<string name="sharedpreference_sort_order" translatable="false">sharedpreference_sort_order</string>
<string name="sharedpreference_sort_direction" translatable="false">sharedpreference_sort_direction</string>
<string name="sharedpreference_card_details" translatable="false">sharedpreference_card_details</string>
<string name="sharedpreference_card_details_show" translatable="false">sharedpreference_card_details_show</string>
<string name="intent_import_card_from_url_share_text">I want to share a card with you</string>
<string name="intent_import_card_from_url_host_catima_app" translatable="false">catima.app</string>
<string name="intent_import_card_from_url_path_prefix_catima_app" translatable="false">/share</string>
@@ -314,4 +313,12 @@
<string name="setBarcodeHeight">Set barcode height</string>
<string name="donate">Donate</string>
<string name="icon_header_click_text">Long press to edit icon</string>
<string name="always_show_name">Always show name</string>
<string name="show_note">Show note</string>
<string name="show_balance">Show balance</string>
<string name="show_validity">Show validity</string>
<string name="sharedpreference_card_details_always_show_name" translatable="false">sharedpreference_card_details_always_show_name</string>
<string name="sharedpreference_card_details_show_note" translatable="false">sharedpreference_card_details_show_note</string>
<string name="sharedpreference_card_details_show_balance" translatable="false">sharedpreference_card_details_show_balance</string>
<string name="sharedpreference_card_details_show_validity" translatable="false">sharedpreference_card_details_show_validity</string>
</resources>

View File

@@ -62,7 +62,7 @@ public class MainActivityTest {
assertEquals(menu.size(), 8);
assertEquals("Search", menu.findItem(R.id.action_search).getTitle().toString());
assertEquals("Sort", menu.findItem(R.id.action_sort).getTitle().toString());
assertEquals("Hide details", menu.findItem(R.id.action_unfold).getTitle().toString());
assertEquals("Show details", menu.findItem(R.id.action_shown_details).getTitle().toString());
assertEquals("Groups", menu.findItem(R.id.action_manage_groups).getTitle().toString());
assertEquals("Archive", menu.findItem(R.id.action_archived).getTitle().toString());
assertEquals("Import/Export", menu.findItem(R.id.action_import_export).getTitle().toString());