Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-24 15:39:11 +03:00
parent 67577e8653
commit b5209c613d
5 changed files with 108 additions and 21 deletions

View file

@ -533,7 +533,7 @@ internal class TokenDetailsModel @Inject constructor(
network = cryptoCurrency.network,
).getOrElse { false }
val isSupported = isXPUBSupported()
val isSupported = isXpubSupported()
val isDynamicAddressesAvailable = isSupported &&
isDynamicAddressesAvailableUseCase(userWallet, cryptoCurrency)
@ -546,7 +546,7 @@ internal class TokenDetailsModel @Inject constructor(
}
}
private suspend fun isXPUBSupported(): Boolean {
private suspend fun isXpubSupported(): Boolean {
return isXpubSupportedUseCase(userWalletId = userWalletId, network = cryptoCurrency.network)
}
@ -1437,15 +1437,17 @@ internal class TokenDetailsModel @Inject constructor(
network = cryptoCurrency.network,
).getOrElse { false }
val isSupported = isXPUBSupported()
val isXpubSupported = isXpubSupported()
val isDynamicAddressesAvailable = isXpubSupported &&
isDynamicAddressesAvailableUseCase(userWallet, cryptoCurrency)
redesignStateController.update(
UpdateTopBarMenuTransformer(
userWallet = userWallet,
hasDerivations = hasDerivations,
isXPubSupported = isSupported,
onGenerateExtendedKey = ::onGenerateExtendedKey,
onHideClick = ::onHideClick,
isXpubSupported = isXpubSupported,
isDynamicAddressesAvailable = isDynamicAddressesAvailable,
clickIntents = this@TokenDetailsModel,
),
)
}

View file

@ -6,6 +6,7 @@ import com.tangem.core.ui.extensions.themedColor
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsUM
import com.tangem.features.tokendetails.impl.R
import com.tangem.utils.transformer.Transformer
@ -15,9 +16,9 @@ import kotlinx.collections.immutable.toImmutableList
internal class UpdateTopBarMenuTransformer(
private val userWallet: UserWallet,
private val hasDerivations: Boolean,
private val isXPubSupported: Boolean,
private val onGenerateExtendedKey: () -> Unit,
private val onHideClick: () -> Unit,
private val isXpubSupported: Boolean,
private val isDynamicAddressesAvailable: Boolean,
private val clickIntents: TokenDetailsClickIntents,
) : Transformer<TokenDetailsUM> {
override fun transform(prevState: TokenDetailsUM): TokenDetailsUM = prevState.copy(
@ -30,12 +31,21 @@ internal class UpdateTopBarMenuTransformer(
persistentListOf()
} else {
buildList {
if (isXPubSupported && hasDerivations) {
if (isDynamicAddressesAvailable) {
add(
TangemDropdownMenuItem(
title = resourceReference(R.string.dynamic_addresses),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = clickIntents::onDynamicAddressesClick,
),
)
}
if (isXpubSupported && hasDerivations) {
add(
TangemDropdownMenuItem(
title = resourceReference(R.string.token_details_generate_xpub),
textColor = themedColor { TangemTheme.colors.text.primary1 },
onClick = onGenerateExtendedKey,
onClick = clickIntents::onGenerateExtendedKey,
),
)
}
@ -43,7 +53,7 @@ internal class UpdateTopBarMenuTransformer(
TangemDropdownMenuItem(
title = resourceReference(R.string.token_details_hide_token),
textColor = themedColor { TangemTheme.colors.text.warning },
onClick = onHideClick,
onClick = clickIntents::onHideClick,
),
)
}.toImmutableList()

View file

@ -7,6 +7,7 @@ import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.card.CardTypesResolver
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
import com.tangem.feature.tokendetails.presentation.tokendetails.state.AddFundsUM
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockUM
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsTopAppBarUM
@ -29,8 +30,7 @@ class UpdateTopBarMenuTransformerTest {
private val coldWallet: UserWallet.Cold = mockk(relaxed = true)
private val hotWallet: UserWallet.Hot = mockk(relaxed = true)
private val cardTypesResolver: CardTypesResolver = mockk(relaxed = true)
private val onGenerateExtendedKey: () -> Unit = mockk(relaxed = true)
private val onHideClick: () -> Unit = mockk(relaxed = true)
private val clickIntents: TokenDetailsClickIntents = mockk(relaxed = true)
@BeforeEach
fun setUp() {
@ -77,8 +77,8 @@ class UpdateTopBarMenuTransformerTest {
assertThat(result.topAppBarUM.menuItems).hasSize(1)
result.topAppBarUM.menuItems.single().onClick()
verify(exactly = 1) { onHideClick.invoke() }
verify(exactly = 0) { onGenerateExtendedKey.invoke() }
verify(exactly = 1) { clickIntents.onHideClick() }
verify(exactly = 0) { clickIntents.onGenerateExtendedKey() }
}
@Test
@ -169,6 +169,48 @@ class UpdateTopBarMenuTransformerTest {
assertThat(result.marketPriceBlockState).isSameInstanceAs(state.marketPriceBlockState)
}
@Test
fun `GIVEN dynamic addresses available WHEN transform THEN dynamic addresses item is shown first`() {
// GIVEN
every { cardTypesResolver.isSingleWalletWithToken() } returns false
val transformer = createTransformer(
userWallet = coldWallet,
hasDerivations = false,
isXPubSupported = false,
isDynamicAddressesAvailable = true,
)
// WHEN
val result = transformer.transform(initialState())
// THEN — Dynamic addresses item first, Hide token second
assertThat(result.topAppBarUM.menuItems).hasSize(2)
result.topAppBarUM.menuItems.first().onClick()
verify(exactly = 1) { clickIntents.onDynamicAddressesClick() }
}
@Test
fun `GIVEN dynamic addresses unavailable WHEN transform THEN dynamic addresses item is hidden`() {
// GIVEN
every { cardTypesResolver.isSingleWalletWithToken() } returns false
val transformer = createTransformer(
userWallet = coldWallet,
hasDerivations = false,
isXPubSupported = false,
isDynamicAddressesAvailable = false,
)
// WHEN
val result = transformer.transform(initialState())
// THEN — only Hide token
assertThat(result.topAppBarUM.menuItems).hasSize(1)
result.topAppBarUM.menuItems.single().onClick()
verify(exactly = 0) { clickIntents.onDynamicAddressesClick() }
}
@Test
fun `GIVEN callbacks WHEN menu items invoked THEN callbacks are dispatched`() {
// GIVEN
@ -177,6 +219,7 @@ class UpdateTopBarMenuTransformerTest {
userWallet = coldWallet,
hasDerivations = true,
isXPubSupported = true,
isDynamicAddressesAvailable = true,
)
// WHEN
@ -184,20 +227,22 @@ class UpdateTopBarMenuTransformerTest {
result.topAppBarUM.menuItems.forEach { it.onClick() }
// THEN
verify(exactly = 1) { onGenerateExtendedKey.invoke() }
verify(exactly = 1) { onHideClick.invoke() }
verify(exactly = 1) { clickIntents.onDynamicAddressesClick() }
verify(exactly = 1) { clickIntents.onGenerateExtendedKey() }
verify(exactly = 1) { clickIntents.onHideClick() }
}
private fun createTransformer(
userWallet: UserWallet,
hasDerivations: Boolean,
isXPubSupported: Boolean,
isDynamicAddressesAvailable: Boolean = false,
) = UpdateTopBarMenuTransformer(
userWallet = userWallet,
hasDerivations = hasDerivations,
isXPubSupported = isXPubSupported,
onGenerateExtendedKey = onGenerateExtendedKey,
onHideClick = onHideClick,
isXpubSupported = isXPubSupported,
isDynamicAddressesAvailable = isDynamicAddressesAvailable,
clickIntents = clickIntents,
)
private fun initialState(): TokenDetailsUM = TokenDetailsUM(