From f7c56ee6fa39a3b510656ccede8b975a096bc775 Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Thu, 15 Apr 2021 11:18:29 -0400 Subject: [PATCH] For #18273 - [Edit card] Delete a saved credit card (#19029) --- .../creditcards/CreditCardEditorFragment.kt | 12 +++++++++- .../creditcards/CreditCardEditorState.kt | 5 +++- .../controller/CreditCardEditorController.kt | 15 ++++++++++++ .../interactor/CreditCardEditorInteractor.kt | 12 ++++++++++ .../creditcards/view/CreditCardEditorView.kt | 13 +++++++++- app/src/main/res/menu/credit_card_editor.xml | 7 ++++++ app/src/main/res/values/strings.xml | 2 ++ .../creditcards/CreditCardEditorStateTest.kt | 2 ++ .../creditcards/CreditCardEditorViewTest.kt | 16 ++++++++++++- .../DefaultCreditCardEditorControllerTest.kt | 24 +++++++++++++++++++ .../DefaultCreditCardEditorInteractorTest.kt | 19 +++++++++++++++ 11 files changed, 123 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt index 7adbf3cd63..b71bb9e192 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt @@ -65,9 +65,15 @@ class CreditCardEditorFragment : Fragment(R.layout.fragment_credit_card_editor) override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.credit_card_editor, menu) + + menu.findItem(R.id.delete_credit_card_button).isVisible = isEditing } override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { + R.id.delete_credit_card_button -> { + args.creditCard?.let { interactor.onDeleteCardButtonClicked(it.guid) } + true + } R.id.save_credit_card_button -> { saveCreditCard() true @@ -88,7 +94,7 @@ class CreditCardEditorFragment : Fragment(R.layout.fragment_credit_card_editor) cardNumber = card_number_input.text.toString(), expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(), expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(), - cardType = "amex" + cardType = CARD_TYPE_PLACEHOLDER ) ) } @@ -96,5 +102,9 @@ class CreditCardEditorFragment : Fragment(R.layout.fragment_credit_card_editor) companion object { // Number of years to show in the expiry year dropdown. const val NUMBER_OF_YEARS_TO_SHOW = 10 + + // Placeholder for the card type. This will be replaced when we can identify the card type. + // This is dependent on https://github.com/mozilla-mobile/android-components/issues/9813. + const val CARD_TYPE_PLACEHOLDER = "" } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorState.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorState.kt index f7c2ce1dc3..ed9c627477 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorState.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorState.kt @@ -11,13 +11,15 @@ import java.util.Calendar /** * The state for the [CreditCardEditorFragment]. * + * @property guid The unique identifier for the edited credit card. * @property billingName The credit card billing name to display. * @property cardNumber The credit card number to display. * @property expiryMonth The selected credit card expiry month. * @property expiryYears The range of expiry years to display. - * @property isEditing Whether or not the credit is being edited. + * @property isEditing Whether or not the credit card is being edited. */ data class CreditCardEditorState( + val guid: String = "", val billingName: String = "", val cardNumber: String = "", val expiryMonth: Int = 1, @@ -33,6 +35,7 @@ fun CreditCard.toCreditCardEditorState(): CreditCardEditorState { val endYear = startYear + NUMBER_OF_YEARS_TO_SHOW return CreditCardEditorState( + guid = guid, billingName = billingName, cardNumber = cardNumber, expiryMonth = expiryMonth.toInt(), diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/controller/CreditCardEditorController.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/controller/CreditCardEditorController.kt index 7094e7018d..0c996cd88d 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/controller/CreditCardEditorController.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/controller/CreditCardEditorController.kt @@ -23,6 +23,11 @@ interface CreditCardEditorController { */ fun handleCancelButtonClicked() + /** + * @see [CreditCardEditorInteractor.onDeleteCardButtonClicked] + */ + fun handleDeleteCreditCard(guid: String) + /** * @see [CreditCardEditorInteractor.onSaveButtonClicked] */ @@ -49,6 +54,16 @@ class DefaultCreditCardEditorController( navController.popBackStack() } + override fun handleDeleteCreditCard(guid: String) { + lifecycleScope.launch(ioDispatcher) { + storage.deleteCreditCard(guid) + + lifecycleScope.launch(Dispatchers.Main) { + navController.popBackStack() + } + } + } + override fun handleSaveCreditCard(creditCardFields: UpdatableCreditCardFields) { lifecycleScope.launch(ioDispatcher) { storage.addCreditCard(creditCardFields) diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/interactor/CreditCardEditorInteractor.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/interactor/CreditCardEditorInteractor.kt index a66551d241..4613ecb811 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/interactor/CreditCardEditorInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/interactor/CreditCardEditorInteractor.kt @@ -18,6 +18,14 @@ interface CreditCardEditorInteractor { */ fun onCancelButtonClicked() + /** + * Deletes the provided credit card in the credit card storage. Called when a user + * taps on the delete menu item or "Delete card" button. + * + * @param guid Unique identifier for the credit card to be deleted. + */ + fun onDeleteCardButtonClicked(guid: String) + /** * Saves the provided credit card field into the credit card storage. Called when a user * taps on the save menu item or "Save" button. @@ -41,6 +49,10 @@ class DefaultCreditCardEditorInteractor( controller.handleCancelButtonClicked() } + override fun onDeleteCardButtonClicked(guid: String) { + controller.handleDeleteCreditCard(guid) + } + override fun onSaveButtonClicked(creditCardFields: UpdatableCreditCardFields) { controller.handleSaveCreditCard(creditCardFields) } diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardEditorView.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardEditorView.kt index 64d51a3df4..e7906391b6 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardEditorView.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/view/CreditCardEditorView.kt @@ -12,6 +12,7 @@ import kotlinx.android.synthetic.main.fragment_credit_card_editor.* import mozilla.components.concept.storage.UpdatableCreditCardFields import mozilla.components.support.ktx.android.view.hideKeyboard import org.mozilla.fenix.ext.toEditable +import org.mozilla.fenix.settings.creditcards.CreditCardEditorFragment.Companion.CARD_TYPE_PLACEHOLDER import org.mozilla.fenix.settings.creditcards.CreditCardEditorState import org.mozilla.fenix.settings.creditcards.interactor.CreditCardEditorInteractor import java.text.SimpleDateFormat @@ -30,6 +31,16 @@ class CreditCardEditorView( * Binds the given [CreditCardEditorState] in the [CreditCardEditorFragment]. */ fun bind(state: CreditCardEditorState) { + if (state.isEditing) { + delete_button.apply { + visibility = View.VISIBLE + + setOnClickListener { + interactor.onDeleteCardButtonClicked(state.guid) + } + } + } + cancel_button.setOnClickListener { interactor.onCancelButtonClicked() } @@ -99,7 +110,7 @@ class CreditCardEditorView( cardNumber = card_number_input.text.toString(), expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(), expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(), - cardType = "amex" + cardType = CARD_TYPE_PLACEHOLDER ) ) } diff --git a/app/src/main/res/menu/credit_card_editor.xml b/app/src/main/res/menu/credit_card_editor.xml index defcc8b303..5b4c672a2a 100644 --- a/app/src/main/res/menu/credit_card_editor.xml +++ b/app/src/main/res/menu/credit_card_editor.xml @@ -4,6 +4,13 @@ - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + Name on Card Card Nickname + + Delete card Delete card diff --git a/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorStateTest.kt b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorStateTest.kt index 5f976bfe28..7e5e4b68b6 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorStateTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorStateTest.kt @@ -34,6 +34,7 @@ class CreditCardEditorStateTest { val endYear = startYear + NUMBER_OF_YEARS_TO_SHOW with(state) { + assertEquals(creditCard.guid, guid) assertEquals(creditCard.billingName, billingName) assertEquals(creditCard.cardNumber, cardNumber) assertEquals(creditCard.expiryMonth.toInt(), expiryMonth) @@ -50,6 +51,7 @@ class CreditCardEditorStateTest { val endYear = startYear + NUMBER_OF_YEARS_TO_SHOW with(state) { + assertEquals("", guid) assertEquals("", billingName) assertEquals("", cardNumber) assertEquals(1, expiryMonth) diff --git a/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorViewTest.kt b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorViewTest.kt index ac88a43846..699a9354aa 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorViewTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorViewTest.kt @@ -18,6 +18,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.R import org.mozilla.fenix.helpers.FenixRobolectricTestRunner +import org.mozilla.fenix.settings.creditcards.CreditCardEditorFragment.Companion.CARD_TYPE_PLACEHOLDER import org.mozilla.fenix.settings.creditcards.CreditCardEditorFragment.Companion.NUMBER_OF_YEARS_TO_SHOW import org.mozilla.fenix.settings.creditcards.interactor.CreditCardEditorInteractor import org.mozilla.fenix.settings.creditcards.view.CreditCardEditorView @@ -73,6 +74,8 @@ class CreditCardEditorViewTest { assertEquals(startYear.toString(), selectedItem.toString()) assertEquals(endYear.toString(), getItemAtPosition(count - 1).toString()) } + + assertEquals(View.GONE, view.delete_button.visibility) } @Test @@ -96,6 +99,17 @@ class CreditCardEditorViewTest { } } + @Test + fun `GIVEN a credit card WHEN the delete card button is clicked THEN interactor is called`() { + creditCardEditorView.bind(creditCard.toCreditCardEditorState()) + + assertEquals(View.VISIBLE, view.delete_button.visibility) + + view.delete_button.performClick() + + verify { interactor.onDeleteCardButtonClicked(creditCard.guid) } + } + @Test fun `WHEN the cancel button is clicked THEN interactor is called`() { creditCardEditorView.bind(getInitialCreditCardEditorState()) @@ -118,7 +132,7 @@ class CreditCardEditorViewTest { cardNumber = creditCard.cardNumber, expiryMonth = creditCard.expiryMonth, expiryYear = creditCard.expiryYear, - cardType = "amex" + cardType = CARD_TYPE_PLACEHOLDER ) ) } diff --git a/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardEditorControllerTest.kt b/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardEditorControllerTest.kt index a47436a153..5721f35d3a 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardEditorControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardEditorControllerTest.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestCoroutineDispatcher import kotlinx.coroutines.test.TestCoroutineScope import kotlinx.coroutines.test.runBlockingTest +import mozilla.components.concept.storage.CreditCard import mozilla.components.concept.storage.UpdatableCreditCardFields import mozilla.components.service.sync.autofill.AutofillCreditCardsAddressesStorage import mozilla.components.support.test.rule.MainCoroutineRule @@ -63,6 +64,29 @@ class DefaultCreditCardEditorControllerTest { } } + @Test + fun handleDeleteCreditCard() = testCoroutineScope.runBlockingTest { + val creditCard = CreditCard( + guid = "id", + billingName = "Banana Apple", + cardNumber = "4111111111111110", + expiryMonth = 1, + expiryYear = 2030, + cardType = "amex", + timeCreated = 1L, + timeLastUsed = 1L, + timeLastModified = 1L, + timesUsed = 1L + ) + + controller.handleDeleteCreditCard(creditCard.guid) + + coVerify { + storage.deleteCreditCard(creditCard.guid) + navController.popBackStack() + } + } + @Test fun handleSaveCreditCard() = testCoroutineScope.runBlockingTest { val creditCardFields = UpdatableCreditCardFields( diff --git a/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardEditorInteractorTest.kt b/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardEditorInteractorTest.kt index 3a441651b2..1c11737442 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardEditorInteractorTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/creditcards/DefaultCreditCardEditorInteractorTest.kt @@ -6,6 +6,7 @@ package org.mozilla.fenix.settings.creditcards import io.mockk.mockk import io.mockk.verify +import mozilla.components.concept.storage.CreditCard import mozilla.components.concept.storage.UpdatableCreditCardFields import org.junit.Before import org.junit.Test @@ -29,6 +30,24 @@ class DefaultCreditCardEditorInteractorTest { verify { controller.handleCancelButtonClicked() } } + @Test + fun onDeleteCardButtonClicked() { + val creditCard = CreditCard( + guid = "id", + billingName = "Banana Apple", + cardNumber = "4111111111111110", + expiryMonth = 1, + expiryYear = 2030, + cardType = "amex", + timeCreated = 1L, + timeLastUsed = 1L, + timeLastModified = 1L, + timesUsed = 1L + ) + interactor.onDeleteCardButtonClicked(creditCard.guid) + verify { controller.handleDeleteCreditCard(creditCard.guid) } + } + @Test fun onSaveButtonClicked() { val creditCardFields = UpdatableCreditCardFields(