diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt
index 527a4d4667..42a6ccc24b 100644
--- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt
+++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt
@@ -110,6 +110,7 @@ internal class ChildFactory @Inject constructor(
private val createWalletBackupComponentFactory: CreateWalletBackupComponent.Factory,
private val updateAccessCodeComponentFactory: UpdateAccessCodeComponent.Factory,
private val viewPhraseComponentFactory: ViewPhraseComponent.Factory,
+ private val forgetWalletComponentFactory: ForgetWalletComponent.Factory,
private val sendWithSwapComponentFactory: SendWithSwapComponent.Factory,
private val sendEntryPointComponentFactory: SendEntryPointComponent.Factory,
private val tangemPayDetailsComponentFactory: TangemPayDetailsComponent.Factory,
@@ -565,6 +566,15 @@ internal class ChildFactory @Inject constructor(
componentFactory = viewPhraseComponentFactory,
)
}
+ is AppRoute.ForgetWallet -> {
+ createComponentChild(
+ context = context,
+ params = ForgetWalletComponent.Params(
+ userWalletId = route.userWalletId,
+ ),
+ componentFactory = forgetWalletComponentFactory,
+ )
+ }
is AppRoute.SendEntryPoint -> {
createComponentChild(
context = context,
diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt
index 8e041577cc..5764799d45 100644
--- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt
+++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt
@@ -359,6 +359,11 @@ sealed class AppRoute(val path: String) : Route {
val userWalletId: UserWalletId,
) : AppRoute(path = "/view_seed_phrase/${userWalletId.stringValue}")
+ @Serializable
+ data class ForgetWallet(
+ val userWalletId: UserWalletId,
+ ) : AppRoute(path = "/forget_wallet/${userWalletId.stringValue}")
+
@Serializable
data class SendEntryPoint(
val userWalletId: UserWalletId,
diff --git a/core/ui/src/main/res/drawable/ic_attention_72.xml b/core/ui/src/main/res/drawable/ic_attention_72.xml
new file mode 100644
index 0000000000..e8a42b0b46
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_attention_72.xml
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/ForgetWalletComponent.kt b/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/ForgetWalletComponent.kt
new file mode 100644
index 0000000000..a363de47e0
--- /dev/null
+++ b/features/hot-wallet/api/src/main/kotlin/com/tangem/features/hotwallet/ForgetWalletComponent.kt
@@ -0,0 +1,14 @@
+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 ForgetWalletComponent : ComposableContentComponent {
+
+ data class Params(
+ val userWalletId: UserWalletId,
+ )
+
+ interface Factory : ComponentFactory
+}
\ No newline at end of file
diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/DefaultForgetWalletComponent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/DefaultForgetWalletComponent.kt
new file mode 100644
index 0000000000..919cfbddf7
--- /dev/null
+++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/DefaultForgetWalletComponent.kt
@@ -0,0 +1,39 @@
+package com.tangem.features.hotwallet.forgetwallet
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.tangem.core.decompose.context.AppComponentContext
+import com.tangem.core.decompose.model.getOrCreateModel
+import com.tangem.features.hotwallet.ForgetWalletComponent
+import com.tangem.features.hotwallet.forgetwallet.ui.ForgetWalletContent
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+@Suppress("UnusedPrivateMember")
+internal class DefaultForgetWalletComponent @AssistedInject constructor(
+ @Assisted private val context: AppComponentContext,
+ @Assisted private val params: ForgetWalletComponent.Params,
+) : ForgetWalletComponent, AppComponentContext by context {
+
+ private val model: ForgetWalletModel = getOrCreateModel(params)
+
+ @Composable
+ override fun Content(modifier: Modifier) {
+ val state by model.uiState.collectAsStateWithLifecycle()
+ ForgetWalletContent(
+ state = state,
+ modifier = modifier,
+ )
+ }
+
+ @AssistedFactory
+ interface Factory : ForgetWalletComponent.Factory {
+ override fun create(
+ context: AppComponentContext,
+ params: ForgetWalletComponent.Params,
+ ): DefaultForgetWalletComponent
+ }
+}
\ No newline at end of file
diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/ForgetWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/ForgetWalletModel.kt
new file mode 100644
index 0000000000..7c146e24d3
--- /dev/null
+++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/ForgetWalletModel.kt
@@ -0,0 +1,114 @@
+package com.tangem.features.hotwallet.forgetwallet
+
+import arrow.core.getOrElse
+import com.tangem.common.routing.AppRoute
+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.core.decompose.ui.UiMessageSender
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.extensions.stringReference
+import com.tangem.core.ui.message.DialogMessage
+import com.tangem.core.ui.message.EventMessageAction
+import com.tangem.core.ui.message.SnackbarMessage
+import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
+import com.tangem.features.hotwallet.ForgetWalletComponent
+import com.tangem.features.hotwallet.forgetwallet.entity.ForgetWalletUM
+import com.tangem.features.hotwallet.impl.R
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import timber.log.Timber
+import javax.inject.Inject
+
+@ModelScoped
+internal class ForgetWalletModel @Inject constructor(
+ paramsContainer: ParamsContainer,
+ override val dispatchers: CoroutineDispatcherProvider,
+ private val router: Router,
+ private val deleteWalletUseCase: DeleteWalletUseCase,
+ private val uiMessageSender: UiMessageSender,
+) : Model() {
+
+ private val params = paramsContainer.require()
+
+ internal val uiState: StateFlow
+ field = MutableStateFlow(
+ ForgetWalletUM(
+ onBackClick = { router.pop() },
+ firstCheckboxChecked = false,
+ secondCheckboxChecked = false,
+ onFirstCheckboxClick = ::onFirstCheckboxClick,
+ onSecondCheckboxClick = ::onSecondCheckboxClick,
+ onForgetWalletClick = ::onForgetWalletClick,
+ isForgetButtonEnabled = false,
+ ),
+ )
+
+ private fun onFirstCheckboxClick() {
+ uiState.update {
+ val newValue = !it.firstCheckboxChecked
+ it.copy(
+ firstCheckboxChecked = newValue,
+ isForgetButtonEnabled = newValue && it.secondCheckboxChecked,
+ )
+ }
+ }
+
+ private fun onSecondCheckboxClick() {
+ uiState.update {
+ val newValue = !it.secondCheckboxChecked
+ it.copy(
+ secondCheckboxChecked = newValue,
+ isForgetButtonEnabled = it.firstCheckboxChecked && newValue,
+ )
+ }
+ }
+
+ private fun onForgetWalletClick() {
+ // TODO actualize strings [REDACTED_TASK_KEY]
+ uiMessageSender.send(
+ DialogMessage(
+ title = stringReference("Attention"),
+ message = stringReference("Are you sure you want to do this?"),
+ firstActionBuilder = {
+ EventMessageAction(
+ title = stringReference("Forget"),
+ isWarning = true,
+ onClick = ::forgetWallet,
+ )
+ },
+ secondActionBuilder = {
+ EventMessageAction(
+ title = stringReference("Cancel"),
+ onClick = {},
+ )
+ },
+ ),
+ )
+ }
+
+ private fun forgetWallet() {
+ modelScope.launch {
+ val hasUserWallets = deleteWalletUseCase(params.userWalletId)
+ .getOrElse {
+ Timber.e("Unable to delete wallet: $it")
+
+ uiMessageSender.send(
+ message = SnackbarMessage(resourceReference(R.string.common_unknown_error)),
+ )
+
+ return@launch
+ }
+
+ if (hasUserWallets) {
+ router.pop()
+ } else {
+ router.replaceAll(AppRoute.Home())
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/di/ForgetWalletModule.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/di/ForgetWalletModule.kt
new file mode 100644
index 0000000000..dcedc8378a
--- /dev/null
+++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/di/ForgetWalletModule.kt
@@ -0,0 +1,25 @@
+package com.tangem.features.hotwallet.forgetwallet.di
+
+import com.tangem.core.decompose.model.Model
+import com.tangem.features.hotwallet.ForgetWalletComponent
+import com.tangem.features.hotwallet.forgetwallet.DefaultForgetWalletComponent
+import com.tangem.features.hotwallet.forgetwallet.ForgetWalletModel
+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 ForgetWalletModule {
+
+ @Binds
+ fun bindForgetWalletComponentFactory(impl: DefaultForgetWalletComponent.Factory): ForgetWalletComponent.Factory
+
+ @Binds
+ @IntoMap
+ @ClassKey(ForgetWalletModel::class)
+ fun bindForgetWalletModel(model: ForgetWalletModel): Model
+}
\ No newline at end of file
diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/entity/ForgetWalletUM.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/entity/ForgetWalletUM.kt
new file mode 100644
index 0000000000..0cb0af23d1
--- /dev/null
+++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/entity/ForgetWalletUM.kt
@@ -0,0 +1,11 @@
+package com.tangem.features.hotwallet.forgetwallet.entity
+
+internal data class ForgetWalletUM(
+ val onBackClick: () -> Unit,
+ val firstCheckboxChecked: Boolean,
+ val secondCheckboxChecked: Boolean,
+ val onFirstCheckboxClick: () -> Unit,
+ val onSecondCheckboxClick: () -> Unit,
+ val onForgetWalletClick: () -> Unit,
+ val isForgetButtonEnabled: Boolean,
+)
\ No newline at end of file
diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/ui/ForgetWalletContent.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/ui/ForgetWalletContent.kt
new file mode 100644
index 0000000000..7b7f5592a9
--- /dev/null
+++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/forgetwallet/ui/ForgetWalletContent.kt
@@ -0,0 +1,155 @@
+package com.tangem.features.hotwallet.forgetwallet.ui
+
+import android.content.res.Configuration
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.material3.*
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.tangem.core.ui.R
+import com.tangem.core.ui.components.PrimaryButton
+import com.tangem.core.ui.components.appbar.TangemTopAppBar
+import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.features.hotwallet.forgetwallet.entity.ForgetWalletUM
+
+@Suppress("LongMethod")
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+internal fun ForgetWalletContent(state: ForgetWalletUM, modifier: Modifier = Modifier) {
+ // TODO actualize strings [REDACTED_TASK_KEY]
+ Column(
+ modifier = modifier
+ .background(TangemTheme.colors.background.primary)
+ .fillMaxSize()
+ .systemBarsPadding(),
+ ) {
+ TangemTopAppBar(
+ modifier = Modifier.statusBarsPadding(),
+ startButton = TopAppBarButtonUM.Back(state.onBackClick),
+ title = TextReference.EMPTY,
+ )
+ Column(
+ modifier = Modifier
+ .weight(1f)
+ .padding(horizontal = 16.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center,
+ ) {
+ Spacer(modifier = Modifier.height(16.dp))
+ Icon(
+ painter = painterResource(R.drawable.ic_attention_72),
+ contentDescription = null,
+ tint = TangemTheme.colors.icon.warning,
+ )
+ Spacer(modifier = Modifier.height(24.dp))
+ Text(
+ text = "Attention",
+ style = TangemTheme.typography.h2,
+ color = TangemTheme.colors.text.primary1,
+ textAlign = TextAlign.Center,
+ )
+ Spacer(modifier = Modifier.height(12.dp))
+ Text(
+ text = "This wallet will be permanently removed from your device",
+ style = TangemTheme.typography.body1,
+ color = TangemTheme.colors.text.secondary,
+ textAlign = TextAlign.Center,
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ }
+ Spacer(modifier = Modifier.height(48.dp))
+ CheckboxItem(
+ modifier = Modifier.padding(horizontal = 16.dp),
+ checked = state.firstCheckboxChecked,
+ onCheckedChange = state.onFirstCheckboxClick,
+ text = "I understand that removing my wallet does not delete it—but simply removes it from my device.",
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ CheckboxItem(
+ modifier = Modifier.padding(horizontal = 16.dp),
+ checked = state.secondCheckboxChecked,
+ onCheckedChange = state.onSecondCheckboxClick,
+ text = "I understand that if I haven't backed up my wallet before removing it, I may lose access to it.",
+ )
+ Spacer(modifier = Modifier.height(32.dp))
+ PrimaryButton(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp),
+ text = "Forget wallet",
+ onClick = state.onForgetWalletClick,
+ enabled = state.isForgetButtonEnabled,
+ )
+ }
+}
+
+@Composable
+private fun CheckboxItem(checked: Boolean, onCheckedChange: () -> Unit, text: String, modifier: Modifier = Modifier) {
+ // TODO actualize strings [REDACTED_TASK_KEY]
+ Row(
+ modifier = modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.Start,
+ verticalAlignment = Alignment.Top,
+ ) {
+ IconToggleButton(
+ checked = checked,
+ onCheckedChange = { onCheckedChange() },
+ ) {
+ AnimatedContent(
+ targetState = checked,
+ label = "Update checked state",
+ ) { isChecked ->
+ Icon(
+ painter = painterResource(
+ if (isChecked) {
+ R.drawable.ic_accepted_20
+ } else {
+ R.drawable.ic_unticked_20
+ },
+ ),
+ contentDescription = null,
+ tint = if (isChecked) {
+ TangemTheme.colors.control.checked
+ } else {
+ TangemTheme.colors.icon.secondary
+ },
+ )
+ }
+ }
+ Spacer(modifier = Modifier.width(12.dp))
+ Text(
+ text = text,
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.primary1,
+ )
+ }
+}
+
+@Preview(showBackground = true, widthDp = 360)
+@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun PreviewForgetWalletContent() {
+ TangemThemePreview {
+ ForgetWalletContent(
+ state = ForgetWalletUM(
+ onBackClick = {},
+ firstCheckboxChecked = true,
+ secondCheckboxChecked = false,
+ onFirstCheckboxClick = {},
+ onSecondCheckboxClick = {},
+ onForgetWalletClick = {},
+ isForgetButtonEnabled = false,
+ ),
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt
index cce7ff570d..7568906434 100644
--- a/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt
+++ b/features/wallet-settings/impl/src/main/kotlin/com/tangem/feature/walletsettings/model/WalletSettingsModel.kt
@@ -18,6 +18,7 @@ import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.settings.SettingsManager
import com.tangem.core.ui.components.bottomsheets.message.*
import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.EventMessageAction
import com.tangem.core.ui.message.SnackbarMessage
@@ -205,24 +206,7 @@ internal class WalletSettingsModel @Inject constructor(
isNFTEnabled = isNFTEnabled,
onCheckedNFTChange = ::onCheckedNFTChange,
forgetWallet = {
- val message = DialogMessage(
- message = resourceReference(
- id = when (userWallet) {
- is UserWallet.Cold -> R.string.user_wallet_list_delete_prompt
- is UserWallet.Hot -> R.string.user_wallet_list_delete_hw_prompt
- },
- ),
- firstActionBuilder = {
- EventMessageAction(
- title = resourceReference(R.string.common_delete),
- isWarning = true,
- onClick = ::forgetWallet,
- )
- },
- secondActionBuilder = { cancelAction() },
- )
-
- messageSender.send(message)
+ onForgetWalletClick(userWallet)
},
onLinkMoreCardsClick = {
when (userWallet) {
@@ -403,4 +387,80 @@ internal class WalletSettingsModel @Inject constructor(
}
}
}
+
+ // TODO actualize strings [REDACTED_TASK_KEY] and remove MaximumLineLength
+ @Suppress("LongMethod", "MaximumLineLength")
+ private fun onForgetWalletClick(userWallet: UserWallet) {
+ val message = when (userWallet) {
+ is UserWallet.Cold -> {
+ DialogMessage(
+ message = resourceReference(
+ id = R.string.user_wallet_list_delete_prompt,
+ ),
+ firstActionBuilder = {
+ EventMessageAction(
+ title = resourceReference(R.string.common_delete),
+ isWarning = true,
+ onClick = ::forgetWallet,
+ )
+ },
+ secondActionBuilder = { cancelAction() },
+ )
+ }
+ is UserWallet.Hot -> {
+ bottomSheetMessage {
+ infoBlock {
+ icon(R.drawable.ic_alert_circle_24) {
+ type = MessageBottomSheetUMV2.Icon.Type.Warning
+ backgroundType = MessageBottomSheetUMV2.Icon.BackgroundType.SameAsTint
+ }
+ title = stringReference("Forget this wallet?")
+ body = if (userWallet.backedUp) {
+ stringReference("A backup for this wallet exists. Review it before forgetting to make sure you can recover later.")
+ } else {
+ stringReference("If you forget this wallet without a backup, you’ll permanently lose access to your funds.")
+ }
+ }
+ if (userWallet.backedUp) {
+ secondaryButton {
+ text = stringReference("Forget wallet")
+ onClick {
+ router.push(AppRoute.ForgetWallet(userWallet.walletId))
+ closeBs()
+ }
+ }
+ } else {
+ secondaryButton {
+ text = stringReference("Forget Anyway")
+ onClick {
+ router.push(AppRoute.ForgetWallet(userWallet.walletId))
+ closeBs()
+ }
+ }
+ }
+ if (userWallet.backedUp) {
+ primaryButton {
+ text = stringReference("View backup")
+ onClick {
+ unlockWalletIfNeedAndProceed {
+ router.push(AppRoute.ViewPhrase(userWallet.walletId))
+ }
+ closeBs()
+ }
+ }
+ } else {
+ primaryButton {
+ text = stringReference("Go to backup")
+ onClick {
+ router.push(AppRoute.CreateWalletBackup(userWallet.walletId))
+ closeBs()
+ }
+ }
+ }
+ }
+ }
+ }
+
+ messageSender.send(message)
+ }
}
\ No newline at end of file