mirror of
https://github.com/CatimaLoyalty/Android.git
synced 2026-01-04 04:57:57 -05:00
1223 lines
48 KiB
Java
1223 lines
48 KiB
Java
package protect.card_locker;
|
|
|
|
import android.content.ActivityNotFoundException;
|
|
import android.content.Intent;
|
|
import android.content.pm.ActivityInfo;
|
|
import android.content.res.ColorStateList;
|
|
import android.content.res.Configuration;
|
|
import android.database.sqlite.SQLiteDatabase;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.Color;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.os.Build;
|
|
import android.os.Bundle;
|
|
import android.text.InputType;
|
|
import android.text.SpannableStringBuilder;
|
|
import android.text.Spanned;
|
|
import android.text.TextUtils;
|
|
import android.text.method.DigitsKeyListener;
|
|
import android.text.style.ForegroundColorSpan;
|
|
import android.text.util.Linkify;
|
|
import android.util.Log;
|
|
import android.view.KeyEvent;
|
|
import android.view.Menu;
|
|
import android.view.MenuItem;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.ViewTreeObserver;
|
|
import android.view.Window;
|
|
import android.view.WindowInsets;
|
|
import android.view.WindowInsetsController;
|
|
import android.view.WindowManager;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.ImageButton;
|
|
import android.widget.ImageView;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.SeekBar;
|
|
import android.widget.TextView;
|
|
import android.widget.Toast;
|
|
|
|
import androidx.activity.OnBackPressedCallback;
|
|
import androidx.annotation.StringRes;
|
|
import androidx.appcompat.app.ActionBar;
|
|
import androidx.appcompat.app.AlertDialog;
|
|
import androidx.appcompat.widget.Toolbar;
|
|
import androidx.core.content.FileProvider;
|
|
import androidx.core.graphics.BlendModeColorFilterCompat;
|
|
import androidx.core.graphics.BlendModeCompat;
|
|
import androidx.core.graphics.ColorUtils;
|
|
import androidx.core.view.ViewCompat;
|
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
|
|
|
import com.google.android.material.color.MaterialColors;
|
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
import com.google.android.material.textfield.TextInputEditText;
|
|
|
|
import java.io.File;
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.math.BigDecimal;
|
|
import java.text.DateFormat;
|
|
import java.text.ParseException;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
import java.util.function.Predicate;
|
|
|
|
import protect.card_locker.async.TaskHandler;
|
|
import protect.card_locker.databinding.LoyaltyCardViewLayoutBinding;
|
|
import protect.card_locker.preferences.Settings;
|
|
|
|
public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements BarcodeImageWriterResultCallback {
|
|
private LoyaltyCardViewLayoutBinding binding;
|
|
private static final String TAG = "Catima";
|
|
|
|
int loyaltyCardId;
|
|
ArrayList<Integer> cardList;
|
|
|
|
LoyaltyCard loyaltyCard;
|
|
List<Group> loyaltyCardGroups;
|
|
boolean rotationEnabled;
|
|
SQLiteDatabase database;
|
|
ImportURIHelper importURIHelper;
|
|
Settings settings;
|
|
|
|
String cardIdString;
|
|
String barcodeIdString;
|
|
CatimaBarcode format;
|
|
|
|
Bitmap frontImageBitmap;
|
|
Bitmap backImageBitmap;
|
|
|
|
boolean backgroundNeedsDarkIcons;
|
|
boolean isFullscreen = false;
|
|
ImageView barcodeRenderTarget;
|
|
int mainImageIndex = 0;
|
|
List<ImageType> imageTypes;
|
|
|
|
static final String STATE_IMAGEINDEX = "imageIndex";
|
|
static final String STATE_FULLSCREEN = "isFullscreen";
|
|
|
|
static final String BUNDLE_ID = "id";
|
|
static final String BUNDLE_CARDLIST = "cardList";
|
|
static final String BUNDLE_TRANSITION_RIGHT = "transition_right";
|
|
|
|
final private TaskHandler mTasks = new TaskHandler();
|
|
Runnable barcodeImageGenerationFinishedCallback;
|
|
|
|
private long initTime = System.currentTimeMillis();
|
|
|
|
@Override
|
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
if (settings.useVolumeKeysForNavigation()) {
|
|
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
|
|
// Navigate to the previous card
|
|
if (initTime < (System.currentTimeMillis() - 1000)) {
|
|
prevNextCard(false);
|
|
}
|
|
return true;
|
|
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
|
|
// Navigate to the next card
|
|
if (initTime < (System.currentTimeMillis() - 1000)) {
|
|
prevNextCard(true);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return super.onKeyDown(keyCode, event);
|
|
}
|
|
|
|
public void onMainImageTap() {
|
|
// If we're in fullscreen, leave fullscreen
|
|
if (isFullscreen) {
|
|
setFullscreen(false);
|
|
return;
|
|
}
|
|
|
|
ImageType imageType = imageTypes.get(mainImageIndex);
|
|
|
|
// If the barcode is shown, switch to fullscreen layout
|
|
if (imageType == ImageType.BARCODE) {
|
|
setFullscreen(true);
|
|
return;
|
|
}
|
|
|
|
// If this is an image, open it in the gallery.
|
|
openImageInGallery(imageType);
|
|
}
|
|
|
|
private void openImageInGallery(ImageType imageType) {
|
|
File file = null;
|
|
|
|
switch (imageType) {
|
|
case ICON:
|
|
file = Utils.retrieveCardImageAsFile(this, loyaltyCardId, ImageLocationType.icon);
|
|
break;
|
|
case IMAGE_FRONT:
|
|
file = Utils.retrieveCardImageAsFile(this, loyaltyCardId, ImageLocationType.front);
|
|
break;
|
|
case IMAGE_BACK:
|
|
file = Utils.retrieveCardImageAsFile(this, loyaltyCardId, ImageLocationType.back);
|
|
break;
|
|
case BARCODE:
|
|
Toast.makeText(this, R.string.barcodeLongPressMessage, Toast.LENGTH_SHORT).show();
|
|
return;
|
|
default:
|
|
// Empty default case for now to keep the spotBugsRelease job happy
|
|
}
|
|
|
|
// Do nothing if there is no file
|
|
if (file == null) {
|
|
Toast.makeText(this, R.string.failedToRetrieveImageFile, Toast.LENGTH_SHORT).show();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
Intent intent = new Intent(Intent.ACTION_VIEW)
|
|
.setDataAndType(FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID, file), "image/*")
|
|
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
startActivity(intent);
|
|
} catch (ActivityNotFoundException e) {
|
|
// Display a toast message if an image viewer is not installed on device
|
|
Toast.makeText(this, R.string.failedLaunchingPhotoPicker, Toast.LENGTH_SHORT).show();
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onBarcodeImageWriterResult(boolean success) {
|
|
if (!success) {
|
|
imageTypes.remove(ImageType.BARCODE);
|
|
|
|
setStateBasedOnImageTypes();
|
|
|
|
// Call correct drawMainImage
|
|
setFullscreen(isFullscreen);
|
|
|
|
Toast.makeText(LoyaltyCardViewActivity.this, getString(R.string.wrongValueForBarcodeType), Toast.LENGTH_LONG).show();
|
|
}
|
|
}
|
|
|
|
enum ImageType {
|
|
NONE,
|
|
ICON,
|
|
BARCODE,
|
|
IMAGE_FRONT,
|
|
IMAGE_BACK
|
|
}
|
|
|
|
private void extractIntentFields(Intent intent) {
|
|
final Bundle b = intent.getExtras();
|
|
loyaltyCardId = b != null ? b.getInt(BUNDLE_ID) : 0;
|
|
cardList = b != null ? b.getIntegerArrayList(BUNDLE_CARDLIST) : null;
|
|
Log.d(TAG, "View activity: id=" + loyaltyCardId);
|
|
}
|
|
|
|
private void setScalerGuideline(int zoomLevel) {
|
|
float scale = zoomLevel / 100f;
|
|
|
|
if (format != null && format.isSquare()) {
|
|
binding.scalerGuideline.setGuidelinePercent(0.75f * scale);
|
|
} else {
|
|
binding.scalerGuideline.setGuidelinePercent(0.5f * scale);
|
|
}
|
|
|
|
}
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
if (savedInstanceState == null) {
|
|
Bundle incomingIntentExtras = getIntent().getExtras();
|
|
|
|
if (incomingIntentExtras == null) {
|
|
Toast.makeText(this, R.string.noCardExistsError, Toast.LENGTH_LONG).show();
|
|
finish();
|
|
return;
|
|
}
|
|
|
|
int transitionRight = incomingIntentExtras.getInt(BUNDLE_TRANSITION_RIGHT, -1);
|
|
if (transitionRight == 1) {
|
|
// right side transition
|
|
overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
|
|
} else if (transitionRight == 0) {
|
|
// left side transition
|
|
overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);
|
|
}
|
|
}
|
|
|
|
super.onCreate(savedInstanceState);
|
|
binding = LoyaltyCardViewLayoutBinding.inflate(getLayoutInflater());
|
|
setContentView(binding.getRoot());
|
|
Toolbar toolbar = binding.toolbar;
|
|
setSupportActionBar(toolbar);
|
|
|
|
settings = new Settings(this);
|
|
|
|
String cardOrientation = settings.getCardViewOrientation();
|
|
if (cardOrientation.equals(getString(R.string.settings_key_follow_sensor_orientation))) {
|
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
|
|
} else if (cardOrientation.equals(getString(R.string.settings_key_lock_on_opening_orientation))) {
|
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
|
|
} else if (cardOrientation.equals(getString(R.string.settings_key_portrait_orientation))) {
|
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
|
} else if (cardOrientation.equals(getString(R.string.settings_key_landscape_orientation))) {
|
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
|
} else {
|
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
|
}
|
|
|
|
if (savedInstanceState != null) {
|
|
mainImageIndex = savedInstanceState.getInt(STATE_IMAGEINDEX);
|
|
isFullscreen = savedInstanceState.getBoolean(STATE_FULLSCREEN);
|
|
}
|
|
|
|
extractIntentFields(getIntent());
|
|
|
|
setContentView(binding.getRoot());
|
|
|
|
database = new DBHelper(this).getWritableDatabase();
|
|
importURIHelper = new ImportURIHelper(this);
|
|
|
|
binding.barcodeScaler.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
|
@Override
|
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
|
if (!fromUser) {
|
|
Log.d(TAG, "non user triggered onProgressChanged, ignoring, progress is " + progress);
|
|
return;
|
|
}
|
|
Log.d(TAG, "Progress is " + progress);
|
|
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);
|
|
|
|
setScalerGuideline(loyaltyCard.zoomLevel);
|
|
|
|
drawMainImage(mainImageIndex, true, isFullscreen);
|
|
}
|
|
|
|
@Override
|
|
public void onStartTrackingTouch(SeekBar seekBar) {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
|
|
|
}
|
|
});
|
|
|
|
rotationEnabled = true;
|
|
|
|
binding.fullscreenButtonMinimize.setOnClickListener(v -> setFullscreen(false));
|
|
|
|
binding.fabEdit.setOnClickListener(v -> {
|
|
Intent intent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
|
|
Bundle bundle = new Bundle();
|
|
bundle.putInt(LoyaltyCardEditActivity.BUNDLE_ID, loyaltyCardId);
|
|
bundle.putBoolean(LoyaltyCardEditActivity.BUNDLE_UPDATE, true);
|
|
intent.putExtras(bundle);
|
|
startActivity(intent);
|
|
});
|
|
binding.fabEdit.bringToFront();
|
|
|
|
binding.bottomAppBarInfoButton.setOnClickListener(view -> showInfoDialog());
|
|
binding.bottomAppBarPreviousButton.setOnClickListener(view -> prevNextCard(false));
|
|
binding.bottomAppBarNextButton.setOnClickListener(view -> prevNextCard(true));
|
|
binding.bottomAppBarUpdateBalanceButton.setOnClickListener(view -> showBalanceUpdateDialog());
|
|
|
|
binding.iconContainer.setOnClickListener(view -> {
|
|
if (loyaltyCard.getImageThumbnail(this) != null) {
|
|
openImageInGallery(ImageType.ICON);
|
|
} else {
|
|
Toast.makeText(LoyaltyCardViewActivity.this, R.string.icon_header_click_text, Toast.LENGTH_LONG).show();
|
|
}
|
|
});
|
|
binding.iconContainer.setOnLongClickListener(view -> {
|
|
Intent intent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
|
|
Bundle bundle = new Bundle();
|
|
bundle.putInt(LoyaltyCardEditActivity.BUNDLE_ID, loyaltyCardId);
|
|
bundle.putBoolean(LoyaltyCardEditActivity.BUNDLE_UPDATE, true);
|
|
bundle.putBoolean(LoyaltyCardEditActivity.BUNDLE_OPEN_SET_ICON_MENU, true);
|
|
intent.putExtras(bundle);
|
|
startActivity(intent);
|
|
finish();
|
|
|
|
return true;
|
|
});
|
|
|
|
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;
|
|
});
|
|
binding.fullscreenImage.setOnClickListener(view -> onMainImageTap());
|
|
|
|
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
|
|
@Override
|
|
public void handleOnBackPressed() {
|
|
if (isFullscreen) {
|
|
setFullscreen(false);
|
|
} else {
|
|
finish();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private SpannableStringBuilder padSpannableString(SpannableStringBuilder spannableStringBuilder) {
|
|
if (spannableStringBuilder.length() > 0) {
|
|
spannableStringBuilder.append("\n\n");
|
|
}
|
|
|
|
return spannableStringBuilder;
|
|
}
|
|
|
|
private boolean hasBalance(LoyaltyCard loyaltyCard) {
|
|
return !loyaltyCard.balance.equals(new BigDecimal(0));
|
|
}
|
|
|
|
private void showInfoDialog() {
|
|
AlertDialog.Builder infoDialog = new MaterialAlertDialogBuilder(this);
|
|
|
|
int dialogContentPadding = getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_padding);
|
|
infoDialog.setTitle(loyaltyCard.store);
|
|
|
|
TextView infoTextview = new TextView(this);
|
|
infoTextview.setPadding(
|
|
dialogContentPadding,
|
|
dialogContentPadding / 2,
|
|
dialogContentPadding,
|
|
0
|
|
);
|
|
infoTextview.setAutoLinkMask(Linkify.ALL);
|
|
infoTextview.setTextIsSelectable(true);
|
|
|
|
SpannableStringBuilder infoText = new SpannableStringBuilder();
|
|
if (!loyaltyCard.note.isEmpty()) {
|
|
infoText.append(loyaltyCard.note);
|
|
}
|
|
|
|
if (loyaltyCardGroups.size() > 0) {
|
|
List<String> groupNames = new ArrayList<>();
|
|
for (Group group : loyaltyCardGroups) {
|
|
groupNames.add(group._id);
|
|
}
|
|
|
|
padSpannableString(infoText);
|
|
infoText.append(getString(R.string.groupsList, TextUtils.join(", ", groupNames)));
|
|
}
|
|
|
|
if (hasBalance(loyaltyCard)) {
|
|
padSpannableString(infoText);
|
|
infoText.append(getString(R.string.balanceSentence, Utils.formatBalance(this, loyaltyCard.balance, loyaltyCard.balanceType)));
|
|
}
|
|
|
|
appendDateInfo(infoText, loyaltyCard.validFrom, (Utils::isNotYetValid), R.string.validFromSentence, R.string.validFromSentence);
|
|
|
|
appendDateInfo(infoText, loyaltyCard.expiry, (Utils::hasExpired), R.string.expiryStateSentenceExpired, R.string.expiryStateSentence);
|
|
|
|
infoTextview.setText(infoText);
|
|
|
|
infoDialog.setView(infoTextview);
|
|
infoDialog.setPositiveButton(R.string.ok, (dialogInterface, i) -> dialogInterface.dismiss());
|
|
infoDialog.create().show();
|
|
}
|
|
|
|
private void appendDateInfo(SpannableStringBuilder infoText, Date date, Predicate<Date> dateCheck, @StringRes int dateCheckTrueString, @StringRes int dateCheckFalseString) {
|
|
if (date != null) {
|
|
String formattedDate = DateFormat.getDateInstance(DateFormat.LONG).format(date);
|
|
|
|
padSpannableString(infoText);
|
|
if (dateCheck.test(date)) {
|
|
int start = infoText.length();
|
|
infoText.append(getString(dateCheckTrueString, formattedDate));
|
|
infoText.setSpan(new ForegroundColorSpan(Color.RED), start, infoText.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
|
} else {
|
|
infoText.append(getString(dateCheckFalseString, formattedDate));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void showBalanceUpdateDialog() {
|
|
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
|
|
|
|
// Header
|
|
builder.setTitle(R.string.updateBalanceTitle);
|
|
|
|
// Layout
|
|
FrameLayout container = new FrameLayout(this);
|
|
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
|
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
);
|
|
int contentPadding = getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_padding);
|
|
params.leftMargin = contentPadding;
|
|
params.topMargin = contentPadding / 2;
|
|
params.rightMargin = contentPadding;
|
|
|
|
LinearLayout layout = new LinearLayout(this);
|
|
layout.setOrientation(LinearLayout.VERTICAL);
|
|
|
|
TextView currentTextview = new TextView(this);
|
|
currentTextview.setText(getString(R.string.currentBalanceSentence, Utils.formatBalance(this, loyaltyCard.balance, loyaltyCard.balanceType)));
|
|
layout.addView(currentTextview);
|
|
|
|
final TextInputEditText input = new TextInputEditText(this);
|
|
input.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
|
|
input.setKeyListener(DigitsKeyListener.getInstance("0123456789,."));
|
|
input.setHint(R.string.updateBalanceHint);
|
|
|
|
layout.addView(input);
|
|
layout.setLayoutParams(params);
|
|
container.addView(layout);
|
|
|
|
// Set layout
|
|
builder.setView(container);
|
|
|
|
// Buttons
|
|
builder.setPositiveButton(R.string.spend, (dialogInterface, i) -> {
|
|
// Calculate and update balance
|
|
try {
|
|
BigDecimal balanceChange = Utils.parseBalance(input.getText().toString(), loyaltyCard.balanceType);
|
|
BigDecimal newBalance = loyaltyCard.balance.subtract(balanceChange).max(new BigDecimal(0));
|
|
DBHelper.updateLoyaltyCardBalance(database, loyaltyCardId, newBalance);
|
|
} catch (ParseException e) {
|
|
Toast.makeText(getApplicationContext(), R.string.amountParsingFailed, Toast.LENGTH_LONG).show();
|
|
}
|
|
|
|
// Reload state
|
|
this.onResume();
|
|
|
|
// Show new balance
|
|
Toast.makeText(getApplicationContext(), getString(R.string.newBalanceSentence, Utils.formatBalance(this, loyaltyCard.balance, loyaltyCard.balanceType)), Toast.LENGTH_LONG).show();
|
|
});
|
|
builder.setNegativeButton(R.string.receive, (dialogInterface, i) -> {
|
|
// Calculate and update balance
|
|
try {
|
|
BigDecimal balanceChange = Utils.parseBalance(input.getText().toString(), loyaltyCard.balanceType);
|
|
BigDecimal newBalance = loyaltyCard.balance.add(balanceChange);
|
|
DBHelper.updateLoyaltyCardBalance(database, loyaltyCardId, newBalance);
|
|
} catch (ParseException e) {
|
|
Toast.makeText(getApplicationContext(), R.string.amountParsingFailed, Toast.LENGTH_LONG).show();
|
|
}
|
|
|
|
// Reload state
|
|
this.onResume();
|
|
|
|
// Show new balance
|
|
Toast.makeText(getApplicationContext(), getString(R.string.newBalanceSentence, Utils.formatBalance(this, loyaltyCard.balance, loyaltyCard.balanceType)), Toast.LENGTH_LONG).show();
|
|
});
|
|
builder.setNeutralButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
|
|
AlertDialog dialog = builder.create();
|
|
|
|
// Now that the dialog exists, we can bind something that affects the buttons
|
|
input.addTextChangedListener(new SimpleTextWatcher() {
|
|
@Override
|
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
BigDecimal balanceChange;
|
|
|
|
try {
|
|
balanceChange = Utils.parseBalance(s.toString(), loyaltyCard.balanceType);
|
|
} catch (ParseException e) {
|
|
input.setError(getString(R.string.amountParsingFailed));
|
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(false);
|
|
return;
|
|
}
|
|
|
|
input.setError(null);
|
|
if (balanceChange.equals(new BigDecimal(0))) {
|
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(false);
|
|
} else {
|
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
|
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(true);
|
|
}
|
|
}
|
|
});
|
|
|
|
dialog.show();
|
|
|
|
// Disable buttons (must be done **after** dialog is shown to prevent crash
|
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(false);
|
|
|
|
// Set focus on input field
|
|
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
|
input.requestFocus();
|
|
}
|
|
|
|
private void setBottomAppBarButtonState() {
|
|
if (!loyaltyCard.note.isEmpty() || !loyaltyCardGroups.isEmpty() || hasBalance(loyaltyCard) || loyaltyCard.validFrom != null || loyaltyCard.expiry != null) {
|
|
binding.bottomAppBarInfoButton.setVisibility(View.VISIBLE);
|
|
} else {
|
|
binding.bottomAppBarInfoButton.setVisibility(View.GONE);
|
|
}
|
|
|
|
if (cardList == null || cardList.size() == 1) {
|
|
binding.bottomAppBarPreviousButton.setVisibility(View.GONE);
|
|
binding.bottomAppBarNextButton.setVisibility(View.GONE);
|
|
} else {
|
|
binding.bottomAppBarPreviousButton.setVisibility(View.VISIBLE);
|
|
binding.bottomAppBarNextButton.setVisibility(View.VISIBLE);
|
|
}
|
|
|
|
binding.bottomAppBarUpdateBalanceButton.setVisibility(hasBalance(loyaltyCard) ? View.VISIBLE : View.GONE);
|
|
}
|
|
|
|
private void prevNextCard(boolean next) {
|
|
// If we're in RTL layout, we want the "left" button to be "next" instead of "previous"
|
|
// So we swap next around
|
|
boolean transitionRight = next;
|
|
if (getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
|
|
next = !next;
|
|
}
|
|
|
|
int cardListPosition = cardList.indexOf(loyaltyCardId);
|
|
|
|
if (next) {
|
|
if (cardListPosition == cardList.size() - 1) {
|
|
cardListPosition = 0;
|
|
} else {
|
|
cardListPosition = cardListPosition + 1;
|
|
}
|
|
} else {
|
|
if (cardListPosition == 0) {
|
|
cardListPosition = cardList.size() - 1;
|
|
} else {
|
|
cardListPosition = cardListPosition - 1;
|
|
}
|
|
}
|
|
|
|
loyaltyCardId = cardList.get(cardListPosition);
|
|
|
|
// Restart activity with new card id and index
|
|
Intent intent = getIntent();
|
|
Bundle b = intent.getExtras();
|
|
b.putInt(BUNDLE_ID, loyaltyCardId);
|
|
b.putInt(BUNDLE_TRANSITION_RIGHT, transitionRight ? 1 : 0);
|
|
intent.putExtras(b);
|
|
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
startActivity(intent);
|
|
}
|
|
|
|
@Override
|
|
public void onNewIntent(Intent intent) {
|
|
super.onNewIntent(intent);
|
|
|
|
Log.i(TAG, "Received new intent");
|
|
extractIntentFields(intent);
|
|
}
|
|
|
|
@Override
|
|
public void onSaveInstanceState(Bundle savedInstanceState) {
|
|
savedInstanceState.putInt(STATE_IMAGEINDEX, mainImageIndex);
|
|
savedInstanceState.putBoolean(STATE_FULLSCREEN, isFullscreen);
|
|
super.onSaveInstanceState(savedInstanceState);
|
|
}
|
|
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
activityOverridesNavBarColor = true;
|
|
super.onResume();
|
|
|
|
Log.i(TAG, "To view card: " + loyaltyCardId);
|
|
|
|
Window window = getWindow();
|
|
if (window != null) {
|
|
// Hide the keyboard if still shown (could be the case when returning from edit activity
|
|
window.setSoftInputMode(
|
|
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
|
|
);
|
|
|
|
WindowManager.LayoutParams attributes = window.getAttributes();
|
|
|
|
// The brightness value is on a scale from [0, ..., 1], where
|
|
// '1' is the brightest. We attempt to maximize the brightness
|
|
// to help barcode readers scan the barcode.
|
|
if (settings.useMaxBrightnessDisplayingBarcode()) {
|
|
attributes.screenBrightness = 1F;
|
|
}
|
|
|
|
if (settings.getKeepScreenOn()) {
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
}
|
|
|
|
if (settings.getDisableLockscreenWhileViewingCard()) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
|
setShowWhenLocked(true);
|
|
} else {
|
|
showWhenLockedSdkLessThan27(window);
|
|
}
|
|
}
|
|
|
|
window.setAttributes(attributes);
|
|
}
|
|
|
|
loyaltyCard = DBHelper.getLoyaltyCard(this, database, loyaltyCardId);
|
|
if (loyaltyCard == null) {
|
|
Log.w(TAG, "Could not lookup loyalty card " + loyaltyCardId);
|
|
Toast.makeText(this, R.string.noCardExistsError, Toast.LENGTH_LONG).show();
|
|
finish();
|
|
return;
|
|
}
|
|
|
|
setTitle(loyaltyCard.store);
|
|
|
|
loyaltyCardGroups = DBHelper.getLoyaltyCardGroups(database, loyaltyCardId);
|
|
|
|
showHideElementsForScreenSize();
|
|
|
|
format = loyaltyCard.barcodeType;
|
|
cardIdString = loyaltyCard.cardId;
|
|
barcodeIdString = loyaltyCard.barcodeId;
|
|
|
|
binding.mainImageDescription.setText(loyaltyCard.cardId);
|
|
|
|
// Display full text on click in case it doesn't fit in a single line
|
|
binding.mainImageDescription.setOnClickListener(v -> {
|
|
if (mainImageIndex != 0) {
|
|
// Don't show cardId dialog, we're displaying something else
|
|
return;
|
|
}
|
|
|
|
TextView cardIdView = new TextView(LoyaltyCardViewActivity.this);
|
|
cardIdView.setText(loyaltyCard.cardId);
|
|
cardIdView.setTextIsSelectable(true);
|
|
int contentPadding = getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_padding);
|
|
cardIdView.setPadding(contentPadding, contentPadding / 2, contentPadding, 0);
|
|
|
|
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(LoyaltyCardViewActivity.this);
|
|
builder.setTitle(R.string.cardId);
|
|
builder.setView(cardIdView);
|
|
builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> dialogInterface.dismiss());
|
|
AlertDialog dialog = builder.create();
|
|
dialog.show();
|
|
});
|
|
|
|
int backgroundHeaderColor = Utils.getHeaderColor(this, loyaltyCard);
|
|
|
|
// Also apply colours to UI elements
|
|
int darkenedColor = ColorUtils.blendARGB(backgroundHeaderColor, Color.BLACK, 0.1f);
|
|
binding.barcodeScaler.setProgressTintList(ColorStateList.valueOf(darkenedColor));
|
|
binding.barcodeScaler.setThumbTintList(ColorStateList.valueOf(darkenedColor));
|
|
|
|
// Set bottomAppBar and system navigation bar color
|
|
binding.bottomAppBar.setBackgroundColor(darkenedColor);
|
|
Utils.setNavigationBarColor(null, window, darkenedColor, Utils.needsDarkForeground(darkenedColor));
|
|
|
|
int complementaryColor = Utils.getComplementaryColor(darkenedColor);
|
|
binding.fabEdit.setBackgroundTintList(ColorStateList.valueOf(complementaryColor));
|
|
Drawable editButtonIcon = binding.fabEdit.getDrawable();
|
|
editButtonIcon.mutate();
|
|
editButtonIcon.setTint(Utils.needsDarkForeground(complementaryColor) ? Color.BLACK : Color.WHITE);
|
|
binding.fabEdit.setImageDrawable(editButtonIcon);
|
|
|
|
Bitmap icon = loyaltyCard.getImageThumbnail(this);
|
|
Utils.setIconOrTextWithBackground(this, loyaltyCard, icon, binding.iconImage, binding.iconText, 1);
|
|
|
|
// If the background is very bright, we should use dark icons
|
|
backgroundNeedsDarkIcons = Utils.needsDarkForeground(backgroundHeaderColor);
|
|
|
|
fixBottomAppBarImageButtonColor(binding.bottomAppBarInfoButton);
|
|
fixBottomAppBarImageButtonColor(binding.bottomAppBarPreviousButton);
|
|
fixBottomAppBarImageButtonColor(binding.bottomAppBarNextButton);
|
|
fixBottomAppBarImageButtonColor(binding.bottomAppBarUpdateBalanceButton);
|
|
setBottomAppBarButtonState();
|
|
|
|
boolean isBarcodeSupported;
|
|
if (format != null && !format.isSupported()) {
|
|
isBarcodeSupported = false;
|
|
|
|
Toast.makeText(this, getString(R.string.unsupportedBarcodeType), Toast.LENGTH_LONG).show();
|
|
} else if (format == null) {
|
|
isBarcodeSupported = false;
|
|
} else {
|
|
isBarcodeSupported = true;
|
|
}
|
|
|
|
imageTypes = new ArrayList<>();
|
|
|
|
if (isBarcodeSupported) {
|
|
imageTypes.add(ImageType.BARCODE);
|
|
}
|
|
|
|
frontImageBitmap = loyaltyCard.getImageFront(this);
|
|
if (frontImageBitmap != null) {
|
|
imageTypes.add(ImageType.IMAGE_FRONT);
|
|
}
|
|
|
|
backImageBitmap = loyaltyCard.getImageBack(this);
|
|
if (backImageBitmap != null) {
|
|
imageTypes.add(ImageType.IMAGE_BACK);
|
|
}
|
|
|
|
setStateBasedOnImageTypes();
|
|
|
|
setFullscreen(isFullscreen);
|
|
|
|
DBHelper.updateLoyaltyCardLastUsed(database, loyaltyCard.id);
|
|
|
|
invalidateOptionsMenu();
|
|
|
|
ShortcutHelper.updateShortcuts(this, loyaltyCard);
|
|
}
|
|
|
|
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")
|
|
private void showWhenLockedSdkLessThan27(Window window) {
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
|
|
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
|
|
}
|
|
|
|
private void fixBottomAppBarImageButtonColor(ImageButton imageButton) {
|
|
imageButton.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(backgroundNeedsDarkIcons ? Color.BLACK : Color.WHITE, BlendModeCompat.SRC_ATOP));
|
|
}
|
|
|
|
@Override
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
|
getMenuInflater().inflate(R.menu.card_view_menu, menu);
|
|
|
|
return super.onCreateOptionsMenu(menu);
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
|
super.onPrepareOptionsMenu(menu);
|
|
|
|
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;
|
|
}
|
|
|
|
@Override
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
|
int id = item.getItemId();
|
|
|
|
if (id == android.R.id.home) {
|
|
finish();
|
|
} else if (id == R.id.action_share) {
|
|
try {
|
|
importURIHelper.startShareIntent(Arrays.asList(loyaltyCard));
|
|
} catch (UnsupportedEncodingException e) {
|
|
Toast.makeText(LoyaltyCardViewActivity.this, R.string.failedGeneratingShareURL, Toast.LENGTH_LONG).show();
|
|
e.printStackTrace();
|
|
}
|
|
|
|
return true;
|
|
} else if (id == R.id.action_duplicate) {
|
|
Intent intent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
|
|
Bundle bundle = new Bundle();
|
|
bundle.putInt(LoyaltyCardEditActivity.BUNDLE_ID, loyaltyCardId);
|
|
bundle.putBoolean(LoyaltyCardEditActivity.BUNDLE_DUPLICATE_ID, true);
|
|
intent.putExtras(bundle);
|
|
startActivity(intent);
|
|
|
|
return true;
|
|
} else if (id == R.id.action_star_unstar) {
|
|
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) {
|
|
DBHelper.updateLoyaltyCardArchiveStatus(database, loyaltyCardId, 1);
|
|
Toast.makeText(LoyaltyCardViewActivity.this, R.string.archived, Toast.LENGTH_LONG).show();
|
|
|
|
ShortcutHelper.removeShortcut(LoyaltyCardViewActivity.this, loyaltyCardId);
|
|
|
|
// Re-init loyaltyCard with new data from DB
|
|
onResume();
|
|
invalidateOptionsMenu();
|
|
|
|
return true;
|
|
} else if (id == R.id.action_unarchive) {
|
|
DBHelper.updateLoyaltyCardArchiveStatus(database, loyaltyCardId, 0);
|
|
Toast.makeText(LoyaltyCardViewActivity.this, R.string.unarchived, Toast.LENGTH_LONG).show();
|
|
|
|
// Re-init loyaltyCard with new data from DB
|
|
onResume();
|
|
invalidateOptionsMenu();
|
|
|
|
return true;
|
|
} else if (id == R.id.action_delete) {
|
|
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
|
|
builder.setTitle(R.string.deleteTitle);
|
|
builder.setMessage(R.string.deleteConfirmation);
|
|
builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
|
|
Log.e(TAG, "Deleting card: " + loyaltyCardId);
|
|
|
|
DBHelper.deleteLoyaltyCard(database, LoyaltyCardViewActivity.this, loyaltyCardId);
|
|
|
|
ShortcutHelper.removeShortcut(LoyaltyCardViewActivity.this, loyaltyCardId);
|
|
|
|
finish();
|
|
dialog.dismiss();
|
|
});
|
|
builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
|
|
AlertDialog dialog = builder.create();
|
|
dialog.show();
|
|
|
|
return true;
|
|
}
|
|
|
|
return super.onOptionsItemSelected(item);
|
|
}
|
|
|
|
private void showHideElementsForScreenSize() {
|
|
int orientation = getResources().getConfiguration().orientation;
|
|
// Detect square-ish screens like the Unihertz Titan
|
|
boolean isSmallHeight = getResources().getDisplayMetrics().heightPixels < (getResources().getDisplayMetrics().widthPixels * 1.5);
|
|
|
|
// Treat sqaure-ish screens as
|
|
if (orientation == Configuration.ORIENTATION_LANDSCAPE || isSmallHeight) {
|
|
Log.d(TAG, "Detected landscape mode or square-ish screen");
|
|
binding.iconContainer.setVisibility(View.GONE);
|
|
} else {
|
|
Log.d(TAG, "Detected portrait mode on non square-ish screen");
|
|
binding.iconContainer.setVisibility(View.VISIBLE);
|
|
}
|
|
|
|
enableToolbarBackButton();
|
|
}
|
|
|
|
private void drawBarcode(boolean addPadding) {
|
|
mTasks.flushTaskList(TaskHandler.TYPE.BARCODE, true, false, false);
|
|
|
|
if (format != null) {
|
|
BarcodeImageWriterTask barcodeWriter = new BarcodeImageWriterTask(
|
|
getApplicationContext(),
|
|
barcodeRenderTarget,
|
|
barcodeIdString != null ? barcodeIdString : cardIdString,
|
|
format,
|
|
null,
|
|
false,
|
|
this,
|
|
addPadding);
|
|
mTasks.executeTask(TaskHandler.TYPE.BARCODE, barcodeWriter);
|
|
}
|
|
}
|
|
|
|
private void redrawBarcodeAfterResize(boolean addPadding) {
|
|
if (format != null) {
|
|
barcodeRenderTarget.getViewTreeObserver().addOnGlobalLayoutListener(
|
|
new ViewTreeObserver.OnGlobalLayoutListener() {
|
|
@Override
|
|
public void onGlobalLayout() {
|
|
barcodeRenderTarget.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
|
|
|
Log.d(TAG, "ImageView size now known");
|
|
drawBarcode(addPadding);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private void drawMainImage(int index, boolean waitForResize, boolean isFullscreen) {
|
|
if (imageTypes.isEmpty()) {
|
|
barcodeRenderTarget.setVisibility(View.GONE);
|
|
binding.mainCardView.setCardBackgroundColor(Color.TRANSPARENT);
|
|
binding.mainImageDescription.setTextColor(MaterialColors.getColor(binding.mainImageDescription, com.google.android.material.R.attr.colorOnSurfaceVariant));
|
|
|
|
binding.mainImageDescription.setText(loyaltyCard.cardId);
|
|
return;
|
|
}
|
|
|
|
ImageType wantedImageType = imageTypes.get(index);
|
|
|
|
if (wantedImageType == ImageType.BARCODE) {
|
|
barcodeRenderTarget.setBackgroundColor(Color.WHITE);
|
|
binding.mainCardView.setCardBackgroundColor(Color.WHITE);
|
|
binding.mainImageDescription.setTextColor(getResources().getColor(R.color.md_theme_light_onSurfaceVariant));
|
|
|
|
if (waitForResize) {
|
|
redrawBarcodeAfterResize(!isFullscreen);
|
|
} else {
|
|
drawBarcode(!isFullscreen);
|
|
}
|
|
|
|
binding.mainImageDescription.setText(loyaltyCard.cardId);
|
|
barcodeRenderTarget.setContentDescription(getString(R.string.barcodeImageDescriptionWithType, format.prettyName()));
|
|
} else if (wantedImageType == ImageType.IMAGE_FRONT) {
|
|
barcodeRenderTarget.setImageBitmap(frontImageBitmap);
|
|
barcodeRenderTarget.setBackgroundColor(Color.TRANSPARENT);
|
|
binding.mainCardView.setCardBackgroundColor(Color.TRANSPARENT);
|
|
binding.mainImageDescription.setTextColor(MaterialColors.getColor(binding.mainImageDescription, com.google.android.material.R.attr.colorOnSurfaceVariant));
|
|
|
|
binding.mainImageDescription.setText(getString(R.string.frontImageDescription));
|
|
barcodeRenderTarget.setContentDescription(getString(R.string.frontImageDescription));
|
|
} else if (wantedImageType == ImageType.IMAGE_BACK) {
|
|
barcodeRenderTarget.setImageBitmap(backImageBitmap);
|
|
barcodeRenderTarget.setBackgroundColor(Color.TRANSPARENT);
|
|
binding.mainCardView.setCardBackgroundColor(Color.TRANSPARENT);
|
|
binding.mainImageDescription.setTextColor(MaterialColors.getColor(binding.mainImageDescription, com.google.android.material.R.attr.colorOnSurfaceVariant));
|
|
|
|
binding.mainImageDescription.setText(getString(R.string.backImageDescription));
|
|
barcodeRenderTarget.setContentDescription(getString(R.string.backImageDescription));
|
|
} else {
|
|
throw new IllegalArgumentException("Unknown image type: " + wantedImageType);
|
|
}
|
|
|
|
barcodeRenderTarget.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, isFullscreen);
|
|
|
|
setMainImagePreviousNextButtons();
|
|
setMainImageAccessibility();
|
|
}
|
|
|
|
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)");
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
final ImageButton prevButton;
|
|
final ImageButton nextButton;
|
|
|
|
if (getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
|
|
prevButton = binding.mainRightButton;
|
|
nextButton = binding.mainLeftButton;
|
|
} else {
|
|
prevButton = binding.mainLeftButton;
|
|
nextButton = binding.mainRightButton;
|
|
}
|
|
|
|
// Enable left button if we can go further left
|
|
if (mainImageIndex > 0) {
|
|
prevButton.setVisibility(View.VISIBLE);
|
|
prevButton.setOnClickListener(view -> setMainImage(false, false));
|
|
} else {
|
|
prevButton.setVisibility(View.INVISIBLE);
|
|
prevButton.setOnClickListener(null);
|
|
}
|
|
|
|
// Enable right button if we can go further right
|
|
if (mainImageIndex < (imageTypes.size() - 1)) {
|
|
nextButton.setVisibility(View.VISIBLE);
|
|
nextButton.setOnClickListener(view -> setMainImage(true, false));
|
|
} else {
|
|
nextButton.setVisibility(View.INVISIBLE);
|
|
nextButton.setOnClickListener(null);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* When enabled, hides the status bar and moves the barcode to the top of the screen.
|
|
* <p>
|
|
* 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(boolean 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);
|
|
|
|
binding.barcodeScaler.setProgress(loyaltyCard.zoomLevel);
|
|
setScalerGuideline(loyaltyCard.zoomLevel);
|
|
|
|
// Hide actionbar
|
|
if (actionBar != null) {
|
|
actionBar.hide();
|
|
}
|
|
|
|
// Hide other UI elements
|
|
binding.bottomAppBar.setVisibility(View.GONE);
|
|
binding.fabEdit.setVisibility(View.GONE);
|
|
|
|
// Set Android to fullscreen mode
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
Window window = getWindow();
|
|
if (window != null) {
|
|
window.setDecorFitsSystemWindows(false);
|
|
WindowInsetsController wic = window.getInsetsController();
|
|
if (wic != null) {
|
|
wic.hide(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars());
|
|
wic.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
|
|
}
|
|
}
|
|
} else {
|
|
setFullscreenModeSdkLessThan30();
|
|
}
|
|
} else {
|
|
Log.d(TAG, "Move out of fullscreen");
|
|
|
|
barcodeRenderTarget = binding.mainImage;
|
|
|
|
// Show only regular view
|
|
binding.container.setVisibility(View.VISIBLE);
|
|
binding.fullscreenLayout.setVisibility(View.GONE);
|
|
|
|
drawMainImage(mainImageIndex, true, isFullscreen);
|
|
|
|
// Show actionbar
|
|
if (actionBar != null) {
|
|
actionBar.show();
|
|
}
|
|
|
|
// Show other UI elements
|
|
binding.bottomAppBar.setVisibility(View.VISIBLE);
|
|
binding.fabEdit.setVisibility(View.VISIBLE);
|
|
|
|
// Unset fullscreen mode
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
Window window = getWindow();
|
|
if (window != null) {
|
|
window.setDecorFitsSystemWindows(true);
|
|
WindowInsetsController wic = window.getInsetsController();
|
|
if (wic != null) {
|
|
wic.show(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars());
|
|
wic.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT);
|
|
}
|
|
}
|
|
} else {
|
|
unsetFullscreenModeSdkLessThan30();
|
|
}
|
|
}
|
|
|
|
Log.d("setFullScreen", "Is full screen enabled? " + enabled + " Zoom Level = " + binding.barcodeScaler.getProgress());
|
|
}
|
|
|
|
@SuppressWarnings("deprecation")
|
|
private void unsetFullscreenModeSdkLessThan30() {
|
|
Window window = getWindow();
|
|
if (window != null) {
|
|
window.getDecorView().setSystemUiVisibility(
|
|
window.getDecorView().getSystemUiVisibility()
|
|
& ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
& ~View.SYSTEM_UI_FLAG_FULLSCREEN
|
|
);
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("deprecation")
|
|
private void setFullscreenModeSdkLessThan30() {
|
|
Window window = getWindow();
|
|
if (window != null) {
|
|
window.getDecorView().setSystemUiVisibility(
|
|
window.getDecorView().getSystemUiVisibility()
|
|
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
|
);
|
|
}
|
|
}
|
|
}
|