Updated on 2026-08-14

This commit is contained in:
Tangem 2026-01-22 16:14:14 +03:00
parent 081128f2cf
commit 63b07cccc3
53 changed files with 614 additions and 464 deletions

View file

@ -12,6 +12,7 @@ import com.tangem.features.details.entity.DetailsUM
import com.tangem.features.details.ui.DetailsScreen
import com.tangem.features.details.utils.ItemsBuilder
import com.tangem.features.details.utils.SocialsBuilder
import com.tangem.features.hotwallet.HotWalletFeatureToggles
import kotlinx.coroutines.runBlocking
internal class PreviewDetailsComponent : DetailsComponent {
@ -19,9 +20,14 @@ internal class PreviewDetailsComponent : DetailsComponent {
private val previewBlocks = runBlocking {
ItemsBuilder(
router = DummyRouter(),
hotWalletFeatureToggles = object : HotWalletFeatureToggles {
override val isHotWalletEnabled: Boolean = true
override val isWalletCreationRestrictionEnabled: Boolean = true
},
).buildAll(
isWalletConnectAvailable = true,
isSupportChatAvailable = true,
hasAnyMobileWallet = true,
userWalletId = UserWalletId(""),
onSupportEmailClick = {},
onSupportChatClick = {},

View file

@ -50,6 +50,7 @@ internal class PreviewUserWalletListComponent : UserWalletListComponent {
),
addNewWalletText = resourceReference(R.string.user_wallet_list_add_button),
isWalletSavingInProgress = true,
addNewWalletIconRes = R.drawable.ic_plus_24,
onAddNewWalletClick = {},
),
)

View file

@ -2,6 +2,7 @@ package com.tangem.features.details.entity
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.block.model.BlockUM
import com.tangem.core.ui.extensions.TextReference
import kotlinx.collections.immutable.ImmutableList
@Immutable
@ -27,4 +28,9 @@ internal sealed class DetailsItemUM {
data object UserWalletList : DetailsItemUM() {
override val id: String = "user_wallet_list"
}
data class UnderSectionText(
override val id: String,
val text: TextReference,
) : DetailsItemUM()
}

View file

@ -1,5 +1,6 @@
package com.tangem.features.details.entity
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Immutable
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
import com.tangem.core.ui.extensions.TextReference
@ -10,5 +11,6 @@ internal data class UserWalletListUM(
val userWallets: ImmutableList<UserWalletItemUM>,
val isWalletSavingInProgress: Boolean,
val addNewWalletText: TextReference,
@DrawableRes val addNewWalletIconRes: Int?,
val onAddNewWalletClick: () -> Unit,
)

View file

@ -97,6 +97,7 @@ internal class DetailsModel @Inject constructor(
itemsBuilder.buildAll(
isWalletConnectAvailable = isWalletConnectAvailable,
isSupportChatAvailable = feedbackFeatureToggles.isUsedeskEnabled,
hasAnyMobileWallet = getWalletsUseCase.invokeSync().any { it is UserWallet.Hot },
userWalletId = params.userWalletId,
onSupportEmailClick = ::sendFeedback,
onSupportChatClick = ::openUseDesk,

View file

@ -60,6 +60,7 @@ internal class UserWalletListModel @Inject constructor(
isWalletSavingInProgress = false,
addNewWalletText = TextReference.EMPTY,
onAddNewWalletClick = ::onAddNewWalletClick,
addNewWalletIconRes = R.drawable.ic_plus_24,
),
)
@ -81,10 +82,11 @@ internal class UserWalletListModel @Inject constructor(
value.copy(
userWallets = userWallets,
isWalletSavingInProgress = isWalletSavingInProgress,
addNewWalletText = if (shouldSaveUserWallets || hotWalletFeatureToggles.isHotWalletEnabled) {
resourceReference(R.string.user_wallet_list_add_button)
} else {
resourceReference(R.string.scan_card_settings_button)
addNewWalletText = when {
shouldSaveUserWallets || hotWalletFeatureToggles.isHotWalletEnabled -> {
resourceReference(R.string.user_wallet_list_add_button)
}
else -> resourceReference(R.string.scan_card_settings_button)
},
)
}
@ -92,7 +94,14 @@ internal class UserWalletListModel @Inject constructor(
private fun onAddNewWalletClick() {
if (hotWalletFeatureToggles.isHotWalletEnabled) {
analyticsEventHandler.send(SignIn.ButtonAddWallet(AnalyticsParam.ScreensSources.Settings))
router.push(AppRoute.CreateWalletSelection)
if (hotWalletFeatureToggles.isWalletCreationRestrictionEnabled) {
withProgress(isWalletSavingInProgress) {
userWalletSaver.scanAndSaveUserWallet(modelScope)
}
} else {
router.push(AppRoute.CreateWalletSelection)
}
} else {
withProgress(isWalletSavingInProgress) {
userWalletSaver.scanAndSaveUserWallet(modelScope)

View file

@ -5,6 +5,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
@ -18,10 +19,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SpacerH16
import com.tangem.core.ui.components.appbar.TangemTopAppBar
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
import com.tangem.core.ui.components.block.BlockItem
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
@ -68,7 +73,7 @@ private fun Content(
) {
LazyColumn(
modifier = modifier.testTag(DetailsScreenTestTags.SCREEN_CONTAINER),
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
verticalArrangement = Arrangement.SpaceBetween,
contentPadding = PaddingValues(
top = TangemTheme.dimens.spacing12,
bottom = TangemTheme.dimens.spacing16,
@ -94,6 +99,7 @@ private fun Content(
}
item(key = "footer") {
SpacerH16()
Footer(
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing12),
model = state.footer,
@ -108,6 +114,16 @@ private fun Block(
userWalletListBlockContent: ComposableContentComponent,
modifier: Modifier = Modifier,
) {
if (model is DetailsItemUM.UnderSectionText) {
UnderSectionTextBlock(
modifier = Modifier.fillMaxWidth(),
text = model.text,
)
return
}
SpacerH16()
Column(
modifier = modifier
.fillMaxWidth()
@ -142,10 +158,21 @@ private fun Block(
is DetailsItemUM.UserWalletList -> {
userWalletListBlockContent.Content(modifier = itemModifier)
}
is DetailsItemUM.UnderSectionText -> { /* Handled above */ }
}
}
}
@Composable
private fun UnderSectionTextBlock(text: TextReference, modifier: Modifier = Modifier) {
Text(
modifier = modifier.padding(horizontal = 30.dp, vertical = 8.dp),
text = text.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
)
}
@Composable
private fun Footer(model: DetailsFooterUM, modifier: Modifier = Modifier) {
Column(

View file

@ -1,6 +1,7 @@
package com.tangem.features.details.ui
import android.content.res.Configuration
import androidx.annotation.DrawableRes
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.CircularProgressIndicator
@ -23,7 +24,6 @@ import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.details.component.UserWalletListComponent
import com.tangem.features.details.component.preview.PreviewUserWalletListComponent
import com.tangem.features.details.entity.UserWalletListUM
import com.tangem.features.details.impl.R
@Composable
internal fun UserWalletListBlock(state: UserWalletListUM, modifier: Modifier = Modifier) {
@ -42,6 +42,7 @@ internal fun UserWalletListBlock(state: UserWalletListUM, modifier: Modifier = M
text = state.addNewWalletText,
isInProgress = state.isWalletSavingInProgress,
onClick = state.onAddNewWalletClick,
icon = state.addNewWalletIconRes,
)
}
}
@ -49,6 +50,7 @@ internal fun UserWalletListBlock(state: UserWalletListUM, modifier: Modifier = M
@Composable
private fun AddWalletButton(
text: TextReference,
@DrawableRes icon: Int?,
isInProgress: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
@ -65,23 +67,25 @@ private fun AddWalletButton(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
) {
AnimatedContent(
modifier = Modifier.size(TangemTheme.dimens.size24),
targetState = isInProgress,
label = "Add wallet progress",
) { isInProgress ->
if (isInProgress) {
CircularProgressIndicator(
modifier = Modifier.size(TangemTheme.dimens.size24),
color = TangemTheme.colors.icon.accent,
)
} else {
Icon(
modifier = Modifier.size(TangemTheme.dimens.size24),
painter = painterResource(id = R.drawable.ic_plus_24),
tint = TangemTheme.colors.icon.accent,
contentDescription = null,
)
if (icon != null) {
AnimatedContent(
modifier = Modifier.size(TangemTheme.dimens.size24),
targetState = isInProgress,
label = "Add wallet progress",
) { isInProgress ->
if (isInProgress) {
CircularProgressIndicator(
modifier = Modifier.size(TangemTheme.dimens.size24),
color = TangemTheme.colors.icon.accent,
)
} else {
Icon(
modifier = Modifier.size(TangemTheme.dimens.size24),
painter = painterResource(id = icon),
tint = TangemTheme.colors.icon.accent,
contentDescription = null,
)
}
}
}

View file

@ -8,6 +8,7 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.features.details.entity.DetailsItemUM
import com.tangem.features.details.impl.R
import com.tangem.features.hotwallet.HotWalletFeatureToggles
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
@ -17,12 +18,16 @@ import javax.inject.Inject
private const val TANGEM_PAY_ITEM_ID = "get_tangem_pay"
@ModelScoped
internal class ItemsBuilder @Inject constructor(private val router: Router) {
internal class ItemsBuilder @Inject constructor(
private val router: Router,
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
) {
@Suppress("LongParameterList")
fun buildAll(
isWalletConnectAvailable: Boolean,
isSupportChatAvailable: Boolean,
hasAnyMobileWallet: Boolean,
userWalletId: UserWalletId,
onSupportEmailClick: () -> Unit,
onSupportChatClick: () -> Unit,
@ -30,6 +35,14 @@ internal class ItemsBuilder @Inject constructor(private val router: Router) {
): ImmutableList<DetailsItemUM> = buildList {
buildWalletConnectBlock(isWalletConnectAvailable, userWalletId)?.let(::add)
buildUserWalletListBlock().let(::add)
if (hotWalletFeatureToggles.isWalletCreationRestrictionEnabled && hasAnyMobileWallet) {
DetailsItemUM.UnderSectionText(
id = "only_one_mobile_wallet_explanation",
text = resourceReference(R.string.only_one_mobile_wallet_explanation),
).let(::add)
}
buildShopBlock(onBuyClick).let(::add)
buildSettingsBlock().let(::add)
buildSupportBlock(