tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit fc569a3a0b1831cb1174a5ffdde497786a94c21c
parent a4876ab450ebfe3cf334116f52af03b00195ccb5
Author: Matthew Tighe <matthewdtighe@gmail.com>
Date:   Tue, 30 Sep 2025 21:36:58 +0000

Bug 1991169 - add credit cards debug drawer page r=android-reviewers,android-l10n-reviewers,sfamisa,007,delphine

Differential Revision: https://phabricator.services.mozilla.com/D266438

Diffstat:
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/addresses/FakeCreditCardsAddressesStorage.kt | 43++++++++++++++++++++++++++++++++++++++-----
Amobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/creditcards/CreditCardsTools.kt | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/navigation/DebugDrawerRoute.kt | 16++++++++++++++++
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/store/DebugDrawerAction.kt | 5+++++
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/store/DebugDrawerNavigationMiddleware.kt | 2++
Mmobile/android/fenix/app/src/main/res/values/strings.xml | 9+++++++++
6 files changed, 203 insertions(+), 5 deletions(-)

diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/addresses/FakeCreditCardsAddressesStorage.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/addresses/FakeCreditCardsAddressesStorage.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.debugsettings.addresses import mozilla.components.concept.storage.Address import mozilla.components.concept.storage.CreditCard import mozilla.components.concept.storage.CreditCardCrypto +import mozilla.components.concept.storage.CreditCardNumber import mozilla.components.concept.storage.CreditCardsAddressesStorage import mozilla.components.concept.storage.NewCreditCardFields import mozilla.components.concept.storage.UpdatableAddressFields @@ -84,8 +85,12 @@ internal class FakeCreditCardsAddressesStorage : CreditCardsAddressesStorage { it.generateFakeAddressForLangTag().toAddress() }.toMutableList() + val creditCards = mutableListOf<CreditCard>() + override suspend fun addCreditCard(creditCardFields: NewCreditCardFields): CreditCard { - throw UnsupportedOperationException() + return creditCardFields.toCreditCard().also { + creditCards.add(it) + } } override suspend fun updateCreditCard( @@ -99,12 +104,10 @@ internal class FakeCreditCardsAddressesStorage : CreditCardsAddressesStorage { throw UnsupportedOperationException() } - override suspend fun getAllCreditCards(): List<CreditCard> { - throw UnsupportedOperationException() - } + override suspend fun getAllCreditCards(): List<CreditCard> = creditCards override suspend fun deleteCreditCard(guid: String): Boolean { - throw UnsupportedOperationException() + return creditCards.remove(creditCards.find { it.guid == guid }) } override suspend fun touchCreditCard(guid: String) { @@ -162,11 +165,41 @@ internal class FakeCreditCardsAddressesStorage : CreditCardsAddressesStorage { email = email, ) + private fun NewCreditCardFields.toCreditCard() = CreditCard( + guid = UUID.randomUUID().toString(), + billingName = billingName, + cardNumberLast4 = cardNumberLast4, + expiryMonth = expiryMonth, + expiryYear = expiryYear, + cardType = cardType, + encryptedCardNumber = CreditCardNumber.Encrypted(plaintextCardNumber.number), + ) + companion object { fun getAllPossibleLocaleLangTags(): List<String> = listOf( "en-US", "en-CA", "fr-CA", ) + DebugLocale.entries.map { it.langTag } + + private val randomNames = listOf("John Doe", "Jane Doe", "Bob Smith", "Alice Johnson") + private val randomCardNumbers = listOf( + "1111 2222 3333 4444", + "5555 6666 7777 8888", + "9999 0000 1111 2222", + ) + private val randomCardTypes = listOf("Visa", "Mastercard", "American Express") + + fun generateCreditCard(): NewCreditCardFields = randomCardNumbers.random().run { + val last4DigitsOfCard = 4 + NewCreditCardFields( + billingName = randomNames.random(), + plaintextCardNumber = CreditCardNumber.Plaintext(this), + cardNumberLast4 = this.takeLast(last4DigitsOfCard), + expiryMonth = (1L..12L).random(), + expiryYear = (2026L..2032L).random(), + cardType = randomCardTypes.random(), + ) + } } } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/creditcards/CreditCardsTools.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/creditcards/CreditCardsTools.kt @@ -0,0 +1,133 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.debugsettings.creditcards + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewLightDark +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.launch +import mozilla.components.compose.base.button.FilledButton +import mozilla.components.concept.storage.CreditCard +import mozilla.components.concept.storage.CreditCardsAddressesStorage +import org.mozilla.fenix.R +import org.mozilla.fenix.compose.list.TextListItem +import org.mozilla.fenix.debugsettings.addresses.FakeCreditCardsAddressesStorage +import org.mozilla.fenix.theme.FirefoxTheme + +/** + * CreditCards UI for the debug drawer that displays various creditCards related tools. + */ +@Composable +fun CreditCardsTools( + creditCardsAddressesStorage: CreditCardsAddressesStorage, +) { + val scope = rememberCoroutineScope() + var creditCards by remember { mutableStateOf(listOf<CreditCard>()) } + LaunchedEffect(Unit) { + creditCards = creditCardsAddressesStorage.getAllCreditCards() + } + val onAddCreditCard: () -> Unit = { + scope.launch { + creditCardsAddressesStorage.addCreditCard(FakeCreditCardsAddressesStorage.generateCreditCard()) + creditCards = creditCardsAddressesStorage.getAllCreditCards() + } + } + val onDeleteCreditCard: (CreditCard) -> Unit = { creditCard -> + scope.launch { + creditCardsAddressesStorage.deleteCreditCard(creditCard.guid) + creditCards = creditCardsAddressesStorage.getAllCreditCards() + } + } + val onDeleteAllCreditCards: () -> Unit = { + scope.launch { + creditCardsAddressesStorage.getAllCreditCards().forEach { creditCard -> + creditCardsAddressesStorage.deleteCreditCard(creditCard.guid) + } + creditCards = creditCardsAddressesStorage.getAllCreditCards() + } + } + + CreditCardsContent( + creditCards = creditCards, + onAddCreditCardClick = onAddCreditCard, + onDeleteCreditCardClick = onDeleteCreditCard, + onDeleteAllCreditCardsClick = onDeleteAllCreditCards, + ) +} + +@Composable +private fun CreditCardsContent( + creditCards: List<CreditCard>, + onAddCreditCardClick: () -> Unit, + onDeleteCreditCardClick: (CreditCard) -> Unit, + onDeleteAllCreditCardsClick: () -> Unit, +) { + Column { + Text( + text = stringResource(R.string.debug_drawer_credit_cards_title), + color = FirefoxTheme.colors.textSecondary, + style = FirefoxTheme.typography.headline7, + ) + + Spacer(Modifier.height(8.dp)) + + FilledButton( + text = stringResource(R.string.debug_drawer_add_new_credit_card), + modifier = Modifier.fillMaxWidth(), + onClick = { onAddCreditCardClick() }, + ) + + Spacer(Modifier.height(8.dp)) + + FilledButton( + text = stringResource(R.string.debug_drawer_delete_all_credit_cards), + modifier = Modifier.fillMaxWidth(), + onClick = onDeleteAllCreditCardsClick, + ) + + Spacer(Modifier.height(8.dp)) + + Column { + creditCards.forEach { creditCard -> + TextListItem( + label = creditCard.cardNumberLast4, + description = creditCard.billingName, + iconPainter = painterResource(R.drawable.ic_delete), + onIconClick = { onDeleteCreditCardClick(creditCard) }, + ) + } + } + } +} + +@Composable +@PreviewLightDark +private fun CreditCardsScreenPreview() { + FirefoxTheme { + Box( + modifier = Modifier.background(color = FirefoxTheme.colors.layer1), + ) { + CreditCardsTools( + creditCardsAddressesStorage = FakeCreditCardsAddressesStorage(), + ) + } + } +} diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/navigation/DebugDrawerRoute.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/navigation/DebugDrawerRoute.kt @@ -17,6 +17,7 @@ import org.mozilla.fenix.debugsettings.addresses.AddressesTools import org.mozilla.fenix.debugsettings.cfrs.CfrToolsState import org.mozilla.fenix.debugsettings.cfrs.CfrToolsStore import org.mozilla.fenix.debugsettings.crashtools.CrashTools +import org.mozilla.fenix.debugsettings.creditcards.CreditCardsTools import org.mozilla.fenix.debugsettings.gleandebugtools.GleanDebugToolsStore import org.mozilla.fenix.debugsettings.gleandebugtools.ui.GleanDebugToolsScreen import org.mozilla.fenix.debugsettings.logins.LoginsTools @@ -49,6 +50,10 @@ enum class DebugDrawerRoute(val route: String, @param:StringRes val title: Int) route = "addresses", title = R.string.debug_drawer_addresses_title, ), + CreditCards( + route = "credit_cards", + title = R.string.debug_drawer_credit_cards_title, + ), CfrTools( route = "cfr_tools", title = R.string.debug_drawer_cfr_tools_title, @@ -135,6 +140,17 @@ enum class DebugDrawerRoute(val route: String, @param:StringRes val title: Int) } } + CreditCards -> { + onClick = { + debugDrawerStore.dispatch(DebugDrawerAction.NavigateTo.CreditCards) + } + content = { + CreditCardsTools( + creditCardsAddressesStorage = creditCardsAddressesStorage, + ) + } + } + CfrTools -> { onClick = { debugDrawerStore.dispatch(DebugDrawerAction.NavigateTo.CfrTools) diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/store/DebugDrawerAction.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/store/DebugDrawerAction.kt @@ -54,6 +54,11 @@ sealed class DebugDrawerAction : Action { data object Addresses : NavigateTo() /** + * [NavigateTo] action fired when the debug drawer needs to navigate to [CreditCardsTools]. + */ + data object CreditCards : NavigateTo() + + /** * [NavigateTo] action fired when the debug drawer needs to navigate to [CfrToolsScreen]. */ object CfrTools : NavigateTo() diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/store/DebugDrawerNavigationMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/debugsettings/store/DebugDrawerNavigationMiddleware.kt @@ -41,6 +41,8 @@ class DebugDrawerNavigationMiddleware( navController.navigate(route = DebugDrawerRoute.Logins.route) is DebugDrawerAction.NavigateTo.Addresses -> navController.navigate(route = DebugDrawerRoute.Addresses.route) + is DebugDrawerAction.NavigateTo.CreditCards -> + navController.navigate(route = DebugDrawerRoute.CreditCards.route) is DebugDrawerAction.NavigateTo.CfrTools -> navController.navigate(route = DebugDrawerRoute.CfrTools.route) is DebugDrawerAction.NavigateTo.GleanDebugTools -> diff --git a/mobile/android/fenix/app/src/main/res/values/strings.xml b/mobile/android/fenix/app/src/main/res/values/strings.xml @@ -3297,6 +3297,15 @@ <!-- The title of the button for deleting in the debug drawer all addresses. --> <string name="debug_drawer_delete_all_addresses">Delete all addresses</string> + <!-- Debug drawer credit cards --> + <!-- The title of the credit cards feature in the Debug Drawer. --> + <string name="debug_drawer_credit_cards_title">Credit cards</string> + <!-- The title of the button in the debug drawer for adding a new credit card --> + <string name="debug_drawer_add_new_credit_card">Add new credit card</string> + <!-- The title of the button for deleting in the debug drawer all addresses. --> + <string name="debug_drawer_delete_all_credit_cards">Delete all credit cards</string> + + <!-- Debug drawer "contextual feature recommendation" (CFR) tools --> <!-- The title of the CFR Tools feature in the Debug Drawer --> <string name="debug_drawer_cfr_tools_title">CFR Tools</string>