Updated on 2026-08-14
This commit is contained in:
commit
687a67632d
23 changed files with 206 additions and 63 deletions
|
|
@ -5,6 +5,8 @@ import com.tangem.domain.card.repository.CardRepository
|
|||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.demo.DemoConfig
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
||||
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
||||
import com.tangem.tap.domain.TangemSdkManager
|
||||
import com.tangem.tap.domain.card.DefaultDerivePublicKeysUseCase
|
||||
import dagger.Module
|
||||
|
|
@ -62,4 +64,10 @@ internal object CardDomainModule {
|
|||
fun provideDerivePublicKeysUseCase(tangemSdkManager: TangemSdkManager): DerivePublicKeysUseCase {
|
||||
return DefaultDerivePublicKeysUseCase(tangemSdkManager = tangemSdkManager)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideIsNeedToBackupUseCase(walletStateHolder: WalletsStateHolder): IsNeedToBackupUseCase {
|
||||
return IsNeedToBackupUseCase(walletStateHolder)
|
||||
}
|
||||
}
|
||||
|
|
@ -450,6 +450,23 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
|
|||
Analytics.send(Onboarding.Backup.Finished(backupState.backupCardsNumber))
|
||||
}
|
||||
|
||||
userWalletsListManager.selectedUserWalletSync?.walletId?.let {
|
||||
scope.launch {
|
||||
userWalletsListManager.update(
|
||||
userWalletId = it,
|
||||
update = { wallet ->
|
||||
wallet.copy(
|
||||
scanResponse = updateScanResponseAfterBackup(
|
||||
scanResponse = wallet.scanResponse,
|
||||
backupState = backupState,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
store.dispatchOnMain(GlobalAction.UpdateUserWalletsListManager(userWalletsListManager))
|
||||
}
|
||||
}
|
||||
|
||||
val notActivatedCardIds = gatherCardIds(backupState, card)
|
||||
.mapNotNull { if (cardActivationIsFinished(it)) null else it }
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ internal class DefaultNetworksRepository(
|
|||
override fun getNetworkStatusesUpdates(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
refresh: Boolean,
|
||||
): Flow<Set<NetworkStatus>> = channelFlow {
|
||||
launch(dispatchers.io) {
|
||||
networksStatusesStore.get(userWalletId)
|
||||
|
|
@ -48,7 +47,7 @@ internal class DefaultNetworksRepository(
|
|||
}
|
||||
|
||||
withContext(dispatchers.io) {
|
||||
fetchNetworksStatusesIfCacheExpired(userWalletId, networks, refresh)
|
||||
fetchNetworksStatusesIfCacheExpired(userWalletId, networks, false)
|
||||
}
|
||||
}.cancellable()
|
||||
|
||||
|
|
|
|||
|
|
@ -37,17 +37,15 @@ class GetCurrencyStatusUpdatesUseCase(
|
|||
operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
currencyId: CryptoCurrency.ID,
|
||||
refresh: Boolean,
|
||||
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
|
||||
return flow {
|
||||
emitAll(getCurrency(userWalletId, currencyId, refresh))
|
||||
emitAll(getCurrency(userWalletId, currencyId))
|
||||
}.flowOn(dispatchers.io)
|
||||
}
|
||||
|
||||
private suspend fun getCurrency(
|
||||
userWalletId: UserWalletId,
|
||||
currencyId: CryptoCurrency.ID,
|
||||
refresh: Boolean,
|
||||
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
|
|
@ -56,7 +54,7 @@ class GetCurrencyStatusUpdatesUseCase(
|
|||
userWalletId = userWalletId,
|
||||
)
|
||||
|
||||
return operations.getCurrencyStatusFlow(currencyId, refresh).map { maybeCurrency ->
|
||||
return operations.getCurrencyStatusFlow(currencyId).map { maybeCurrency ->
|
||||
maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,16 +67,13 @@ internal class CurrenciesStatusesOperations(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun getCurrencyStatusFlow(
|
||||
currencyId: CryptoCurrency.ID,
|
||||
refresh: Boolean = false,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
suspend fun getCurrencyStatusFlow(currencyId: CryptoCurrency.ID): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getMultiCurrencyWalletCurrency(currencyId) },
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(currency, refresh)
|
||||
return getCurrencyStatusFlow(currency)
|
||||
}
|
||||
|
||||
suspend fun getNetworkCoinFlow(networkId: Network.ID): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
|
|
@ -97,10 +94,7 @@ internal class CurrenciesStatusesOperations(
|
|||
return getCurrencyStatusFlow(currency)
|
||||
}
|
||||
|
||||
private fun getCurrencyStatusFlow(
|
||||
currency: CryptoCurrency,
|
||||
refresh: Boolean = false,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
private fun getCurrencyStatusFlow(currency: CryptoCurrency): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val (networks, currenciesIds) = getIds(nonEmptyListOf(currency))
|
||||
|
||||
val quoteFlow = getQuotes(currenciesIds)
|
||||
|
|
@ -111,7 +105,7 @@ internal class CurrenciesStatusesOperations(
|
|||
}
|
||||
}
|
||||
|
||||
val statusFlow = getNetworksStatuses(networks, refresh)
|
||||
val statusFlow = getNetworksStatuses(networks)
|
||||
.map { maybeStatuses ->
|
||||
maybeStatuses.flatMap { statuses ->
|
||||
statuses.singleOrNull { it.network == currency.network }?.right()
|
||||
|
|
@ -210,11 +204,8 @@ internal class CurrenciesStatusesOperations(
|
|||
.onEmpty { emit(Error.EmptyQuotes.left()) }
|
||||
}
|
||||
|
||||
private fun getNetworksStatuses(
|
||||
networks: NonEmptySet<Network>,
|
||||
refresh: Boolean = false,
|
||||
): Flow<Either<Error, Set<NetworkStatus>>> {
|
||||
return networksRepository.getNetworkStatusesUpdates(userWalletId, networks, refresh)
|
||||
private fun getNetworksStatuses(networks: NonEmptySet<Network>): Flow<Either<Error, Set<NetworkStatus>>> {
|
||||
return networksRepository.getNetworkStatusesUpdates(userWalletId, networks)
|
||||
.map<Set<NetworkStatus>, Either<Error, Set<NetworkStatus>>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyNetworksStatuses.left()) }
|
||||
|
|
|
|||
|
|
@ -16,14 +16,9 @@ interface NetworksRepository {
|
|||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @param networks A set of network which statuses are to be retrieved.
|
||||
* @param refresh A boolean flag indicating whether the data should be refreshed from remote.
|
||||
* @return A [Flow] emitting a set of [NetworkStatus] objects corresponding to the specified networks.
|
||||
*/
|
||||
fun getNetworkStatusesUpdates(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
refresh: Boolean = false,
|
||||
): Flow<Set<NetworkStatus>>
|
||||
fun getNetworkStatusesUpdates(userWalletId: UserWalletId, networks: Set<Network>): Flow<Set<NetworkStatus>>
|
||||
|
||||
/**
|
||||
* Retrieves network statuses of specified blockchain networks for a specific user wallet.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ internal class MockNetworksRepository(
|
|||
override fun getNetworkStatusesUpdates(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
refresh: Boolean,
|
||||
): Flow<Set<NetworkStatus>> {
|
||||
return statuses.map { it.getOrElse { e -> throw e } }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/**
|
||||
* Use case that checks if wallet need backup cards
|
||||
*/
|
||||
class IsNeedToBackupUseCase(private val walletsStateHolder: WalletsStateHolder) {
|
||||
|
||||
operator fun invoke(id: UserWalletId): Flow<Boolean> {
|
||||
val userWalletsListManager = requireNotNull(walletsStateHolder.userWalletsListManager)
|
||||
|
||||
return userWalletsListManager.userWallets
|
||||
.map { wallets ->
|
||||
val wallet = wallets.firstOrNull { it.walletId == id }
|
||||
if (wallet == null) {
|
||||
false
|
||||
} else {
|
||||
wallet.scanResponse.card.backupStatus is CardDTO.BackupStatus.NoBackup
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,14 +11,12 @@ import com.tangem.features.tokendetails.impl.R
|
|||
// TODO: Finalize notification strings [REDACTED_JIRA]
|
||||
@Immutable
|
||||
sealed class TokenDetailsNotification(
|
||||
open val isVisible: Boolean = true,
|
||||
open val config: NotificationConfig,
|
||||
) {
|
||||
|
||||
data class RentInfo(
|
||||
private val rentInfo: CryptoCurrencyWarning.Rent,
|
||||
private val onCloseClick: () -> Unit,
|
||||
override val isVisible: Boolean = true,
|
||||
) : TokenDetailsNotification(
|
||||
config = NotificationConfig(
|
||||
title = TextReference.Res(R.string.send_network_fee_title),
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory
|
||||
|
||||
import com.tangem.common.extensions.cast
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.extensions.removeBy
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
|
|
@ -17,15 +17,9 @@ internal class TokenDetailsNotificationConverter(
|
|||
return value.map(::mapToNotification).toImmutableList()
|
||||
}
|
||||
|
||||
fun getStateRentInfoVisibility(
|
||||
currentState: TokenDetailsState,
|
||||
isVisible: Boolean,
|
||||
): ImmutableList<TokenDetailsNotification> {
|
||||
fun removeRentInfo(currentState: TokenDetailsState): ImmutableList<TokenDetailsNotification> {
|
||||
val newNotifications = currentState.notifications.toMutableList()
|
||||
val oldNotification = newNotifications.find { it is TokenDetailsNotification.RentInfo }
|
||||
oldNotification?.let {
|
||||
newNotifications.add(it.cast<TokenDetailsNotification.RentInfo>().copy(isVisible = isVisible))
|
||||
}
|
||||
newNotifications.removeBy { it is TokenDetailsNotification.RentInfo }
|
||||
return newNotifications.toImmutableList()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -139,9 +139,7 @@ internal class TokenDetailsStateFactory(
|
|||
}
|
||||
|
||||
fun getRefreshedState(): TokenDetailsState {
|
||||
val state = currentStateProvider()
|
||||
return refreshStateConverter.convert(false)
|
||||
.copy(notifications = notificationConverter.getStateRentInfoVisibility(state, true))
|
||||
}
|
||||
|
||||
fun getStateWithReceiveBottomSheet(
|
||||
|
|
@ -212,6 +210,6 @@ internal class TokenDetailsStateFactory(
|
|||
|
||||
fun getStateWithRemovedRentNotification(): TokenDetailsState {
|
||||
val state = currentStateProvider()
|
||||
return state.copy(notifications = notificationConverter.getStateRentInfoVisibility(state, false))
|
||||
return state.copy(notifications = notificationConverter.removeRentInfo(state))
|
||||
}
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) {
|
|||
)
|
||||
}
|
||||
items(
|
||||
items = state.notifications.filter { it.isVisible },
|
||||
items = state.notifications,
|
||||
key = { it.config::class.java },
|
||||
contentType = { it.config::class.java },
|
||||
itemContent = { Notification(config = it.config, modifier = itemModifier.animateItemPlacement()) },
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -71,6 +72,7 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
|
||||
private val marketPriceJobHolder = JobHolder()
|
||||
private val refreshStateJobHolder = JobHolder()
|
||||
private val networkStatusAutoUpdateStateJobHolder = JobHolder()
|
||||
private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null
|
||||
private var wallet by Delegates.notNull<UserWallet>()
|
||||
|
||||
|
|
@ -148,7 +150,6 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
getCurrencyStatusUpdatesUseCase(
|
||||
userWalletId = selectedWallet.walletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
refresh = true,
|
||||
)
|
||||
.distinctUntilChanged()
|
||||
.onEach { either ->
|
||||
|
|
@ -161,6 +162,17 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
.saveIn(marketPriceJobHolder)
|
||||
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
// Wait for blockchain updates pending transactions.
|
||||
// Immediate update doesn't receive any changes.
|
||||
delay(NETWORK_STATUS_AUTO_UPDATE_DELAY)
|
||||
fetchCurrencyStatusUseCase.invoke(
|
||||
userWalletId = wallet.walletId,
|
||||
id = cryptoCurrency.id,
|
||||
refresh = true,
|
||||
)
|
||||
}.saveIn(networkStatusAutoUpdateStateJobHolder)
|
||||
}
|
||||
|
||||
private fun updateTxHistory(refresh: Boolean = false) {
|
||||
|
|
@ -365,7 +377,7 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
refresh = true,
|
||||
)
|
||||
updateTxHistory(refresh = true)
|
||||
|
||||
updateWarnings(wallet)
|
||||
uiState = stateFactory.getRefreshedState()
|
||||
}.saveIn(refreshStateJobHolder)
|
||||
}
|
||||
|
|
@ -377,4 +389,8 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
override fun onCloseRentInfoNotification() {
|
||||
uiState = stateFactory.getStateWithRemovedRentNotification()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NETWORK_STATUS_AUTO_UPDATE_DELAY = 1000L
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ internal object WalletPreviewData {
|
|||
imageResId = R.drawable.ill_businessman_3d,
|
||||
onRenameClick = { _, _ -> },
|
||||
onDeleteClick = {},
|
||||
cardCount = 1,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -65,6 +66,7 @@ internal object WalletPreviewData {
|
|||
onDeleteClick = {},
|
||||
balance = "8923,05 $",
|
||||
additionalInfo = TextReference.Str("3 cards • Seed phrase"),
|
||||
cardCount = 1,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ internal sealed interface WalletCardState {
|
|||
* @property onRenameClick lambda be invoked when Rename button is clicked
|
||||
* @property onDeleteClick lambda be invoked when Delete button is clicked
|
||||
* @property additionalInfo wallet additional info
|
||||
* @property cardCount number of cards in the wallet
|
||||
* @property balance wallet balance
|
||||
*/
|
||||
data class Content(
|
||||
|
|
@ -43,6 +44,7 @@ internal sealed interface WalletCardState {
|
|||
override val onRenameClick: (UserWalletId, String) -> Unit,
|
||||
override val onDeleteClick: (UserWalletId) -> Unit,
|
||||
val additionalInfo: TextReference,
|
||||
val cardCount: Int?,
|
||||
val balance: String,
|
||||
) : WalletCardState
|
||||
|
||||
|
|
@ -55,6 +57,7 @@ internal sealed interface WalletCardState {
|
|||
* @property onRenameClick lambda be invoked when Rename button is clicked
|
||||
* @property onDeleteClick lambda be invoked when Delete button is clicked
|
||||
* @property additionalInfo wallet additional info
|
||||
* @property cardCount number of cards in the wallet
|
||||
* @property balance wallet balance
|
||||
*/
|
||||
data class HiddenContent(
|
||||
|
|
@ -65,6 +68,7 @@ internal sealed interface WalletCardState {
|
|||
override val onDeleteClick: (UserWalletId) -> Unit,
|
||||
val additionalInfo: TextReference,
|
||||
val balance: String,
|
||||
val cardCount: Int?,
|
||||
) : WalletCardState
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.domain.tokens.error.CurrencyStatusError
|
|||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||
|
|
@ -96,6 +97,7 @@ internal class WalletSingleCurrencyLoadedBalanceConverter(
|
|||
onRenameClick = selectedWallet.onRenameClick,
|
||||
onDeleteClick = selectedWallet.onDeleteClick,
|
||||
balance = formatFiatAmount(status = status, appCurrency = appCurrencyProvider()),
|
||||
cardCount = currentWalletProvider().getCardsCount(),
|
||||
)
|
||||
}
|
||||
is CryptoCurrencyStatus.Loading -> {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,13 @@ internal class WalletStateFactory(
|
|||
|
||||
private val hiddenStateConverter by lazy { HiddenStateConverter(currentStateProvider) }
|
||||
|
||||
private val walletUpdateCardCountConverter by lazy {
|
||||
WalletUpdateCardCountConverter(
|
||||
currentStateProvider,
|
||||
currentWalletProvider,
|
||||
)
|
||||
}
|
||||
|
||||
private val tokenListErrorConverter by lazy {
|
||||
TokenListErrorConverter(currentStateProvider)
|
||||
}
|
||||
|
|
@ -134,6 +141,8 @@ internal class WalletStateFactory(
|
|||
|
||||
fun getStateWithUpdatedWalletName(name: String): WalletState = walletRenameStateConverter.convert(value = name)
|
||||
|
||||
fun getStateWithUpdatedWalletCardCount(): WalletState = walletUpdateCardCountConverter.convert(Unit)
|
||||
|
||||
fun getUnlockedState(action: WalletsUpdateActionResolver.Action.UnlockWallet): WalletState {
|
||||
return walletsUnlockStateConverter.convert(value = action)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.factory
|
||||
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletsListConfig
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class WalletUpdateCardCountConverter(
|
||||
private val currentStateProvider: Provider<WalletState>,
|
||||
private val currentWalletProvider: Provider<UserWallet>,
|
||||
) : Converter<Unit, WalletState> {
|
||||
|
||||
override fun convert(value: Unit): WalletState {
|
||||
return when (val state = currentStateProvider()) {
|
||||
is WalletState.ContentState -> {
|
||||
state.copySealed(
|
||||
walletsListConfig = state.walletsListConfig.refreshCardCount(),
|
||||
)
|
||||
}
|
||||
is WalletState.Initial -> state
|
||||
}
|
||||
}
|
||||
|
||||
private fun WalletsListConfig.refreshCardCount(): WalletsListConfig {
|
||||
return copy(
|
||||
wallets = wallets
|
||||
.mapIndexed { index, walletCard ->
|
||||
if (index == selectedWalletIndex) {
|
||||
when (walletCard) {
|
||||
is WalletCardState.Content -> walletCard.copy(
|
||||
additionalInfo = WalletAdditionalInfoFactory.resolve(
|
||||
wallet = currentWalletProvider(),
|
||||
),
|
||||
cardCount = currentWalletProvider().getCardsCount(),
|
||||
)
|
||||
is WalletCardState.HiddenContent -> walletCard.copy(
|
||||
additionalInfo = WalletAdditionalInfoFactory.resolve(
|
||||
wallet = currentWalletProvider(),
|
||||
),
|
||||
cardCount = currentWalletProvider().getCardsCount(),
|
||||
)
|
||||
else -> walletCard
|
||||
}
|
||||
} else {
|
||||
walletCard
|
||||
}
|
||||
}
|
||||
.toImmutableList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.tokens.model.TokenList.FiatBalance
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
|
|
@ -54,6 +55,7 @@ internal class FiatBalanceToWalletCardConverter(
|
|||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
),
|
||||
additionalInfo = WalletAdditionalInfoFactory.resolve(wallet = currentWalletProvider()),
|
||||
cardCount = currentWalletProvider().getCardsCount(),
|
||||
)
|
||||
} else {
|
||||
WalletCardState.Content(
|
||||
|
|
@ -68,6 +70,7 @@ internal class FiatBalanceToWalletCardConverter(
|
|||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
),
|
||||
cardCount = currentWalletProvider().getCardsCount(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ internal class WalletHiddenBalanceStateConverter {
|
|||
onRenameClick = content.onRenameClick,
|
||||
onDeleteClick = content.onDeleteClick,
|
||||
balance = content.balance,
|
||||
cardCount = content.cardCount,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -37,6 +38,7 @@ internal class WalletHiddenBalanceStateConverter {
|
|||
onRenameClick = hiddenContent.onRenameClick,
|
||||
onDeleteClick = hiddenContent.onDeleteClick,
|
||||
balance = hiddenContent.balance,
|
||||
cardCount = hiddenContent.cardCount,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,8 @@ import com.tangem.domain.demo.IsDemoCardUseCase
|
|||
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -16,9 +18,10 @@ import kotlin.collections.count
|
|||
/**
|
||||
* Wallet notifications list factory
|
||||
*
|
||||
* @property isDemoCardUseCase use case that check if card is demo
|
||||
* @property isReadyToShowRateAppUseCase use case that check if card is user already rate app
|
||||
* @property wasCardScannedUseCase use case that check if card was scanned
|
||||
* @property isDemoCardUseCase use case that checks if card is demo
|
||||
* @property isReadyToShowRateAppUseCase use case that checks if card is user already rate app
|
||||
* @property wasCardScannedUseCase use case that checks if card was scanned
|
||||
* @property isNeedToBackupUseCase use case that checks if wallet need backup cards
|
||||
* @property clickIntents screen click intents
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -27,17 +30,20 @@ internal class WalletNotificationsListFactory(
|
|||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||
private val wasCardScannedUseCase: WasCardScannedUseCase,
|
||||
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
) {
|
||||
|
||||
fun create(
|
||||
selectedWalletId: UserWalletId,
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
cryptoCurrencyList: List<CryptoCurrencyStatus>,
|
||||
): Flow<ImmutableList<WalletNotification>> {
|
||||
return combine(
|
||||
flow = wasCardScannedUseCase(cardTypesResolver.getCardId()),
|
||||
flow2 = isReadyToShowRateAppUseCase(),
|
||||
) { wasCardScanned, isReadyToShowRating ->
|
||||
flow3 = isNeedToBackupUseCase(selectedWalletId),
|
||||
) { wasCardScanned, isReadyToShowRating, isNeedToBackup ->
|
||||
buildList {
|
||||
addCriticalNotifications(cardTypesResolver)
|
||||
|
||||
|
|
@ -45,7 +51,7 @@ internal class WalletNotificationsListFactory(
|
|||
|
||||
addRateTheAppNotification(isReadyToShowRating)
|
||||
|
||||
addWarningNotifications(cardTypesResolver, cryptoCurrencyList, wasCardScanned)
|
||||
addWarningNotifications(cardTypesResolver, cryptoCurrencyList, wasCardScanned, isNeedToBackup)
|
||||
}.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
|
@ -116,12 +122,13 @@ internal class WalletNotificationsListFactory(
|
|||
cardTypesResolver: CardTypesResolver,
|
||||
cryptoCurrencyList: List<CryptoCurrencyStatus>,
|
||||
wasCardScanned: Boolean,
|
||||
isNeedToBackup: Boolean,
|
||||
) {
|
||||
addIf(
|
||||
element = WalletNotification.Warning.MissingBackup(
|
||||
onStartBackupClick = clickIntents::onBackupCardClick,
|
||||
),
|
||||
condition = !cardTypesResolver.isBackupForbidden() && !cardTypesResolver.hasBackup(),
|
||||
condition = isNeedToBackup,
|
||||
)
|
||||
|
||||
val isDemo = isDemoCardUseCase(cardId = cardTypesResolver.getCardId())
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
wasCardScannedUseCase: WasCardScannedUseCase,
|
||||
isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||
isDemoCardUseCase: IsDemoCardUseCase,
|
||||
isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
||||
// endregion Parameters
|
||||
) : ViewModel(), DefaultLifecycleObserver, WalletClickIntents {
|
||||
|
||||
|
|
@ -135,6 +136,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
wasCardScannedUseCase = wasCardScannedUseCase,
|
||||
isReadyToShowRateAppUseCase = isReadyToShowRateAppUseCase,
|
||||
isDemoCardUseCase = isDemoCardUseCase,
|
||||
isNeedToBackupUseCase = isNeedToBackupUseCase,
|
||||
clickIntents = this,
|
||||
)
|
||||
|
||||
|
|
@ -227,6 +229,9 @@ internal class WalletViewModel @Inject constructor(
|
|||
is WalletsUpdateActionResolver.Action.AddWallet -> {
|
||||
scrollAndUpdateState(action.selectedWalletIndex)
|
||||
}
|
||||
is WalletsUpdateActionResolver.Action.UpdateWalletCardCount -> {
|
||||
uiState = stateFactory.getStateWithUpdatedWalletCardCount()
|
||||
}
|
||||
is WalletsUpdateActionResolver.Action.Unknown -> Unit
|
||||
}
|
||||
}
|
||||
|
|
@ -983,6 +988,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
|
||||
private fun updateNotifications(index: Int, tokenList: TokenList? = null) {
|
||||
notificationsListFactory.create(
|
||||
selectedWalletId = getWallet(index).walletId,
|
||||
cardTypesResolver = getCardTypeResolver(index = index),
|
||||
cryptoCurrencyList = if (tokenList != null) {
|
||||
when (tokenList) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.common.Provider
|
|||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletLockedState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
|
||||
|
|
@ -110,20 +111,29 @@ internal class WalletsUpdateActionResolver(
|
|||
selectedWallet: UserWallet,
|
||||
): Action {
|
||||
val selectedWalletName = selectedWallet.name
|
||||
val previousWalletState = state.getPrevSelectedWallet()
|
||||
return when {
|
||||
previousWalletState.title != selectedWalletName -> {
|
||||
Action.UpdateWalletName(selectedWalletName)
|
||||
}
|
||||
|
||||
if (state.getPrevSelectedWallet().title != selectedWalletName) {
|
||||
return Action.UpdateWalletName(selectedWalletName)
|
||||
state is WalletLockedState && !selectedWallet.isLocked -> {
|
||||
Action.UnlockWallet(
|
||||
selectedWalletIndex = wallets.indexOfWallet(id = selectedWallet.walletId),
|
||||
selectedWallet = selectedWallet,
|
||||
unlockedWallets = wallets.filterNot(UserWallet::isLocked),
|
||||
)
|
||||
}
|
||||
|
||||
previousWalletState is WalletCardState.Content &&
|
||||
previousWalletState.cardCount != selectedWallet.getCardsCount() ||
|
||||
previousWalletState is WalletCardState.HiddenContent &&
|
||||
previousWalletState.cardCount != selectedWallet.getCardsCount() -> {
|
||||
Action.UpdateWalletCardCount
|
||||
}
|
||||
|
||||
else -> Action.Unknown
|
||||
}
|
||||
|
||||
if (state is WalletLockedState && !selectedWallet.isLocked) {
|
||||
return Action.UnlockWallet(
|
||||
selectedWalletIndex = wallets.indexOfWallet(id = selectedWallet.walletId),
|
||||
selectedWallet = selectedWallet,
|
||||
unlockedWallets = wallets.filterNot(UserWallet::isLocked),
|
||||
)
|
||||
}
|
||||
|
||||
return Action.Unknown
|
||||
}
|
||||
|
||||
private fun WalletState.ContentState.getPrevSelectedWallet(): WalletCardState {
|
||||
|
|
@ -163,6 +173,8 @@ internal class WalletsUpdateActionResolver(
|
|||
|
||||
data class AddWallet(val selectedWalletIndex: Int) : Action()
|
||||
|
||||
object UpdateWalletCardCount : Action()
|
||||
|
||||
object Unknown : Action()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue