commit e83fc3220a8abec378a3bbb0e25c21e7ff7924bf parent 90d07dd003158c82c3e3ad9203cb38033420faa9 Author: Alexandru Marc <amarc@mozilla.com> Date: Tue, 25 Nov 2025 13:16:09 +0200 Revert "Bug 1980027: composify the autofill settings fragment r=android-reviewers,android-l10n-reviewers,flod,sfamisa" for causing fenix failures This reverts commit 672a2ccd3d3376eb2306e24c44a9561a2e7d485f. Diffstat:
12 files changed, 1 insertion(+), 1290 deletions(-)
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/AutofillScreenDestination.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/AutofillScreenDestination.kt @@ -1,18 +0,0 @@ -/* 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.settings.autofill - -/** - * Defines destinations used when navigating to other fragments - */ -object AutofillScreenDestination { - const val SYNC_SIGN_IN = "sync sign in" - const val ADD_ADDRESS = "add address" - const val MANAGE_ADDRESSES = "manage addresses" - const val ADD_CREDIT_CARD = "add credit card" - const val MANAGE_CREDIT_CARDS = "manage credit cards" - const val ADDRESS = "address" - const val CREDIT_CARD = "credit card" -} diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/AutofillSettingFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/AutofillSettingFragment.kt @@ -14,11 +14,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.annotation.VisibleForTesting -import androidx.compose.ui.platform.ComposeView -import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.lifecycle.lifecycleScope import androidx.navigation.NavController -import androidx.navigation.NavHostController import androidx.navigation.fragment.findNavController import androidx.preference.Preference import androidx.preference.SwitchPreference @@ -28,19 +25,13 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch import mozilla.components.lib.state.ext.consumeFrom -import mozilla.components.lib.state.helpers.StoreProvider.Companion.fragmentStore import mozilla.components.lib.state.helpers.StoreProvider.Companion.storeProvider import mozilla.components.service.fxa.SyncEngine -import mozilla.components.service.fxa.manager.SyncEnginesStorage import mozilla.components.service.sync.autofill.AutofillCreditCardsAddressesStorage import mozilla.components.ui.widgets.withCenterAlignedButtons -import org.mozilla.fenix.Config import org.mozilla.fenix.NavGraphDirections import org.mozilla.fenix.R -import org.mozilla.fenix.components.LogMiddleware import org.mozilla.fenix.components.accounts.FenixFxAEntryPoint -import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.hideToolbar import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.runIfFragmentIsAttached import org.mozilla.fenix.ext.secure @@ -48,20 +39,13 @@ import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.settings.SharedPreferenceUpdater import org.mozilla.fenix.settings.SyncPreferenceView -import org.mozilla.fenix.settings.autofill.ui.AccountAuthState -import org.mozilla.fenix.settings.autofill.ui.AutofillSettingsMiddleware -import org.mozilla.fenix.settings.autofill.ui.AutofillSettingsScreen -import org.mozilla.fenix.settings.autofill.ui.AutofillSettingsState -import org.mozilla.fenix.settings.autofill.ui.AutofillSettingsStore import org.mozilla.fenix.settings.biometric.BiometricPromptPreferenceFragment import org.mozilla.fenix.settings.requirePreference -import org.mozilla.fenix.theme.FirefoxTheme -import kotlin.Boolean import com.google.android.material.R as materialR import mozilla.components.ui.icons.R as iconsR /** - * Autofill settings fragment displays a list of settings related to auto filling, adding and + * Autofill settings fragment displays a list of settings related to autofilling, adding and * syncing credit cards and addresses. */ @SuppressWarnings("TooManyFunctions") @@ -98,10 +82,6 @@ class AutofillSettingFragment : BiometricPromptPreferenceFragment() { container: ViewGroup?, savedInstanceState: Bundle?, ): View { - if (requireContext().settings().enableComposeAutofillSettings) { - return autofillSettingsComposeView() - } - store = storeProvider.get { restoredState -> AutofillFragmentStore(restoredState ?: AutofillFragmentState()) } @@ -110,10 +90,6 @@ class AutofillSettingFragment : BiometricPromptPreferenceFragment() { } override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - if (requireContext().settings().enableComposeAutofillSettings) { - return - } - setPreferencesFromResource( if (requireComponents.settings.addressFeature) { R.xml.autofill_preferences @@ -150,72 +126,9 @@ class AutofillSettingFragment : BiometricPromptPreferenceFragment() { } } - private fun autofillSettingsComposeView(): View = - ComposeView(requireContext()).apply { - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - val buildStore = { _: NavHostController -> - - val autofillStore by fragmentStore( - AutofillSettingsState.default.copy( - saveFillAddresses = requireContext().settings().shouldAutofillAddressDetails, - saveFillCards = requireContext().settings().shouldAutofillCreditCardDetails, - syncAddresses = requireContext().settings().shouldSyncAddressesAcrossDevices, - syncCreditCards = requireContext().settings().shouldSyncCreditCardsAcrossDevices, - accountAuthState = if (requireContext().settings().signedInFxaAccount) { - AccountAuthState.Authenticated - } else { - AccountAuthState.LoggedOut - }, - ), - ) { - AutofillSettingsStore( - initialState = it, - middleware = listOf( - LogMiddleware( - tag = "AutofillSettingsStore", - shouldIncludeDetailedData = { Config.channel.isDebug }, - ), - createAutofillSettingsMiddleware(), - ), - ) - } - - autofillStore - } - setContent { - FirefoxTheme { - AutofillSettingsScreen( - buildStore = buildStore, - accountManager = requireComponents.backgroundServices.accountManager, - isAddressSyncEnabled = requireComponents.settings.isAddressSyncEnabled, - ) - } - } - } - - private fun createAutofillSettingsMiddleware() = - AutofillSettingsMiddleware( - autofillSettingsStorage = requireContext().components.core.autofillStorage, - accountManager = requireComponents.backgroundServices.accountManager, - updateSaveFillStatus = { destination, newValue -> - updateSaveFillStatus(destination, newValue) - }, - updateSyncStatusAcrossDevices = { destination, newValue -> - updateSyncStatusAcrossDevices(destination, newValue) - }, - goToScreen = { nextFragment -> - goToFragment(nextFragment) - }, - exitAutofillSettings = { this@AutofillSettingFragment.findNavController().popBackStack() }, - ) - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - if (requireContext().settings().enableComposeAutofillSettings) { - return - } - requirePreference<SwitchPreference>(R.string.pref_key_credit_cards_save_and_autofill_cards).summary = getString(R.string.preferences_credit_cards_save_and_autofill_cards_summary_2, getString(R.string.app_name)) @@ -237,11 +150,6 @@ class AutofillSettingFragment : BiometricPromptPreferenceFragment() { override fun onResume() { super.onResume() - if (requireContext().settings().enableComposeAutofillSettings) { - hideToolbar() - return - } - if (requireComponents.settings.addressFeature) { showToolbar(getString(R.string.preferences_autofill)) } else { @@ -450,50 +358,6 @@ class AutofillSettingFragment : BiometricPromptPreferenceFragment() { startForResult.launch(intent) } - private fun goToFragment(destination: String) { - with(AutofillScreenDestination) { - when (destination) { - ADD_ADDRESS -> { - navigateToAddAddressFragment() - } - MANAGE_ADDRESSES -> { - navigateToAddressManagementFragment() - } - ADD_CREDIT_CARD -> { - navigateToAddCreditCardFragment() - } - - MANAGE_CREDIT_CARDS -> { - navigateToCreditCardManagementFragment() - } - SYNC_SIGN_IN -> { - syncSignIn() - } - } - } - } - - private fun navigateToAddAddressFragment() { - val directions = - AutofillSettingFragmentDirections - .actionAutofillSettingFragmentToAddressEditorFragment() - findNavController().navigate(directions) - } - - private fun navigateToAddressManagementFragment() { - val directions = - AutofillSettingFragmentDirections - .actionAutofillSettingFragmentToAddressManagementFragment() - findNavController().navigate(directions) - } - - private fun navigateToAddCreditCardFragment() { - val directions = - AutofillSettingFragmentDirections - .actionAutofillSettingFragmentToCreditCardEditorFragment() - findNavController().navigate(directions) - } - private fun navigateToCreditCardManagementFragment() { val directions = AutofillSettingFragmentDirections @@ -501,40 +365,6 @@ class AutofillSettingFragment : BiometricPromptPreferenceFragment() { findNavController().navigate(directions) } - private fun syncSignIn() { - findNavController().navigate( - NavGraphDirections.actionGlobalTurnOnSync(entrypoint = FenixFxAEntryPoint.AutofillSetting), - ) - } - - private fun updateSyncStatusAcrossDevices(destination: String, newValue: Boolean) { - when (destination) { - AutofillScreenDestination.ADDRESS -> { - SyncEnginesStorage(requireContext()).setStatus(SyncEngine.Addresses, newValue) - requireContext().settings().shouldSyncAddressesAcrossDevices = - newValue - } - - AutofillScreenDestination.CREDIT_CARD -> { - SyncEnginesStorage(requireContext()).setStatus(SyncEngine.CreditCards, newValue) - requireContext().settings().shouldSyncCreditCardsAcrossDevices = - newValue - } - } - } - - private fun updateSaveFillStatus(destination: String, newValue: Boolean) { - when (destination) { - AutofillScreenDestination.ADDRESS -> { - requireContext().settings().shouldAutofillAddressDetails = newValue - } - - AutofillScreenDestination.CREDIT_CARD -> { - requireContext().settings().shouldAutofillCreditCardDetails = newValue - } - } - } - companion object { const val SHORT_DELAY_MS = 100L } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsAction.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsAction.kt @@ -1,36 +0,0 @@ -/* 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.settings.autofill.ui - -import mozilla.components.concept.storage.Address -import mozilla.components.concept.storage.CreditCard -import mozilla.components.lib.state.Action - -/** - * Actions relating to the AutofillSettings screen. - */ -internal sealed interface AutofillSettingsAction : Action -internal data object ViewDisposed : AutofillSettingsAction -internal data object InitializeAddressesAndCreditCards : AutofillSettingsAction -internal data class UpdateAddresses(val addresses: List<Address>) : AutofillSettingsAction -internal data object AddAddressClicked : AutofillSettingsAction -internal data class ChangeAddressSaveFillPreference(val isChecked: Boolean) : AutofillSettingsAction -internal data object SyncAddressesAcrossDevicesClicked : AutofillSettingsAction -internal data class UpdateCreditCards(val creditCards: List<CreditCard>) : AutofillSettingsAction -internal data object AddCardClicked : AutofillSettingsAction -internal data object SyncCardsAcrossDevicesClicked : AutofillSettingsAction -internal data class ChangeCardSaveFillPreference(val isChecked: Boolean) : AutofillSettingsAction -internal data object ManageAddressesClicked : AutofillSettingsAction -internal data object ManageCreditCardsClicked : AutofillSettingsAction -internal data object AutofillSettingsBackClicked : AutofillSettingsAction - -internal sealed class AccountAuthenticationAction : AutofillSettingsAction { - data object Authenticated : AccountAuthenticationAction() - data object NotAuthenticated : AccountAuthenticationAction() - data object Failed : AccountAuthenticationAction() -} - -internal data class UpdateAddressesSyncStatus(val newStatus: Boolean) : AutofillSettingsAction -internal data class UpdateCreditCardsSyncStatus(val newStatus: Boolean) : AutofillSettingsAction diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsMiddleware.kt @@ -1,135 +0,0 @@ -/* 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.settings.autofill.ui - -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import mozilla.components.concept.sync.AccountObserver -import mozilla.components.concept.sync.AuthType -import mozilla.components.concept.sync.OAuthAccount -import mozilla.components.lib.state.Middleware -import mozilla.components.lib.state.MiddlewareContext -import mozilla.components.lib.state.Store -import mozilla.components.service.fxa.manager.FxaAccountManager -import mozilla.components.service.sync.autofill.AutofillCreditCardsAddressesStorage -import org.mozilla.fenix.settings.autofill.AutofillScreenDestination -import org.mozilla.fenix.settings.logins.ui.LoginsAction - -/** - * A middleware for handling side-effects in response to [LoginsAction]s. - * - * @param autofillSettingsStorage Storage layer for reading and writing addresses/cards. - * @param accountManager The account manager that offers information on account auth state. - * @param updateSaveFillStatus Invoked when changing the save fill status option for addresses or cards. - * @param updateSyncStatusAcrossDevices Invoked when changing the sync status option for addresses or cards. - * @param goToScreen Invoked when navigating to another screen. - * @param exitAutofillSettings Invoked when back is clicked while the navController's backstack is empty. - * @param ioDispatcher Coroutine dispatcher for IO operations. - */ -internal class AutofillSettingsMiddleware( - private val autofillSettingsStorage: AutofillCreditCardsAddressesStorage, - private val accountManager: FxaAccountManager, - private val updateSaveFillStatus: (String, Boolean) -> Unit, - private val updateSyncStatusAcrossDevices: (String, Boolean) -> Unit, - private val goToScreen: (String) -> Unit, - private val exitAutofillSettings: () -> Unit, - private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO, -) : Middleware<AutofillSettingsState, AutofillSettingsAction> { - - private val scope = CoroutineScope(ioDispatcher) - private lateinit var observer: AccountObserver - - override fun invoke( - context: MiddlewareContext<AutofillSettingsState, AutofillSettingsAction>, - next: (AutofillSettingsAction) -> Unit, - action: AutofillSettingsAction, - ) { - next(action) - - when (action) { - is InitializeAddressesAndCreditCards -> { - context.store.registerObserverForAccountChanges(accountManager) - context.store.loadAddressesAndCreditCards() - } - is AddAddressClicked -> { - goToScreen(AutofillScreenDestination.ADD_ADDRESS) - } - is AddCardClicked -> { - goToScreen(AutofillScreenDestination.ADD_CREDIT_CARD) - } - is AutofillSettingsBackClicked -> { - exitAutofillSettings() - } - is ChangeAddressSaveFillPreference -> { - updateSaveFillStatus(AutofillScreenDestination.ADDRESS, action.isChecked) - } - is ChangeCardSaveFillPreference -> { - updateSaveFillStatus(AutofillScreenDestination.CREDIT_CARD, action.isChecked) - } - is SyncAddressesAcrossDevicesClicked -> { - goToScreen(AutofillScreenDestination.SYNC_SIGN_IN) - } - is SyncCardsAcrossDevicesClicked -> { - goToScreen(AutofillScreenDestination.SYNC_SIGN_IN) - } - is UpdateAddressesSyncStatus -> { - updateSyncStatusAcrossDevices(AutofillScreenDestination.ADDRESS, action.newStatus) - } - is UpdateCreditCardsSyncStatus -> { - updateSyncStatusAcrossDevices( - AutofillScreenDestination.CREDIT_CARD, - action.newStatus, - ) - } - is ManageAddressesClicked -> { - goToScreen(AutofillScreenDestination.MANAGE_ADDRESSES) - } - is ManageCreditCardsClicked -> { - goToScreen(AutofillScreenDestination.MANAGE_CREDIT_CARDS) - } - is ViewDisposed -> { - accountManager.unregister(observer) - } - is UpdateAddresses, - is UpdateCreditCards, - is AccountAuthenticationAction.Authenticated, - is AccountAuthenticationAction.Failed, - is AccountAuthenticationAction.NotAuthenticated, - -> Unit - } - } - - private fun Store<AutofillSettingsState, AutofillSettingsAction>.loadAddressesAndCreditCards() = - scope.launch { - val addresses = autofillSettingsStorage.getAllAddresses() - val creditCards = autofillSettingsStorage.getAllCreditCards() - - dispatch(UpdateAddresses(addresses = addresses)) - dispatch(UpdateCreditCards(creditCards = creditCards)) - } - - private fun Store<AutofillSettingsState, AutofillSettingsAction>.registerObserverForAccountChanges( - accountManager: FxaAccountManager, - ) = - scope.launch { - observer = object : AccountObserver { - override fun onAuthenticated(account: OAuthAccount, authType: AuthType) { - dispatch(AccountAuthenticationAction.Authenticated) - } - - override fun onLoggedOut() { - dispatch(AccountAuthenticationAction.NotAuthenticated) - } - - override fun onAuthenticationProblems() { - dispatch(AccountAuthenticationAction.Failed) - } - } - - accountManager.register(observer) - } -} diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsReducer.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsReducer.kt @@ -1,63 +0,0 @@ -/* 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.settings.autofill.ui - -/** - * Function for reducing a new autofill settings state based on the received action. - */ -internal fun autofillSettingsReducer(state: AutofillSettingsState, action: AutofillSettingsAction) = - when (action) { - is UpdateAddresses -> { - state.copy( - addresses = action.addresses, - ) - } - - is UpdateCreditCards -> { - state.copy( - creditCards = action.creditCards, - ) - } - - is AutofillSettingsBackClicked -> { - state.copy( - addresses = listOf(), - creditCards = listOf(), - ) - } - - is ChangeAddressSaveFillPreference -> { - state.copy(saveFillAddresses = action.isChecked) - } - - is ChangeCardSaveFillPreference -> { - state.copy(saveFillCards = action.isChecked) - } - - is AccountAuthenticationAction.Authenticated -> { - state.copy(accountAuthState = AccountAuthState.Authenticated) - } - - is AccountAuthenticationAction.Failed -> { - state.copy(accountAuthState = AccountAuthState.NeedsReauthentication) - } - - is AccountAuthenticationAction.NotAuthenticated -> { - state.copy(accountAuthState = AccountAuthState.LoggedOut) - } - - is UpdateAddressesSyncStatus -> { - state.copy(syncAddresses = action.newStatus) - } - - is UpdateCreditCardsSyncStatus -> { - state.copy(syncCreditCards = action.newStatus) - } - - ViewDisposed, - is InitializeAddressesAndCreditCards, AddAddressClicked, AddCardClicked, SyncAddressesAcrossDevicesClicked, - SyncCardsAcrossDevicesClicked, ManageAddressesClicked, ManageCreditCardsClicked, - -> state - } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsScreen.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsScreen.kt @@ -1,395 +0,0 @@ -/* 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.settings.autofill.ui - -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Switch -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.Role -import androidx.compose.ui.unit.dp -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import mozilla.components.compose.base.annotation.FlexibleWindowLightDarkPreview -import mozilla.components.compose.base.button.IconButton -import mozilla.components.lib.state.ext.observeAsState -import mozilla.components.service.fxa.manager.FxaAccountManager -import org.mozilla.fenix.R -import org.mozilla.fenix.compose.list.IconListItem -import org.mozilla.fenix.theme.FirefoxTheme -import mozilla.components.ui.icons.R as iconsR - -private const val WEIGHT_TEXT = 5f -private const val WEIGHT_SWITCH = 2f - -@Composable -internal fun AutofillSettingsScreen( - buildStore: (NavHostController) -> AutofillSettingsStore, - accountManager: FxaAccountManager?, - isAddressSyncEnabled: Boolean, -) { - val navController = rememberNavController() - val store = buildStore(navController) - - DisposableEffect(Unit) { - val authenticated = accountManager?.authenticatedAccount() != null - val needsReauthentication = accountManager?.accountNeedsReauth() == true - - when { - needsReauthentication -> { - store.dispatch(AccountAuthenticationAction.Failed) - } - authenticated -> { - store.dispatch(AccountAuthenticationAction.Authenticated) - } - !authenticated -> { - store.dispatch(AccountAuthenticationAction.NotAuthenticated) - } - } - - onDispose { - store.dispatch(ViewDisposed) - } - } - - Scaffold( - topBar = { - AutofillSettingsTopBar(store) - }, - containerColor = FirefoxTheme.colors.layer1, - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxWidth(), - ) { - Spacer(modifier = Modifier.height(FirefoxTheme.layout.space.static200)) - AutofillSettingsAddressSection(store, isAddressSyncEnabled) - - // delimiter line between sections - HorizontalDivider( - modifier = Modifier.padding( - start = 4.dp, - end = 4.dp, - top = 16.dp, - bottom = 16.dp, - ), - color = FirefoxTheme.colors.indicatorInactive, thickness = 0.3.dp, - ) - - AutofillSettingsCreditCardSection(store) - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun AutofillSettingsTopBar(store: AutofillSettingsStore) { - TopAppBar( - colors = TopAppBarDefaults.topAppBarColors(containerColor = FirefoxTheme.colors.layer1), - windowInsets = WindowInsets( - top = 0.dp, - bottom = 0.dp, - ), - title = { - Text( - text = stringResource(R.string.preferences_autofill), - color = FirefoxTheme.colors.textPrimary, - style = FirefoxTheme.typography.headline6, - ) - }, - navigationIcon = { - IconButton( - modifier = Modifier - .padding(horizontal = FirefoxTheme.layout.space.static50), - onClick = { store.dispatch(AutofillSettingsBackClicked) }, - contentDescription = stringResource( - R.string.autofill_settings_navigate_back_button_content_description, - ), - ) { - Icon( - painter = painterResource(iconsR.drawable.mozac_ic_back_24), - contentDescription = null, - tint = FirefoxTheme.colors.iconPrimary, - ) - } - }, - ) -} - -@Composable -private fun AutofillSettingsAddressSection( - store: AutofillSettingsStore, - isAddressSyncEnabled: Boolean, -) { - val state by store.observeAsState(store.state) { it } - - AddSectionLabel(label = stringResource(id = R.string.preferences_addresses)) - Spacer(modifier = Modifier.height(FirefoxTheme.layout.space.static200)) - SaveFillSwitch( - title = stringResource(id = R.string.preferences_addresses_save_and_autofill_addresses_2), - label = stringResource(id = R.string.preferences_addresses_save_and_autofill_addresses_summary_2), - isChecked = state.saveFillAddresses, - onStateChange = { store.dispatch(ChangeAddressSaveFillPreference(!state.saveFillAddresses)) }, - ) - Spacer(modifier = Modifier.height(FirefoxTheme.layout.space.static100)) - - if (isAddressSyncEnabled) { - if (state.accountAuthState == AccountAuthState.Authenticated) { - SyncAcrossDevicesForAuthenticatedAccount( - text = stringResource(id = R.string.preferences_addresses_sync_addresses), - isChecked = state.syncAddresses, - onSyncStateChange = { store.dispatch(UpdateAddressesSyncStatus(!state.syncAddresses)) }, - ) - } else { - SyncAcrossDevicesForNotAuthenticatedAccount( - text = stringResource(id = R.string.preferences_addresses_sync_addresses_across_devices), - onClick = { store.dispatch(SyncAddressesAcrossDevicesClicked) }, - ) - } - } - - if (state.addresses.isEmpty()) { - Spacer(modifier = Modifier.height(FirefoxTheme.layout.space.static100)) - - AddItem( - label = stringResource(R.string.preferences_addresses_add_address), - onAddItemClicked = { store.dispatch(AddAddressClicked) }, - ) - } else { - Spacer(modifier = Modifier.height(FirefoxTheme.layout.space.static150)) - - ManageItem( - text = stringResource(id = R.string.preferences_addresses_manage_addresses), - onClick = { store.dispatch(ManageAddressesClicked) }, - ) - } -} - -@Composable -private fun AutofillSettingsCreditCardSection(store: AutofillSettingsStore) { - val state by store.observeAsState(store.state) { it } - - AddSectionLabel(label = stringResource(id = R.string.preferences_credit_cards_2)) - Spacer(modifier = Modifier.height(FirefoxTheme.layout.space.static200)) - SaveFillSwitch( - title = stringResource(id = R.string.preferences_credit_cards_save_and_autofill_cards_2), - label = stringResource( - id = R.string.preferences_credit_cards_save_and_autofill_cards_summary_2, - stringResource(id = R.string.app_name), - ), - isChecked = state.saveFillCards, - onStateChange = { store.dispatch(ChangeCardSaveFillPreference(!state.saveFillCards)) }, - ) - Spacer(modifier = Modifier.height(FirefoxTheme.layout.space.static100)) - - if (state.accountAuthState == AccountAuthState.Authenticated) { - SyncAcrossDevicesForAuthenticatedAccount( - text = stringResource(id = R.string.preferences_credit_cards_sync_cards), - isChecked = state.syncCreditCards, - onSyncStateChange = { store.dispatch(UpdateCreditCardsSyncStatus(!state.syncCreditCards)) }, - ) - } else { - SyncAcrossDevicesForNotAuthenticatedAccount( - text = stringResource(id = R.string.preferences_credit_cards_sync_cards_across_devices), - onClick = { store.dispatch(SyncCardsAcrossDevicesClicked) }, - ) - } - - if (state.creditCards.isEmpty()) { - Spacer(modifier = Modifier.height(FirefoxTheme.layout.space.static100)) - - AddItem( - label = stringResource(R.string.credit_cards_add_card), - onAddItemClicked = { store.dispatch(AddCardClicked) }, - ) - } else { - Spacer(modifier = Modifier.height(FirefoxTheme.layout.space.static150)) - ManageItem( - text = stringResource(id = R.string.preferences_credit_cards_manage_saved_cards_2), - onClick = { store.dispatch(ManageCreditCardsClicked) }, - ) - } -} - -@Composable -private fun AddSectionLabel(label: String) { - Text( - text = label, - modifier = Modifier.padding(start = FirefoxTheme.layout.space.static200), - style = FirefoxTheme.typography.headline8, - color = MaterialTheme.colorScheme.tertiary, - ) -} - -@Composable -private fun SaveFillSwitch( - title: String, - label: String, - isChecked: Boolean, - onStateChange: (Boolean) -> Unit, -) { - val interactionSource = remember { MutableInteractionSource() } - Text( - text = title, - modifier = Modifier.padding(start = FirefoxTheme.layout.space.static400), - style = FirefoxTheme.typography.body1, - color = FirefoxTheme.colors.textPrimary, - ) - - Row( - modifier = Modifier - .clickable( - interactionSource = interactionSource, - indication = null, - role = Role.Switch, - onClick = { - onStateChange(!isChecked) - }, - ) - .width(FirefoxTheme.layout.size.containerMaxWidth), - horizontalArrangement = Arrangement.Absolute.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - text = label, - modifier = Modifier - .padding(start = FirefoxTheme.layout.space.static500) - .weight(WEIGHT_TEXT), - maxLines = 2, - style = FirefoxTheme.typography.body2, - color = FirefoxTheme.colors.textSecondary, - ) - - Switch( - checked = isChecked, - modifier = Modifier.weight(WEIGHT_SWITCH), - onCheckedChange = { - onStateChange(it) - }, - ) - } -} - -@Composable -private fun SyncAcrossDevicesForAuthenticatedAccount( - text: String, - isChecked: Boolean, - onSyncStateChange: (Boolean) -> Unit, -) { - val interactionSource = remember { MutableInteractionSource() } - Row( - modifier = Modifier - .clickable( - interactionSource = interactionSource, - indication = null, - role = Role.Switch, - onClick = { - onSyncStateChange(!isChecked) - }, - ) - .width(FirefoxTheme.layout.size.containerMaxWidth), - horizontalArrangement = Arrangement.Absolute.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - text = text, - modifier = Modifier - .padding(start = FirefoxTheme.layout.space.static400) - .weight(WEIGHT_TEXT), - maxLines = 2, - style = FirefoxTheme.typography.body1, - color = FirefoxTheme.colors.textPrimary, - ) - - Switch( - checked = isChecked, - modifier = Modifier.weight(WEIGHT_SWITCH), - onCheckedChange = { - onSyncStateChange(it) - }, - ) - } -} - -@Composable -private fun SyncAcrossDevicesForNotAuthenticatedAccount(text: String, onClick: () -> Unit) { - Text( - text = text, - modifier = Modifier - .padding(start = FirefoxTheme.layout.space.static400) - .clickable(onClick = onClick), - style = FirefoxTheme.typography.body1, - color = FirefoxTheme.colors.textPrimary, - ) -} - -@Composable -private fun AddItem( - label: String, - onAddItemClicked: () -> Unit, -) { - IconListItem( - label = label, - modifier = Modifier - .padding(start = 10.dp) - .width(FirefoxTheme.layout.size.containerMaxWidth), - beforeIconPainter = painterResource(iconsR.drawable.mozac_ic_plus_24), - onClick = { onAddItemClicked() }, - ) -} - -@Composable -private fun ManageItem(text: String, onClick: () -> Unit) { - Text( - text = text, - modifier = Modifier - .padding(start = FirefoxTheme.layout.space.static400) - .clickable(onClick = onClick), - style = FirefoxTheme.typography.body1, - color = FirefoxTheme.colors.textPrimary, - ) -} - -@Composable -@FlexibleWindowLightDarkPreview -private fun AutofillSettingsScreenPreview() { - val store = { _: NavHostController -> - AutofillSettingsStore( - initialState = AutofillSettingsState.default, - ) - } - FirefoxTheme { - Box(modifier = Modifier.background(color = FirefoxTheme.colors.layer1)) { - AutofillSettingsScreen(store, null, true) - } - } -} diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsState.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsState.kt @@ -1,48 +0,0 @@ -/* 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.settings.autofill.ui - -import mozilla.components.concept.storage.Address -import mozilla.components.concept.storage.CreditCard -import mozilla.components.lib.state.State - -/** - * Represents the state of the autofill settings screen. - * - * @property addresses The list of [Address]es to display in the address list. - * @property creditCards The list of [CreditCard]s to display in the credit card list. - * @property saveFillAddresses True if the option of saving and filling addresses info is enabled. - * @property saveFillCards True if the option of saving and filling cards info is enabled. - * @property accountAuthState The account authentication state. - * @property syncAddresses True if the option of syncing addresses across devices is enabled. - * @property syncCreditCards True if the option of syncing credit cards across devices is enabled. - */ -internal data class AutofillSettingsState( - val addresses: List<Address>, - val creditCards: List<CreditCard>, - val saveFillAddresses: Boolean, - val saveFillCards: Boolean, - val accountAuthState: AccountAuthState, - val syncAddresses: Boolean, - val syncCreditCards: Boolean, -) : State { - companion object { - val default: AutofillSettingsState = AutofillSettingsState( - addresses = listOf(), - creditCards = listOf(), - saveFillAddresses = false, - saveFillCards = false, - accountAuthState = AccountAuthState.LoggedOut, - syncAddresses = false, - syncCreditCards = false, - ) - } -} - -internal sealed class AccountAuthState { - data object LoggedOut : AccountAuthState() - data object Authenticated : AccountAuthState() - data object NeedsReauthentication : AccountAuthState() -} diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsStore.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsStore.kt @@ -1,30 +0,0 @@ -/* 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.settings.autofill.ui - -import mozilla.components.lib.state.Middleware -import mozilla.components.lib.state.Reducer -import mozilla.components.lib.state.Store - -/** - * A Store for handling [AutofillSettingsState] and dispatching [AutofillSettingsAction]. - * - * @param initialState The initial state for the Store. - * @param reducer Reducer to handle state updates based on dispatched actions. - * @param middleware Middleware to handle side-effects in response to dispatched actions. - */ -internal class AutofillSettingsStore( - initialState: AutofillSettingsState = AutofillSettingsState.default, - reducer: Reducer<AutofillSettingsState, AutofillSettingsAction> = ::autofillSettingsReducer, - middleware: List<Middleware<AutofillSettingsState, AutofillSettingsAction>> = listOf(), -) : Store<AutofillSettingsState, AutofillSettingsAction>( - initialState = initialState, - reducer = reducer, - middleware = middleware, -) { - init { - dispatch(InitializeAddressesAndCreditCards) - } -} diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -2024,16 +2024,6 @@ class Settings( ) /** - * Stores the user choice from the "Autofill" settings for whether - * credit cards should be synced across devices or not, when the user is authenticated. - * If set to `true`, then the credit cards will be synced across devices. - */ - var shouldSyncCreditCardsAcrossDevices by booleanPreference( - appContext.getPreferenceKey(R.string.pref_key_credit_cards_sync_cards_across_devices), - default = false, - ) - - /** * Stores the user choice from the "Autofill Addresses" settings for whether * save and autofill addresses should be enabled or not. * If set to `true` when the user focuses on address fields in a webpage an Android prompt is shown, @@ -2045,16 +2035,6 @@ class Settings( ) /** - * Stores the user choice from the "Autofill" settings for whether - * addresses should be synced across devices or not, when the user is authenticated. - * If set to `true`, then the addresses will be synced across devices. - */ - var shouldSyncAddressesAcrossDevices by booleanPreference( - appContext.getPreferenceKey(R.string.pref_key_addresses_sync_cards_across_devices), - default = false, - ) - - /** * Get the profile id to use in the sponsored stories communications with the Pocket endpoint. */ val pocketSponsoredStoriesProfileId by stringPreference( @@ -2632,14 +2612,6 @@ class Settings( ) /** - * Indicates whether or not we should use the new compose autofill settings UI - */ - var enableComposeAutofillSettings by booleanPreference( - key = appContext.getPreferenceKey(R.string.pref_key_enable_compose_logins), - default = false, - ) - - /** * Indicates whether or not to show the entry point for the DNS over HTTPS settings */ val showDohEntryPoint by lazyFeatureFlagPreference( diff --git a/mobile/android/fenix/app/src/main/res/values/strings.xml b/mobile/android/fenix/app/src/main/res/values/strings.xml @@ -2526,8 +2526,6 @@ <string name="preferences_addresses_sync_addresses_across_devices">Sync addresses across devices</string> <!-- Preference option for syncing addresses across devices. This is displayed when the user is signed into sync --> <string name="preferences_addresses_sync_addresses">Sync addresses</string> - <!-- Content description navigating back from autofill settings screen. --> - <string name="autofill_settings_navigate_back_button_content_description">Back</string> <!-- Title of the "Add card" screen --> <string name="credit_cards_add_card">Add card</string> diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsMiddlewareTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsMiddlewareTest.kt @@ -1,153 +0,0 @@ -/* 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.settings.autofill.ui - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import kotlinx.coroutines.test.StandardTestDispatcher -import kotlinx.coroutines.test.runTest -import mozilla.components.lib.dataprotect.SecureAbove22Preferences -import mozilla.components.service.fxa.manager.FxaAccountManager -import mozilla.components.service.sync.autofill.AutofillCreditCardsAddressesStorage -import mozilla.components.support.test.mock -import mozilla.components.support.test.robolectric.testContext -import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -class AutofillSettingsMiddlewareTest { - - private lateinit var securePrefs: SecureAbove22Preferences - private lateinit var autofillSettingsStorage: AutofillCreditCardsAddressesStorage - private lateinit var accountManager: FxaAccountManager - private lateinit var updateSaveFillStatus: (String, Boolean) -> Unit - private lateinit var updateSyncStatusAcrossDevices: (String, Boolean) -> Unit - private lateinit var goToScreen: (String) -> Unit - private lateinit var exitAutofillSettings: () -> Unit - - private val testDispatcher = StandardTestDispatcher() - - @Before - fun setup() { - securePrefs = SecureAbove22Preferences(testContext, "autofill", forceInsecure = true) - autofillSettingsStorage = - AutofillCreditCardsAddressesStorage(testContext, lazy { securePrefs }) - accountManager = mock() - updateSaveFillStatus = { _, _ -> } - updateSyncStatusAcrossDevices = { _, _ -> } - goToScreen = { } - exitAutofillSettings = { } - } - - @Test - fun `GIVEN no addresses in storage WHEN store is initialized THEN list of addresses will be empty`() = - runTest(testDispatcher) { - val middleware = buildMiddleware() - val store = middleware.makeStore() - testDispatcher.scheduler.advanceUntilIdle() - - assertEquals(0, store.state.addresses.size) - } - - @Test - fun `GIVEN no credit cards in storage WHEN store is initialized THEN list of credit cards will be empty`() = - runTest(testDispatcher) { - val middleware = buildMiddleware() - val store = middleware.makeStore() - testDispatcher.scheduler.advanceUntilIdle() - - assertEquals(0, store.state.creditCards.size) - } - - @Test - fun `WHEN back is clicked THEN exit autofill settings`() = - runTest(testDispatcher) { - var exited = false - exitAutofillSettings = { exited = true } - val middleware = buildMiddleware() - val store = middleware.makeStore() - - store.dispatch(AutofillSettingsBackClicked) - testDispatcher.scheduler.advanceUntilIdle() - - assertTrue(exited) - } - - @Test - fun `GIVEN an autofill settings store WHEN save fill addresses option is changed THEN save the new value`() = - runTest(testDispatcher) { - var newSaveFillAddressesOption = false - updateSaveFillStatus = { _, newOption -> - newSaveFillAddressesOption = newOption - } - val middleware = buildMiddleware() - val store = middleware.makeStore() - store.dispatch(ChangeAddressSaveFillPreference(true)) - testDispatcher.scheduler.advanceUntilIdle() - assertTrue(newSaveFillAddressesOption) - } - - @Test - fun `GIVEN an autofill settings store WHEN save fill credit cards option is changed THEN save the new value`() = - runTest(testDispatcher) { - var newSaveFillCreditCardsOption = true - updateSaveFillStatus = { _, newOption -> - newSaveFillCreditCardsOption = newOption - } - val middleware = buildMiddleware() - val store = middleware.makeStore() - store.dispatch(ChangeCardSaveFillPreference(false)) - testDispatcher.scheduler.advanceUntilIdle() - assertFalse(newSaveFillCreditCardsOption) - } - - @Test - fun `GIVEN an autofill settings store WHEN sync addresses option is changed THEN save the new value`() = - runTest(testDispatcher) { - var newSyncAddressesOption = false - updateSyncStatusAcrossDevices = { _, newOption -> - newSyncAddressesOption = newOption - } - val middleware = buildMiddleware() - val store = middleware.makeStore() - store.dispatch(UpdateAddressesSyncStatus(true)) - testDispatcher.scheduler.advanceUntilIdle() - assertTrue(newSyncAddressesOption) - } - - @Test - fun `GIVEN an autofill settings store WHEN sync credit cards option is changed THEN save the new value`() = - runTest(testDispatcher) { - var newSyncCreditCardsOption = true - updateSyncStatusAcrossDevices = { _, newOption -> - newSyncCreditCardsOption = newOption - } - val middleware = buildMiddleware() - val store = middleware.makeStore() - store.dispatch(UpdateCreditCardsSyncStatus(false)) - testDispatcher.scheduler.advanceUntilIdle() - assertFalse(newSyncCreditCardsOption) - } - - private fun buildMiddleware() = AutofillSettingsMiddleware( - autofillSettingsStorage = autofillSettingsStorage, - accountManager = accountManager, - updateSaveFillStatus = updateSaveFillStatus, - updateSyncStatusAcrossDevices = updateSyncStatusAcrossDevices, - goToScreen = goToScreen, - exitAutofillSettings = exitAutofillSettings, - ioDispatcher = testDispatcher, - ) - - private fun AutofillSettingsMiddleware.makeStore( - initialState: AutofillSettingsState = AutofillSettingsState.default, - ) = AutofillSettingsStore( - initialState = initialState, - middleware = listOf(this), - ) -} diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsReducerTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/autofill/ui/AutofillSettingsReducerTest.kt @@ -1,211 +0,0 @@ -/* 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.settings.autofill.ui - -import mozilla.components.concept.storage.Address -import mozilla.components.concept.storage.CreditCard -import mozilla.components.concept.storage.CreditCardNumber -import org.junit.Assert.assertEquals -import org.junit.Test - -class AutofillSettingsReducerTest { - - @Test - fun `WHEN addresses are loaded THEN they are added to state`() { - val state = AutofillSettingsState.default - val addresses = List(5) { - Address( - guid = "$it", - name = "name$it", - organization = "organization$it", - streetAddress = "street$it", - addressLevel1 = "", - addressLevel2 = "", - addressLevel3 = "", - postalCode = "40066$it", - country = "country$it", - tel = "123456$it", - email = "user$it@gmail.com", - timeCreated = System.currentTimeMillis(), - timeLastUsed = System.currentTimeMillis(), - timeLastModified = System.currentTimeMillis(), - timesUsed = 1L, - ) - } - - val result = autofillSettingsReducer( - state, - UpdateAddresses( - addresses = addresses, - ), - ) - - val expected = state.copy( - addresses = addresses, - ) - assertEquals(expected, result) - } - - @Test - fun `WHEN creditCards are loaded THEN they are added to state`() { - val state = AutofillSettingsState.default - val creditCards = List(5) { - CreditCard( - guid = "$it", - billingName = "name$it", - encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111111"), - cardNumberLast4 = "211$it", - expiryMonth = 12, - expiryYear = 2029, - cardType = "Visa", - timeCreated = System.currentTimeMillis(), - timeLastUsed = System.currentTimeMillis(), - timeLastModified = System.currentTimeMillis(), - timesUsed = 1L, - ) - } - - val result = autofillSettingsReducer( - state, - UpdateCreditCards( - creditCards = creditCards, - ), - ) - - val expected = state.copy( - creditCards = creditCards, - ) - assertEquals(expected, result) - } - - @Test - fun `WHEN the back button is clicked THEN remove all addresses from state`() { - val addresses = List(5) { - Address( - guid = "$it", - name = "name$it", - organization = "organization$it", - streetAddress = "street$it", - addressLevel1 = "", - addressLevel2 = "", - addressLevel3 = "", - postalCode = "40066$it", - country = "country$it", - tel = "123456$it", - email = "user$it@gmail.com", - timeCreated = System.currentTimeMillis(), - timeLastUsed = System.currentTimeMillis(), - timeLastModified = System.currentTimeMillis(), - timesUsed = 1L, - ) - } - - val state = AutofillSettingsState.default.copy(addresses = addresses) - val result = autofillSettingsReducer(state, AutofillSettingsBackClicked) - - val expectedResult = state.copy(addresses = listOf()) - - assertEquals(result, expectedResult) - } - - @Test - fun `WHEN the back button is clicked THEN remove all credit cards from state`() { - val creditCards = List(5) { - CreditCard( - guid = "$it", - billingName = "name$it", - encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111111"), - cardNumberLast4 = "211$it", - expiryMonth = 12, - expiryYear = 2029, - cardType = "Visa", - timeCreated = System.currentTimeMillis(), - timeLastUsed = System.currentTimeMillis(), - timeLastModified = System.currentTimeMillis(), - timesUsed = 1L, - ) - } - - val state = AutofillSettingsState.default.copy(creditCards = creditCards) - val result = autofillSettingsReducer(state, AutofillSettingsBackClicked) - - val expectedResult = state.copy(creditCards = listOf()) - - assertEquals(result, expectedResult) - } - - @Test - fun `WHEN save and fill addresses option is changed THEN this is reflected in the state`() { - val state = AutofillSettingsState.default.copy(saveFillAddresses = true) - val result = autofillSettingsReducer(state, ChangeAddressSaveFillPreference(false)) - - val expectedResult = state.copy(saveFillAddresses = false) - - assertEquals(result, expectedResult) - } - - @Test - fun `WHEN save and fill credit cards option is changed THEN this is reflected in the state`() { - val state = AutofillSettingsState.default.copy(saveFillAddresses = false) - val result = autofillSettingsReducer(state, ChangeAddressSaveFillPreference(true)) - - val expectedResult = state.copy(saveFillAddresses = true) - - assertEquals(result, expectedResult) - } - - @Test - fun `WHEN sync addresses option is changed THEN this is reflected in the state`() { - val state = AutofillSettingsState.default.copy(syncAddresses = true) - val result = autofillSettingsReducer(state, UpdateAddressesSyncStatus(false)) - - val expectedResult = state.copy(syncAddresses = false) - - assertEquals(result, expectedResult) - } - - @Test - fun `WHEN sync credit cards option is changed THEN this is reflected in the state`() { - val state = AutofillSettingsState.default.copy(syncCreditCards = false) - val result = autofillSettingsReducer(state, UpdateCreditCardsSyncStatus(true)) - - val expectedResult = state.copy(syncCreditCards = true) - - assertEquals(result, expectedResult) - } - - @Test - fun `WHEN account authentication succeeds THEN this is reflected in the state`() { - val state = - AutofillSettingsState.default.copy(accountAuthState = AccountAuthState.LoggedOut) - val result = autofillSettingsReducer(state, AccountAuthenticationAction.Authenticated) - - val expectedResult = state.copy(accountAuthState = AccountAuthState.Authenticated) - - assertEquals(result, expectedResult) - } - - @Test - fun `WHEN account authentication encounters a problem THEN this is reflected in the state`() { - val state = - AutofillSettingsState.default.copy(accountAuthState = AccountAuthState.Authenticated) - val result = autofillSettingsReducer(state, AccountAuthenticationAction.Failed) - - val expectedResult = state.copy(accountAuthState = AccountAuthState.NeedsReauthentication) - - assertEquals(result, expectedResult) - } - - @Test - fun `WHEN account authentication fails THEN this is reflected in the state`() { - val state = - AutofillSettingsState.default.copy(accountAuthState = AccountAuthState.Authenticated) - val result = autofillSettingsReducer(state, AccountAuthenticationAction.NotAuthenticated) - - val expectedResult = state.copy(accountAuthState = AccountAuthState.LoggedOut) - - assertEquals(result, expectedResult) - } -}