diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java
index 058d183eb..b85af6b9b 100644
--- a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java
+++ b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java
@@ -5,11 +5,11 @@ import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.Outline;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.GestureDetector;
@@ -18,13 +18,13 @@ 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.WindowManager;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
@@ -46,8 +46,10 @@ import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.Guideline;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
+import androidx.core.widget.NestedScrollView;
import androidx.core.widget.TextViewCompat;
import protect.card_locker.async.TaskHandler;
import protect.card_locker.preferences.Settings;
@@ -59,8 +61,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
TextView cardIdFieldView;
BottomSheetBehavior behavior;
- View bottomSheet;
- View bottomSheetContentWrapper;
+ LinearLayout bottomSheet;
+ NestedScrollView bottomSheetContentWrapper;
ImageView bottomSheetButton;
TextView noteView;
TextView groupsView;
@@ -74,7 +76,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
View collapsingToolbarLayout;
AppBarLayout appBarLayout;
ImageView iconImage;
- RelativeLayout relativeLayout;
Toolbar landscapeToolbar;
int loyaltyCardId;
@@ -104,10 +105,13 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
private ImageView[] dots;
boolean isBarcodeSupported = true;
+ int bottomSheetState;
+
static final String STATE_IMAGEINDEX = "imageIndex";
static final String STATE_FULLSCREEN = "isFullscreen";
+ static final String STATE_BOTTOMSHEET = "bottomSheetState";
- private final int HEADER_FILTER_ALPHA = 70;
+ private final int HEADER_FILTER_ALPHA = 127;
final private TaskHandler mTasks = new TaskHandler();
@@ -241,6 +245,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
if (savedInstanceState != null) {
mainImageIndex = savedInstanceState.getInt(STATE_IMAGEINDEX);
isFullscreen = savedInstanceState.getBoolean(STATE_FULLSCREEN);
+ bottomSheetState = savedInstanceState.getInt(STATE_BOTTOMSHEET);
}
settings = new Settings(this);
@@ -268,7 +273,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
collapsingToolbarLayout = findViewById(R.id.collapsingToolbarLayout);
appBarLayout = findViewById(R.id.app_bar_layout);
iconImage = findViewById(R.id.icon_image);
- relativeLayout = findViewById(R.id.relative_layout);
landscapeToolbar = findViewById(R.id.toolbar_landscape);
centerGuideline = findViewById(R.id.centerGuideline);
@@ -329,20 +333,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
behavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
- if (newState == BottomSheetBehavior.STATE_DRAGGING) {
- editButton.hide();
- } else if (newState == BottomSheetBehavior.STATE_EXPANDED) {
- bottomSheetButton.setImageResource(R.drawable.ic_baseline_arrow_drop_down_24);
- editButton.hide();
- } else if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
- bottomSheetButton.setImageResource(R.drawable.ic_baseline_arrow_drop_up_24);
- if (!isFullscreen) {
- editButton.show();
- }
-
- // Scroll bottomsheet content back to top
- bottomSheetContentWrapper.setScrollY(0);
- }
+ changeUiToBottomSheetState(newState);
}
@Override
@@ -358,56 +349,18 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
}
});
- // Fix bottom sheet content sizing
- ViewTreeObserver viewTreeObserver = bottomSheet.getViewTreeObserver();
- viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ appBarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
- public void onGlobalLayout() {
- Log.d("onGlobalLayout", "checking if bottom sheet size has to be changed");
- DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
- int height = displayMetrics.heightPixels;
- int maxHeight = height - appBarLayout.getHeight() - bottomSheetButton.getHeight();
- Log.d(TAG, "Button sheet should be " + maxHeight + " pixels high");
- // setting it to the same value triggers this callback again on android 11, but it has to stay for when the activity starts fullscreen
- // so check for if changes are needed instead of throwing the callback away
- ViewGroup.LayoutParams params = bottomSheetContentWrapper.getLayoutParams();
- if (params.height != maxHeight || params.width != LinearLayout.LayoutParams.MATCH_PARENT) {
- Log.d("onGlobalLayout", "setting max height: " + maxHeight);
- bottomSheetContentWrapper.setLayoutParams(
- new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- maxHeight
- )
- );
- }
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ adjustLayoutHeights();
}
});
- // synchronizing iconImage size with it's layer above
- collapsingToolbarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ appBarLayout.setOutlineProvider(new ViewOutlineProvider() {
@Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
- Log.d("onLayoutChange", "collapsing toolbar change, height: " + v.getHeight());
- // on android 11, setAdjustViewBounds on the imageView triggers this callback again to my horror, so adding an if to block it
- if(iconImage.getHeight() != v.getHeight()) {
- // setAdjustViewBounds and scale type breaks when an image is set, then the following has to be execute in this order
- iconImage.setAdjustViewBounds(true);
- iconImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
- iconImage.setMaxHeight(v.getHeight());
- iconImage.setMaxWidth(v.getWidth());
- }
- }
- });
- landscapeToolbar.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) {
- Log.d("onLayoutChange", "landscape toolbar change, height: " + v.getHeight());
- if(iconImage.getHeight() != v.getHeight()) {
- iconImage.setAdjustViewBounds(true);
- iconImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
- iconImage.setMaxHeight(v.getHeight());
- iconImage.setMaxWidth(v.getWidth());
- }
+ public void getOutline(View view, Outline outline) {
+ ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
+ outline.setAlpha(0f);
}
});
@@ -416,6 +369,57 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
mainImage.setOnTouchListener(gestureTouchListener);
}
+ private void changeUiToBottomSheetState(int newState){
+ if (newState == BottomSheetBehavior.STATE_DRAGGING) {
+ editButton.hide();
+ } else if (newState == BottomSheetBehavior.STATE_EXPANDED) {
+ bottomSheetButton.setImageResource(R.drawable.ic_baseline_arrow_drop_down_24);
+ editButton.hide();
+ } else if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
+ bottomSheetButton.setImageResource(R.drawable.ic_baseline_arrow_drop_up_24);
+ if (!isFullscreen) {
+ editButton.show();
+ }
+
+ // Scroll bottomsheet content back to top
+ bottomSheetContentWrapper.setScrollY(0);
+ }
+ bottomSheetState = newState;
+ }
+
+ private void adjustLayoutHeights(){
+ // use getLayoutParams instead of getHeight when heights are pre-determined in xml! getHeight could return 0 if a View is not inflated
+ if(iconImage.getLayoutParams().height != appBarLayout.getHeight()) {
+ Log.d("adjustLayoutHeights", "setting imageIcon height from: " + iconImage.getLayoutParams().height + " to: " + appBarLayout.getHeight());
+ iconImage.setLayoutParams(new CoordinatorLayout.LayoutParams(
+ CoordinatorLayout.LayoutParams.MATCH_PARENT, appBarLayout.getHeight())
+ );
+ }
+ int bottomSheetHeight = getResources().getDisplayMetrics().heightPixels - appBarLayout.getHeight() - bottomSheetButton.getLayoutParams().height;
+ ViewGroup.LayoutParams params = bottomSheetContentWrapper.getLayoutParams();
+ if (params.height != bottomSheetHeight || params.width != LinearLayout.LayoutParams.MATCH_PARENT) {
+ // XXX android 5 - 9 has so much quirks with setting bottomSheetContent height
+ // just invalidate the wrapper works on 10 onward
+ // bottomSheetContentWrapper.invalidate();
+ // The below worked on android 5 but not 6, reloading the card then it breaks again on 6, entirely random :(
+ // for (int i = 0; i < bottomSheetContentWrapper.getChildCount(); i++) {
+ // bottomSheetContentWrapper.getChildAt(i).invalidate();
+ // }
+ // since it's basically allergic to getting enlarged then shrunk again, and setting it at all when fullscreen makes no sense
+ if(!isFullscreen){
+ Log.d("adjustLayoutHeights", "setting bottomSheet height from: " + params.height + " to: " + bottomSheetHeight);
+ bottomSheetContentWrapper.setLayoutParams(
+ new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, bottomSheetHeight)
+ );
+ }
+ }
+ // XXX
+ // from android 5 - 9 a padding magically grows on top of bottomSheet after leaving fullscreen
+ // I suspect that it's a bug with going into immersive mode then out, along with coordinator layout bottom sheet
+ Log.d("adjustLayoutHeights", "padding top: " + bottomSheet.getPaddingTop() + " padding bottom: " + bottomSheet.getPaddingBottom());
+ }
+
+
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
@@ -428,6 +432,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putInt(STATE_IMAGEINDEX, mainImageIndex);
savedInstanceState.putBoolean(STATE_FULLSCREEN, isFullscreen);
+ savedInstanceState.putInt(STATE_BOTTOMSHEET, bottomSheetState);
super.onSaveInstanceState(savedInstanceState);
}
@@ -546,8 +551,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
backgroundHeaderColor = LetterBitmap.getDefaultColor(this, loyaltyCard.store);
}
- appBarLayout.setBackgroundColor(backgroundHeaderColor);
-
int textColor;
if (Utils.needsDarkForeground(backgroundHeaderColor)) {
textColor = Color.BLACK;
@@ -555,7 +558,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
textColor = Color.WHITE;
}
storeName.setTextColor(textColor);
- ((Toolbar) findViewById(R.id.toolbar_landscape)).setTitleTextColor(textColor);
+ landscapeToolbar.setTitleTextColor(textColor);
Bitmap icon = Utils.retrieveCardImage(this, loyaltyCard.id, ImageLocationType.icon);
if (icon != null){
@@ -563,16 +566,12 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
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));
- collapsingToolbarLayout.setBackgroundColor(backgroundWithAlpha);
- landscapeToolbar.setBackgroundColor(backgroundWithAlpha);
// for images that has alpha
- iconImage.setBackgroundColor(backgroundWithAlpha);
+ appBarLayout.setBackgroundColor(backgroundWithAlpha);
}else{
Bitmap plain = Bitmap.createBitmap(new int[]{backgroundHeaderColor}, 1, 1, Bitmap.Config.ARGB_8888);
iconImage.setImageBitmap(plain);
- collapsingToolbarLayout.setBackgroundColor(Color.TRANSPARENT);
- landscapeToolbar.setBackgroundColor(Color.TRANSPARENT);
- iconImage.setBackgroundColor(Color.TRANSPARENT);
+ appBarLayout.setBackgroundColor(Color.TRANSPARENT);
}
// If the background is very bright, we should use dark icons
@@ -635,6 +634,9 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
setFullscreen(isFullscreen);
+ // restore bottomSheet UI states from changing orientation
+ changeUiToBottomSheetState(bottomSheetState);
+
db.updateLoyaltyCardLastUsed(loyaltyCard.id);
}
@@ -721,7 +723,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
private void setupOrientation() {
Toolbar portraitToolbar = findViewById(R.id.toolbar);
- Toolbar landscapeToolbar = findViewById(R.id.toolbar_landscape);
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
@@ -888,7 +889,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
// Or the barcode will be centered instead of on top of the screen
// Don't ask me why...
appBarLayout.setVisibility(View.INVISIBLE);
- relativeLayout.setVisibility(View.GONE);
+ collapsingToolbarLayout.setVisibility(View.GONE);
+ landscapeToolbar.setVisibility(View.GONE);
// Hide other UI elements
cardIdFieldView.setVisibility(View.GONE);
@@ -896,6 +898,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
editButton.hide();
+
// Set Android to fullscreen mode
getWindow().getDecorView().setSystemUiVisibility(
getWindow().getDecorView().getSystemUiVisibility()
@@ -924,9 +927,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
// Show appropriate toolbar
// And restore 24dp paddingTop for appBarLayout
appBarLayout.setVisibility(View.VISIBLE);
- DisplayMetrics metrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(metrics);
- relativeLayout.setVisibility(View.VISIBLE);
+ setupOrientation();
// Show other UI elements
cardIdFieldView.setVisibility(View.VISIBLE);
diff --git a/app/src/main/res/layout/loyalty_card_view_layout.xml b/app/src/main/res/layout/loyalty_card_view_layout.xml
index 368cefcb3..5f8e06754 100644
--- a/app/src/main/res/layout/loyalty_card_view_layout.xml
+++ b/app/src/main/res/layout/loyalty_card_view_layout.xml
@@ -155,8 +155,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/inputBackground"
- android:fitsSystemWindows="false"
android:orientation="vertical"
+ android:paddingTop="0px"
android:visibility="gone"
app:behavior_hideable="false"
app:behavior_peekHeight="80dp"
@@ -168,10 +168,10 @@
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_gravity="top|start"
- android:scaleType="fitCenter"
android:contentDescription="@string/toggleMoreInfo"
- app:tint="#ffffff"
- app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24" />
+ android:scaleType="fitCenter"
+ app:srcCompat="@drawable/ic_baseline_arrow_drop_up_24"
+ app:tint="#ffffff" />
+
+ >
-
+
+
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:minHeight="56.0dip"
+ app:contentScrim="?colorPrimary"
+ app:expandedTitleGravity="top"
+ app:expandedTitleMarginEnd="64dp"
+ app:expandedTitleMarginStart="48dp">
-
+ 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" />
-
-
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java
index 0c1c93f67..76fcbc8f4 100644
--- a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java
+++ b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java
@@ -1274,7 +1274,6 @@ public class LoyaltyCardViewActivityTest
ImageView mainImage = activity.findViewById(R.id.mainImage);
View collapsingToolbarLayout = activity.findViewById(R.id.collapsingToolbarLayout);
- View relativeLayout = activity.findViewById(R.id.relative_layout);
View bottomSheet = activity.findViewById(R.id.bottom_sheet);
ImageButton maximizeButton = activity.findViewById(R.id.maximizeButton);
ImageButton minimizeButton = activity.findViewById(R.id.minimizeButton);
@@ -1306,7 +1305,7 @@ public class LoyaltyCardViewActivityTest
assertEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions);
// Elements should not be visible (except minimize button and scaler)
- assertEquals(View.GONE, relativeLayout.getVisibility());
+ assertEquals(View.GONE, collapsingToolbarLayout.getVisibility());
assertEquals(View.GONE, bottomSheet.getVisibility());
assertEquals(View.GONE, maximizeButton.getVisibility());
assertEquals(View.VISIBLE, minimizeButton.getVisibility());
@@ -1320,7 +1319,7 @@ public class LoyaltyCardViewActivityTest
uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions);
assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions);
- assertEquals(View.VISIBLE, relativeLayout.getVisibility());
+ assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility());
assertEquals(View.VISIBLE, bottomSheet.getVisibility());
assertEquals(View.VISIBLE, maximizeButton.getVisibility());
assertEquals(View.GONE, minimizeButton.getVisibility());
@@ -1334,7 +1333,7 @@ public class LoyaltyCardViewActivityTest
uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
assertEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions);
assertEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions);
- assertEquals(View.GONE, relativeLayout.getVisibility());
+ assertEquals(View.GONE, collapsingToolbarLayout.getVisibility());
assertEquals(View.GONE, bottomSheet.getVisibility());
assertEquals(View.GONE, maximizeButton.getVisibility());
assertEquals(View.VISIBLE, minimizeButton.getVisibility());
@@ -1348,7 +1347,7 @@ public class LoyaltyCardViewActivityTest
uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions);
assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions);
- assertEquals(View.VISIBLE, relativeLayout.getVisibility());
+ assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility());
assertEquals(View.VISIBLE, bottomSheet.getVisibility());
assertEquals(View.VISIBLE, maximizeButton.getVisibility());
assertEquals(View.GONE, minimizeButton.getVisibility());