diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bbc355a2..e58df18c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Improved support for screen readers - Don't crash when trying to open a video from gallery +- Swipe support on loyalty card view screen ## v2.4.0 - 81 (2021-08-29) diff --git a/app/src/main/java/protect/card_locker/AboutActivity.java b/app/src/main/java/protect/card_locker/AboutActivity.java index dc92dd911..1cc63df9a 100644 --- a/app/src/main/java/protect/card_locker/AboutActivity.java +++ b/app/src/main/java/protect/card_locker/AboutActivity.java @@ -8,10 +8,6 @@ import android.util.Log; import android.view.MenuItem; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.widget.Toolbar; -import androidx.core.text.HtmlCompat; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -20,6 +16,10 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.List; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.Toolbar; +import androidx.core.text.HtmlCompat; + public class AboutActivity extends CatimaAppCompatActivity { private static final String TAG = "Catima"; diff --git a/app/src/main/java/protect/card_locker/BarcodeSelectorActivity.java b/app/src/main/java/protect/card_locker/BarcodeSelectorActivity.java index 942de9d81..c086014c0 100644 --- a/app/src/main/java/protect/card_locker/BarcodeSelectorActivity.java +++ b/app/src/main/java/protect/card_locker/BarcodeSelectorActivity.java @@ -1,7 +1,6 @@ package protect.card_locker; import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; @@ -15,9 +14,6 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.widget.Toolbar; - import com.google.zxing.BarcodeFormat; import java.util.Arrays; @@ -27,6 +23,9 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.Map; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.Toolbar; + /** * This activity is callable and will allow a user to enter * barcode data and generate all barcodes possible for diff --git a/app/src/main/java/protect/card_locker/CardShortcutConfigure.java b/app/src/main/java/protect/card_locker/CardShortcutConfigure.java index b21a58036..9e86426a2 100644 --- a/app/src/main/java/protect/card_locker/CardShortcutConfigure.java +++ b/app/src/main/java/protect/card_locker/CardShortcutConfigure.java @@ -6,6 +6,8 @@ import android.util.Log; import android.view.View; import android.widget.Toast; +import com.google.android.material.floatingactionbutton.FloatingActionButton; + import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.core.content.pm.ShortcutInfoCompat; @@ -14,8 +16,6 @@ import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.material.floatingactionbutton.FloatingActionButton; - /** * The configuration screen for creating a shortcut. */ diff --git a/app/src/main/java/protect/card_locker/CatimaAppCompatActivity.java b/app/src/main/java/protect/card_locker/CatimaAppCompatActivity.java index e67c3cd39..27c08254f 100644 --- a/app/src/main/java/protect/card_locker/CatimaAppCompatActivity.java +++ b/app/src/main/java/protect/card_locker/CatimaAppCompatActivity.java @@ -3,13 +3,9 @@ package protect.card_locker; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; -import android.util.Log; import android.util.TypedValue; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; -import java.util.Map; import androidx.appcompat.app.AppCompatActivity; import androidx.preference.PreferenceManager; diff --git a/app/src/main/java/protect/card_locker/GroupCursorAdapter.java b/app/src/main/java/protect/card_locker/GroupCursorAdapter.java index b23a92faf..886c73879 100644 --- a/app/src/main/java/protect/card_locker/GroupCursorAdapter.java +++ b/app/src/main/java/protect/card_locker/GroupCursorAdapter.java @@ -10,7 +10,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.appcompat.widget.AppCompatImageButton; import androidx.recyclerview.widget.RecyclerView; - import protect.card_locker.preferences.Settings; class GroupCursorAdapter extends BaseCursorAdapter diff --git a/app/src/main/java/protect/card_locker/ImportExportActivity.java b/app/src/main/java/protect/card_locker/ImportExportActivity.java index 01edb063a..22969b746 100644 --- a/app/src/main/java/protect/card_locker/ImportExportActivity.java +++ b/app/src/main/java/protect/card_locker/ImportExportActivity.java @@ -2,7 +2,6 @@ package protect.card_locker; import android.Manifest; import android.content.ActivityNotFoundException; -import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; @@ -17,12 +16,6 @@ import android.widget.Button; import android.widget.EditText; import android.widget.Toast; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.widget.Toolbar; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; - import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -32,6 +25,11 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; import protect.card_locker.importexport.DataFormat; import protect.card_locker.importexport.ImportExportResult; diff --git a/app/src/main/java/protect/card_locker/LoyaltyCard.java b/app/src/main/java/protect/card_locker/LoyaltyCard.java index d2434710d..75b82f87b 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCard.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCard.java @@ -4,14 +4,14 @@ import android.database.Cursor; import android.os.Parcel; import android.os.Parcelable; -import androidx.annotation.Nullable; - import com.google.zxing.BarcodeFormat; import java.math.BigDecimal; import java.util.Currency; import java.util.Date; +import androidx.annotation.Nullable; + public class LoyaltyCard implements Parcelable { public final int id; public final String store; diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java b/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java index 1a50bde17..14ea94ac2 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardCursorAdapter.java @@ -17,15 +17,12 @@ import android.widget.TextView; import com.google.android.material.card.MaterialCardView; -import androidx.cardview.widget.CardView; -import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.recyclerview.widget.RecyclerView; - import java.math.BigDecimal; import java.text.DateFormat; import java.util.ArrayList; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.RecyclerView; import protect.card_locker.preferences.Settings; public class LoyaltyCardCursorAdapter extends BaseCursorAdapter diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java index 19406cd5c..1e442843e 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java @@ -35,14 +35,6 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; -import androidx.annotation.NonNull; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.widget.Toolbar; -import androidx.core.content.FileProvider; -import androidx.exifinterface.media.ExifInterface; -import androidx.fragment.app.DialogFragment; - import com.google.android.material.chip.Chip; import com.google.android.material.chip.ChipGroup; import com.google.android.material.floatingactionbutton.FloatingActionButton; @@ -71,6 +63,14 @@ import java.util.Locale; import java.util.NoSuchElementException; import java.util.concurrent.Callable; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.FileProvider; +import androidx.exifinterface.media.ExifInterface; +import androidx.fragment.app.DialogFragment; + public class LoyaltyCardEditActivity extends CatimaAppCompatActivity { private static final String TAG = "Catima"; diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java b/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java index e954400d6..4765f6fc9 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardLockerApplication.java @@ -2,7 +2,6 @@ package protect.card_locker; import androidx.appcompat.app.AppCompatDelegate; import androidx.multidex.MultiDexApplication; - import protect.card_locker.preferences.Settings; public class LoyaltyCardLockerApplication extends MultiDexApplication { diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java index bd291e99c..7086f2351 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java @@ -1,6 +1,5 @@ package protect.card_locker; -import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -13,8 +12,10 @@ import android.text.TextUtils; import android.util.DisplayMetrics; 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.ViewTreeObserver; import android.view.Window; @@ -26,15 +27,6 @@ import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; -import androidx.annotation.NonNull; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.content.res.AppCompatResources; -import androidx.appcompat.widget.AppCompatTextView; -import androidx.appcompat.widget.Toolbar; -import androidx.constraintlayout.widget.Guideline; -import androidx.core.graphics.drawable.DrawableCompat; -import androidx.core.widget.TextViewCompat; - import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.floatingactionbutton.FloatingActionButton; @@ -47,28 +39,35 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.content.res.AppCompatResources; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.appcompat.widget.Toolbar; +import androidx.constraintlayout.widget.Guideline; +import androidx.core.graphics.drawable.DrawableCompat; +import androidx.core.widget.TextViewCompat; import protect.card_locker.preferences.Settings; -public class LoyaltyCardViewActivity extends CatimaAppCompatActivity +public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements GestureDetector.OnGestureListener { private static final String TAG = "Catima"; + private GestureDetector mGestureDetector; + TextView cardIdFieldView; BottomSheetBehavior behavior; View bottomSheet; View bottomSheetContentWrapper; ImageView bottomSheetButton; - View frontImageView; - ImageView frontImage; - View backImageView; - ImageView backImage; TextView noteView; TextView groupsView; TextView balanceView; TextView expiryView; AppCompatTextView storeName; ImageButton maximizeButton; - ImageView barcodeImage; + ImageView mainImage; + LinearLayout dotIndicator; ImageButton minimizeButton; View collapsingToolbarLayout; AppBarLayout appBarLayout; @@ -93,12 +92,85 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity boolean starred; boolean backgroundNeedsDarkIcons; - FullscreenType fullscreenType = FullscreenType.NONE; + boolean isFullscreen = false; + int mainImageIndex = 0; + List imageTypes; + private ImageView[] dots; boolean isBarcodeSupported = true; - static final String STATE_FULLSCREENTYPE = "fullscreenType"; + static final String STATE_IMAGEINDEX = "imageIndex"; + static final String STATE_FULLSCREEN = "isFullscreen"; - enum FullscreenType { + @Override + public boolean onDown(MotionEvent e) { + return true; + } + + @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) { + // Also switch on long-press for accessibility + setMainImage(true, true); + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + Log.d(TAG, "On fling"); + + if (Math.abs(velocityY) > (0.75 * Math.abs(velocityX))) { + // Vertical swipe + // Swipe up + if (velocityY < -150) { + if (!isFullscreen) { + setFullscreen(true); + } + return true; + } + + // Swipe down + if (velocityY > 150) { + if (isFullscreen) { + setFullscreen(false); + } + return true; + } + } else if (Math.abs(velocityX) > (0.75 * Math.abs(velocityY))) { + // Horizontal swipe + // Swipe right + if (velocityX < -150) { + setMainImage(true, false); + return true; + } + + // Swipe left + if (velocityX > 150) { + setMainImage(false, false); + return true; + } + + if (imageTypes.size() > 1) { + Toast.makeText(this, getString(R.string.swipeToSwitchImages), Toast.LENGTH_SHORT).show(); + } + } + + return false; + } + + enum ImageType { NONE, BARCODE, IMAGE_FRONT, @@ -112,6 +184,15 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity Log.d(TAG, "View activity: id=" + loyaltyCardId); } + private Drawable getDotIcon(boolean active) { + Drawable unwrappedIcon = AppCompatResources.getDrawable(this, active ? R.drawable.active_dot : R.drawable.inactive_dot); + assert unwrappedIcon != null; + Drawable wrappedIcon = DrawableCompat.wrap(unwrappedIcon); + DrawableCompat.setTint(wrappedIcon, getResources().getColor(R.color.iconColor)); + + return wrappedIcon; + } + private Drawable getIcon(int icon, boolean dark) { Drawable unwrappedIcon = AppCompatResources.getDrawable(this, icon); @@ -135,7 +216,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity super.onCreate(savedInstanceState); if (savedInstanceState != null) { - fullscreenType = FullscreenType.valueOf(savedInstanceState.getString(STATE_FULLSCREENTYPE)); + mainImageIndex = savedInstanceState.getInt(STATE_IMAGEINDEX); + isFullscreen = savedInstanceState.getBoolean(STATE_FULLSCREEN); } settings = new Settings(this); @@ -151,17 +233,14 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity bottomSheet = findViewById(R.id.bottom_sheet); bottomSheetContentWrapper = findViewById(R.id.bottomSheetContentWrapper); bottomSheetButton = findViewById(R.id.bottomSheetButton); - frontImageView = findViewById(R.id.frontImageView); - frontImage = findViewById(R.id.frontImage); - backImageView = findViewById(R.id.backImageView); - backImage = findViewById(R.id.backImage); noteView = findViewById(R.id.noteView); groupsView = findViewById(R.id.groupsView); balanceView = findViewById(R.id.balanceView); expiryView = findViewById(R.id.expiryView); storeName = findViewById(R.id.storeName); maximizeButton = findViewById(R.id.maximizeButton); - barcodeImage = findViewById(R.id.barcode); + mainImage = findViewById(R.id.mainImage); + dotIndicator = findViewById(R.id.dotIndicator); minimizeButton = findViewById(R.id.minimizeButton); collapsingToolbarLayout = findViewById(R.id.collapsingToolbarLayout); appBarLayout = findViewById(R.id.app_bar_layout); @@ -170,8 +249,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity centerGuideline.setGuidelinePercent(0.5f); barcodeScaler = findViewById(R.id.barcodeScaler); barcodeScaler.setProgress(100); - minimizeButton.setBackgroundColor(getThemeColor()); maximizeButton.setBackgroundColor(getThemeColor()); + minimizeButton.setBackgroundColor(getThemeColor()); bottomSheetButton.setBackgroundColor(getThemeColor()); barcodeScaler.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override @@ -181,7 +260,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity float scale = (float) progress / (float) barcodeScaler.getMax(); Log.d(TAG, "Scaling to " + scale); - if (fullscreenType == FullscreenType.BARCODE) { + if (imageTypes.get(mainImageIndex) == ImageType.BARCODE) { redrawBarcodeAfterResize(); } centerGuideline.setGuidelinePercent(0.5f * scale); @@ -201,29 +280,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity rotationEnabled = true; // Allow making barcode fullscreen on tap - maximizeButton.setOnClickListener(v -> setFullscreen(FullscreenType.BARCODE)); - barcodeImage.setOnClickListener(view -> { - if (fullscreenType != FullscreenType.NONE) { - setFullscreen(FullscreenType.NONE); - } else { - setFullscreen(FullscreenType.BARCODE); - } - }); - frontImageView.setOnClickListener(view -> { - if (fullscreenType != FullscreenType.IMAGE_FRONT) { - setFullscreen(FullscreenType.IMAGE_FRONT); - } else { - setFullscreen(FullscreenType.NONE); - } - }); - backImageView.setOnClickListener(view -> { - if (fullscreenType != FullscreenType.IMAGE_BACK) { - setFullscreen(FullscreenType.IMAGE_BACK); - } else { - setFullscreen(FullscreenType.NONE); - } - }); - minimizeButton.setOnClickListener(v -> setFullscreen(FullscreenType.NONE)); + maximizeButton.setOnClickListener(v -> setFullscreen(true)); + minimizeButton.setOnClickListener(v -> setFullscreen(false)); editButton = findViewById(R.id.fabEdit); editButton.setOnClickListener(v -> { @@ -248,7 +306,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity editButton.hide(); } else if (newState == BottomSheetBehavior.STATE_COLLAPSED) { bottomSheetButton.setImageResource(R.drawable.ic_baseline_arrow_drop_up_24); - if (fullscreenType == FullscreenType.NONE) { + if (!isFullscreen) { editButton.show(); } @@ -287,6 +345,10 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity ); } }); + + mGestureDetector = new GestureDetector(this, this); + View.OnTouchListener gestureTouchListener = (v, event) -> mGestureDetector.onTouchEvent(event); + mainImage.setOnTouchListener(gestureTouchListener); } @Override @@ -300,7 +362,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity @Override public void onSaveInstanceState(Bundle savedInstanceState) { - savedInstanceState.putString(STATE_FULLSCREENTYPE, String.valueOf(fullscreenType)); + savedInstanceState.putInt(STATE_IMAGEINDEX, mainImageIndex); + savedInstanceState.putBoolean(STATE_FULLSCREEN, isFullscreen); super.onSaveInstanceState(savedInstanceState); } @@ -357,22 +420,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity settings.getFontSizeMin(settings.getLargeFont()), settings.getFontSizeMax(settings.getLargeFont()), 1, TypedValue.COMPLEX_UNIT_SP); - frontImageBitmap = Utils.retrieveCardImage(this, loyaltyCard.id, true); - if (frontImageBitmap != null) { - frontImageView.setVisibility(View.VISIBLE); - frontImage.setImageBitmap(frontImageBitmap); - } else { - frontImageView.setVisibility(View.GONE); - } - - backImageBitmap = Utils.retrieveCardImage(this, loyaltyCard.id, false); - if (backImageBitmap != null) { - backImageView.setVisibility(View.VISIBLE); - backImage.setImageBitmap(backImageBitmap); - } else { - backImageView.setVisibility(View.GONE); - } - if(loyaltyCard.note.length() > 0) { noteView.setVisibility(View.VISIBLE); @@ -428,7 +475,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity } expiryView.setTag(loyaltyCard.expiry); - if (fullscreenType == FullscreenType.NONE) { + if (!isFullscreen) { makeBottomSheetVisibleIfUseful(); } @@ -491,16 +538,51 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity isBarcodeSupported = false; Toast.makeText(this, getString(R.string.unsupportedBarcodeType), Toast.LENGTH_LONG).show(); + } else if (format == null) { + isBarcodeSupported = false; } - setFullscreen(fullscreenType); + imageTypes = new ArrayList<>(); + + if (isBarcodeSupported) { + imageTypes.add(ImageType.BARCODE); + } + + frontImageBitmap = Utils.retrieveCardImage(this, loyaltyCard.id, true); + backImageBitmap = Utils.retrieveCardImage(this, loyaltyCard.id, false); + + if (frontImageBitmap != null) { + imageTypes.add(ImageType.IMAGE_FRONT); + } + + if (backImageBitmap != null) { + imageTypes.add(ImageType.IMAGE_BACK); + } + + 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)); + + 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); + } + + dotIndicator.setVisibility(View.VISIBLE); + } + + setFullscreen(isFullscreen); } @Override public void onBackPressed() { - if (fullscreenType != FullscreenType.NONE) + if (isFullscreen) { - setFullscreen(FullscreenType.NONE); + setFullscreen(false); return; } @@ -620,6 +702,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity actionBar.setDisplayHomeAsUpEnabled(true); } } + private void setOrientatonLock(MenuItem item, boolean lock) { if(lock) @@ -639,7 +722,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity private void makeBottomSheetVisibleIfUseful() { - if (frontImageView.getVisibility() == View.VISIBLE || backImageView.getVisibility() == View.VISIBLE || noteView.getVisibility() == View.VISIBLE || groupsView.getVisibility() == View.VISIBLE || balanceView.getVisibility() == View.VISIBLE || expiryView.getVisibility() == View.VISIBLE) { + if (noteView.getVisibility() == View.VISIBLE || groupsView.getVisibility() == View.VISIBLE || balanceView.getVisibility() == View.VISIBLE || expiryView.getVisibility() == View.VISIBLE) { bottomSheet.setVisibility(View.VISIBLE); } else @@ -648,52 +731,98 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity } } - private void redrawBarcodeAfterResize() - { + private void drawBarcode() { if (format != null) { - barcodeImage.getViewTreeObserver().addOnGlobalLayoutListener( + new BarcodeImageWriterTask( + getApplicationContext(), + mainImage, + barcodeIdString != null ? barcodeIdString : cardIdString, + format, + null, + false, + null) + .execute(); + } + } + + private void redrawBarcodeAfterResize() { + if (format != null) { + mainImage.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { - barcodeImage.getViewTreeObserver().removeOnGlobalLayoutListener(this); + mainImage.getViewTreeObserver().removeOnGlobalLayoutListener(this); Log.d(TAG, "ImageView size now known"); - new BarcodeImageWriterTask( - getApplicationContext(), - barcodeImage, - barcodeIdString != null ? barcodeIdString : cardIdString, - format, - null, - false, - null) - .execute(); + drawBarcode(); } }); }; } + private void drawMainImage(int index, boolean waitForResize) { + if (imageTypes.isEmpty()) { + mainImage.setVisibility(View.GONE); + return; + } + + if (dots != null) { + for (int i = 0; i < dots.length; i++) { + dots[i].setImageDrawable(getDotIcon(i == index)); + } + } + + ImageType wantedImageType = imageTypes.get(index); + + if (wantedImageType == ImageType.BARCODE) { + if (waitForResize) { + redrawBarcodeAfterResize(); + } else { + drawBarcode(); + } + mainImage.setBackgroundColor(Color.WHITE); + } else if (wantedImageType == ImageType.IMAGE_FRONT) { + mainImage.setImageBitmap(frontImageBitmap); + mainImage.setBackgroundColor(Color.TRANSPARENT); + } else if (wantedImageType == ImageType.IMAGE_BACK) { + mainImage.setImageBitmap(backImageBitmap); + mainImage.setBackgroundColor(Color.TRANSPARENT); + } else { + throw new IllegalArgumentException("Unknown image type: " + wantedImageType); + } + + mainImage.setVisibility(View.VISIBLE); + } + + private void setMainImage(boolean next, boolean overflow) { + int newIndex = mainImageIndex + (next ? 1 : -1); + + if (newIndex >= imageTypes.size() && overflow) { + newIndex = 0; + } + + if (newIndex == -1 || newIndex >= imageTypes.size()) { + return; + } + + mainImageIndex = newIndex; + + drawMainImage(newIndex, false); + } + /** * When enabled, hides the status bar and moves the barcode to the top of the screen. * * The purpose of this function is to make sure the barcode can be scanned from the phone * by machines which offer no space to insert the complete device. */ - private void setFullscreen(FullscreenType fullscreenType) - { + private void setFullscreen(boolean enabled) { ActionBar actionBar = getSupportActionBar(); - if (fullscreenType != FullscreenType.NONE) { + + if (enabled && !imageTypes.isEmpty()) { Log.d(TAG, "Move into fullscreen"); - if (fullscreenType == FullscreenType.IMAGE_FRONT) { - barcodeImage.setImageBitmap(frontImageBitmap); - barcodeImage.setVisibility(View.VISIBLE); - } else if (fullscreenType == FullscreenType.IMAGE_BACK) { - barcodeImage.setImageBitmap(backImageBitmap); - barcodeImage.setVisibility(View.VISIBLE); - } else { - // Prepare redraw after size change - redrawBarcodeAfterResize(); - } + drawMainImage(mainImageIndex, true); // Hide maximize and show minimize button and scaler maximizeButton.setVisibility(View.GONE); @@ -735,17 +864,11 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity // Reset center guideline barcodeScaler.setProgress(100); - // Prepare redraw after size change - if (format != null && isBarcodeSupported) { - redrawBarcodeAfterResize(); - } else { - barcodeImage.setVisibility(View.GONE); - } + drawMainImage(mainImageIndex, true); // Show maximize and hide minimize button and scaler - if (format != null && isBarcodeSupported) { - maximizeButton.setVisibility(View.VISIBLE); - } + maximizeButton.setVisibility(imageTypes.isEmpty() ? View.GONE : View.VISIBLE); + minimizeButton.setVisibility(View.GONE); barcodeScaler.setVisibility(View.GONE); @@ -775,6 +898,6 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity ); } - this.fullscreenType = fullscreenType; + isFullscreen = enabled; } } diff --git a/app/src/main/java/protect/card_locker/MainActivity.java b/app/src/main/java/protect/card_locker/MainActivity.java index a10cc5c6a..1e9b95d36 100644 --- a/app/src/main/java/protect/card_locker/MainActivity.java +++ b/app/src/main/java/protect/card_locker/MainActivity.java @@ -18,21 +18,18 @@ import android.view.MotionEvent; import android.view.View; import android.widget.Toast; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.view.ActionMode; -import androidx.appcompat.widget.SearchView; -import androidx.appcompat.widget.Toolbar; -import androidx.core.app.ActivityCompat; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.tabs.TabLayout; import java.io.UnsupportedEncodingException; import java.util.List; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.view.ActionMode; +import androidx.appcompat.widget.SearchView; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; +import androidx.recyclerview.widget.RecyclerView; import protect.card_locker.preferences.SettingsActivity; public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener, GestureDetector.OnGestureListener @@ -214,12 +211,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard mGestureDetector = new GestureDetector(this, this); - View.OnTouchListener gestureTouchListener = new View.OnTouchListener() { - @Override - public boolean onTouch(final View v, final MotionEvent event){ - return mGestureDetector.onTouchEvent(event); - } - }; + View.OnTouchListener gestureTouchListener = (v, event) -> mGestureDetector.onTouchEvent(event); mHelpText = findViewById(R.id.helpText); mNoMatchingCardsText = findViewById(R.id.noMatchingCardsText); diff --git a/app/src/main/java/protect/card_locker/ManageGroupsActivity.java b/app/src/main/java/protect/card_locker/ManageGroupsActivity.java index 6f8943141..60e6dd35f 100644 --- a/app/src/main/java/protect/card_locker/ManageGroupsActivity.java +++ b/app/src/main/java/protect/card_locker/ManageGroupsActivity.java @@ -10,6 +10,10 @@ import android.view.WindowManager; import android.widget.EditText; import android.widget.TextView; +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +import java.util.List; + import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.Toolbar; @@ -17,10 +21,6 @@ import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.material.floatingactionbutton.FloatingActionButton; - -import java.util.List; - public class ManageGroupsActivity extends CatimaAppCompatActivity implements GroupCursorAdapter.GroupAdapterListener { private static final String TAG = "Catima"; diff --git a/app/src/main/java/protect/card_locker/ScanActivity.java b/app/src/main/java/protect/card_locker/ScanActivity.java index fba311164..e68dfa78a 100644 --- a/app/src/main/java/protect/card_locker/ScanActivity.java +++ b/app/src/main/java/protect/card_locker/ScanActivity.java @@ -1,7 +1,6 @@ package protect.card_locker; import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; @@ -12,9 +11,6 @@ import android.view.MenuItem; import android.view.View; import android.widget.Toast; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.widget.Toolbar; - import com.google.zxing.ResultPoint; import com.google.zxing.client.android.Intents; import com.journeyapps.barcodescanner.BarcodeCallback; @@ -24,6 +20,9 @@ import com.journeyapps.barcodescanner.DecoratedBarcodeView; import java.util.List; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.Toolbar; + /** * Custom Scannner Activity extending from Activity to display a custom layout form scanner view. * diff --git a/app/src/main/java/protect/card_locker/ShortcutHelper.java b/app/src/main/java/protect/card_locker/ShortcutHelper.java index 7e06fdf68..29bbff461 100644 --- a/app/src/main/java/protect/card_locker/ShortcutHelper.java +++ b/app/src/main/java/protect/card_locker/ShortcutHelper.java @@ -5,15 +5,15 @@ import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; -import androidx.core.content.pm.ShortcutInfoCompat; -import androidx.core.content.pm.ShortcutManagerCompat; -import androidx.core.graphics.drawable.IconCompat; - import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; +import androidx.core.content.pm.ShortcutInfoCompat; +import androidx.core.content.pm.ShortcutManagerCompat; +import androidx.core.graphics.drawable.IconCompat; + class ShortcutHelper { // Android documentation says that no more than 5 shortcuts diff --git a/app/src/main/java/protect/card_locker/Utils.java b/app/src/main/java/protect/card_locker/Utils.java index ecfa246c9..6c5542acb 100644 --- a/app/src/main/java/protect/card_locker/Utils.java +++ b/app/src/main/java/protect/card_locker/Utils.java @@ -15,9 +15,6 @@ import android.provider.MediaStore; import android.util.Log; import android.widget.Toast; -import androidx.core.graphics.ColorUtils; -import androidx.exifinterface.media.ExifInterface; - import com.google.zxing.BinaryBitmap; import com.google.zxing.LuminanceSource; import com.google.zxing.MultiFormatReader; @@ -37,10 +34,11 @@ import java.util.Calendar; import java.util.Currency; import java.util.Date; import java.util.GregorianCalendar; -import java.util.HashMap; import java.util.Locale; import java.util.Map; +import androidx.core.graphics.ColorUtils; +import androidx.exifinterface.media.ExifInterface; import protect.card_locker.preferences.Settings; public class Utils { diff --git a/app/src/main/java/protect/card_locker/preferences/Settings.java b/app/src/main/java/protect/card_locker/preferences/Settings.java index aed6c3858..a28ac5f8a 100644 --- a/app/src/main/java/protect/card_locker/preferences/Settings.java +++ b/app/src/main/java/protect/card_locker/preferences/Settings.java @@ -3,13 +3,12 @@ package protect.card_locker.preferences; import android.content.Context; import android.content.SharedPreferences; +import java.util.Locale; + import androidx.annotation.IntegerRes; import androidx.annotation.StringRes; import androidx.appcompat.app.AppCompatDelegate; import androidx.preference.PreferenceManager; - -import java.util.Locale; - import protect.card_locker.R; import protect.card_locker.Utils; diff --git a/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java b/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java index 7fbaf0418..1bf4d8df1 100644 --- a/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java +++ b/app/src/main/java/protect/card_locker/preferences/SettingsActivity.java @@ -1,10 +1,13 @@ package protect.card_locker.preferences; -import android.content.Context; import android.os.Bundle; import android.view.MenuItem; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.widget.Toolbar; @@ -14,11 +17,6 @@ import androidx.fragment.app.FragmentActivity; import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - import nl.invissvenska.numberpickerpreference.NumberDialogPreference; import nl.invissvenska.numberpickerpreference.NumberPickerPreferenceDialogFragment; import protect.card_locker.CatimaAppCompatActivity; diff --git a/app/src/main/res/drawable/active_dot.xml b/app/src/main/res/drawable/active_dot.xml new file mode 100644 index 000000000..093c5de27 --- /dev/null +++ b/app/src/main/res/drawable/active_dot.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/inactive_dot.xml b/app/src/main/res/drawable/inactive_dot.xml new file mode 100644 index 000000000..91fb8b14a --- /dev/null +++ b/app/src/main/res/drawable/inactive_dot.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file 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 571eb4918..7f46e2270 100644 --- a/app/src/main/res/layout/loyalty_card_view_layout.xml +++ b/app/src/main/res/layout/loyalty_card_view_layout.xml @@ -56,18 +56,19 @@ android:contentDescription="@string/moveBarcodeToTopOfScreen" app:tint="#ffffff" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@+id/barcode" + app:layout_constraintBottom_toTopOf="@+id/mainImage" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> + + - - - - - - - - - - - - - - - #B53F3F #E87575 #840000 + #484848 #ffc107 #fff350 #c79100 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6b97d2d89..003194f04 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -241,4 +241,5 @@ Made possible by: %s Toggle showing more info + Swipe or long press to switch images diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 5f901bd6d..6f865763d 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -4,6 +4,7 @@ @color/colorPrimary @color/colorPrimaryDark + 1.5 @color/colorSecondary @color/colorPrimary @color/colorPrimary diff --git a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java index 27aaf2f72..1043005a9 100644 --- a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java +++ b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java @@ -23,6 +23,7 @@ import android.widget.Button; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.TextView; @@ -1270,11 +1271,12 @@ public class LoyaltyCardViewActivityTest assertEquals(false, activity.isFinishing()); - ImageView barcodeImage = activity.findViewById(R.id.barcode); + ImageView mainImage = activity.findViewById(R.id.mainImage); View collapsingToolbarLayout = activity.findViewById(R.id.collapsingToolbarLayout); View bottomSheet = activity.findViewById(R.id.bottom_sheet); ImageButton maximizeButton = activity.findViewById(R.id.maximizeButton); ImageButton minimizeButton = activity.findViewById(R.id.minimizeButton); + LinearLayout dotIndicator = activity.findViewById(R.id.dotIndicator); FloatingActionButton editButton = activity.findViewById(R.id.fabEdit); SeekBar barcodeScaler = activity.findViewById(R.id.barcodeScaler); @@ -1290,9 +1292,10 @@ public class LoyaltyCardViewActivityTest assertEquals(View.GONE, minimizeButton.getVisibility()); assertEquals(View.VISIBLE, editButton.getVisibility()); assertEquals(View.GONE, barcodeScaler.getVisibility()); + assertEquals(View.GONE, dotIndicator.getVisibility()); // We have no images, only a barcode - // Click barcode to toggle fullscreen - barcodeImage.performClick(); + // Click maximize button to activate fullscreen + maximizeButton.performClick(); shadowOf(getMainLooper()).idle(); // Android should be in fullscreen mode @@ -1307,9 +1310,10 @@ public class LoyaltyCardViewActivityTest assertEquals(View.VISIBLE, minimizeButton.getVisibility()); assertEquals(View.GONE, editButton.getVisibility()); assertEquals(View.VISIBLE, barcodeScaler.getVisibility()); + assertEquals(View.GONE, dotIndicator.getVisibility()); // We have no images, only a barcode - // Clicking barcode again should deactivate fullscreen mode - barcodeImage.performClick(); + // Clicking minimize button should deactivate fullscreen mode + minimizeButton.performClick(); shadowOf(getMainLooper()).idle(); uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility(); assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions); @@ -1320,9 +1324,10 @@ public class LoyaltyCardViewActivityTest assertEquals(View.GONE, minimizeButton.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 - barcodeImage.performClick(); + maximizeButton.performClick(); shadowOf(getMainLooper()).idle(); uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility(); assertEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions); @@ -1333,6 +1338,7 @@ public class LoyaltyCardViewActivityTest assertEquals(View.VISIBLE, minimizeButton.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(); @@ -1346,6 +1352,7 @@ public class LoyaltyCardViewActivityTest assertEquals(View.GONE, minimizeButton.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();