Redesign of home screen and view UI (#1296)

* Redesign of home screen and view UI

* Update screenshots and CHANGELOG

* Make spotbugs happy

* Fix double store name announcement
This commit is contained in:
Sylvia van Os
2023-05-17 21:15:56 +02:00
committed by GitHub
parent ebc2bfcbbb
commit b48de921fc
28 changed files with 544 additions and 927 deletions

View File

@@ -1,5 +1,9 @@
# Changelog
## Unreleased - 120
- Complete redesign of main and loyalty card view screens
## v2.22.1 - 119
- Use Material You colours on more devices (Google library update)

View File

@@ -0,0 +1,5 @@
package protect.card_locker;
public interface BarcodeImageWriterResultCallback {
void onBarcodeImageWriterResult(boolean success);
}

View File

@@ -42,12 +42,12 @@ public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
private final int imageHeight;
private final int imageWidth;
private final boolean showFallback;
private final Runnable callback;
private final BarcodeImageWriterResultCallback callback;
BarcodeImageWriterTask(
Context context, ImageView imageView, String cardIdString,
CatimaBarcode barcodeFormat, TextView textView,
boolean showFallback, Runnable callback, boolean roundCornerPadding
boolean showFallback, BarcodeImageWriterResultCallback callback, boolean roundCornerPadding
) {
mContext = context;
@@ -282,7 +282,7 @@ public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
}
if (callback != null) {
callback.run();
callback.onBarcodeImageWriterResult(isSuccesful);
}
}

View File

@@ -17,7 +17,6 @@ import protect.card_locker.databinding.GroupLayoutBinding;
import protect.card_locker.preferences.Settings;
public class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.GroupListItemViewHolder> {
Settings mSettings;
public final Context mContext;
private final GroupAdapterListener mListener;
SQLiteDatabase mDatabase;
@@ -25,7 +24,6 @@ public class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.Gro
public GroupCursorAdapter(Context inputContext, Cursor inputCursor, GroupAdapterListener inputListener) {
super(inputCursor, DBHelper.LoyaltyCardDbGroups.ORDER);
setHasStableIds(true);
mSettings = new Settings(inputContext);
mContext = inputContext;
mListener = inputListener;
mDatabase = new DBHelper(inputContext).getReadableDatabase();
@@ -63,8 +61,6 @@ public class GroupCursorAdapter extends BaseCursorAdapter<GroupCursorAdapter.Gro
}
inputHolder.mCardCount.setText(cardCountText);
inputHolder.mName.setTextSize(mSettings.getFontSizeMax(mSettings.getMediumFont()));
inputHolder.mCardCount.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
applyClickEvents(inputHolder);
}

View File

@@ -35,7 +35,6 @@ import protect.card_locker.preferences.Settings;
public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCursorAdapter.LoyaltyCardListItemViewHolder> {
private int mCurrentSelectedIndex = -1;
Settings mSettings;
boolean mDarkModeEnabled;
public final Context mContext;
private final CardAdapterListener mListener;
@@ -47,7 +46,6 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener) {
super(inputCursor, DBHelper.LoyaltyCardDbIds.ID);
setHasStableIds(true);
mSettings = new Settings(inputContext);
mContext = inputContext;
mListener = inputListener;
mSelectedItems = new SparseBooleanArray();
@@ -107,7 +105,6 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(inputCursor);
inputHolder.setStoreField(loyaltyCard.store);
if (mShowDetails && !loyaltyCard.note.isEmpty()) {
inputHolder.setNoteField(loyaltyCard.note);
} else {
@@ -132,15 +129,8 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
inputHolder.setExtraField(inputHolder.mExpiryField, null, null);
}
setHeaderHeight(inputHolder, mShowDetails);
Bitmap cardIcon = Utils.retrieveCardImage(mContext, loyaltyCard.id, ImageLocationType.icon);
if (cardIcon != null) {
inputHolder.mCardIcon.setImageBitmap(cardIcon);
inputHolder.mCardIcon.setScaleType(ImageView.ScaleType.CENTER_CROP);
} else {
inputHolder.mCardIcon.setImageBitmap(Utils.generateIcon(mContext, loyaltyCard.store, loyaltyCard.headerColor).getLetterTile());
inputHolder.mCardIcon.setScaleType(ImageView.ScaleType.FIT_CENTER);
}
inputHolder.mCardIcon.setContentDescription(loyaltyCard.store);
Utils.setIconOrTextWithBackground(mContext, loyaltyCard, inputHolder.mCardIcon, inputHolder.mCardText);
inputHolder.setIconBackgroundColor(loyaltyCard.headerColor != null ? loyaltyCard.headerColor : androidx.appcompat.R.attr.colorPrimary);
inputHolder.toggleCardStateIcon(loyaltyCard.starStatus != 0, loyaltyCard.archiveStatus != 0, itemSelected(inputCursor.getPosition()));
@@ -153,19 +143,6 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
inputHolder.mRow.requestLayout();
}
private void setHeaderHeight(LoyaltyCardListItemViewHolder inputHolder, boolean expanded) {
int iconHeight;
if (expanded) {
iconHeight = ViewGroup.LayoutParams.MATCH_PARENT;
} else {
iconHeight = (int) mContext.getResources().getDimension(R.dimen.cardThumbnailSize);
}
inputHolder.mIconLayout.getLayoutParams().height = expanded ? 0 : iconHeight;
inputHolder.mCardIcon.getLayoutParams().height = iconHeight;
inputHolder.mTickIcon.getLayoutParams().height = iconHeight;
}
private void applyClickEvents(LoyaltyCardListItemViewHolder inputHolder, final int inputPosition) {
inputHolder.mRow.setOnClickListener(inputView -> mListener.onRowClicked(inputPosition));
@@ -241,28 +218,25 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
public class LoyaltyCardListItemViewHolder extends RecyclerView.ViewHolder {
public TextView mStoreField, mNoteField, mBalanceField, mValidFromField, mExpiryField;
public TextView mCardText, mNoteField, mBalanceField, mValidFromField, mExpiryField;
public ImageView mCardIcon, mStarBackground, mStarBorder, mTickIcon, mArchivedBackground;
public MaterialCardView mRow, mIconLayout;
public MaterialCardView mRow;
public ConstraintLayout mStar, mArchived;
public View mDivider;
private int mIconBackgroundColor;
protected LoyaltyCardListItemViewHolder(LoyaltyCardLayoutBinding loyaltyCardLayoutBinding, CardAdapterListener inputListener) {
super(loyaltyCardLayoutBinding.getRoot());
View inputView = loyaltyCardLayoutBinding.getRoot();
mRow = loyaltyCardLayoutBinding.row;
mDivider = loyaltyCardLayoutBinding.infoDivider;
mStoreField = loyaltyCardLayoutBinding.store;
mNoteField = loyaltyCardLayoutBinding.note;
mBalanceField = loyaltyCardLayoutBinding.balance;
mValidFromField = loyaltyCardLayoutBinding.validFrom;
mExpiryField = loyaltyCardLayoutBinding.expiry;
mIconLayout = loyaltyCardLayoutBinding.iconLayout;
mCardIcon = loyaltyCardLayoutBinding.thumbnail;
mCardText = loyaltyCardLayoutBinding.thumbnailText;
mStar = loyaltyCardLayoutBinding.star;
mStarBackground = loyaltyCardLayoutBinding.starBackground;
mStarBorder = loyaltyCardLayoutBinding.starBorder;
@@ -285,20 +259,15 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
return;
}
int size = mSettings.getFontSizeMax(mSettings.getSmallFont());
field.setVisibility(View.VISIBLE);
field.setText(text);
field.setTextSize(size);
field.setTextColor(color != null ? color : MaterialColors.getColor(mContext, com.google.android.material.R.attr.colorSecondary, ContextCompat.getColor(mContext, mDarkModeEnabled ? R.color.md_theme_dark_secondary : R.color.md_theme_light_secondary)));
int drawableSize = dpToPx((size * 24) / 14, mContext);
mDivider.setVisibility(View.VISIBLE);
field.setVisibility(View.VISIBLE);
Drawable icon = field.getCompoundDrawables()[0];
if (icon != null) {
icon.mutate();
icon.setBounds(0, 0, drawableSize, drawableSize);
field.setCompoundDrawablesRelative(icon, null, null, null);
if (color != null) {
@@ -311,19 +280,12 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
field.requestLayout();
}
public void setStoreField(String text) {
mStoreField.setText(text);
mStoreField.setTextSize(mSettings.getFontSizeMax(mSettings.getMediumFont()));
mStoreField.requestLayout();
}
public void setNoteField(String text) {
if (text == null) {
mNoteField.setVisibility(View.GONE);
} else {
mNoteField.setVisibility(View.VISIBLE);
mNoteField.setText(text);
mNoteField.setTextSize(mSettings.getFontSizeMax(mSettings.getSmallFont()));
}
mNoteField.requestLayout();
}

View File

@@ -83,7 +83,7 @@ import protect.card_locker.async.TaskHandler;
import protect.card_locker.databinding.LayoutChipChoiceBinding;
import protect.card_locker.databinding.LoyaltyCardEditActivityBinding;
public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements BarcodeImageWriterResultCallback {
private LoyaltyCardEditActivityBinding binding;
private static final String TAG = "Catima";
@@ -169,8 +169,6 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
AlertDialog confirmExitDialog = null;
boolean validBalance = true;
Runnable barcodeImageGenerationFinishedCallback;
HashMap<String, Currency> currencies = new HashMap<>();
LoyaltyCard tempLoyaltyCard;
@@ -348,13 +346,6 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
enterButton = binding.enterButton;
barcodeImageGenerationFinishedCallback = () -> {
if (!(boolean) barcodeImage.getTag()) {
barcodeImageLayout.setVisibility(View.GONE);
Toast.makeText(LoyaltyCardEditActivity.this, getString(R.string.wrongValueForBarcodeType), Toast.LENGTH_LONG).show();
}
};
storeFieldEdit.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
@@ -1150,6 +1141,14 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
}
}
@Override
public void onBarcodeImageWriterResult(boolean success) {
if (!success) {
barcodeImageLayout.setVisibility(View.GONE);
Toast.makeText(LoyaltyCardEditActivity.this, getString(R.string.wrongValueForBarcodeType), Toast.LENGTH_LONG).show();
}
}
class EditCardIdAndBarcode implements View.OnClickListener {
@Override
public void onClick(View v) {
@@ -1547,13 +1546,13 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity {
barcodeImage.getViewTreeObserver().removeOnGlobalLayoutListener(this);
Log.d(TAG, "ImageView size now known");
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, barcodeImageGenerationFinishedCallback, true);
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, LoyaltyCardEditActivity.this, true);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
});
} else {
Log.d(TAG, "ImageView size known known, creating barcode");
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, barcodeImageGenerationFinishedCallback, true);
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(getApplicationContext(), barcodeImage, cardIdString, barcodeFormat, null, false, this, true);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
}

View File

@@ -9,8 +9,6 @@ import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
@@ -23,13 +21,10 @@ import android.text.style.ForegroundColorSpan;
import android.text.util.Linkify;
import android.util.Log;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowInsets;
@@ -47,23 +42,17 @@ import androidx.annotation.StringRes;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Guideline;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.content.FileProvider;
import androidx.core.graphics.BlendModeColorFilterCompat;
import androidx.core.graphics.BlendModeCompat;
import androidx.core.graphics.ColorUtils;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.view.WindowInsetsControllerCompat;
import androidx.core.view.ViewCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.widget.TextViewCompat;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.bottomappbar.BottomAppBar;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.textfield.TextInputEditText;
import java.io.File;
@@ -82,31 +71,10 @@ import protect.card_locker.async.TaskHandler;
import protect.card_locker.databinding.LoyaltyCardViewLayoutBinding;
import protect.card_locker.preferences.Settings;
public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements GestureDetector.OnGestureListener {
public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements BarcodeImageWriterResultCallback {
private LoyaltyCardViewLayoutBinding binding;
private static final String TAG = "Catima";
private GestureDetector mGestureDetector;
CoordinatorLayout coordinatorLayout;
ConstraintLayout mainLayout;
TextView cardIdFieldView;
BottomAppBar bottomAppBar;
ImageButton bottomAppBarInfoButton;
ImageButton bottomAppBarPreviousButton;
ImageButton bottomAppBarNextButton;
ImageButton bottomAppBarUpdateBalanceButton;
AppCompatTextView storeName;
ImageButton maximizeButton;
ImageView mainImage;
LinearLayout dotIndicator;
ImageButton minimizeButton;
View collapsingToolbarLayout;
AppBarLayout appBarLayout;
ImageView iconImage;
Toolbar portraitToolbar;
Toolbar landscapeToolbar;
int loyaltyCardId;
ArrayList<Integer> cardList;
@@ -121,56 +89,36 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
String barcodeIdString;
CatimaBarcode format;
FloatingActionButton editButton;
Guideline centerGuideline;
SeekBar barcodeScaler;
Bitmap frontImageBitmap;
Bitmap backImageBitmap;
boolean starred;
boolean backgroundNeedsDarkIcons;
boolean isFullscreen = false;
ImageView barcodeRenderTarget;
int mainImageIndex = 0;
List<ImageType> imageTypes;
private ImageView[] dots;
boolean isBarcodeSupported = true;
static final String STATE_IMAGEINDEX = "imageIndex";
static final String STATE_FULLSCREEN = "isFullscreen";
private final int HEADER_FILTER_ALPHA = 127;
final private TaskHandler mTasks = new TaskHandler();
Runnable barcodeImageGenerationFinishedCallback;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
if (imageTypes.size() > 1) {
Toast.makeText(this, getString(R.string.swipeToSwitchImages), Toast.LENGTH_SHORT).show();
public void onMainImageTap() {
// If we're in fullscreen, leave fullscreen
if (isFullscreen) {
setFullscreen(false);
return;
}
return false;
}
// If the barcode is shown, switch to fullscreen layout
if (imageTypes.get(mainImageIndex) == ImageType.BARCODE) {
setFullscreen(true);
return;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// If this is an image, open it in the gallery.
openCurrentMainImageInGallery();
}
@@ -212,46 +160,17 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.d(TAG, "On fling");
public void onBarcodeImageWriterResult(boolean success) {
if (!success) {
imageTypes.remove(ImageType.BARCODE);
if (Math.abs(velocityY) > (0.75 * Math.abs(velocityX))) {
// Vertical swipe
// Swipe up
if (velocityY < -150) {
if (!isFullscreen) {
setFullscreen(true);
}
return false;
}
setStateBasedOnImageTypes();
// Swipe down
if (velocityY > 150) {
if (isFullscreen) {
setFullscreen(false);
}
return false;
}
} else if (Math.abs(velocityX) > (0.75 * Math.abs(velocityY))) {
// Horizontal swipe
// Swipe right
if (velocityX < -150) {
setMainImage(true, false);
return false;
}
// Call correct drawMainImage
setFullscreen(isFullscreen);
// Swipe left
if (velocityX > 150) {
setMainImage(false, false);
return false;
}
Toast.makeText(LoyaltyCardViewActivity.this, getString(R.string.wrongValueForBarcodeType), Toast.LENGTH_LONG).show();
}
if (imageTypes.size() > 1) {
Toast.makeText(this, getString(R.string.swipeToSwitchImages), Toast.LENGTH_SHORT).show();
}
return true;
}
enum ImageType {
@@ -268,40 +187,13 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
Log.d(TAG, "View activity: id=" + loyaltyCardId);
}
private Drawable getDotIcon(boolean active, boolean darkMode) {
Drawable unwrappedIcon = AppCompatResources.getDrawable(this, active ? R.drawable.active_dot : R.drawable.inactive_dot);
assert unwrappedIcon != null;
Drawable wrappedIcon = DrawableCompat.wrap(unwrappedIcon);
if (darkMode) {
DrawableCompat.setTint(wrappedIcon, Color.WHITE);
} else {
DrawableCompat.setTint(wrappedIcon, Color.BLACK);
}
return wrappedIcon;
}
private Drawable getIcon(int icon, boolean dark) {
Drawable unwrappedIcon = AppCompatResources.getDrawable(this, icon);
assert unwrappedIcon != null;
Drawable wrappedIcon = DrawableCompat.wrap(unwrappedIcon);
wrappedIcon.mutate();
if (dark) {
DrawableCompat.setTint(wrappedIcon, Color.BLACK);
} else {
DrawableCompat.setTintList(wrappedIcon, null);
}
return wrappedIcon;
}
private void setCenterGuideline(int zoomLevel) {
private void setScalerGuideline(int zoomLevel) {
float scale = zoomLevel / 100f;
if (format != null && format.isSquare()) {
centerGuideline.setGuidelinePercent(0.75f * scale);
binding.scalerGuideline.setGuidelinePercent(0.75f * scale);
} else {
centerGuideline.setGuidelinePercent(0.5f * scale);
binding.scalerGuideline.setGuidelinePercent(0.5f * scale);
}
}
@@ -329,6 +221,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
super.onCreate(savedInstanceState);
binding = LoyaltyCardViewLayoutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
Toolbar toolbar = binding.toolbar;
setSupportActionBar(toolbar);
settings = new Settings(this);
@@ -355,43 +250,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
database = new DBHelper(this).getWritableDatabase();
importURIHelper = new ImportURIHelper(this);
coordinatorLayout = binding.coordinatorLayout;
mainLayout = binding.mainLayout;
cardIdFieldView = binding.cardIdView;
storeName = binding.storeName;
maximizeButton = binding.maximizeButton;
mainImage = binding.mainImage;
mainImage.setClipToOutline(true);
dotIndicator = binding.dotIndicator;
minimizeButton = binding.minimizeButton;
collapsingToolbarLayout = binding.collapsingToolbarLayout;
appBarLayout = binding.appBarLayout;
bottomAppBar = binding.bottomAppBar;
iconImage = binding.iconImage;
portraitToolbar = binding.toolbar;
landscapeToolbar = binding.toolbarLandscape;
bottomAppBarInfoButton = binding.buttonShowInfo;
bottomAppBarPreviousButton = binding.buttonPrevious;
bottomAppBarNextButton = binding.buttonNext;
bottomAppBarUpdateBalanceButton = binding.buttonUpdateBalance;
barcodeImageGenerationFinishedCallback = () -> {
if (!(boolean) mainImage.getTag()) {
mainImage.setVisibility(View.GONE);
imageTypes.remove(ImageType.BARCODE);
// Redraw UI
setDotIndicator(Utils.isDarkModeEnabled(LoyaltyCardViewActivity.this));
setFullscreen(isFullscreen);
Toast.makeText(LoyaltyCardViewActivity.this, getString(R.string.wrongValueForBarcodeType), Toast.LENGTH_LONG).show();
}
};
centerGuideline = binding.centerGuideline;
barcodeScaler = binding.barcodeScaler;
barcodeScaler.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
binding.barcodeScaler.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (!fromUser) {
@@ -399,14 +258,14 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
return;
}
Log.d(TAG, "Progress is " + progress);
Log.d(TAG, "Max is " + barcodeScaler.getMax());
float scale = (float) progress / (float) barcodeScaler.getMax();
Log.d(TAG, "Max is " + binding.barcodeScaler.getMax());
float scale = (float) progress / (float) binding.barcodeScaler.getMax();
Log.d(TAG, "Scaling to " + scale);
loyaltyCard.zoomLevel = progress;
DBHelper.updateLoyaltyCardZoomLevel(database, loyaltyCardId, loyaltyCard.zoomLevel);
setCenterGuideline(loyaltyCard.zoomLevel);
setScalerGuideline(loyaltyCard.zoomLevel);
drawMainImage(mainImageIndex, true, isFullscreen);
}
@@ -424,12 +283,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
rotationEnabled = true;
// Allow making barcode fullscreen on tap
maximizeButton.setOnClickListener(v -> setFullscreen(true));
minimizeButton.setOnClickListener(v -> setFullscreen(false));
binding.fullscreenButtonMinimize.setOnClickListener(v -> setFullscreen(false));
editButton = binding.fabEdit;
editButton.setOnClickListener(v -> {
binding.fabEdit.setOnClickListener(v -> {
Intent intent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("id", loyaltyCardId);
@@ -438,35 +294,21 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
startActivity(intent);
finish();
});
editButton.bringToFront();
binding.fabEdit.bringToFront();
appBarLayout.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
outline.setAlpha(0f);
}
binding.bottomAppBarInfoButton.setOnClickListener(view -> showInfoDialog());
binding.bottomAppBarPreviousButton.setOnClickListener(view -> prevNextCard(false));
binding.bottomAppBarNextButton.setOnClickListener(view -> prevNextCard(true));
binding.bottomAppBarUpdateBalanceButton.setOnClickListener(view -> showBalanceUpdateDialog());
binding.mainImage.setOnClickListener(view -> onMainImageTap());
// This long-press was originally only intended for when Talkback was used but sadly limiting
// this doesn't seem to work well
binding.mainImage.setOnLongClickListener(view -> {
setMainImage(true, true);
return true;
});
bottomAppBarInfoButton.setOnClickListener(view -> showInfoDialog());
bottomAppBarPreviousButton.setOnClickListener(view -> prevNextCard(false));
bottomAppBarNextButton.setOnClickListener(view -> prevNextCard(true));
bottomAppBarUpdateBalanceButton.setOnClickListener(view -> showBalanceUpdateDialog());
mGestureDetector = new GestureDetector(this, this);
View.OnTouchListener gestureTouchListener = (v, event) -> mGestureDetector.onTouchEvent(event);
mainImage.setOnTouchListener(gestureTouchListener);
appBarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
iconImage.setLayoutParams(new CoordinatorLayout.LayoutParams(
CoordinatorLayout.LayoutParams.MATCH_PARENT, appBarLayout.getHeight())
);
iconImage.setClipBounds(new Rect(left, top, right, bottom));
}
});
this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
binding.fullscreenImage.setOnClickListener(view -> onMainImageTap());
}
private SpannableStringBuilder padSpannableString(SpannableStringBuilder spannableStringBuilder) {
@@ -493,7 +335,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
dialogContentPadding,
dialogTitlePadding
);
infoTitleView.setTextSize(settings.getFontSizeMax(settings.getMediumFont()));
infoTitleView.setText(loyaltyCard.store);
infoDialog.setCustomTitle(infoTitleView);
infoDialog.setTitle(loyaltyCard.store);
@@ -630,20 +471,20 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
private void setBottomAppBarButtonState() {
if (!loyaltyCard.note.isEmpty() || !loyaltyCardGroups.isEmpty() || hasBalance(loyaltyCard) || loyaltyCard.validFrom != null || loyaltyCard.expiry != null) {
bottomAppBarInfoButton.setVisibility(View.VISIBLE);
binding.bottomAppBarInfoButton.setVisibility(View.VISIBLE);
} else {
bottomAppBarInfoButton.setVisibility(View.GONE);
binding.bottomAppBarInfoButton.setVisibility(View.GONE);
}
if (cardList == null || cardList.size() == 1) {
bottomAppBarPreviousButton.setVisibility(View.GONE);
bottomAppBarNextButton.setVisibility(View.GONE);
binding.bottomAppBarPreviousButton.setVisibility(View.GONE);
binding.bottomAppBarNextButton.setVisibility(View.GONE);
} else {
bottomAppBarPreviousButton.setVisibility(View.VISIBLE);
bottomAppBarNextButton.setVisibility(View.VISIBLE);
binding.bottomAppBarPreviousButton.setVisibility(View.VISIBLE);
binding.bottomAppBarNextButton.setVisibility(View.VISIBLE);
}
bottomAppBarUpdateBalanceButton.setVisibility(hasBalance(loyaltyCard) ? View.VISIBLE : View.GONE);
binding.bottomAppBarUpdateBalanceButton.setVisibility(hasBalance(loyaltyCard) ? View.VISIBLE : View.GONE);
}
private void prevNextCard(boolean next) {
@@ -738,6 +579,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
return;
}
setTitle(loyaltyCard.store);
loyaltyCardGroups = DBHelper.getLoyaltyCardGroups(database, loyaltyCardId);
setupOrientation();
@@ -746,19 +589,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
cardIdString = loyaltyCard.cardId;
barcodeIdString = loyaltyCard.barcodeId;
cardIdFieldView.setText(loyaltyCard.cardId);
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(cardIdFieldView,
settings.getFontSizeMin(settings.getLargeFont()), settings.getFontSizeMax(settings.getLargeFont()),
1, TypedValue.COMPLEX_UNIT_SP);
storeName.setText(loyaltyCard.store);
storeName.setTextSize(settings.getFontSizeMax(settings.getLargeFont()));
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(
storeName,
settings.getFontSizeMin(settings.getLargeFont()),
settings.getFontSizeMax(settings.getLargeFont()),
1,
TypedValue.COMPLEX_UNIT_DIP);
binding.cardIdView.setText(loyaltyCard.cardId);
int backgroundHeaderColor;
if (loyaltyCard.headerColor != null) {
@@ -767,72 +598,29 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
backgroundHeaderColor = LetterBitmap.getDefaultColor(this, loyaltyCard.store);
}
int textColor;
if (Utils.needsDarkForeground(backgroundHeaderColor)) {
textColor = Color.BLACK;
} else {
textColor = Color.WHITE;
}
storeName.setTextColor(textColor);
landscapeToolbar.setTitleTextColor(textColor);
// Also apply colours to UI elements
int darkenedColor = ColorUtils.blendARGB(backgroundHeaderColor, Color.BLACK, 0.1f);
barcodeScaler.setProgressTintList(ColorStateList.valueOf(darkenedColor));
barcodeScaler.setThumbTintList(ColorStateList.valueOf(darkenedColor));
maximizeButton.setBackgroundColor(darkenedColor);
minimizeButton.setBackgroundColor(darkenedColor);
bottomAppBar.setBackgroundColor(darkenedColor);
maximizeButton.setColorFilter(textColor);
minimizeButton.setColorFilter(textColor);
binding.barcodeScaler.setProgressTintList(ColorStateList.valueOf(darkenedColor));
binding.barcodeScaler.setThumbTintList(ColorStateList.valueOf(darkenedColor));
binding.bottomAppBar.setBackgroundColor(darkenedColor);
int complementaryColor = Utils.getComplementaryColor(darkenedColor);
editButton.setBackgroundTintList(ColorStateList.valueOf(complementaryColor));
Drawable editButtonIcon = editButton.getDrawable();
binding.fabEdit.setBackgroundTintList(ColorStateList.valueOf(complementaryColor));
Drawable editButtonIcon = binding.fabEdit.getDrawable();
editButtonIcon.mutate();
editButtonIcon.setTint(Utils.needsDarkForeground(complementaryColor) ? Color.BLACK : Color.WHITE);
editButton.setImageDrawable(editButtonIcon);
binding.fabEdit.setImageDrawable(editButtonIcon);
Bitmap icon = Utils.retrieveCardImage(this, loyaltyCard.id, ImageLocationType.icon);
if (icon != null) {
int backgroundAlphaColor = Utils.needsDarkForeground(backgroundHeaderColor) ? Color.WHITE : Color.BLACK;
Log.d("onResume", "setting icon image");
iconImage.setImageBitmap(icon);
int backgroundWithAlpha = Color.argb(HEADER_FILTER_ALPHA, Color.red(backgroundAlphaColor), Color.green(backgroundAlphaColor), Color.blue(backgroundAlphaColor));
// for images that has alpha
appBarLayout.setBackgroundColor(backgroundWithAlpha);
} else {
Bitmap plain = Bitmap.createBitmap(new int[]{backgroundHeaderColor}, 1, 1, Bitmap.Config.ARGB_8888);
iconImage.setImageBitmap(plain);
appBarLayout.setBackgroundColor(Color.TRANSPARENT);
}
Utils.setIconOrTextWithBackground(this, loyaltyCard, binding.iconImage, binding.iconText);
// If the background is very bright, we should use dark icons
backgroundNeedsDarkIcons = Utils.needsDarkForeground(backgroundHeaderColor);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setHomeAsUpIndicator(getIcon(R.drawable.home_arrow_back_white, backgroundNeedsDarkIcons));
}
fixImageButtonColor(bottomAppBarInfoButton);
fixImageButtonColor(bottomAppBarPreviousButton);
fixImageButtonColor(bottomAppBarNextButton);
fixImageButtonColor(bottomAppBarUpdateBalanceButton);
fixBottomAppBarImageButtonColor(binding.bottomAppBarInfoButton);
fixBottomAppBarImageButtonColor(binding.bottomAppBarPreviousButton);
fixBottomAppBarImageButtonColor(binding.bottomAppBarNextButton);
fixBottomAppBarImageButtonColor(binding.bottomAppBarUpdateBalanceButton);
setBottomAppBarButtonState();
// Make notification area light if dark icons are needed
if (Build.VERSION.SDK_INT >= 23) {
View decorView = getWindow().getDecorView();
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(getWindow(), decorView);
wic.setAppearanceLightStatusBars(backgroundNeedsDarkIcons);
window.setStatusBarColor(Color.TRANSPARENT);
} else {
// Darken statusbar if icons won't be visible otherwise
window.setStatusBarColor(backgroundNeedsDarkIcons ? ColorUtils.blendARGB(backgroundHeaderColor, Color.BLACK, 0.15f) : Color.TRANSPARENT);
}
// Set shadow colour of store text so even same color on same color would be readable
storeName.setShadowLayer(1, 1, 1, backgroundNeedsDarkIcons ? Color.BLACK : Color.WHITE);
if (format != null && !format.isSupported()) {
isBarcodeSupported = false;
@@ -857,11 +645,29 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
imageTypes.add(ImageType.IMAGE_BACK);
}
setDotIndicator(Utils.isDarkModeEnabled(this));
setStateBasedOnImageTypes();
setFullscreen(isFullscreen);
DBHelper.updateLoyaltyCardLastUsed(database, loyaltyCard.id);
invalidateOptionsMenu();
}
private void setStateBasedOnImageTypes() {
// Decrease the card holder size to only fit the value if there is no barcode
// This looks much cleaner
ViewGroup.LayoutParams cardHolderLayoutParams = binding.cardHolder.getLayoutParams();
if (imageTypes.isEmpty()) {
cardHolderLayoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
} else {
cardHolderLayoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
}
binding.cardHolder.setLayoutParams(cardHolderLayoutParams);
// Ensure buttons and accessibility are correct
setMainImagePreviousNextButtons();
setMainImageAccessibility();
}
@SuppressWarnings("deprecation")
@@ -870,7 +676,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
}
private void fixImageButtonColor(ImageButton imageButton) {
private void fixBottomAppBarImageButtonColor(ImageButton imageButton) {
imageButton.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(backgroundNeedsDarkIcons ? Color.BLACK : Color.WHITE, BlendModeCompat.SRC_ATOP));
}
@@ -887,18 +693,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.card_view_menu, menu);
starred = loyaltyCard.starStatus != 0;
if (loyaltyCard.archiveStatus != 0) {
menu.findItem(R.id.action_unarchive).setVisible(true);
menu.findItem(R.id.action_archive).setVisible(false);
} else {
menu.findItem(R.id.action_unarchive).setVisible(false);
menu.findItem(R.id.action_archive).setVisible(true);
}
menu.findItem(R.id.action_overflow).setIcon(getIcon(R.drawable.ic_overflow_menu, backgroundNeedsDarkIcons));
menu.findItem(R.id.action_share).setIcon(getIcon(R.drawable.ic_share_white, backgroundNeedsDarkIcons));
return super.onCreateOptionsMenu(menu);
}
@@ -907,13 +701,27 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
if (starred) {
menu.findItem(R.id.action_star_unstar).setIcon(getIcon(R.drawable.ic_starred_white, backgroundNeedsDarkIcons));
menu.findItem(R.id.action_star_unstar).setTitle(R.string.unstar);
} else {
menu.findItem(R.id.action_star_unstar).setIcon(getIcon(R.drawable.ic_unstarred_white, backgroundNeedsDarkIcons));
menu.findItem(R.id.action_star_unstar).setTitle(R.string.star);
if (loyaltyCard != null) {
// Update star status
if (loyaltyCard.starStatus == 1) {
menu.findItem(R.id.action_star_unstar).setIcon(R.drawable.ic_starred);
menu.findItem(R.id.action_star_unstar).setTitle(R.string.unstar);
} else {
menu.findItem(R.id.action_star_unstar).setIcon(R.drawable.ic_unstarred);
menu.findItem(R.id.action_star_unstar).setTitle(R.string.star);
}
// Update archive/unarchive button
if (loyaltyCard.archiveStatus != 0) {
menu.findItem(R.id.action_unarchive).setVisible(true);
menu.findItem(R.id.action_archive).setVisible(false);
} else {
menu.findItem(R.id.action_unarchive).setVisible(false);
menu.findItem(R.id.action_archive).setVisible(true);
}
}
return true;
}
@@ -942,11 +750,11 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
return true;
} else if (id == R.id.action_star_unstar) {
starred = !starred;
DBHelper.updateLoyaltyCardStarStatus(database, loyaltyCardId, starred ? 1 : 0);
DBHelper.updateLoyaltyCardStarStatus(database, loyaltyCardId, loyaltyCard.starStatus == 0 ? 1 : 0);
// Re-init loyaltyCard with new data from DB
onResume();
invalidateOptionsMenu();
return true;
} else if (id == R.id.action_archive) {
@@ -955,6 +763,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
// Re-init loyaltyCard with new data from DB
onResume();
invalidateOptionsMenu();
return true;
} else if (id == R.id.action_unarchive) {
@@ -963,6 +772,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
// Re-init loyaltyCard with new data from DB
onResume();
invalidateOptionsMenu();
return true;
} else if (id == R.id.action_delete) {
@@ -993,23 +803,10 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.d(TAG, "Detected landscape mode");
setTitle(loyaltyCard.store);
collapsingToolbarLayout.setVisibility(View.GONE);
portraitToolbar.setVisibility(View.GONE);
landscapeToolbar.setVisibility(View.VISIBLE);
setSupportActionBar(landscapeToolbar);
binding.iconContainer.setVisibility(View.GONE);
} else {
Log.d(TAG, "Detected portrait mode");
setTitle("");
collapsingToolbarLayout.setVisibility(View.VISIBLE);
portraitToolbar.setVisibility(View.VISIBLE);
landscapeToolbar.setVisibility(View.GONE);
setSupportActionBar(portraitToolbar);
binding.iconContainer.setVisibility(View.VISIBLE);
}
enableToolbarBackButton();
@@ -1017,15 +814,16 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
private void drawBarcode(boolean addPadding) {
mTasks.flushTaskList(TaskHandler.TYPE.BARCODE, true, false, false);
if (format != null) {
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(
getApplicationContext(),
mainImage,
barcodeRenderTarget,
barcodeIdString != null ? barcodeIdString : cardIdString,
format,
null,
false,
barcodeImageGenerationFinishedCallback,
this,
addPadding);
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
}
@@ -1033,11 +831,11 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
private void redrawBarcodeAfterResize(boolean addPadding) {
if (format != null) {
mainImage.getViewTreeObserver().addOnGlobalLayoutListener(
barcodeRenderTarget.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mainImage.getViewTreeObserver().removeOnGlobalLayoutListener(this);
barcodeRenderTarget.getViewTreeObserver().removeOnGlobalLayoutListener(this);
Log.d(TAG, "ImageView size now known");
drawBarcode(addPadding);
@@ -1048,25 +846,18 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
private void drawMainImage(int index, boolean waitForResize, boolean isFullscreen) {
if (imageTypes.isEmpty()) {
mainImage.setVisibility(View.GONE);
barcodeRenderTarget.setVisibility(View.GONE);
return;
}
if (dots != null) {
boolean darkMode = Utils.isDarkModeEnabled(getApplicationContext());
for (int i = 0; i < dots.length; i++) {
dots[i].setImageDrawable(getDotIcon(i == index, darkMode));
}
}
ImageType wantedImageType = imageTypes.get(index);
if (wantedImageType == ImageType.BARCODE) {
// Use border in non-fullscreen mode
if (!isFullscreen) {
mainImage.setBackground(AppCompatResources.getDrawable(this, R.drawable.round_outline));
barcodeRenderTarget.setBackground(AppCompatResources.getDrawable(this, R.drawable.round_outline));
} else {
mainImage.setBackgroundColor(Color.WHITE);
barcodeRenderTarget.setBackgroundColor(Color.WHITE);
}
if (waitForResize) {
@@ -1075,27 +866,27 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
drawBarcode(!isFullscreen);
}
mainImage.setContentDescription(getString(R.string.barcodeImageDescriptionWithType, format.prettyName()));
barcodeRenderTarget.setContentDescription(getString(R.string.barcodeImageDescriptionWithType, format.prettyName()));
} else if (wantedImageType == ImageType.IMAGE_FRONT) {
mainImage.setImageBitmap(frontImageBitmap);
mainImage.setBackgroundColor(Color.TRANSPARENT);
mainImage.setContentDescription(getString(R.string.frontImageDescription));
barcodeRenderTarget.setImageBitmap(frontImageBitmap);
barcodeRenderTarget.setBackgroundColor(Color.TRANSPARENT);
barcodeRenderTarget.setContentDescription(getString(R.string.frontImageDescription));
} else if (wantedImageType == ImageType.IMAGE_BACK) {
mainImage.setImageBitmap(backImageBitmap);
mainImage.setBackgroundColor(Color.TRANSPARENT);
mainImage.setContentDescription(getString(R.string.backImageDescription));
barcodeRenderTarget.setImageBitmap(backImageBitmap);
barcodeRenderTarget.setBackgroundColor(Color.TRANSPARENT);
barcodeRenderTarget.setContentDescription(getString(R.string.backImageDescription));
} else {
throw new IllegalArgumentException("Unknown image type: " + wantedImageType);
}
mainImage.setVisibility(View.VISIBLE);
barcodeRenderTarget.setVisibility(View.VISIBLE);
}
private void setMainImage(boolean next, boolean overflow) {
int newIndex = mainImageIndex + (next ? 1 : -1);
if (newIndex >= imageTypes.size() && overflow) {
newIndex = 0;
newIndex = 0;
}
if (newIndex == -1 || newIndex >= imageTypes.size()) {
@@ -1105,24 +896,85 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
mainImageIndex = newIndex;
drawMainImage(newIndex, false, isFullscreen);
setMainImagePreviousNextButtons();
setMainImageAccessibility();
}
private void setDotIndicator(boolean darkMode) {
dotIndicator.removeAllViews();
if (imageTypes.size() >= 2) {
dots = new ImageView[imageTypes.size()];
for (int i = 0; i < imageTypes.size(); i++) {
dots[i] = new ImageView(this);
dots[i].setImageDrawable(getDotIcon(false, darkMode));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(8, 0, 8, 0);
dotIndicator.addView(dots[i], params);
private void setMainImageAccessibility() {
// Single-click actions
if (mainImageIndex == 0) {
ViewCompat.replaceAccessibilityAction(
binding.mainImage,
AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
getString(R.string.moveBarcodeToTopOfScreen),
null
);
} else {
int accessibilityClickAction;
if (mainImageIndex == 1) {
accessibilityClickAction = R.string.openFrontImageInGalleryApp;
} else if (mainImageIndex == 2) {
accessibilityClickAction = R.string.openBackImageInGalleryApp;
} else {
throw new IndexOutOfBoundsException("setMainImageAccessibility was out of range (action_click)");
}
dotIndicator.setVisibility(View.VISIBLE);
ViewCompat.replaceAccessibilityAction(
binding.mainImage,
AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
getString(accessibilityClickAction),
null
);
}
// Long-press actions
int accessibilityLongPressAction;
if (mainImageIndex == 0) {
accessibilityLongPressAction = R.string.switchToFrontImage;
} else if (mainImageIndex == 1) {
accessibilityLongPressAction = R.string.switchToBackImage;
} else if (mainImageIndex == 2) {
accessibilityLongPressAction = R.string.switchToBarcode;
} else {
throw new IndexOutOfBoundsException("setMainImageAccessibility was out of range (action_long_click)");
}
ViewCompat.replaceAccessibilityAction(
binding.mainImage,
AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK,
getString(accessibilityLongPressAction),
null
);
}
private void setMainImagePreviousNextButtons() {
if (imageTypes.size() < 2) {
binding.mainLeftButton.setVisibility(View.INVISIBLE);
binding.mainRightButton.setVisibility(View.INVISIBLE);
binding.mainLeftButton.setOnClickListener(null);
binding.mainRightButton.setOnClickListener(null);
return;
}
// Enable left button if we can go further left
if (mainImageIndex > 0) {
binding.mainLeftButton.setVisibility(View.VISIBLE);
binding.mainLeftButton.setOnClickListener(view -> setMainImage(false, false));
} else {
binding.mainLeftButton.setVisibility(View.INVISIBLE);
binding.mainLeftButton.setOnClickListener(null);
}
// Enable right button if we can go further right
if (mainImageIndex < (imageTypes.size() - 1)) {
binding.mainRightButton.setVisibility(View.VISIBLE);
binding.mainRightButton.setOnClickListener(view -> setMainImage(true, false));
} else {
binding.mainRightButton.setVisibility(View.INVISIBLE);
binding.mainRightButton.setOnClickListener(null);
}
}
@@ -1133,37 +985,31 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
* by machines which offer no space to insert the complete device.
*/
private void setFullscreen(boolean enabled) {
isFullscreen = enabled;
ActionBar actionBar = getSupportActionBar();
isFullscreen = enabled;
if (enabled && !imageTypes.isEmpty()) {
Log.d(TAG, "Move into fullscreen");
barcodeRenderTarget = binding.fullscreenImage;
// Show only fullscreen view
binding.container.setVisibility(View.GONE);
binding.fullscreenLayout.setVisibility(View.VISIBLE);
drawMainImage(mainImageIndex, true, isFullscreen);
barcodeScaler.setProgress(loyaltyCard.zoomLevel);
setCenterGuideline(loyaltyCard.zoomLevel);
// Hide maximize and show minimize button and scaler
maximizeButton.setVisibility(View.GONE);
minimizeButton.setVisibility(View.VISIBLE);
barcodeScaler.setVisibility(View.VISIBLE);
binding.barcodeScaler.setProgress(loyaltyCard.zoomLevel);
setScalerGuideline(loyaltyCard.zoomLevel);
// Hide actionbar
if (actionBar != null) {
actionBar.hide();
}
// Hide toolbars
appBarLayout.setVisibility(View.INVISIBLE);
iconImage.setVisibility(View.INVISIBLE);
collapsingToolbarLayout.setVisibility(View.GONE);
landscapeToolbar.setVisibility(View.GONE);
// Hide other UI elements
cardIdFieldView.setVisibility(View.GONE);
bottomAppBar.setVisibility(View.GONE);
editButton.setVisibility(View.GONE);
binding.bottomAppBar.setVisibility(View.GONE);
binding.fabEdit.setVisibility(View.GONE);
// Set Android to fullscreen mode
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
@@ -1178,31 +1024,22 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
} else {
Log.d(TAG, "Move out of fullscreen");
// Reset center guideline
setCenterGuideline(100);
barcodeRenderTarget = binding.mainImage;
// Show only regular view
binding.container.setVisibility(View.VISIBLE);
binding.fullscreenLayout.setVisibility(View.GONE);
drawMainImage(mainImageIndex, true, isFullscreen);
// Show maximize and hide minimize button and scaler
maximizeButton.setVisibility(imageTypes.isEmpty() ? View.GONE : View.VISIBLE);
minimizeButton.setVisibility(View.GONE);
barcodeScaler.setVisibility(View.GONE);
// Show actionbar
if (actionBar != null) {
actionBar.show();
}
// Show appropriate toolbar
appBarLayout.setVisibility(View.VISIBLE);
setupOrientation();
iconImage.setVisibility(View.VISIBLE);
// Show other UI elements
cardIdFieldView.setVisibility(View.VISIBLE);
editButton.setVisibility(View.VISIBLE);
bottomAppBar.setVisibility(View.VISIBLE);
binding.bottomAppBar.setVisibility(View.VISIBLE);
binding.fabEdit.setVisibility(View.VISIBLE);
// Unset fullscreen mode
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
@@ -1216,7 +1053,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
}
Log.d("setFullScreen", "Is full screen enabled? " + enabled + " Zoom Level = " + barcodeScaler.getProgress());
Log.d("setFullScreen", "Is full screen enabled? " + enabled + " Zoom Level = " + binding.barcodeScaler.getProgress());
}
@SuppressWarnings("deprecation")

View File

@@ -50,7 +50,7 @@ import protect.card_locker.databinding.MainActivityBinding;
import protect.card_locker.databinding.SortingOptionBinding;
import protect.card_locker.preferences.SettingsActivity;
public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener, GestureDetector.OnGestureListener {
public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener {
private MainActivityBinding binding;
private ArchiveActivityBinding archiveActivityBinding;
private ContentMainBinding contentMainBinding;
@@ -63,7 +63,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
private LoyaltyCardCursorAdapter mAdapter;
private ActionMode mCurrentActionMode;
private SearchView mSearchView;
private GestureDetector mGestureDetector;
private int mLoyaltyCardCount = 0;
protected String mFilter = "";
protected Object mGroup = null;
@@ -282,19 +281,11 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
});
mGestureDetector = new GestureDetector(this, this);
View.OnTouchListener gestureTouchListener = (v, event) -> mGestureDetector.onTouchEvent(event);
mHelpSection = contentMainBinding.helpSection;
mNoMatchingCardsText = contentMainBinding.noMatchingCardsText;
mNoGroupCardsText = contentMainBinding.noGroupCardsText;
mCardList = contentMainBinding.list;
mNoMatchingCardsText.setOnTouchListener(gestureTouchListener);
mCardList.setOnTouchListener(gestureTouchListener);
mNoGroupCardsText.setOnTouchListener(gestureTouchListener);
mAdapter = new LoyaltyCardCursorAdapter(this, null, this);
mCardList.setAdapter(mAdapter);
registerForContextMenu(mCardList);
@@ -768,83 +759,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
updateLoyaltyCardList(false);
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mGestureDetector.onTouchEvent(ev);
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.d(TAG, "On fling");
// Don't swipe if we have too much vertical movement
if (Math.abs(velocityY) > (0.75 * Math.abs(velocityX))) {
return false;
}
if (groupsTabLayout.getTabCount() < 2) {
return false;
}
Integer currentTab = groupsTabLayout.getSelectedTabPosition();
Log.d("onFling", "Current Tab " + currentTab);
// Swipe right
if (velocityX < -150) {
Log.d("onFling", "Right Swipe detected " + velocityX);
Integer nextTab = currentTab + 1;
if (nextTab == groupsTabLayout.getTabCount()) {
groupsTabLayout.selectTab(groupsTabLayout.getTabAt(0));
} else {
groupsTabLayout.selectTab(groupsTabLayout.getTabAt(nextTab));
}
return true;
}
// Swipe left
if (velocityX > 150) {
Log.d("onFling", "Left Swipe detected " + velocityX);
Integer nextTab = currentTab - 1;
if (nextTab < 0) {
groupsTabLayout.selectTab(groupsTabLayout.getTabAt(groupsTabLayout.getTabCount() - 1));
} else {
groupsTabLayout.selectTab(groupsTabLayout.getTabAt(nextTab));
}
return true;
}
return false;
}
@Override
public void onRowLongClicked(int inputPosition) {
enableActionMode(inputPosition);

View File

@@ -18,6 +18,9 @@ import android.provider.MediaStore;
import android.util.Log;
import android.util.TypedValue;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.RawRes;
@@ -599,4 +602,24 @@ public class Utils {
return result.toString();
}
public static void setIconOrTextWithBackground(Context context, LoyaltyCard loyaltyCard, ImageView backgroundOrIcon, TextView textWhenNoImage) {
Bitmap icon = Utils.retrieveCardImage(context, loyaltyCard.id, ImageLocationType.icon);
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);
textWhenNoImage.setText(loyaltyCard.store);
textWhenNoImage.setTextColor(Utils.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE);
}
}
}

View File

@@ -63,30 +63,6 @@ public class Settings {
return AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
}
public double getFontSizeScale() {
return getInt(R.string.settings_key_max_font_size_scale, R.integer.settings_max_font_size_scale_pct) / 100.0;
}
public int getSmallFont() {
return 14;
}
public int getMediumFont() {
return 28;
}
public int getLargeFont() {
return 40;
}
public int getFontSizeMin(int fontSize) {
return (int) (Math.round(fontSize / 2.0) - 1);
}
public int getFontSizeMax(int fontSize) {
return (int) Math.round(fontSize * getFontSizeScale());
}
public boolean useMaxBrightnessDisplayingBarcode() {
return getBoolean(R.string.settings_key_display_barcode_max_brightness, true);
}

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" android:useLevel="true"
android:dither="true">
<size android:height="12dip" android:width="12dip"/>
<solid android:color="@android:color/white"/>
</shape>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="#FFFFFF"
<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="M15.41,7.41L14,6l-6,6 6,6 1.41,-1.41L10.83,12z"/>

View File

@@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="#FFFFFF"
<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="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
</vector>

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,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
</vector>

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="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
</vector>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" android:useLevel="true"
android:dither="true">
<size android:height="8dip" android:width="8dip"/>
<solid android:color="@android:color/white"/>
</shape>

View File

@@ -9,8 +9,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp">
android:layout_height="wrap_content">
<com.google.android.material.card.MaterialCardView
android:id="@+id/icon_layout"
@@ -19,12 +18,11 @@
android:outlineProvider="none"
app:cardCornerRadius="8dp"
app:strokeWidth="0dp"
app:layout_constraintBottom_toTopOf="@+id/store"
app:layout_constraintBottom_toTopOf="@+id/note"
app:layout_constraintDimensionRatio="85.6f:53.98f"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:importantForAccessibility="no"
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -36,6 +34,20 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/thumbnail_text"
android:importantForAccessibility="no"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textStyle="bold"
app:autoSizeTextType="uniform"
app:autoSizeMinTextSize="12sp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeStepGranularity="2sp"
android:gravity="center"
android:maxLines="1"
android:layout_margin="20dp" />
<ImageView
android:importantForAccessibility="no"
android:id="@+id/selected_thumbnail"
@@ -117,20 +129,6 @@
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/store"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp"
android:textAppearance="?attr/textAppearanceHeadline1"
app:layout_constraintTop_toBottomOf="@+id/icon_layout"
app:layout_constraintBottom_toTopOf="@+id/note"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="Example store"/>
<TextView
android:id="@+id/note"
android:layout_width="match_parent"
@@ -142,7 +140,7 @@
android:textColor="?android:attr/textColorSecondary"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toBottomOf="@+id/store"
app:layout_constraintTop_toBottomOf="@+id/icon_layout"
app:layout_constraintBottom_toTopOf="@+id/info_divider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@@ -6,215 +6,196 @@
android:id="@+id/coordinator_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fitsSystemWindows="true">
android:fitsSystemWindows="false">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:clipChildren="false"
android:clipToPadding="false"
android:fitsSystemWindows="true"
android:weightSum="1.0">
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_landscape"
android:layout_width="fill_parent"
android:layout_height="?actionBarSize"
android:background="@android:color/transparent"
android:fitsSystemWindows="false"
android:paddingTop="0dp"
android:visibility="gone"
app:contentInsetStart="72.0dip"
app:layout_collapseMode="pin" />
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
style="?attr/toolbarStyle" />
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="fill_parent"
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
android:layout_marginBottom="100dp"
android:orientation="vertical"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp">
<LinearLayout
android:id="@+id/icon_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:minHeight="56.0dip"
app:contentScrim="?colorPrimary"
app:expandedTitleGravity="top"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp">
android:layout_marginBottom="20dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/storeName"
<Space
android:layout_width="50dp"
android:layout_height="0dp"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<com.google.android.material.card.MaterialCardView
android:id="@+id/icon_holder"
android:layout_width="match_parent"
android:layout_height="0dp"
app:cardCornerRadius="8dp"
android:layout_margin="10dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="85.6f:53.98f">
<ImageView
android:id="@+id/icon_image"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="@+id/icon_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textStyle="bold"
app:autoSizeTextType="uniform"
app:autoSizeMinTextSize="12sp"
app:autoSizeMaxTextSize="100sp"
app:autoSizeStepGranularity="2sp"
android:gravity="center"
android:maxLines="1"
android:layout_margin="20dp" />
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
<Space
android:layout_width="50dp"
android:layout_height="0dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp">
<!-- We don't use these buttons for Talkback -->
<ImageButton
android:importantForAccessibility="no"
android:id="@+id/main_left_button"
android:layout_width="50dp"
android:layout_height="match_parent"
app:srcCompat="@drawable/ic_baseline_chevron_left_24"
android:background="@android:color/transparent"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/card_holder"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="8dp"
android:layout_margin="10dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="4dp"
android:orientation="vertical">
<ImageView
android:id="@+id/main_image"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:id="@+id/card_id_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/text_size_large"
android:gravity="center"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- We don't use these buttons for Talkback -->
<ImageButton
android:importantForAccessibility="no"
android:id="@+id/main_right_button"
android:layout_width="50dp"
android:layout_height="match_parent"
app:srcCompat="@drawable/ic_baseline_chevron_right_24"
android:background="@android:color/transparent"/>
</LinearLayout>
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/fullscreen_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:importantForAccessibility="no"
android:id="@+id/fullscreen_image"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/scaler_guideline"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/scaler_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/fullscreen_button_minimize"
android:layout_marginBottom="50dp"
android:layout_marginStart="15.0dip"
android:layout_marginEnd="15.0dip">
<TextView
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/height"/>
<SeekBar
android:id="@+id/barcode_scaler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="?actionBarSize"
android:layout_marginBottom="?actionBarSize"
android:ellipsize="end"
android:maxLines="1"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textSize="40sp"
app:layout_collapseMode="parallax" />
android:contentDescription="@string/setBarcodeHeight"
android:max="100" />
</LinearLayout>
<androidx.appcompat.widget.Toolbar
android:id="@id/toolbar"
android:layout_width="fill_parent"
android:layout_height="?actionBarSize"
android:background="@android:color/transparent"
app:contentInsetStart="72.0dip"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<ImageView
android:id="@+id/icon_image"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_alignParentTop="true"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
app:srcCompat="@drawable/ic_launcher_foreground"
tools:ignore="ContentDescription" />
<FrameLayout
android:clipChildren="false"
android:clipToPadding="false"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/centerGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/scalerGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.75"/>
<ImageButton
android:id="@+id/maximizeButton"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginStart="15.0dip"
android:layout_marginTop="10dp"
android:layout_marginEnd="15.0dip"
android:background="?attr/colorPrimary"
android:contentDescription="@string/moveBarcodeToTopOfScreen"
android:padding="0dp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/mainImage"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24"
app:tint="?attr/colorOnPrimary"
tools:visibility="visible" />
<ImageView
android:id="@+id/mainImage"
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="horizontal"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_marginStart="15.0dip"
android:layout_marginEnd="15.0dip"
app:layout_constraintBottom_toTopOf="@+id/centerGuideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/maximizeButton"/>
<ImageButton
android:id="@+id/minimizeButton"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginStart="15.0dip"
android:layout_marginTop="10dp"
android:layout_marginEnd="15.0dip"
android:background="?attr/colorPrimary"
android:contentDescription="@string/moveBarcodeToCenterOfScreen"
android:padding="0dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/mainImage"
app:srcCompat="@drawable/ic_baseline_arrow_drop_down_24"
app:tint="?attr/colorOnPrimary"
tools:visibility="visible" />
<LinearLayout
android:id="@+id/dotIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="15.0dip"
android:layout_marginTop="10dp"
android:layout_marginEnd="15.0dip"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/minimizeButton"
tools:visibility="visible" />
<SeekBar
android:id="@+id/barcodeScaler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/inputPadding"
android:layout_marginStart="15.0dip"
android:layout_marginEnd="15.0dip"
android:contentDescription="@string/set_scale"
android:max="100"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/scalerGuideline" />
<TextView
android:id="@+id/cardIdView"
android:enabled="true"
android:textIsSelectable="true"
android:focusable="true"
android:longClickable="true"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="10.0dip"
android:layout_marginRight="10.0dip"
android:paddingBottom="80dp"
app:layout_constraintTop_toBottomOf="@+id/dotIndicator"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:textAlignment="center"
app:autoSizeTextType="uniform"
app:autoSizeMinTextSize="@dimen/singleCardCardIdTextSizeMin"
app:autoSizeMaxTextSize="@dimen/singleCardCardIdTextSizeMax"
android:ellipsize="end"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<View
android:id="@+id/drop_shadow_actionbar"
android:layout_width="fill_parent"
android:layout_height="5.0dip"
android:layout_gravity="top"/>
</FrameLayout>
<ImageButton
android:id="@+id/fullscreen_button_minimize"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/ic_baseline_expand_more_24"
android:tooltipText="@string/moveDown"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="50dp"
android:background="@android:color/transparent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottom_app_bar"
@@ -230,7 +211,7 @@
app:fabAlignmentMode="center">
<ImageButton
android:id="@+id/button_previous"
android:id="@+id/bottom_app_bar_previous_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="left"
@@ -242,7 +223,7 @@
android:visibility="gone" />
<ImageButton
android:id="@+id/button_show_info"
android:id="@+id/bottom_app_bar_info_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
@@ -254,7 +235,7 @@
android:visibility="gone" />
<ImageButton
android:id="@+id/button_next"
android:id="@+id/bottom_app_bar_next_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
@@ -266,7 +247,7 @@
android:visibility="gone" />
<ImageButton
android:id="@+id/button_update_balance"
android:id="@+id/bottom_app_bar_update_balance_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"

View File

@@ -4,13 +4,13 @@
<item
android:id="@+id/action_share"
android:icon="@drawable/ic_share_white"
android:icon="@drawable/ic_share"
android:title="@string/share"
app:showAsAction="always"/>
<item
android:id="@+id/action_star_unstar"
android:icon="@drawable/ic_unstarred_white"
android:icon="@drawable/ic_unstarred"
android:title="@string/star"
app:showAsAction="always" />

View File

@@ -313,4 +313,12 @@
<string name="anyDate">Any date</string>
<string name="chooseValidFromDate">Choose valid from date</string>
<string name="validFromSentence">Valid from: <xliff:g>%s</xliff:g></string>
<string name="height">Height:</string>
<string name="switchToFrontImage">Switch to front image</string>
<string name="switchToBackImage">Switch to back image</string>
<string name="switchToBarcode">Switch to barcode</string>
<string name="openImageInGallery">Open image in gallery app</string>
<string name="openFrontImageInGalleryApp">Open front image in gallery app</string>
<string name="openBackImageInGalleryApp">Open back image in gallery app</string>
<string name="setBarcodeHeight">Set barcode height</string>
</resources>

View File

@@ -60,25 +60,13 @@ public class LoyaltyCardCursorAdapterTest {
return viewHolder.itemView;
}
private void checkView(final View view, final String store, final String note, final String validFrom, final String expiry, final String balance, boolean checkFontSizes) {
final TextView storeField = view.findViewById(R.id.store);
private void checkView(final View view, final String store, final String note, final String validFrom, final String expiry, final String balance) {
final TextView storeField = view.findViewById(R.id.thumbnail_text);
final TextView noteField = view.findViewById(R.id.note);
final TextView validFromField = view.findViewById(R.id.validFrom);
final TextView expiryField = view.findViewById(R.id.expiry);
final TextView balanceField = view.findViewById(R.id.balance);
if (checkFontSizes) {
Settings preferences = new Settings(activity.getApplicationContext());
int mediumFontSize = preferences.getFontSizeMax(preferences.getMediumFont());
int smallFontSize = preferences.getFontSizeMax(preferences.getSmallFont());
assertEquals(mediumFontSize, (int) storeField.getTextSize());
assertEquals(smallFontSize, (int) noteField.getTextSize());
assertEquals(smallFontSize, (int) validFromField.getTextSize());
assertEquals(smallFontSize, (int) expiryField.getTextSize());
}
assertEquals(store, storeField.getText().toString());
if (!note.isEmpty()) {
assertEquals(View.VISIBLE, noteField.getVisibility());
assertEquals(note, noteField.getText().toString());
@@ -119,7 +107,7 @@ public class LoyaltyCardCursorAdapterTest {
View view = createView(cursor);
checkView(view, card.store, card.note, "", "", "", false);
checkView(view, card.store, card.note, "", "", "");
cursor.close();
}
@@ -134,30 +122,7 @@ public class LoyaltyCardCursorAdapterTest {
View view = createView(cursor);
checkView(view, card.store, card.note, "", "", "", false);
cursor.close();
}
@Test
public void TestCursorAdapterFontSizes() {
Date date = new Date();
String dateString = DateFormat.getDateInstance(DateFormat.LONG).format(date);
DBHelper.insertLoyaltyCard(mDatabase, "store", "note", date, date, new BigDecimal("0"), null, "cardId", null, CatimaBarcode.fromBarcode(BarcodeFormat.UPC_A), Color.BLACK, 0, null,0);
LoyaltyCard card = DBHelper.getLoyaltyCard(mDatabase, 1);
Cursor cursor = DBHelper.getLoyaltyCardCursor(mDatabase);
cursor.moveToFirst();
setFontScale(50);
View view = createView(cursor);
checkView(view, card.store, card.note, dateString, dateString, "", true);
setFontScale(200);
view = createView(cursor);
checkView(view, card.store, card.note, dateString, dateString, "", true);
checkView(view, card.store, card.note, "", "", "");
cursor.close();
}
@@ -223,7 +188,7 @@ public class LoyaltyCardCursorAdapterTest {
View view = createView(cursor);
checkView(view, card.store, card.note, "", "", "", false);
checkView(view, card.store, card.note, "", "", "");
cursor.close();
}
@@ -238,7 +203,7 @@ public class LoyaltyCardCursorAdapterTest {
View view = createView(cursor);
checkView(view, card.store, card.note, "", "", "", false);
checkView(view, card.store, card.note, "", "", "");
cursor.close();
}
@@ -253,7 +218,7 @@ public class LoyaltyCardCursorAdapterTest {
View view = createView(cursor);
checkView(view, card.store, card.note, "", "", "100 points", false);
checkView(view, card.store, card.note, "", "", "100 points");
cursor.close();
}
@@ -268,7 +233,7 @@ public class LoyaltyCardCursorAdapterTest {
View view = createView(cursor);
checkView(view, card.store, card.note, "", "", "$10.00", false);
checkView(view, card.store, card.note, "", "", "$10.00");
cursor.close();
}

View File

@@ -59,6 +59,7 @@ import java.util.Currency;
import java.util.Date;
import androidx.appcompat.app.AlertDialog;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.widget.TextViewCompat;
import androidx.preference.PreferenceManager;
@@ -309,7 +310,7 @@ public class LoyaltyCardViewActivityTest {
final String barcodeId, final String barcodeType,
final Bitmap frontImage, final Bitmap backImage) {
if (mode == ViewMode.VIEW_CARD) {
checkFieldProperties(activity, R.id.cardIdView, View.VISIBLE, cardId, FieldTypeView.TextView);
checkFieldProperties(activity, R.id.card_id_view, View.VISIBLE, cardId, FieldTypeView.TextView);
} else {
int editVisibility = View.VISIBLE;
@@ -621,7 +622,7 @@ public class LoyaltyCardViewActivityTest {
}
@Test
public void startWithLoyaltyCardViewModeCheckDisplay() throws IOException {
public void startWithLoyaltyCardViewModeCheckDisplay() {
ActivityController activityController = createActivityWithLoyaltyCard(false);
Activity activity = (Activity) activityController.get();
final Context context = activity.getApplicationContext();
@@ -1131,40 +1132,6 @@ public class LoyaltyCardViewActivityTest {
database.close();
}
@Test
public void startCheckFontSizes() {
ActivityController activityController = createActivityWithLoyaltyCard(false);
Activity activity = (Activity) activityController.get();
SQLiteDatabase database = TestHelpers.getEmptyDb(activity).getWritableDatabase();
DBHelper.insertLoyaltyCard(database, "store", "note", null, null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, Color.BLACK, 0, null,0);
final int LARGE_FONT_SIZE = 40;
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(activity);
settings.edit()
.putInt(activity.getResources().getString(R.string.settings_key_max_font_size_scale), 100)
.apply();
activityController.start();
activityController.visible();
activityController.resume();
assertEquals(false, activity.isFinishing());
TextView storeName = activity.findViewById(R.id.storeName);
TextView cardIdFieldView = activity.findViewById(R.id.cardIdView);
TextViewCompat.getAutoSizeMaxTextSize(storeName);
TextViewCompat.getAutoSizeMaxTextSize(storeName);
assertEquals(LARGE_FONT_SIZE, TextViewCompat.getAutoSizeMaxTextSize(cardIdFieldView));
shadowOf(activity).clickMenuItem(android.R.id.home);
assertEquals(true, activity.isFinishing());
database.close();
}
@Test
public void checkPushStarIcon() {
ActivityController activityController = createActivityWithLoyaltyCard(false);
@@ -1213,13 +1180,12 @@ public class LoyaltyCardViewActivityTest {
assertFalse(activity.isFinishing());
View collapsingToolbarLayout = activity.findViewById(R.id.collapsingToolbarLayout);
BottomAppBar bottomAppBar = activity.findViewById(R.id.bottom_app_bar);
ImageButton maximizeButton = activity.findViewById(R.id.maximizeButton);
ImageButton minimizeButton = activity.findViewById(R.id.minimizeButton);
LinearLayout dotIndicator = activity.findViewById(R.id.dotIndicator);
ImageView mainImage = activity.findViewById(R.id.main_image);
LinearLayout container = activity.findViewById(R.id.container);
ConstraintLayout fullScreenLayout = activity.findViewById(R.id.fullscreen_layout);
ImageButton minimizeButton = activity.findViewById(R.id.fullscreen_button_minimize);
FloatingActionButton editButton = activity.findViewById(R.id.fabEdit);
SeekBar barcodeScaler = activity.findViewById(R.id.barcodeScaler);
// Android should not be in fullscreen mode
assertTrue(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.statusBars()));
@@ -1227,16 +1193,13 @@ public class LoyaltyCardViewActivityTest {
assertEquals(WindowInsetsController.BEHAVIOR_DEFAULT, activity.getWindow().getInsetsController().getSystemBarsBehavior());
// Elements should be visible (except minimize button and scaler)
assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility());
assertEquals(View.VISIBLE, bottomAppBar.getVisibility());
assertEquals(View.VISIBLE, maximizeButton.getVisibility());
assertEquals(View.GONE, minimizeButton.getVisibility());
assertEquals(View.VISIBLE, container.getVisibility());
assertEquals(View.GONE, fullScreenLayout.getVisibility());
assertEquals(View.VISIBLE, editButton.getVisibility());
assertEquals(View.GONE, barcodeScaler.getVisibility());
assertEquals(View.GONE, dotIndicator.getVisibility()); // We have no images, only a barcode
// Click maximize button to activate fullscreen
maximizeButton.performClick();
mainImage.performClick();
shadowOf(getMainLooper()).idle();
// Android should be in fullscreen mode
@@ -1245,13 +1208,10 @@ public class LoyaltyCardViewActivityTest {
assertEquals(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE, activity.getWindow().getInsetsController().getSystemBarsBehavior());
// Elements should not be visible (except minimize button and scaler)
assertEquals(View.GONE, collapsingToolbarLayout.getVisibility());
assertEquals(View.GONE, bottomAppBar.getVisibility());
assertEquals(View.GONE, maximizeButton.getVisibility());
assertEquals(View.VISIBLE, minimizeButton.getVisibility());
assertEquals(View.GONE, container.getVisibility());
assertEquals(View.VISIBLE, fullScreenLayout.getVisibility());
assertEquals(View.GONE, editButton.getVisibility());
assertEquals(View.VISIBLE, barcodeScaler.getVisibility());
assertEquals(View.GONE, dotIndicator.getVisibility()); // We have no images, only a barcode
// Clicking minimize button should deactivate fullscreen mode
minimizeButton.performClick();
@@ -1261,29 +1221,23 @@ public class LoyaltyCardViewActivityTest {
assertTrue(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.navigationBars()));
assertEquals(WindowInsetsController.BEHAVIOR_DEFAULT, activity.getWindow().getInsetsController().getSystemBarsBehavior());
assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility());
assertEquals(View.VISIBLE, bottomAppBar.getVisibility());
assertEquals(View.VISIBLE, maximizeButton.getVisibility());
assertEquals(View.GONE, minimizeButton.getVisibility());
assertEquals(View.VISIBLE, container.getVisibility());
assertEquals(View.GONE, fullScreenLayout.getVisibility());
assertEquals(View.VISIBLE, editButton.getVisibility());
assertEquals(View.GONE, barcodeScaler.getVisibility());
assertEquals(View.GONE, dotIndicator.getVisibility()); // We have no images, only a barcode
// Another click back to fullscreen
maximizeButton.performClick();
mainImage.performClick();
shadowOf(getMainLooper()).idle();
assertFalse(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.statusBars()));
assertFalse(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.navigationBars()));
assertEquals(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE, activity.getWindow().getInsetsController().getSystemBarsBehavior());
assertEquals(View.GONE, collapsingToolbarLayout.getVisibility());
assertEquals(View.GONE, bottomAppBar.getVisibility());
assertEquals(View.GONE, maximizeButton.getVisibility());
assertEquals(View.VISIBLE, minimizeButton.getVisibility());
assertEquals(View.GONE, container.getVisibility());
assertEquals(View.VISIBLE, fullScreenLayout.getVisibility());
assertEquals(View.GONE, editButton.getVisibility());
assertEquals(View.VISIBLE, barcodeScaler.getVisibility());
assertEquals(View.GONE, dotIndicator.getVisibility()); // We have no images, only a barcode
// In full screen mode, back button should disable fullscreen
activity.onBackPressed();
@@ -1293,13 +1247,10 @@ public class LoyaltyCardViewActivityTest {
assertTrue(activity.getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.navigationBars()));
assertEquals(WindowInsetsController.BEHAVIOR_DEFAULT, activity.getWindow().getInsetsController().getSystemBarsBehavior());
assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility());
assertEquals(View.VISIBLE, bottomAppBar.getVisibility());
assertEquals(View.VISIBLE, maximizeButton.getVisibility());
assertEquals(View.GONE, minimizeButton.getVisibility());
assertEquals(View.VISIBLE, container.getVisibility());
assertEquals(View.GONE, fullScreenLayout.getVisibility());
assertEquals(View.VISIBLE, editButton.getVisibility());
assertEquals(View.GONE, barcodeScaler.getVisibility());
assertEquals(View.GONE, dotIndicator.getVisibility()); // We have no images, only a barcode
// Pressing back when not in full screen should finish activity
activity.onBackPressed();
@@ -1323,12 +1274,10 @@ public class LoyaltyCardViewActivityTest {
assertEquals(false, activity.isFinishing());
View collapsingToolbarLayout = activity.findViewById(R.id.collapsingToolbarLayout);
BottomAppBar bottomAppBar = activity.findViewById(R.id.bottom_app_bar);
ImageButton maximizeButton = activity.findViewById(R.id.maximizeButton);
ImageButton minimizeButton = activity.findViewById(R.id.minimizeButton);
ImageView mainImage = activity.findViewById(R.id.main_image);
ConstraintLayout fullScreenLayout = activity.findViewById(R.id.fullscreen_layout);
FloatingActionButton editButton = activity.findViewById(R.id.fabEdit);
SeekBar barcodeScaler = activity.findViewById(R.id.barcodeScaler);
// Android should not be in fullscreen mode
int uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
@@ -1336,12 +1285,10 @@ public class LoyaltyCardViewActivityTest {
assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions);
// Elements should be visible (except minimize/maximize buttons and barcode and scaler)
assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility());
assertEquals(View.VISIBLE, bottomAppBar.getVisibility());
assertEquals(View.GONE, maximizeButton.getVisibility());
assertEquals(View.GONE, minimizeButton.getVisibility());
assertEquals(View.GONE, mainImage.getVisibility());
assertEquals(View.GONE, fullScreenLayout.getVisibility());
assertEquals(View.VISIBLE, editButton.getVisibility());
assertEquals(View.GONE, barcodeScaler.getVisibility());
// Pressing back when not in full screen should finish activity
activity.onBackPressed();

View File

@@ -153,10 +153,10 @@ public class MainActivityTest {
list.measure(0, 0);
list.layout(0, 0, 100, 1000);
assertEquals("storeC", ((TextView) list.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.store)).getText());
assertEquals("storeD", ((TextView) list.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.store)).getText());
assertEquals("storeA", ((TextView) list.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.store)).getText());
assertEquals("storeB", ((TextView) list.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.store)).getText());
assertEquals("storeC", ((TextView) list.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.thumbnail_text)).getText());
assertEquals("storeD", ((TextView) list.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.thumbnail_text)).getText());
assertEquals("storeA", ((TextView) list.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.thumbnail_text)).getText());
assertEquals("storeB", ((TextView) list.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.thumbnail_text)).getText());
database.close();
}

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 54 KiB