diff --git a/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt index 3d1b711ccf..0f3fab437c 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt @@ -84,4 +84,10 @@ internal object CardDomainModule { fun provideResetCardUseCase(tangemSdkManager: TangemSdkManager): ResetCardUseCase { return DefaultResetCardUseCase(tangemSdkManager) } + + @Provides + @Singleton + fun provideNetworkHasDerivationUseCase(): NetworkHasDerivationUseCase { + return NetworkHasDerivationUseCase() + } } \ No newline at end of file diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/NetworkHasDerivationUseCase.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/NetworkHasDerivationUseCase.kt new file mode 100644 index 0000000000..7bc68e0d66 --- /dev/null +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/NetworkHasDerivationUseCase.kt @@ -0,0 +1,16 @@ +package com.tangem.domain.card + +import arrow.core.Either +import com.tangem.blockchain.common.Blockchain +import com.tangem.domain.common.util.hasDerivation +import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.tokens.model.Network + +class NetworkHasDerivationUseCase { + + operator fun invoke(scanResponse: ScanResponse, network: Network): Either { + val blockchain = Blockchain.fromId(network.id.value) + val derivationPath = network.derivationPath.value + return Either.catch { derivationPath != null && scanResponse.hasDerivation(blockchain, derivationPath) } + } +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt index a96bde767a..8339f1f69b 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt @@ -1,5 +1,6 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory +import arrow.core.getOrElse import com.tangem.core.ui.components.marketprice.MarketPriceBlockState import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.event.consumedEvent @@ -7,8 +8,11 @@ import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.networkIconResId import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.res.TangemTheme +import com.tangem.domain.card.NetworkHasDerivationUseCase import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.Network +import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsActionButton import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsPullToRefreshConfig @@ -25,6 +29,9 @@ import kotlinx.coroutines.flow.MutableStateFlow internal class TokenDetailsSkeletonStateConverter( private val clickIntents: TokenDetailsClickIntents, private val featureToggles: TokenDetailsFeatureToggles, + private val networkHasDerivationUseCase: NetworkHasDerivationUseCase, + private val getUserWalletUseCase: GetUserWalletUseCase, + private val userWalletId: UserWalletId, ) : Converter { private val iconStateConverter by lazy { TokenDetailsIconStateConverter() } @@ -78,13 +85,7 @@ internal class TokenDetailsSkeletonStateConverter( private fun createMenu(cryptoCurrency: CryptoCurrency): TokenDetailsAppBarMenuConfig = TokenDetailsAppBarMenuConfig( items = buildList { - if (featureToggles.isGenerateXPubEnabled() && isBitcoin(cryptoCurrency.network.id.value)) { - TokenDetailsAppBarMenuConfig.MenuItem( - title = resourceReference(R.string.token_details_generate_xpub), - textColorProvider = { TangemTheme.colors.text.primary1 }, - onClick = clickIntents::onGenerateExtendedKey, - ).let(::add) - } + addGenerateXPubMenuItem(cryptoCurrency) TokenDetailsAppBarMenuConfig.MenuItem( title = TextReference.Res(id = R.string.token_details_hide_token), textColorProvider = { TangemTheme.colors.text.warning }, @@ -93,6 +94,26 @@ internal class TokenDetailsSkeletonStateConverter( }.toImmutableList(), ) + private fun MutableList.addGenerateXPubMenuItem( + cryptoCurrency: CryptoCurrency, + ) { + val userWallet = getUserWalletUseCase(userWalletId).getOrNull() ?: return + val isGenerateXPubEnabled = featureToggles.isGenerateXPubEnabled() + val isBitcoin = isBitcoin(cryptoCurrency.network.id.value) + val hasDerivations = + networkHasDerivationUseCase(userWallet.scanResponse, cryptoCurrency.network).getOrElse { false } + + if (isGenerateXPubEnabled && isBitcoin && hasDerivations) { + add( + TokenDetailsAppBarMenuConfig.MenuItem( + title = resourceReference(R.string.token_details_generate_xpub), + textColorProvider = { TangemTheme.colors.text.primary1 }, + onClick = clickIntents::onGenerateExtendedKey, + ), + ) + } + } + private fun createButtons(): ImmutableList { return persistentListOf( TokenDetailsActionButton.Buy(dimContent = false, onClick = {}), diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt index 952b0d2dc6..789a0a6f82 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt @@ -15,6 +15,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.res.TangemTheme import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.card.NetworkHasDerivationUseCase import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.staking.model.StakingAvailability import com.tangem.domain.staking.model.StakingEntryInfo @@ -24,6 +25,11 @@ import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.domain.txhistory.models.TxHistoryListError import com.tangem.domain.txhistory.models.TxHistoryStateError +import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.domain.wallets.usecase.GetUserWalletUseCase +import com.tangem.feature.tokendetails.presentation.tokendetails.state.SwapTransactionsState +import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsAppBarMenuConfig +import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsDialogConfig import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadedTxHistoryConverter @@ -46,6 +52,9 @@ internal class TokenDetailsStateFactory( private val cryptoCurrencyStatusProvider: Provider, private val clickIntents: TokenDetailsClickIntents, private val featureToggles: TokenDetailsFeatureToggles, + private val networkHasDerivationUseCase: NetworkHasDerivationUseCase, + private val getUserWalletUseCase: GetUserWalletUseCase, + private val userWalletId: UserWalletId, stakingFeatureToggles: StakingFeatureToggles, symbol: String, decimals: Int, @@ -55,6 +64,9 @@ internal class TokenDetailsStateFactory( TokenDetailsSkeletonStateConverter( clickIntents = clickIntents, featureToggles = featureToggles, + networkHasDerivationUseCase = networkHasDerivationUseCase, + getUserWalletUseCase = getUserWalletUseCase, + userWalletId = userWalletId, ) } @@ -348,12 +360,16 @@ internal class TokenDetailsStateFactory( ) } - fun getStateWithUpdatedMenu(cardTypesResolver: CardTypesResolver, isBitcoin: Boolean): TokenDetailsState { + fun getStateWithUpdatedMenu( + cardTypesResolver: CardTypesResolver, + hasDerivations: Boolean, + isBitcoin: Boolean, + ): TokenDetailsState { return with(currentStateProvider()) { copy( topAppBarConfig = topAppBarConfig.copy( tokenDetailsAppBarMenuConfig = topAppBarConfig.tokenDetailsAppBarMenuConfig - ?.updateMenu(cardTypesResolver, isBitcoin), + ?.updateMenu(cardTypesResolver, hasDerivations, isBitcoin), ), ) } @@ -367,13 +383,14 @@ internal class TokenDetailsStateFactory( private fun TokenDetailsAppBarMenuConfig.updateMenu( cardTypesResolver: CardTypesResolver, + hasDerivations: Boolean, isBitcoin: Boolean, ): TokenDetailsAppBarMenuConfig? { if (cardTypesResolver.isSingleWalletWithToken()) return null val showGenerateExtendedKey = featureToggles.isGenerateXPubEnabled() && isBitcoin return copy( items = buildList { - if (showGenerateExtendedKey) { + if (showGenerateExtendedKey && hasDerivations) { TokenDetailsAppBarMenuConfig.MenuItem( title = resourceReference(R.string.token_details_generate_xpub), textColorProvider = { TangemTheme.colors.text.primary1 }, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index bccaa00b68..245dd160ad 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -25,6 +25,7 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.card.GetExtendedPublicKeyForCurrencyUseCase +import com.tangem.domain.card.NetworkHasDerivationUseCase import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.redux.ReduxStateHolder @@ -108,6 +109,7 @@ internal class TokenDetailsViewModel @Inject constructor( private val stakingFeatureToggles: StakingFeatureToggles, private val getStakingAvailabilityUseCase: GetStakingAvailabilityUseCase, private val getYieldUseCase: GetYieldUseCase, + private val networkHasDerivationUseCase: NetworkHasDerivationUseCase, private val swapRepository: SwapRepository, private val swapTransactionRepository: SwapTransactionRepository, private val quotesRepository: QuotesRepository, @@ -118,8 +120,8 @@ internal class TokenDetailsViewModel @Inject constructor( private val analyticsEventsHandler: AnalyticsEventHandler, private val hapticManager: HapticManager, private val clipboardManager: ClipboardManager, + private val getUserWalletUseCase: GetUserWalletUseCase, tokenDetailsFeatureToggles: TokenDetailsFeatureToggles, - getUserWalletUseCase: GetUserWalletUseCase, deepLinksRegistry: DeepLinksRegistry, savedStateHandle: SavedStateHandle, ) : ViewModel(), DefaultLifecycleObserver, TokenDetailsClickIntents { @@ -156,6 +158,9 @@ internal class TokenDetailsViewModel @Inject constructor( decimals = cryptoCurrency.decimals, featureToggles = tokenDetailsFeatureToggles, stakingFeatureToggles = stakingFeatureToggles, + userWalletId = userWalletId, + networkHasDerivationUseCase = networkHasDerivationUseCase, + getUserWalletUseCase = getUserWalletUseCase, ) private val exchangeStatusFactory by lazy(mode = LazyThreadSafetyMode.NONE) { @@ -395,8 +400,11 @@ internal class TokenDetailsViewModel @Inject constructor( private fun updateTopBarMenu() { viewModelScope.launch(dispatchers.main) { + val hasDerivations = + networkHasDerivationUseCase(userWallet.scanResponse, cryptoCurrency.network).getOrElse { false } internalUiState.value = stateFactory.getStateWithUpdatedMenu( cardTypesResolver = userWallet.scanResponse.cardTypesResolver, + hasDerivations = hasDerivations, isBitcoin = isBitcoin(cryptoCurrency.network.id.value), ) }