diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java index 47c977925..965000277 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java @@ -1,6 +1,7 @@ package protect.card_locker; import android.content.ActivityNotFoundException; +import android.content.ClipboardManager; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.ColorStateList; @@ -146,6 +147,21 @@ public void onMainImageTap() { openImageInGallery(imageType); } + private boolean copyBarcodeToClipBoard(){ + if (imageTypes.get(mainImageIndex) == ImageType.BARCODE) { + String barcodeString = barcodeIdString != null ? barcodeIdString : cardIdString; + ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); + if (clipboard != null) { + android.content.ClipData clip = android.content.ClipData.newPlainText("Barcode", barcodeString); + clipboard.setPrimaryClip(clip); + Toast.makeText(this, R.string.copy_success, Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(this, R.string.copy_failed, Toast.LENGTH_SHORT).show(); + } + } + return true; + } + private void openImageInGallery(ImageType imageType) { File file = null; @@ -350,12 +366,16 @@ public void onStopTrackingTouch(SeekBar seekBar) { }); 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.mainImageDescription.setOnLongClickListener(view -> copyBarcodeToClipBoard()); + binding.fullscreenImage.setOnClickListener(view -> onMainImageTap()); getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { @@ -698,6 +718,7 @@ protected void onResume() { builder.setTitle(R.string.cardId); builder.setView(cardIdView); builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> dialogInterface.dismiss()); + builder.setNeutralButton(R.string.copy, (dialogInterface, i) -> copyBarcodeToClipBoard()); AlertDialog dialog = builder.create(); dialog.show(); }); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e782652fd..bf5bec02f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -361,4 +361,7 @@ Select a Passbook file (.pkpass) This file is not supported Sorry, something went wrong, please try again... + Copy + Copied to clipboard + Failed to copy to clipboard diff --git a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java index 2fc8d6121..831a822b4 100644 --- a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java +++ b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java @@ -12,6 +12,8 @@ import android.app.Activity; import android.app.DatePickerDialog; import android.app.Dialog; +import android.content.ClipData; +import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -1389,4 +1391,51 @@ public void importCardOldFormat() { checkAllFields(activity, ViewMode.ADD_CARD, "Example Store", "", context.getString(R.string.anyDate), context.getString(R.string.never), "0", context.getString(R.string.points), "123456", context.getString(R.string.sameAsCardId), "Aztec", null, null); assertEquals(-416706, ((ColorDrawable) activity.findViewById(R.id.thumbnail).getBackground()).getColor()); } + + + @Test + public void longPressOnBarcodeShouldCopyTheBarcodeValue() { + final Context context = ApplicationProvider.getApplicationContext(); + SQLiteDatabase database = TestHelpers.getEmptyDb(context).getWritableDatabase(); + + long cardId = DBHelper.insertLoyaltyCard(database, "store", "note", null, null, new BigDecimal("0"), null, BARCODE_DATA, null, BARCODE_TYPE, Color.BLACK, 0, null, 0); + + ActivityController activityController = createActivityWithLoyaltyCard(false, (int) cardId); + Activity activity = (Activity) activityController.get(); + + activityController.start(); + activityController.visible(); + activityController.resume(); + + // Short press on description to open the modal + TextView barcodeTextView = activity.findViewById(R.id.main_image_description); + barcodeTextView.performClick(); + shadowOf(getMainLooper()).idle(); + + // click on the copy neutral button + AlertDialog barcodeDialog = (AlertDialog) (ShadowDialog.getLatestDialog()); + assertNotNull(barcodeDialog); + barcodeDialog.getButton(AlertDialog.BUTTON_NEUTRAL).performClick(); + shadowOf(getMainLooper()).idle(); + + // Check if the barcode value is copied to the clipboard + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clipData = clipboard.getPrimaryClip(); + assertNotNull(clipData); + assertEquals(BARCODE_DATA, clipData.getItemAt(0).getText().toString()); + + //clear the clipboard + clipboard.setPrimaryClip(ClipData.newPlainText("", "")); + + //quit the dialog + barcodeDialog.dismiss(); + + // Long press on the barcode description should copy the barcode value + barcodeTextView.performLongClick(); + shadowOf(getMainLooper()).idle(); + // Check if the barcode value is copied to the clipboard + clipData = clipboard.getPrimaryClip(); + assertNotNull(clipData); + assertEquals(BARCODE_DATA, clipData.getItemAt(0).getText().toString()); + } }