Updated on 2026-08-14
This commit is contained in:
parent
49d8e8f51c
commit
cfd237fc30
6 changed files with 92 additions and 36 deletions
|
|
@ -16,6 +16,7 @@ import dagger.hilt.android.scopes.ViewModelScoped
|
|||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
@Suppress("TooManyFunctions")
|
||||
internal object TokensDomainModule {
|
||||
|
||||
@Provides
|
||||
|
|
@ -212,4 +213,12 @@ internal object TokensDomainModule {
|
|||
networksRepository = networksRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideHasMissedAddressesCryptoCurrenciesUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
): GetMissedAddressesCryptoCurrenciesUseCase {
|
||||
return GetMissedAddressesCryptoCurrenciesUseCase(currenciesRepository = currenciesRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import com.tangem.datasource.local.userwallet.UserWalletsStore
|
|||
import com.tangem.domain.common.extensions.toCoinId
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.hasDerivation
|
||||
import com.tangem.domain.core.error.DataError
|
||||
import com.tangem.domain.demo.DemoConfig
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
|
@ -274,6 +275,24 @@ internal class DefaultCurrenciesRepository(
|
|||
}.cancellable()
|
||||
}
|
||||
|
||||
override fun getMissedAddressesCryptoCurrencies(userWalletId: UserWalletId): Flow<List<CryptoCurrency>> {
|
||||
return channelFlow {
|
||||
ensureIsCorrectUserWallet(userWalletId, isMultiCurrencyWalletExpected = true)
|
||||
|
||||
val userWallet = getUserWallet(userWalletId = userWalletId)
|
||||
getMultiCurrencyWalletCurrencies(userWallet = userWallet)
|
||||
.map {
|
||||
it.filter { currency ->
|
||||
val blockchain = Blockchain.fromId(id = currency.network.id.value)
|
||||
val derivationPath = currency.network.derivationPath.value
|
||||
|
||||
derivationPath != null && !userWallet.scanResponse.hasDerivation(blockchain, derivationPath)
|
||||
}
|
||||
}
|
||||
.collectLatest(::send)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMultiCurrencyWalletCurrencies(userWallet: UserWallet): Flow<List<CryptoCurrency>> {
|
||||
return userTokensStore.get(userWallet.walletId).map { storedTokens ->
|
||||
responseCurrenciesFactory.createCurrencies(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.tokens.error.GetCurrenciesError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class GetMissedAddressesCryptoCurrenciesUseCase(private val currenciesRepository: CurrenciesRepository) {
|
||||
|
||||
operator fun invoke(userWalletId: UserWalletId): Flow<Either<GetCurrenciesError, List<CryptoCurrency>>> {
|
||||
return currenciesRepository.getMissedAddressesCryptoCurrencies(userWalletId)
|
||||
.map(List<CryptoCurrency>::right)
|
||||
.catch { GetCurrenciesError.DataError(it).left() }
|
||||
}
|
||||
}
|
||||
|
|
@ -166,4 +166,6 @@ interface CurrenciesRepository {
|
|||
* ID provided.
|
||||
*/
|
||||
fun isTokensSortedByBalance(userWalletId: UserWalletId): Flow<Boolean>
|
||||
|
||||
fun getMissedAddressesCryptoCurrencies(userWalletId: UserWalletId): Flow<List<CryptoCurrency>>
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.viewmodels
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.card.WasCardScannedUseCase
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
||||
import com.tangem.domain.tokens.GetMissedAddressesCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.tokens.error.GetCurrenciesError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -13,7 +16,6 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlin.collections.count
|
||||
|
||||
/**
|
||||
* Wallet notifications list factory
|
||||
|
|
@ -31,6 +33,7 @@ internal class WalletNotificationsListFactory(
|
|||
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||
private val wasCardScannedUseCase: WasCardScannedUseCase,
|
||||
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
||||
private val getMissedAddressCryptoCurrenciesUseCase: GetMissedAddressesCryptoCurrenciesUseCase,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
) {
|
||||
|
||||
|
|
@ -45,12 +48,13 @@ internal class WalletNotificationsListFactory(
|
|||
flow = wasCardScannedUseCase(cardTypesResolver.getCardId()),
|
||||
flow2 = isReadyToShowRateAppUseCase(),
|
||||
flow3 = isNeedToBackupUseCase(selectedWalletId),
|
||||
) { wasCardScanned, isReadyToShowRating, isNeedToBackup ->
|
||||
flow4 = getMissedAddressCryptoCurrenciesUseCase(selectedWalletId),
|
||||
) { wasCardScanned, isReadyToShowRating, isNeedToBackup, maybeMissedAddressCurrencies ->
|
||||
readyForRateAppNotification = true
|
||||
buildList {
|
||||
addCriticalNotifications(cardTypesResolver)
|
||||
|
||||
addInformationalNotifications(cardTypesResolver, cryptoCurrencyList)
|
||||
addInformationalNotifications(cardTypesResolver, maybeMissedAddressCurrencies)
|
||||
|
||||
addWarningNotifications(cardTypesResolver, cryptoCurrencyList, wasCardScanned, isNeedToBackup)
|
||||
|
||||
|
|
@ -136,14 +140,14 @@ internal class WalletNotificationsListFactory(
|
|||
|
||||
private fun MutableList<WalletNotification>.addInformationalNotifications(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
cryptoCurrencyList: List<CryptoCurrencyStatus>,
|
||||
maybeMissedAddressCurrencies: Either<GetCurrenciesError, List<CryptoCurrency>>,
|
||||
) {
|
||||
addIf(
|
||||
element = WalletNotification.Informational.DemoCard,
|
||||
condition = isDemoCardUseCase(cardId = cardTypesResolver.getCardId()),
|
||||
)
|
||||
|
||||
addMissingAddressesNotification(cryptoCurrencyList)
|
||||
addMissingAddressesNotification(maybeMissedAddressCurrencies)
|
||||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addIf(element: WalletNotification, condition: Boolean) {
|
||||
|
|
@ -156,27 +160,21 @@ internal class WalletNotificationsListFactory(
|
|||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addMissingAddressesNotification(
|
||||
cryptoCurrencyList: List<CryptoCurrencyStatus>,
|
||||
maybeCurrencies: Either<GetCurrenciesError, List<CryptoCurrency>>,
|
||||
) {
|
||||
val missedAddressCurrencies = cryptoCurrencyList.getMissedAddressCurrencies()
|
||||
val missingAddressCurrencies = (maybeCurrencies as? Either.Right)?.value ?: return
|
||||
|
||||
addIf(
|
||||
element = WalletNotification.Informational.MissingAddresses(
|
||||
missingAddressesCount = missedAddressCurrencies.count(),
|
||||
missingAddressesCount = missingAddressCurrencies.count(),
|
||||
onGenerateClick = {
|
||||
clickIntents.onGenerateMissedAddressesClick(missedAddressCurrencies = missedAddressCurrencies)
|
||||
clickIntents.onGenerateMissedAddressesClick(missedAddressCurrencies = missingAddressCurrencies)
|
||||
},
|
||||
),
|
||||
condition = missedAddressCurrencies.isNotEmpty(),
|
||||
condition = missingAddressCurrencies.isNotEmpty(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<CryptoCurrencyStatus>.getMissedAddressCurrencies(): List<CryptoCurrency> {
|
||||
return this
|
||||
.filter { it.value is CryptoCurrencyStatus.MissedDerivation }
|
||||
.map(CryptoCurrencyStatus::currency)
|
||||
}
|
||||
|
||||
private fun List<CryptoCurrencyStatus>.hasUnreachableNetworks(): Boolean {
|
||||
return any { it.value is CryptoCurrencyStatus.Unreachable }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||
isDemoCardUseCase: IsDemoCardUseCase,
|
||||
isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
||||
getMissedAddressesCryptoCurrenciesUseCase: GetMissedAddressesCryptoCurrenciesUseCase,
|
||||
// endregion Parameters
|
||||
) : ViewModel(), DefaultLifecycleObserver, WalletClickIntents {
|
||||
|
||||
|
|
@ -147,6 +148,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
isReadyToShowRateAppUseCase = isReadyToShowRateAppUseCase,
|
||||
isDemoCardUseCase = isDemoCardUseCase,
|
||||
isNeedToBackupUseCase = isNeedToBackupUseCase,
|
||||
getMissedAddressCryptoCurrenciesUseCase = getMissedAddressesCryptoCurrenciesUseCase,
|
||||
clickIntents = this,
|
||||
)
|
||||
|
||||
|
|
@ -333,13 +335,21 @@ internal class WalletViewModel @Inject constructor(
|
|||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
config.primaryCurve(blockchain = Blockchain.fromId(it.network.id.value))?.let { curve ->
|
||||
getNewDerivations(curve, scanResponse, currencyList)
|
||||
getNewDerivations(curve, scanResponse, it)
|
||||
}
|
||||
}
|
||||
|
||||
val derivations = derivationDataList
|
||||
.associate(DerivationData::derivations)
|
||||
.ifEmpty { return }
|
||||
val derivations = buildMap<ByteArrayKey, MutableList<DerivationPath>> {
|
||||
derivationDataList.forEach {
|
||||
val current = this[it.derivations.first]
|
||||
if (current != null) {
|
||||
current.addAll(it.derivations.second)
|
||||
current.distinct()
|
||||
} else {
|
||||
this[it.derivations.first] = it.derivations.second.toMutableList()
|
||||
}
|
||||
}
|
||||
}.ifEmpty { return }
|
||||
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
derivePublicKeysUseCase(cardId = scanResponse.card.cardId, derivations = derivations)
|
||||
|
|
@ -364,30 +374,27 @@ internal class WalletViewModel @Inject constructor(
|
|||
private fun getNewDerivations(
|
||||
curve: EllipticCurve,
|
||||
scanResponse: ScanResponse,
|
||||
currencyList: List<CryptoCurrency>,
|
||||
currency: CryptoCurrency,
|
||||
): DerivationData? {
|
||||
val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
|
||||
|
||||
val manageTokensCandidates = currencyList
|
||||
.map { Blockchain.fromId(it.network.id.value) }
|
||||
.distinct()
|
||||
.filter { it.getSupportedCurves().contains(curve) }
|
||||
.mapNotNull { it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle()) }
|
||||
val blockchain = Blockchain.fromId(currency.network.id.value)
|
||||
val supportedCurves = blockchain.getSupportedCurves()
|
||||
val path = blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val customTokensCandidates = currencyList
|
||||
.filter { Blockchain.fromId(it.network.id.value).getSupportedCurves().contains(curve) }
|
||||
.mapNotNull { it.network.derivationPath.value }
|
||||
.map(::DerivationPath)
|
||||
val customPath = currency.network.derivationPath.value?.let {
|
||||
DerivationPath(it)
|
||||
}.takeIf { supportedCurves.contains(curve) }
|
||||
|
||||
val bothCandidates = (manageTokensCandidates + customTokensCandidates).distinct().toMutableList()
|
||||
val bothCandidates = listOfNotNull(path, customPath).distinct().toMutableList()
|
||||
if (bothCandidates.isEmpty()) return null
|
||||
|
||||
currencyList.find { it is CryptoCurrency.Coin && Blockchain.fromId(it.network.id.value) == Blockchain.Cardano }
|
||||
?.let { currency ->
|
||||
currency.network.derivationPath.value?.let {
|
||||
bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
|
||||
}
|
||||
if (currency is CryptoCurrency.Coin && blockchain == Blockchain.Cardano) {
|
||||
currency.network.derivationPath.value?.let {
|
||||
bothCandidates.add(CardanoUtils.extendedDerivationPath(DerivationPath(it)))
|
||||
}
|
||||
}
|
||||
|
||||
val mapKeyOfWalletPublicKey = wallet.publicKey.toMapKey()
|
||||
val alreadyDerivedKeys: ExtendedPublicKeysMap =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue