Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-13 12:43:56 +05:00
parent e98a8dd6c8
commit 0617e32475
22 changed files with 276 additions and 19 deletions

View file

@ -17,6 +17,7 @@ import com.tangem.features.hotwallet.AddExistingWalletComponent
import com.tangem.features.hotwallet.CreateMobileWalletComponent
import com.tangem.features.hotwallet.WalletActivationComponent
import com.tangem.features.hotwallet.WalletBackupComponent
import com.tangem.features.hotwallet.UpdateAccessCodeComponent
import com.tangem.features.managetokens.component.ChooseManagedTokensComponent
import com.tangem.features.managetokens.component.ManageTokensComponent
import com.tangem.features.managetokens.component.ManageTokensSource
@ -95,6 +96,7 @@ internal class ChildFactory @Inject constructor(
private val createMobileWalletComponentFactory: CreateMobileWalletComponent.Factory,
private val addExistingWalletComponentFactory: AddExistingWalletComponent.Factory,
private val walletActivationComponentFactory: WalletActivationComponent.Factory,
private val updateAccessCodeComponentFactory: UpdateAccessCodeComponent.Factory,
private val sendWithSwapComponentFactory: SendWithSwapComponent.Factory,
private val sendEntryPointComponentFactory: SendEntryPointComponent.Factory,
private val walletConnectFeatureToggles: WalletConnectFeatureToggles,
@ -479,6 +481,15 @@ internal class ChildFactory @Inject constructor(
componentFactory = walletActivationComponentFactory,
)
}
is AppRoute.UpdateAccessCode -> {
createComponentChild(
context = context,
params = UpdateAccessCodeComponent.Params(
userWalletId = route.userWalletId,
),
componentFactory = updateAccessCodeComponentFactory,
)
}
is AppRoute.SendEntryPoint -> {
createComponentChild(
context = context,

View file

@ -308,6 +308,11 @@ sealed class AppRoute(val path: String) : Route {
val userWalletId: UserWalletId,
) : AppRoute(path = "/wallet_activation/${userWalletId.stringValue}")
@Serializable
data class UpdateAccessCode(
val userWalletId: UserWalletId,
) : AppRoute(path = "/update_access_code/${userWalletId.stringValue}")
@Serializable
data class SendEntryPoint(
val userWalletId: UserWalletId,

View file

@ -0,0 +1,10 @@
package com.tangem.features.hotwallet
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.models.wallet.UserWalletId
interface UpdateAccessCodeComponent : ComposableContentComponent {
data class Params(val userWalletId: UserWalletId)
interface Factory : ComponentFactory<Params, UpdateAccessCodeComponent>
}

View file

@ -1,4 +1,4 @@
package com.tangem.features.hotwallet.setaccesscode
package com.tangem.features.hotwallet.accesscode
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -8,7 +8,7 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.security.DisableScreenshotsDisposableEffect
import com.tangem.features.hotwallet.setaccesscode.ui.AccessCode
import com.tangem.features.hotwallet.accesscode.ui.AccessCode
import com.tangem.domain.models.wallet.UserWalletId
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory

View file

@ -1,4 +1,4 @@
package com.tangem.features.hotwallet.setaccesscode
package com.tangem.features.hotwallet.accesscode
import androidx.compose.runtime.Stable
import arrow.core.getOrElse
@ -9,7 +9,7 @@ import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
import com.tangem.features.hotwallet.setaccesscode.entity.AccessCodeUM
import com.tangem.features.hotwallet.accesscode.entity.AccessCodeUM
import com.tangem.hot.sdk.TangemHotSdk
import com.tangem.hot.sdk.model.HotAuth
import com.tangem.hot.sdk.model.UnlockHotWallet

View file

@ -0,0 +1,3 @@
package com.tangem.features.hotwallet.accesscode
const val ACCESS_CODE_LENGTH = 6

View file

@ -1,7 +1,7 @@
package com.tangem.features.hotwallet.setaccesscode.di
package com.tangem.features.hotwallet.accesscode.di
import com.tangem.core.decompose.model.Model
import com.tangem.features.hotwallet.setaccesscode.AccessCodeModel
import com.tangem.features.hotwallet.accesscode.AccessCodeModel
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn

View file

@ -1,6 +1,6 @@
package com.tangem.features.hotwallet.setaccesscode.entity
package com.tangem.features.hotwallet.accesscode.entity
import com.tangem.features.hotwallet.setaccesscode.ACCESS_CODE_LENGTH
import com.tangem.features.hotwallet.accesscode.ACCESS_CODE_LENGTH
internal data class AccessCodeUM(
val accessCode: String,

View file

@ -1,4 +1,4 @@
package com.tangem.features.hotwallet.setaccesscode.ui
package com.tangem.features.hotwallet.accesscode.ui
import android.content.res.Configuration
import androidx.compose.foundation.background
@ -16,7 +16,7 @@ import com.tangem.core.ui.components.fields.PinTextField
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.hotwallet.setaccesscode.entity.AccessCodeUM
import com.tangem.features.hotwallet.accesscode.entity.AccessCodeUM
@Suppress("LongParameterList", "LongMethod")
@Composable

View file

@ -3,7 +3,7 @@ package com.tangem.features.hotwallet.accesscoderequest
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
import com.tangem.features.hotwallet.setaccesscode.ACCESS_CODE_LENGTH
import com.tangem.features.hotwallet.accesscode.ACCESS_CODE_LENGTH
import com.tangem.features.hotwallet.accesscoderequest.entity.HotAccessCodeRequestUM
import com.tangem.hot.sdk.model.HotAuth
import com.tangem.utils.coroutines.CoroutineDispatcherProvider

View file

@ -11,7 +11,7 @@ import com.tangem.features.hotwallet.addexistingwallet.entry.routing.AddExisting
import com.tangem.features.hotwallet.addexistingwallet.im.port.AddExistingWalletImportComponent
import com.tangem.features.hotwallet.addexistingwallet.start.AddExistingWalletStartComponent
import com.tangem.features.hotwallet.manualbackup.completed.ManualBackupCompletedComponent
import com.tangem.features.hotwallet.setaccesscode.AccessCodeComponent
import com.tangem.features.hotwallet.accesscode.AccessCodeComponent
import com.tangem.features.hotwallet.setupfinished.MobileWalletSetupFinishedComponent
import com.tangem.features.hotwallet.stepper.api.HotWalletStepperComponent
import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacks

View file

@ -6,7 +6,7 @@ import com.tangem.features.hotwallet.addexistingwallet.entry.AddExistingWalletMo
import com.tangem.features.hotwallet.addexistingwallet.im.port.AddExistingWalletImportComponent
import com.tangem.features.hotwallet.addexistingwallet.start.AddExistingWalletStartComponent
import com.tangem.features.hotwallet.manualbackup.completed.ManualBackupCompletedComponent
import com.tangem.features.hotwallet.setaccesscode.AccessCodeComponent
import com.tangem.features.hotwallet.accesscode.AccessCodeComponent
import com.tangem.features.hotwallet.setupfinished.MobileWalletSetupFinishedComponent
import com.tangem.features.pushnotifications.api.PushNotificationsComponent
import com.tangem.features.pushnotifications.api.PushNotificationsParams

View file

@ -1,3 +0,0 @@
package com.tangem.features.hotwallet.setaccesscode
const val ACCESS_CODE_LENGTH = 6

View file

@ -0,0 +1,60 @@
package com.tangem.features.hotwallet.updateaccesscode
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.stack.childStack
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.features.hotwallet.UpdateAccessCodeComponent
import com.tangem.features.hotwallet.updateaccesscode.routing.UpdateAccessCodeChildFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
internal class DefaultUpdateAccessCodeComponent @AssistedInject constructor(
@Assisted private val appComponentContext: AppComponentContext,
@Assisted private val params: UpdateAccessCodeComponent.Params,
private val childFactory: UpdateAccessCodeChildFactory,
) : UpdateAccessCodeComponent, AppComponentContext by appComponentContext {
private val model: UpdateAccessCodeModel = getOrCreateModel(params)
private val innerStack = childStack(
key = "hotWalletAccessCodeInnerStack",
source = model.stackNavigation,
serializer = null,
initialConfiguration = model.startRoute,
handleBackButton = true,
childFactory = { configuration, factoryContext ->
childFactory.createChild(
route = configuration,
childContext = childByContext(factoryContext),
model = model,
)
},
)
@Composable
override fun Content(modifier: Modifier) {
val stackState by innerStack.subscribeAsState()
BackHandler(onBack = model::onChildBack)
SetAccessCodeContent(
onBackClick = model::onChildBack,
stackState = stackState,
)
}
@AssistedFactory
interface Factory : UpdateAccessCodeComponent.Factory {
override fun create(
context: AppComponentContext,
params: UpdateAccessCodeComponent.Params,
): DefaultUpdateAccessCodeComponent
}
}

View file

@ -0,0 +1,47 @@
package com.tangem.features.hotwallet.updateaccesscode
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.extensions.compose.stack.Children
import com.arkivanov.decompose.extensions.compose.stack.animation.slide
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
import com.arkivanov.decompose.router.stack.ChildStack
import com.tangem.core.ui.R
import com.tangem.core.ui.components.appbar.TangemTopAppBar
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.hotwallet.updateaccesscode.routing.UpdateAccessCodeRoute
@Composable
internal fun SetAccessCodeContent(
onBackClick: () -> Unit,
stackState: ChildStack<UpdateAccessCodeRoute, ComposableContentComponent>,
) {
Column(
modifier = Modifier
.background(color = TangemTheme.colors.background.primary)
.fillMaxSize()
.imePadding()
.systemBarsPadding(),
) {
TangemTopAppBar(
modifier = Modifier,
title = stringResourceSafe(R.string.access_code_navtitle),
startButton = TopAppBarButtonUM.Back(onBackClick),
)
Children(
stack = stackState,
animation = stackAnimation(slide()),
modifier = Modifier.fillMaxSize(),
) {
it.instance.Content(Modifier.fillMaxSize())
}
}
}

View file

@ -0,0 +1,45 @@
package com.tangem.features.hotwallet.updateaccesscode
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.pop
import com.arkivanov.decompose.router.stack.push
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.decompose.navigation.Router
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.features.hotwallet.UpdateAccessCodeComponent
import com.tangem.features.hotwallet.updateaccesscode.routing.UpdateAccessCodeRoute
import com.tangem.features.hotwallet.accesscode.AccessCodeComponent
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject
@ModelScoped
internal class UpdateAccessCodeModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
private val router: Router,
paramsContainer: ParamsContainer,
) : Model(), AccessCodeComponent.ModelCallbacks {
private val params = paramsContainer.require<UpdateAccessCodeComponent.Params>()
val stackNavigation = StackNavigation<UpdateAccessCodeRoute>()
val startRoute: UpdateAccessCodeRoute = UpdateAccessCodeRoute.SetAccessCode(params.userWalletId)
val currentRoute: MutableStateFlow<UpdateAccessCodeRoute> = MutableStateFlow(startRoute)
fun onChildBack() {
when (currentRoute.value) {
is UpdateAccessCodeRoute.SetAccessCode -> router.pop()
is UpdateAccessCodeRoute.ConfirmAccessCode -> stackNavigation.pop()
}
}
override fun onAccessCodeSet(userWalletId: UserWalletId, accessCode: String) {
stackNavigation.push(UpdateAccessCodeRoute.ConfirmAccessCode(userWalletId, accessCode))
}
override fun onAccessCodeConfirmed(userWalletId: UserWalletId) {
router.pop()
}
}

View file

@ -0,0 +1,27 @@
package com.tangem.features.hotwallet.updateaccesscode.di
import com.tangem.core.decompose.model.Model
import com.tangem.features.hotwallet.UpdateAccessCodeComponent
import com.tangem.features.hotwallet.updateaccesscode.DefaultUpdateAccessCodeComponent
import com.tangem.features.hotwallet.updateaccesscode.UpdateAccessCodeModel
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
@Module
@InstallIn(SingletonComponent::class)
internal interface UpdateAccessCodeModule {
@Binds
fun bindUpdateAccessCodeComponentFactory(
impl: DefaultUpdateAccessCodeComponent.Factory,
): UpdateAccessCodeComponent.Factory
@Binds
@IntoMap
@ClassKey(UpdateAccessCodeModel::class)
fun bindUpdateAccessCodeModel(model: UpdateAccessCodeModel): Model
}

View file

@ -0,0 +1,38 @@
package com.tangem.features.hotwallet.updateaccesscode.routing
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.hotwallet.updateaccesscode.UpdateAccessCodeModel
import com.tangem.features.hotwallet.accesscode.AccessCodeComponent
import javax.inject.Inject
internal class UpdateAccessCodeChildFactory @Inject constructor(
private val accessCodeComponentFactory: AccessCodeComponent.Factory,
) {
fun createChild(
route: UpdateAccessCodeRoute,
childContext: AppComponentContext,
model: UpdateAccessCodeModel,
): ComposableContentComponent {
return when (route) {
is UpdateAccessCodeRoute.SetAccessCode -> accessCodeComponentFactory.create(
context = childContext,
params = AccessCodeComponent.Params(
isConfirmMode = false,
userWalletId = route.userWalletId,
callbacks = model,
),
)
is UpdateAccessCodeRoute.ConfirmAccessCode -> accessCodeComponentFactory.create(
context = childContext,
params = AccessCodeComponent.Params(
isConfirmMode = true,
accessCodeToConfirm = route.accessCode,
userWalletId = route.userWalletId,
callbacks = model,
),
)
}
}
}

View file

@ -0,0 +1,14 @@
package com.tangem.features.hotwallet.updateaccesscode.routing
import com.tangem.core.decompose.navigation.Route
import com.tangem.domain.models.wallet.UserWalletId
import kotlinx.serialization.Serializable
internal sealed class UpdateAccessCodeRoute : Route {
@Serializable
data class SetAccessCode(val userWalletId: UserWalletId) : UpdateAccessCodeRoute()
@Serializable
data class ConfirmAccessCode(val userWalletId: UserWalletId, val accessCode: String) : UpdateAccessCodeRoute()
}

View file

@ -14,7 +14,7 @@ import com.tangem.features.hotwallet.manualbackup.check.ManualBackupCheckCompone
import com.tangem.features.hotwallet.manualbackup.completed.ManualBackupCompletedComponent
import com.tangem.features.hotwallet.manualbackup.phrase.ManualBackupPhraseComponent
import com.tangem.features.hotwallet.manualbackup.start.ManualBackupStartComponent
import com.tangem.features.hotwallet.setaccesscode.AccessCodeComponent
import com.tangem.features.hotwallet.accesscode.AccessCodeComponent
import com.tangem.features.hotwallet.setupfinished.MobileWalletSetupFinishedComponent
import com.tangem.features.hotwallet.walletactivation.entry.routing.WalletActivationRoute
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION

View file

@ -6,7 +6,7 @@ import com.tangem.features.hotwallet.manualbackup.check.ManualBackupCheckCompone
import com.tangem.features.hotwallet.manualbackup.completed.ManualBackupCompletedComponent
import com.tangem.features.hotwallet.manualbackup.phrase.ManualBackupPhraseComponent
import com.tangem.features.hotwallet.manualbackup.start.ManualBackupStartComponent
import com.tangem.features.hotwallet.setaccesscode.AccessCodeComponent
import com.tangem.features.hotwallet.accesscode.AccessCodeComponent
import com.tangem.features.hotwallet.setupfinished.MobileWalletSetupFinishedComponent
import com.tangem.features.hotwallet.walletactivation.entry.WalletActivationModel
import com.tangem.features.pushnotifications.api.PushNotificationsComponent

View file

@ -330,6 +330,6 @@ internal class WalletSettingsModel @Inject constructor(
}
private fun onAccessCodeClick() {
// TODO [REDACTED_TASK_KEY]
router.push(AppRoute.UpdateAccessCode(params.userWalletId))
}
}