From 721115e64e60f1b1ee0e656666b60a5435d910c0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Apr 2026 13:17:34 +0100 Subject: [PATCH] Updated on 2026-08-14 --- core/res/src/main/res/values/strings.xml | 70 +++++++++++++------ .../DefaultAddressSyncComponent.kt | 14 +--- .../v2/addresssync/model/AddressSyncIntent.kt | 2 +- .../v2/addresssync/model/AddressSyncModel.kt | 56 +++++++++++---- .../addresssync/navigation/AddressSyncStep.kt | 11 +-- .../DefaultOnboardingMultiWalletComponent.kt | 1 + .../impl/model/OnboardingMultiWalletModel.kt | 7 +- .../v2/multiwallet/impl/model/Utils.kt | 2 +- .../addresssync/model/AddressSyncModelTest.kt | 53 ++++++++++++-- 9 files changed, 160 insertions(+), 56 deletions(-) diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index da1a8d484c..b40fb7272c 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -274,6 +274,10 @@ day days + + %d day ago + %d days ago + Delete Disable Disabled @@ -308,6 +312,10 @@ Hide Hold to %s hour + + %dh ago + %dh ago + Import In progress Insufficient balance @@ -318,6 +326,10 @@ Locked Locked Wallets Main network + + %d minute ago + %d minutes ago + month Network fee Amount sent will be reduced by %1$s (%2$s) to cover the selected fee level @@ -487,7 +499,6 @@ Disable dynamic addresses Dynamic addresses disabled Dynamic addresses enabled - Dynamic address Use a new address for each transaction to reduce traceability and improve on-chain privacy. Enhanced Privacy Easily receive funds in UTXO-based networks with automatic address generation — no manual address management required. @@ -498,6 +509,9 @@ Dynamic Addresses Unavailable We can’t connect to the provider right now. Please try again later. Service unavailable. Please try again. + Funds were found on additional addresses. Enable Dynamic Addresses to access them. + Funds found on additional addresses + Dynamic address Best opportunities Clear filter The list is temporarily empty as it’s being refreshed. Check back in a moment. @@ -569,6 +583,7 @@ Provider Best rate FCA Warning List + Fixed rate is unavailable Competitive rate Provider in FCA warning list Available up to %s @@ -781,6 +796,7 @@ No data **Add to your portfolio** to start buying, exchanging or receiving this asset In your portfolio + Your portfolio Market Pulse Quick actions Clear all @@ -1020,7 +1036,9 @@ Getting started Another wallet has already been created on the card you\'re trying to add. If you have funds in this wallet, please withdraw it and then reset this card and add it as a backup. Save your wallet + Use biometrics Creating a backup + Last step Biometrics Read more about seed phrase @@ -1516,13 +1534,21 @@ Feel confident with round-the-clock support to help with any issues Always Here Multiple trusted providers in one place—swap any asset effortlessly in your wallet + Exchange crypto directly in Tangem\nNo additional transfers
\nNo moving funds to exchanges Swap With Us + Swap Inside Your Wallet No fumbles, no turnovers, no blind spots—your transaction is always protected + Swaps are executed through trusted providers. Your keys remain in your Tangem wallet at all times. 
Clear. Transparent. Self-custodial. Impenetrable Defense + You Stay in Control Maximize your value with rates sourced from a wide network of trusted providers, always choosing the best one + Tangem compares multiple providers, both DEX and CEX. The best rate is selected automatically. Prefer another provider? You can choose it manually. Unbeatable Rates + Best Available Rate Hassle-free and intuitive, allowing you to swap tokens in just a few taps + Swap across major networks
and thousands of tokens 0% fee on stablecoin-to-stablecoin swaps Simply Convenient + 90+ Blockchains
\n16,000+ Assets Swap via provider Your assets The amount includes:\n• service provider\'s fee\n• network fee for sending %s from the exchange back to the user\'s address. @@ -1557,17 +1583,6 @@ Explore transaction Service fees Fee - Replace card - Replace your card? - This generates a new set of card details. Your old details will stop working. You can\'t undo this. - Replacement fee - Replace card - Replacing your digital card - Usually takes up to 5 minutes. In rare cases, up to 48 hours. - Insufficient funds to replace the card - Unable to cover fee - Deposit USDC to payment account to cover the issuing fee - Replacement fee info unreachable Keep your money safe. You can unfreeze anytime. Freeze your card? Failed to freeze the card. Try again later. @@ -1629,6 +1644,7 @@ Share your address or show QR-code Technical issues detected. Please try again later or contact support. Receive unavailable now + Replace card Only letters and numbers are allowed. Invalid characters Reveal @@ -1643,14 +1659,18 @@ Withdraw unavailable now You can\'t initiate swap or new withdrawal till the current one is finished Withdrawal in progress - Card settings - Daily limit - Current limit Change - Daily limit unavailable + Current limit We couldn\'t load your daily limit. Please try again. + Daily limit unavailable + You can change it again anytime you like + Daily limit is set + Daily limit + Card settings Change PIN-code Come back to the app if you forget it. + Set a limit from %s to %s + Set limits Digital card I understand that I will completely lose access to my Tangem Pay Card and all funds on it without the possibility of recovery Failed to issue card @@ -1693,12 +1713,22 @@ Payment account Payment account is not synced Invalid PIN: avoid sequences or repeats + Replace card + This generates a new set of card details. Your old details will stop working. You can\'t undo this. + Replacement fee + Replacement fee info unreachable + Replacing your digital card + Usually takes up to 5 minutes. In rare cases, up to 48 hours. + Insufficient funds to replace the card + Deposit USDC to payment account to cover the issuing fee + Unable to cover fee + Replace your card? We’re fixing a technical issue. Please try again later. Service temporarily unavailable Unable to display details. However, card payments are still working. Set \nPIN code Session expired - Restore access + Renew session Use USDC for everyday payments Tangem Pay is temporarily unreachable Tangem Pay @@ -1786,7 +1816,7 @@ Use %s or scan a card/ring to have access to your wallet Connection failed: This dApp uses Wallet Connect version 1.0, which is not supported. Please ensure the dApp supports Wallet Connect version 2.0 to connect successfully. Previous permission will be revoked and a new one will be issued. Network will charge token approval fee for each of theses actions. You will see a zero-amount transaction in the history as a revoke evidence. - Transaction exceeds previously granted permission amount.\nUpdate permission to proceed + Transaction exceeds previously granted permission amount.\nUpdate permission to proceed Update permission Upgrade to hardware wallet Stay up to date with the latest features and news @@ -2157,8 +2187,6 @@ At least one network is required for dApp connection Specify selected networks Successfully signed - Share Addresses - Addresses to share WalletConnect To Transaction request @@ -2268,7 +2296,7 @@ All your future incoming %1$s deposits will be automatically supplied to Aave. Active Paused - Disabling Yield Mode + Disable Yield Mode Turning this off will withdraw your assets from Aave, convert them back to %s in your wallet, and stop yield accrual. A network fee is charged by the blockchain when you exit Yield Mode. Disable Yield Mode diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/DefaultAddressSyncComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/DefaultAddressSyncComponent.kt index 255027abc8..f5999ae461 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/DefaultAddressSyncComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/DefaultAddressSyncComponent.kt @@ -1,6 +1,5 @@ package com.tangem.features.onboarding.v2.addresssync -import androidx.activity.compose.BackHandler import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.arkivanov.decompose.DelicateDecomposeApi @@ -18,6 +17,7 @@ import com.tangem.features.onboarding.v2.addresssync.model.AddressSyncIntent import com.tangem.features.onboarding.v2.addresssync.model.AddressSyncModel import com.tangem.features.onboarding.v2.addresssync.navigation.AddressSyncStep import com.tangem.features.onboarding.v2.addresssync.ui.AddressSyncContent +import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams import com.tangem.features.pushnotifications.api.PushNotificationsComponent import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacks import com.tangem.features.pushnotifications.api.PushNotificationsParams @@ -25,11 +25,12 @@ import com.tangem.features.pushnotifications.api.PushNotificationsParams @OptIn(DelicateDecomposeApi::class) internal class DefaultAddressSyncComponent( appComponentContext: AppComponentContext, + params: MultiWalletChildParams, private val askBiometryComponentFactory: AskBiometryComponent.Factory, private val pushNotificationsComponentFactory: PushNotificationsComponent.Factory, ) : AppComponentContext by appComponentContext, AddressSyncComponent { - private val model: AddressSyncModel = getOrCreateModel() + private val model: AddressSyncModel = getOrCreateModel(params) private val childStack: Value> = childStack( @@ -58,10 +59,6 @@ internal class DefaultAddressSyncComponent( } }, ) - - BackHandler { - model.onIntent(AddressSyncIntent.Back) - } } private fun createChild(step: AddressSyncStep, childContext: AppComponentContext): ComposableContentComponent { @@ -82,7 +79,6 @@ internal class DefaultAddressSyncComponent( model.onIntent( AddressSyncIntent.Next( step = AddressSyncStep.ASK_NOTIFICATIONS, - shouldReplace = true, ), ) } @@ -91,7 +87,6 @@ internal class DefaultAddressSyncComponent( model.onIntent( AddressSyncIntent.Next( step = AddressSyncStep.ASK_NOTIFICATIONS, - shouldReplace = false, ), ) } @@ -109,7 +104,6 @@ internal class DefaultAddressSyncComponent( model.onIntent( AddressSyncIntent.Next( step = AddressSyncStep.ADDRESS_SYNC, - shouldReplace = true, ), ) } @@ -118,7 +112,6 @@ internal class DefaultAddressSyncComponent( model.onIntent( AddressSyncIntent.Next( step = AddressSyncStep.ADDRESS_SYNC, - shouldReplace = false, ), ) } @@ -127,7 +120,6 @@ internal class DefaultAddressSyncComponent( model.onIntent( AddressSyncIntent.Next( step = AddressSyncStep.ADDRESS_SYNC, - shouldReplace = false, ), ) } diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncIntent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncIntent.kt index 1293c244d5..0776ea3cc7 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncIntent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncIntent.kt @@ -3,6 +3,6 @@ package com.tangem.features.onboarding.v2.addresssync.model import com.tangem.features.onboarding.v2.addresssync.navigation.AddressSyncStep sealed interface AddressSyncIntent { - data class Next(val step: AddressSyncStep, val shouldReplace: Boolean) : AddressSyncIntent + data class Next(val step: AddressSyncStep) : AddressSyncIntent data object Back : AddressSyncIntent } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncModel.kt index b06e54736c..a73fa83fae 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncModel.kt @@ -3,16 +3,19 @@ package com.tangem.features.onboarding.v2.addresssync.model import com.arkivanov.decompose.DelicateDecomposeApi import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.pop -import com.arkivanov.decompose.router.stack.push import com.arkivanov.decompose.router.stack.replaceCurrent import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model +import com.tangem.core.decompose.model.ParamsContainer +import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.settings.CanUseBiometryUseCase import com.tangem.domain.settings.ShouldAskPermissionUseCase import com.tangem.domain.settings.ShouldShowAskBiometryUseCase import com.tangem.features.onboarding.v2.addresssync.navigation.AddressSyncStep +import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import javax.inject.Inject @@ -23,10 +26,24 @@ internal class AddressSyncModel @Inject constructor( private val shouldShowAskBiometryUseCase: ShouldShowAskBiometryUseCase, private val canUseBiometryUseCase: CanUseBiometryUseCase, private val shouldAskPermissionUseCase: ShouldAskPermissionUseCase, + paramsContainer: ParamsContainer, ) : Model() { + private val params = paramsContainer.require() val stackNavigation = StackNavigation() + init { + params.innerNavigation.update { innerNavigationState -> + innerNavigationState.copy( + stackSize = AddressSyncStep.ASK_BIOMETRY.pageNumber, + stackMaxSize = ADDRESS_SYNC_MAX_STEPS, + ) + } + modelScope.launch { + trySkippingScreen(AddressSyncStep.ASK_BIOMETRY) + } + } + fun onIntent(intent: AddressSyncIntent) { when (intent) { is AddressSyncIntent.Next -> nextScreen(intent) @@ -35,27 +52,24 @@ internal class AddressSyncModel @Inject constructor( } private fun nextScreen(next: AddressSyncIntent.Next) { - val (nextStep, replace) = next - if (replace) { - stackNavigation.replaceCurrent(configuration = nextStep) - } else { - stackNavigation.push(configuration = nextStep) - } - modelScope.launch { trySkippingScreen(next) } + stackNavigation.replaceCurrent(configuration = next.step) + updateStepperPage(next) + updateTitle(next) + modelScope.launch { trySkippingScreen(next.step) } } - private suspend fun trySkippingScreen(next: AddressSyncIntent.Next) { - when (next.step) { + private suspend fun trySkippingScreen(step: AddressSyncStep) { + when (step) { AddressSyncStep.ASK_BIOMETRY -> { val shouldShowAskBiometry = canUseBiometryUseCase.strict() && shouldShowAskBiometryUseCase() if (shouldShowAskBiometry.not()) { - nextScreen(AddressSyncIntent.Next(step = AddressSyncStep.ASK_NOTIFICATIONS, shouldReplace = true)) + nextScreen(AddressSyncIntent.Next(step = AddressSyncStep.ASK_NOTIFICATIONS)) } } AddressSyncStep.ASK_NOTIFICATIONS -> { val shouldShowAskNotification = shouldAskPermissionUseCase(PUSH_PERMISSION) if (shouldShowAskNotification.not()) { - nextScreen(AddressSyncIntent.Next(step = AddressSyncStep.ADDRESS_SYNC, shouldReplace = true)) + nextScreen(AddressSyncIntent.Next(step = AddressSyncStep.ADDRESS_SYNC)) } } AddressSyncStep.ADDRESS_SYNC -> Unit @@ -65,4 +79,22 @@ internal class AddressSyncModel @Inject constructor( private fun goBack() { stackNavigation.pop() } + + private fun updateStepperPage(next: AddressSyncIntent.Next) { + params.innerNavigation.update { innerNavigationState -> + innerNavigationState.copy( + stackSize = next.step.pageNumber, + ) + } + } + + private fun updateTitle(next: AddressSyncIntent.Next) { + params.parentParams.titleProvider.changeTitle( + text = resourceReference(next.step.stringId), + ) + } + + private companion object { + const val ADDRESS_SYNC_MAX_STEPS = 3 + } } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/navigation/AddressSyncStep.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/navigation/AddressSyncStep.kt index edd056ce90..c03a4fc662 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/navigation/AddressSyncStep.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/addresssync/navigation/AddressSyncStep.kt @@ -1,7 +1,10 @@ package com.tangem.features.onboarding.v2.addresssync.navigation -enum class AddressSyncStep { - ASK_BIOMETRY, - ASK_NOTIFICATIONS, - ADDRESS_SYNC, +import androidx.annotation.StringRes +import com.tangem.features.onboarding.v2.impl.R + +enum class AddressSyncStep(val pageNumber: Int, @StringRes val stringId: Int) { + ASK_BIOMETRY(pageNumber = 1, stringId = R.string.onboarding_navbar_title_biometrics), + ASK_NOTIFICATIONS(pageNumber = 2, stringId = R.string.onboarding_title_notifications), + ADDRESS_SYNC(pageNumber = 3, stringId = R.string.onboarding_navbar_title_last_step), } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt index 4fe733a371..4f7588e705 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt @@ -194,6 +194,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor ) AddressSync -> DefaultAddressSyncComponent( appComponentContext = childContext, + params = childParams, askBiometryComponentFactory = askBiometryComponentFactory, pushNotificationsComponentFactory = pushNotificationsComponentFactory, ) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt index cb903802ce..050a14f74e 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/OnboardingMultiWalletModel.kt @@ -1,5 +1,6 @@ package com.tangem.features.onboarding.v2.multiwallet.impl.model +import com.tangem.common.routing.AppRoute import com.tangem.common.ui.userwallet.converter.ArtworkUMConverter import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped @@ -70,7 +71,11 @@ internal class OnboardingMultiWalletModel @Inject constructor( onConfirm = { modelScope.launch { onboardingRepository.clearUnfinishedFinalizeOnboarding() - router.pop() + if (params.mode == OnboardingMultiWalletComponent.Mode.AddressSync) { + router.replaceAll(AppRoute.Wallet) + } else { + router.pop() + } } }, ), diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt index aff07ca039..5e4f6a5152 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/model/Utils.kt @@ -15,5 +15,5 @@ fun screenTitleByStep(step: OnboardingMultiWalletState.Step): TextReference = wh OnboardingMultiWalletState.Step.Finalize -> resourceReference(R.string.onboarding_button_finalize_backup) OnboardingMultiWalletState.Step.Done -> resourceReference(R.string.common_done) OnboardingMultiWalletState.Step.UpgradeWallet -> resourceReference(R.string.common_tangem) - OnboardingMultiWalletState.Step.AddressSync -> TODO("Will be implemented during [REDACTED_TASK_KEY]") + OnboardingMultiWalletState.Step.AddressSync -> resourceReference(R.string.onboarding_navbar_title_biometrics) } \ No newline at end of file diff --git a/features/onboarding-v2/impl/src/test/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncModelTest.kt b/features/onboarding-v2/impl/src/test/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncModelTest.kt index 0e4a8acc7d..f784c38c74 100644 --- a/features/onboarding-v2/impl/src/test/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncModelTest.kt +++ b/features/onboarding-v2/impl/src/test/kotlin/com/tangem/features/onboarding/v2/addresssync/model/AddressSyncModelTest.kt @@ -1,15 +1,23 @@ package com.tangem.features.onboarding.v2.addresssync.model import com.arkivanov.decompose.router.stack.StackNavigation +import com.tangem.core.decompose.model.ParamsContainer +import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.settings.CanUseBiometryUseCase import com.tangem.domain.settings.ShouldAskPermissionUseCase import com.tangem.domain.settings.ShouldShowAskBiometryUseCase +import com.tangem.features.onboarding.v2.TitleProvider import com.tangem.features.onboarding.v2.addresssync.navigation.AddressSyncStep +import com.tangem.features.onboarding.v2.multiwallet.impl.MultiWalletInnerNavigationState +import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider import io.mockk.coEvery +import io.mockk.every import io.mockk.mockk +import io.mockk.verify import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceUntilIdle @@ -23,12 +31,36 @@ internal class AddressSyncModelTest { private val shouldShowAskBiometryUseCase: ShouldShowAskBiometryUseCase = mockk() private val canUseBiometryUseCase: CanUseBiometryUseCase = mockk() private val shouldAskPermissionUseCase: ShouldAskPermissionUseCase = mockk() + private val paramsContainer: ParamsContainer = mockk() + private val testInnerNavigation = MutableStateFlow( + value = MultiWalletInnerNavigationState( + stackSize = 0, + stackMaxSize = 0, + ) + ) + private val titleProvider: TitleProvider = mockk(relaxUnitFun = true) + private val params: MultiWalletChildParams = mockk { + every { innerNavigation } returns testInnerNavigation + every { parentParams } returns mockk { + every { titleProvider } returns this@AddressSyncModelTest.titleProvider + } + } @BeforeEach fun setUp() { coEvery { canUseBiometryUseCase.strict() } returns false coEvery { shouldShowAskBiometryUseCase() } returns false coEvery { shouldAskPermissionUseCase(PUSH_PERMISSION) } returns false + every { paramsContainer.require() } returns params + } + + @Test + fun `WHEN model is created THEN inner navigation stack size and max size are set`() = runTest { + createModel(this) + + val state = testInnerNavigation.value + assert(state.stackSize == AddressSyncStep.ASK_BIOMETRY.pageNumber) + assert(state.stackMaxSize == AddressSyncStep.entries.size) } @Test @@ -39,10 +71,11 @@ internal class AddressSyncModelTest { val model = createModel(this) val stack = model.stackNavigation.trackStack() - model.onIntent(AddressSyncIntent.Next(step = AddressSyncStep.ASK_BIOMETRY, shouldReplace = false)) + model.onIntent(AddressSyncIntent.Next(step = AddressSyncStep.ASK_BIOMETRY)) advanceUntilIdle() assert(stack == listOf(AddressSyncStep.ASK_BIOMETRY)) + assertStepperAndTitleFor(AddressSyncStep.ASK_BIOMETRY) } @Test @@ -55,10 +88,11 @@ internal class AddressSyncModelTest { val model = createModel(this) val stack = model.stackNavigation.trackStack() - model.onIntent(AddressSyncIntent.Next(step = AddressSyncStep.ASK_BIOMETRY, shouldReplace = false)) + model.onIntent(AddressSyncIntent.Next(step = AddressSyncStep.ASK_BIOMETRY)) advanceUntilIdle() assert(stack == listOf(AddressSyncStep.ASK_NOTIFICATIONS)) + assertStepperAndTitleFor(AddressSyncStep.ASK_NOTIFICATIONS) } @Test @@ -70,10 +104,11 @@ internal class AddressSyncModelTest { val model = createModel(this) val stack = model.stackNavigation.trackStack() - model.onIntent(AddressSyncIntent.Next(step = AddressSyncStep.ASK_BIOMETRY, shouldReplace = false)) + model.onIntent(AddressSyncIntent.Next(step = AddressSyncStep.ASK_BIOMETRY)) advanceUntilIdle() assert(stack == listOf(AddressSyncStep.ADDRESS_SYNC)) + assertStepperAndTitleFor(AddressSyncStep.ADDRESS_SYNC) } @Test @@ -83,10 +118,11 @@ internal class AddressSyncModelTest { val model = createModel(this) val stack = model.stackNavigation.trackStack() - model.onIntent(AddressSyncIntent.Next(step = AddressSyncStep.ASK_NOTIFICATIONS, shouldReplace = false)) + model.onIntent(AddressSyncIntent.Next(step = AddressSyncStep.ASK_NOTIFICATIONS)) advanceUntilIdle() assert(stack == listOf(AddressSyncStep.ASK_NOTIFICATIONS)) + assertStepperAndTitleFor(AddressSyncStep.ASK_NOTIFICATIONS) } @Test @@ -96,10 +132,16 @@ internal class AddressSyncModelTest { val model = createModel(this) val stack = model.stackNavigation.trackStack() - model.onIntent(AddressSyncIntent.Next(step = AddressSyncStep.ASK_NOTIFICATIONS, shouldReplace = false)) + model.onIntent(AddressSyncIntent.Next(step = AddressSyncStep.ASK_NOTIFICATIONS)) advanceUntilIdle() assert(stack == listOf(AddressSyncStep.ADDRESS_SYNC)) + assertStepperAndTitleFor(AddressSyncStep.ADDRESS_SYNC) + } + + private fun assertStepperAndTitleFor(step: AddressSyncStep) { + assert(testInnerNavigation.value.stackSize == step.pageNumber) + verify { titleProvider.changeTitle(resourceReference(step.stringId)) } } private fun StackNavigation.trackStack(): List { @@ -118,6 +160,7 @@ internal class AddressSyncModelTest { shouldShowAskBiometryUseCase = shouldShowAskBiometryUseCase, canUseBiometryUseCase = canUseBiometryUseCase, shouldAskPermissionUseCase = shouldAskPermissionUseCase, + paramsContainer = paramsContainer, ) }