For #18273 - [Edit card] Delete a saved credit card (#19029)

upstream-sync
Gabriel Luong 3 years ago committed by GitHub
parent d8660341a1
commit f7c56ee6fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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 = ""
}
}

@ -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(),

@ -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)

@ -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)
}

@ -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
)
)
}

@ -4,6 +4,13 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/delete_credit_card_button"
android:icon="@drawable/ic_delete"
android:title="@string/credit_cards_menu_delete_card"
android:visible="false"
app:iconTint="?primaryText"
app:showAsAction="ifRoom" />
<item
android:id="@+id/save_credit_card_button"
android:icon="@drawable/mozac_ic_check"

@ -1542,6 +1542,8 @@
<string name="credit_cards_name_on_card">Name on Card</string>
<!-- The header for the nickname for a credit card -->
<string name="credit_cards_card_nickname">Card Nickname</string>
<!-- The text for the "Delete card" menu item for deleting a credit card -->
<string name="credit_cards_menu_delete_card">Delete card</string>
<!-- The text for the "Delete card" button for deleting a credit card -->
<string name="credit_cards_delete_card_button">Delete card</string>
<!-- The title for the "Save" menu item for saving a credit card -->

@ -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)

@ -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
)
)
}

@ -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(

@ -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(

Loading…
Cancel
Save