Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-07 20:04:35 +05:00
parent 1d47d83d70
commit 6178034e71
20 changed files with 401 additions and 160 deletions

View file

@ -65,4 +65,7 @@ dependencies {
implementation(deps.kotlin.immutable.collections)
implementation(deps.timber)
implementation(deps.reKotlin)
/** Tangem libraries */
implementation(tangemDeps.hot.core)
}

View file

@ -4,11 +4,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.core.analytics.DummyAnalyticsEventHandler
import com.tangem.core.decompose.navigation.DummyRouter
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.feature.walletsettings.component.WalletSettingsComponent
import com.tangem.feature.walletsettings.entity.WalletSettingsUM
import com.tangem.feature.walletsettings.ui.WalletSettingsScreen
import com.tangem.feature.walletsettings.utils.ItemsBuilder
import com.tangem.hot.sdk.model.HotWalletId
internal class PreviewWalletSettingsComponent : WalletSettingsComponent {
@ -18,7 +20,13 @@ internal class PreviewWalletSettingsComponent : WalletSettingsComponent {
router = DummyRouter(),
analyticsEventHandler = DummyAnalyticsEventHandler(),
).buildItems(
userWalletId = UserWalletId("011"),
userWallet = UserWallet.Hot(
walletId = UserWalletId("011"),
name = "My Wallet",
hotWalletId = HotWalletId("", HotWalletId.AuthType.NoPassword),
wallets = null,
backedUp = false,
),
userWalletName = "My Wallet",
isReferralAvailable = true,
isLinkMoreCardsAvailable = true,
@ -36,7 +44,7 @@ internal class PreviewWalletSettingsComponent : WalletSettingsComponent {
onCheckedNotificationsChanged = {},
onNotificationsDescriptionClick = {},
isNotificationsPermissionGranted = false,
isHotWalletEnabled = false,
onAccessCodeClick = {},
),
requestPushNotificationsPermission = false,
onPushNotificationPermissionGranted = {},

View file

@ -31,8 +31,6 @@ import com.tangem.domain.notifications.repository.NotificationsRepository
import com.tangem.domain.notifications.toggles.NotificationsFeatureToggles
import com.tangem.domain.settings.repositories.PermissionRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.isMultiCurrency
import com.tangem.domain.models.wallet.requireColdWallet
import com.tangem.domain.wallets.usecase.*
import com.tangem.feature.walletsettings.analytics.Settings
import com.tangem.feature.walletsettings.analytics.WalletSettingsAnalyticEvents
@ -43,7 +41,6 @@ import com.tangem.feature.walletsettings.entity.WalletSettingsItemUM
import com.tangem.feature.walletsettings.entity.WalletSettingsUM
import com.tangem.feature.walletsettings.impl.R
import com.tangem.feature.walletsettings.utils.ItemsBuilder
import com.tangem.features.hotwallet.HotWalletFeatureToggles
import com.tangem.features.pushnotifications.api.analytics.PushNotificationAnalyticEvents
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.collections.immutable.PersistentList
@ -75,7 +72,6 @@ internal class WalletSettingsModel @Inject constructor(
private val setNotificationsEnabledUseCase: SetNotificationsEnabledUseCase,
private val settingsManager: SettingsManager,
private val permissionsRepository: PermissionRepository,
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
private val notificationsRepository: NotificationsRepository,
private val getIsHuaweiDeviceWithoutGoogleServicesUseCase: GetIsHuaweiDeviceWithoutGoogleServicesUseCase,
) : Model() {
@ -100,7 +96,6 @@ internal class WalletSettingsModel @Inject constructor(
getWalletNotificationsEnabledUseCase(params.userWalletId),
) { maybeWallet, nftEnabled, notificationsEnabled ->
val wallet = maybeWallet.getOrNull() ?: return@combine
wallet.requireColdWallet() // TODO [REDACTED_TASK_KEY] [Hot Wallet] Wallet Settings
val isRenameWalletAvailable = getShouldSaveUserWalletsSyncUseCase()
val isNeedShowNotifications = notificationsToggles.isNotificationsEnabled &&
!getIsHuaweiDeviceWithoutGoogleServicesUseCase()
@ -114,7 +109,6 @@ internal class WalletSettingsModel @Inject constructor(
isNotificationsEnabled = notificationsEnabled,
isNotificationsFeatureEnabled = isNeedShowNotifications,
isNotificationsPermissionGranted = isNotificationsPermissionGranted(),
isHotWalletEnabled = hotWalletFeatureToggles.isHotWalletEnabled,
),
)
}
@ -133,51 +127,65 @@ internal class WalletSettingsModel @Inject constructor(
}
private fun buildItems(
userWallet: UserWallet.Cold,
userWallet: UserWallet,
dialogNavigation: SlotNavigation<DialogConfig>,
isRenameWalletAvailable: Boolean,
isNFTEnabled: Boolean,
isNotificationsFeatureEnabled: Boolean,
isNotificationsEnabled: Boolean,
isNotificationsPermissionGranted: Boolean,
isHotWalletEnabled: Boolean,
): PersistentList<WalletSettingsItemUM> = itemsBuilder.buildItems(
userWalletId = userWallet.walletId,
userWalletName = userWallet.name,
isReferralAvailable = userWallet.cardTypesResolver.isTangemWallet(),
isLinkMoreCardsAvailable = userWallet.scanResponse.card.backupStatus == CardDTO.BackupStatus.NoBackup,
isManageTokensAvailable = userWallet.isMultiCurrency,
isRenameWalletAvailable = isRenameWalletAvailable,
renameWallet = { openRenameWalletDialog(userWallet, dialogNavigation) },
isNFTFeatureEnabled = userWallet.isMultiCurrency,
isNFTEnabled = isNFTEnabled,
onCheckedNFTChange = ::onCheckedNFTChange,
forgetWallet = {
val message = DialogMessage(
message = resourceReference(R.string.user_wallet_list_delete_prompt),
firstActionBuilder = {
EventMessageAction(
title = resourceReference(R.string.common_delete),
warning = true,
onClick = ::forgetWallet,
)
},
secondActionBuilder = { cancelAction() },
)
): PersistentList<WalletSettingsItemUM> {
val isMultiCurrency = when (userWallet) {
is UserWallet.Cold -> userWallet.isMultiCurrency
is UserWallet.Hot -> true
}
return itemsBuilder.buildItems(
userWallet = userWallet,
userWalletName = userWallet.name,
isReferralAvailable = when (userWallet) {
is UserWallet.Cold -> userWallet.cardTypesResolver.isTangemWallet()
is UserWallet.Hot -> false
},
isLinkMoreCardsAvailable = when (userWallet) {
is UserWallet.Cold -> userWallet.scanResponse.card.backupStatus == CardDTO.BackupStatus.NoBackup
is UserWallet.Hot -> false
},
isManageTokensAvailable = isMultiCurrency,
isRenameWalletAvailable = isRenameWalletAvailable,
renameWallet = { openRenameWalletDialog(userWallet, dialogNavigation) },
isNFTFeatureEnabled = isMultiCurrency,
isNFTEnabled = isNFTEnabled,
onCheckedNFTChange = ::onCheckedNFTChange,
forgetWallet = {
val message = DialogMessage(
message = resourceReference(R.string.user_wallet_list_delete_prompt),
firstActionBuilder = {
EventMessageAction(
title = resourceReference(R.string.common_delete),
warning = true,
onClick = ::forgetWallet,
)
},
secondActionBuilder = { cancelAction() },
)
messageSender.send(message)
},
onLinkMoreCardsClick = {
onLinkMoreCardsClick(scanResponse = userWallet.scanResponse)
},
onReferralClick = { onReferralClick(userWallet) },
isNotificationsEnabled = isNotificationsEnabled,
isNotificationsFeatureEnabled = isNotificationsFeatureEnabled,
isNotificationsPermissionGranted = isNotificationsPermissionGranted,
onCheckedNotificationsChanged = ::onCheckedNotificationsChange,
onNotificationsDescriptionClick = ::onNotificationsDescriptionClick,
isHotWalletEnabled = isHotWalletEnabled,
)
messageSender.send(message)
},
onLinkMoreCardsClick = {
when (userWallet) {
is UserWallet.Cold -> onLinkMoreCardsClick(scanResponse = userWallet.scanResponse)
is UserWallet.Hot -> Unit
}
},
onReferralClick = { onReferralClick(userWallet) },
isNotificationsEnabled = isNotificationsEnabled,
isNotificationsFeatureEnabled = isNotificationsFeatureEnabled,
isNotificationsPermissionGranted = isNotificationsPermissionGranted,
onCheckedNotificationsChanged = ::onCheckedNotificationsChange,
onNotificationsDescriptionClick = ::onNotificationsDescriptionClick,
onAccessCodeClick = ::onAccessCodeClick,
)
}
private fun openRenameWalletDialog(userWallet: UserWallet, dialogNavigation: SlotNavigation<DialogConfig>) {
val config = DialogConfig.RenameWallet(
@ -320,4 +328,8 @@ internal class WalletSettingsModel @Inject constructor(
router.push(AppRoute.ReferralProgram(userWallet.walletId))
}
}
private fun onAccessCodeClick() {
// TODO [REDACTED_TASK_KEY]
}
}

View file

@ -6,12 +6,15 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.ui.components.block.model.BlockUM
import com.tangem.core.ui.components.label.entity.LabelStyle
import com.tangem.core.ui.components.label.entity.LabelUM
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.walletsettings.analytics.Settings
import com.tangem.feature.walletsettings.entity.WalletSettingsItemUM
import com.tangem.feature.walletsettings.impl.R
import com.tangem.hot.sdk.model.HotWalletId
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
@ -25,7 +28,7 @@ internal class ItemsBuilder @Inject constructor(
@Suppress("LongParameterList")
fun buildItems(
userWalletId: UserWalletId,
userWallet: UserWallet,
userWalletName: String,
isLinkMoreCardsAvailable: Boolean,
isReferralAvailable: Boolean,
@ -43,25 +46,18 @@ internal class ItemsBuilder @Inject constructor(
renameWallet: () -> Unit,
onLinkMoreCardsClick: () -> Unit,
onReferralClick: () -> Unit,
isHotWalletEnabled: Boolean,
onAccessCodeClick: () -> Unit,
): PersistentList<WalletSettingsItemUM> = persistentListOf<WalletSettingsItemUM>()
.add(buildNameItem(userWalletName, isRenameWalletAvailable, renameWallet))
.run {
if (isNFTFeatureEnabled) {
add(buildNFTItem(isNFTEnabled, onCheckedNFTChange))
} else {
this
}
}
.addAll(buildAccessCodeItem(userWallet, onAccessCodeClick))
.add(
buildCardItem(
userWalletId = userWalletId,
userWallet = userWallet,
isLinkMoreCardsAvailable = isLinkMoreCardsAvailable,
isReferralAvailable = isReferralAvailable,
isManageTokensAvailable = isManageTokensAvailable,
onLinkMoreCardsClick = onLinkMoreCardsClick,
onReferralClick = onReferralClick,
isHotWalletEnabled = isHotWalletEnabled,
),
)
.addAll(
@ -73,8 +69,27 @@ internal class ItemsBuilder @Inject constructor(
onNotificationsDescriptionClick = onNotificationsDescriptionClick,
),
)
.addAll(
buildNFTItems(
isNFTFeatureEnabled = isNFTFeatureEnabled,
isNFTEnabled = isNFTEnabled,
onCheckedNFTChange = onCheckedNFTChange,
),
)
.add(buildForgetItem(forgetWallet))
private fun buildNFTItems(
isNFTFeatureEnabled: Boolean,
isNFTEnabled: Boolean,
onCheckedNFTChange: (Boolean) -> Unit,
): List<WalletSettingsItemUM> {
return if (isNFTFeatureEnabled) {
listOf(buildNFTItem(isNFTEnabled, onCheckedNFTChange))
} else {
emptyList()
}
}
private fun buildNotificationItems(
isNotificationsFeatureEnabled: Boolean,
isNotificationsPermissionGranted: Boolean,
@ -133,17 +148,35 @@ internal class ItemsBuilder @Inject constructor(
@Suppress("LongParameterList")
private fun buildCardItem(
userWalletId: UserWalletId,
userWallet: UserWallet,
isLinkMoreCardsAvailable: Boolean,
isReferralAvailable: Boolean,
isManageTokensAvailable: Boolean,
onLinkMoreCardsClick: () -> Unit,
onReferralClick: () -> Unit,
isHotWalletEnabled: Boolean,
) = WalletSettingsItemUM.WithItems(
id = "card",
description = resourceReference(R.string.settings_card_settings_footer),
blocks = buildList {
val userWalletId = userWallet.walletId
val isHotWallet = userWallet is UserWallet.Hot
if (isHotWallet) {
val hasBackup = userWallet.backedUp
BlockUM(
text = resourceReference(R.string.common_backup),
iconRes = R.drawable.ic_more_cards_24,
onClick = { router.push(AppRoute.WalletBackup(userWalletId)) },
label = if (hasBackup) {
null
} else {
LabelUM(
text = resourceReference(R.string.hw_backup_no_backup),
style = LabelStyle.WARNING,
)
},
).let(::add)
}
if (isManageTokensAvailable) {
BlockUM(
text = resourceReference(R.string.add_tokens_title),
@ -163,17 +196,11 @@ internal class ItemsBuilder @Inject constructor(
).let(::add)
}
BlockUM(
text = resourceReference(R.string.card_settings_title),
iconRes = R.drawable.ic_card_settings_24,
onClick = { router.push(AppRoute.CardSettings(userWalletId)) },
).let(::add)
if (isHotWalletEnabled) {
if (!isHotWallet) {
BlockUM(
text = resourceReference(R.string.common_backup),
iconRes = R.drawable.ic_more_cards_24,
onClick = { router.push(AppRoute.WalletBackup(userWalletId)) },
text = resourceReference(R.string.card_settings_title),
iconRes = R.drawable.ic_card_settings_24,
onClick = { router.push(AppRoute.CardSettings(userWalletId)) },
).let(::add)
}
@ -199,4 +226,36 @@ internal class ItemsBuilder @Inject constructor(
),
),
)
private fun buildAccessCodeItem(userWallet: UserWallet, onItemClick: () -> Unit): List<WalletSettingsItemUM> {
return when (userWallet) {
is UserWallet.Cold -> emptyList()
is UserWallet.Hot -> buildHotWalletAccessCodeItem(userWallet, onItemClick)
}
}
private fun buildHotWalletAccessCodeItem(
userWallet: UserWallet.Hot,
onItemClick: () -> Unit,
): List<WalletSettingsItemUM> {
val isCodeSet = userWallet.hotWalletId.authType != HotWalletId.AuthType.NoPassword
return listOf(
WalletSettingsItemUM.WithItems(
id = "access_code",
description = resourceReference(R.string.wallet_settings_access_code_description),
blocks = persistentListOf(
BlockUM(
text = if (isCodeSet) {
resourceReference(R.string.wallet_settings_change_access_code_title)
} else {
resourceReference(R.string.wallet_settings_set_access_code_title)
},
iconRes = R.drawable.ic_lock_24,
onClick = onItemClick,
accentType = BlockUM.AccentType.ACCENT,
),
),
),
)
}
}