Updated on 2026-08-14
This commit is contained in:
parent
4ea8243da3
commit
f009a78876
12 changed files with 104 additions and 52 deletions
|
|
@ -3,7 +3,6 @@ package com.tangem.features.send.v2.send.confirm.model
|
|||
import android.os.SystemClock
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.getOrElse
|
||||
import arrow.core.left
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.common.routing.AppRouter
|
||||
|
|
@ -22,6 +21,7 @@ import com.tangem.core.navigation.url.UrlOpener
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
||||
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
||||
|
|
@ -33,6 +33,7 @@ import com.tangem.domain.settings.IsSendTapHelpEnabledUseCase
|
|||
import com.tangem.domain.settings.NeverShowTapHelpUseCase
|
||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.transaction.usecase.CreateTransferTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||
|
|
@ -108,6 +109,8 @@ internal class SendConfirmModel @Inject constructor(
|
|||
private val sendAmountReduceTrigger: SendAmountReduceTrigger,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
sendBalanceUpdaterFactory: SendBalanceUpdater.Factory,
|
||||
) : Model(), SendConfirmClickIntents, FeeSelectorModelCallback, SendNotificationsComponent.ModelCallback {
|
||||
|
||||
|
|
@ -433,10 +436,10 @@ internal class SendConfirmModel @Inject constructor(
|
|||
|
||||
modelScope.launch(dispatchers.default) {
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
// val tokenToAdd = currenciesRepository.createTokenCurrency(cryptoCurrency, network)
|
||||
// saveCryptoCurrenciesUseCase(accountId = accountId, add = tokenToAdd)
|
||||
// TODO account
|
||||
IllegalStateException("Not implemented yet").left()
|
||||
val accountId = receivingUserWallet.accountId ?: return@launch
|
||||
|
||||
val tokenToAdd = currenciesRepository.createTokenCurrency(cryptoCurrency, network)
|
||||
manageCryptoCurrenciesUseCase(accountId = accountId, add = tokenToAdd)
|
||||
} else {
|
||||
withContext(NonCancellable) {
|
||||
addCryptoCurrenciesUseCase(
|
||||
|
|
@ -445,8 +448,7 @@ internal class SendConfirmModel @Inject constructor(
|
|||
network = network,
|
||||
)
|
||||
}
|
||||
}
|
||||
.onLeft(Timber::e)
|
||||
}.onLeft(Timber::e)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -180,8 +180,8 @@ internal class SendAmountModel @Inject constructor(
|
|||
|
||||
private fun initialState(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
@Suppress("UnusedParameter") account: Account.CryptoPortfolio?,
|
||||
@Suppress("UnusedParameter") isAccountsMode: Boolean,
|
||||
account: Account.CryptoPortfolio?,
|
||||
isAccountsMode: Boolean,
|
||||
) {
|
||||
if (uiState.value is AmountState.Empty && userWallet != null) {
|
||||
val isOnlyOneWallet = getWalletsUseCase.invokeSync().size == 1
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ import com.tangem.core.decompose.model.ParamsContainer
|
|||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
||||
import com.tangem.domain.account.status.supplier.MultiAccountStatusListSupplier
|
||||
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.network.CryptoCurrencyAddress
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.isLocked
|
||||
|
|
@ -68,9 +69,9 @@ internal class SendDestinationModel @Inject constructor(
|
|||
private val listenToQrScanningUseCase: ListenToQrScanningUseCase,
|
||||
private val parseQrCodeUseCase: ParseQrCodeUseCase,
|
||||
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
|
||||
private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val multiAccountStatusListSupplier: MultiAccountStatusListSupplier,
|
||||
) : Model(), SendDestinationClickIntents {
|
||||
private val params: SendDestinationComponentParams = paramsContainer.require()
|
||||
|
||||
|
|
@ -189,8 +190,14 @@ internal class SendDestinationModel @Inject constructor(
|
|||
|
||||
private fun getWalletsAndRecent() {
|
||||
combine(
|
||||
flow = getWalletsUseCase().conflate().map {
|
||||
waitForDelay(RECENT_LOAD_DELAY) { it.toAvailableWallets() }
|
||||
flow = if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
getAddedAddresses()
|
||||
} else {
|
||||
getWalletsUseCase().conflate().map {
|
||||
waitForDelay(RECENT_LOAD_DELAY) {
|
||||
it.toAvailableWallets()
|
||||
}
|
||||
}
|
||||
},
|
||||
flow2 = getFixedTxHistoryItemsUseCase(
|
||||
userWalletId = userWalletId,
|
||||
|
|
@ -200,12 +207,7 @@ internal class SendDestinationModel @Inject constructor(
|
|||
waitForDelay(RECENT_LOAD_DELAY) { it }
|
||||
}.conflate(),
|
||||
flow3 = isAccountsModeEnabledUseCase().distinctUntilChanged(),
|
||||
flow4 = if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
getAccountCurrencyStatusUseCase(userWalletId, cryptoCurrency).distinctUntilChanged()
|
||||
} else {
|
||||
flowOf(null)
|
||||
},
|
||||
) { destinationWalletList, txHistoryList, isAccountsMode, accountCurrencyStatus ->
|
||||
) { destinationWalletList, txHistoryList, isAccountsMode ->
|
||||
val isSelfSendAvailable = isSelfSendAvailableUseCase.invokeSync(
|
||||
userWalletId = userWalletId,
|
||||
network = cryptoCurrency.network,
|
||||
|
|
@ -217,7 +219,6 @@ internal class SendDestinationModel @Inject constructor(
|
|||
isSelfSendAvailable = isSelfSendAvailable,
|
||||
destinationWalletList = destinationWalletList,
|
||||
txHistoryList = txHistoryList,
|
||||
account = accountCurrencyStatus?.account,
|
||||
isAccountsMode = isAccountsMode,
|
||||
),
|
||||
)
|
||||
|
|
@ -266,6 +267,46 @@ internal class SendDestinationModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getAddedAddresses(): Flow<List<DestinationWalletUM>> {
|
||||
return combine(
|
||||
flow = getWalletsUseCase().conflate(),
|
||||
flow2 = multiAccountStatusListSupplier(Unit).conflate(),
|
||||
) { wallets, accountList ->
|
||||
val cryptoCurrencyNetwork = cryptoCurrency.network
|
||||
|
||||
coroutineScope {
|
||||
accountList.mapNotNull { accountStatusList ->
|
||||
val wallet =
|
||||
wallets.filterNot { it.isLocked }.firstOrNull { it.walletId == accountStatusList.userWalletId }
|
||||
?: return@mapNotNull null
|
||||
|
||||
async {
|
||||
accountStatusList.accountStatuses.map { accountStatus ->
|
||||
async {
|
||||
accountStatus.flattenCurrencies()
|
||||
.filter { it.currency.network.rawId == cryptoCurrencyNetwork.rawId }
|
||||
.mapNotNull { cryptoCurrencyStatus ->
|
||||
val address = cryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value
|
||||
?: return@mapNotNull null
|
||||
|
||||
async {
|
||||
DestinationWalletUM(
|
||||
name = wallet.name,
|
||||
address = address,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
userWalletId = wallet.walletId,
|
||||
account = accountStatus.account as? Account.CryptoPortfolio,
|
||||
)
|
||||
}
|
||||
}.awaitAll()
|
||||
}
|
||||
}.awaitAll().flatten()
|
||||
}
|
||||
}.awaitAll().flatten()
|
||||
}
|
||||
}.flowOn(dispatchers.default)
|
||||
}
|
||||
|
||||
private fun validate(address: String, memo: String?, type: EnterAddressSource? = null) {
|
||||
modelScope.launch {
|
||||
_uiState.update(SendDestinationValidationStartedTransformer)
|
||||
|
|
@ -291,7 +332,12 @@ internal class SendDestinationModel @Inject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
_uiState.update(SendDestinationValidationResultTransformer(addressValidationResult, memoValidationResult))
|
||||
_uiState.update(
|
||||
SendDestinationValidationResultTransformer(
|
||||
addressValidationResult,
|
||||
memoValidationResult,
|
||||
),
|
||||
)
|
||||
autoNextFromRecipient(type, addressValidationResult.isRight(), memoValidationResult.isRight())
|
||||
}.saveIn(validationJobHolder)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
package com.tangem.features.send.v2.subcomponents.destination.model.converters
|
||||
|
||||
import com.tangem.common.ui.account.AccountTitleUM
|
||||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationRecipientListUM
|
||||
import com.tangem.features.send.v2.subcomponents.destination.model.transformers.WALLET_DEFAULT_COUNT
|
||||
import com.tangem.features.send.v2.subcomponents.destination.model.transformers.WALLET_KEY_TAG
|
||||
import com.tangem.features.send.v2.subcomponents.destination.model.transformers.emptyListState
|
||||
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationRecipientListUM
|
||||
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationWalletUM
|
||||
import com.tangem.utils.StringsSigns
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
|
@ -14,6 +17,7 @@ import kotlinx.collections.immutable.toPersistentList
|
|||
internal class SendRecipientWalletListConverter(
|
||||
private val senderAddress: String?,
|
||||
private val isSelfSendAvailable: Boolean,
|
||||
private val isAccountsMode: Boolean,
|
||||
) :
|
||||
Converter<List<DestinationWalletUM?>, PersistentList<DestinationRecipientListUM>> {
|
||||
override fun convert(value: List<DestinationWalletUM?>): PersistentList<DestinationRecipientListUM> {
|
||||
|
|
@ -46,13 +50,24 @@ internal class SendRecipientWalletListConverter(
|
|||
wallet.name
|
||||
}
|
||||
|
||||
val account = wallet.account
|
||||
DestinationRecipientListUM(
|
||||
id = "${WALLET_KEY_TAG}${walletsCounter++}",
|
||||
title = stringReference(wallet.address),
|
||||
subtitle = stringReference(name),
|
||||
accountTitleUM = if (account != null && isAccountsMode) {
|
||||
AccountTitleUM.Account(
|
||||
name = account.accountName.toUM().value,
|
||||
icon = account.icon.toUM(),
|
||||
prefixText = stringReference(StringsSigns.DOT),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
address = wallet.address,
|
||||
userWalletId = wallet.userWalletId,
|
||||
network = wallet.cryptoCurrency.network,
|
||||
accountId = account?.accountId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,12 +54,12 @@ internal class SendDestinationInitialStateTransformer(
|
|||
isValuePasted = false,
|
||||
)
|
||||
},
|
||||
accountTitleUM = null,
|
||||
wallets = loadingListState(WALLET_KEY_TAG, WALLET_DEFAULT_COUNT),
|
||||
recent = loadingListState(RECENT_KEY_TAG, RECENT_DEFAULT_COUNT),
|
||||
networkName = cryptoCurrency.network.name,
|
||||
isValidating = false,
|
||||
isRecentHidden = false,
|
||||
isAccountsMode = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,11 @@
|
|||
package com.tangem.features.send.v2.subcomponents.destination.model.transformers
|
||||
|
||||
import com.tangem.common.ui.account.AccountTitleUM
|
||||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.TxInfo
|
||||
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationUM
|
||||
import com.tangem.features.send.v2.subcomponents.destination.model.converters.SendRecipientHistoryListConverter
|
||||
import com.tangem.features.send.v2.subcomponents.destination.model.converters.SendRecipientWalletListConverter
|
||||
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationWalletUM
|
||||
import com.tangem.utils.StringsSigns
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
|
|
@ -21,25 +15,17 @@ internal class SendDestinationRecentListTransformer(
|
|||
private val isSelfSendAvailable: Boolean,
|
||||
private val destinationWalletList: List<DestinationWalletUM>,
|
||||
private val txHistoryList: List<TxInfo>,
|
||||
private val account: Account.CryptoPortfolio?,
|
||||
private val isAccountsMode: Boolean,
|
||||
) : Transformer<DestinationUM> {
|
||||
override fun transform(prevState: DestinationUM): DestinationUM {
|
||||
val state = prevState as? DestinationUM.Content ?: return prevState
|
||||
|
||||
return state.copy(
|
||||
accountTitleUM = if (account != null && isAccountsMode) {
|
||||
AccountTitleUM.Account(
|
||||
name = account.accountName.toUM().value,
|
||||
icon = account.icon.toUM(),
|
||||
prefixText = stringReference(StringsSigns.DOT),
|
||||
)
|
||||
} else {
|
||||
AccountTitleUM.Text(TextReference.EMPTY)
|
||||
},
|
||||
isAccountsMode = isAccountsMode,
|
||||
wallets = SendRecipientWalletListConverter(
|
||||
senderAddress = senderAddress,
|
||||
isSelfSendAvailable = isSelfSendAvailable,
|
||||
isAccountsMode = isAccountsMode,
|
||||
).convert(destinationWalletList),
|
||||
recent = SendRecipientHistoryListConverter(
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
|
|
|
|||
|
|
@ -144,7 +144,6 @@ private class DestinationBlockPreviewProvider : PreviewParameterProvider<Destina
|
|||
isValidating = false,
|
||||
isInitialized = true,
|
||||
isRecentHidden = false,
|
||||
accountTitleUM = null,
|
||||
)
|
||||
|
||||
override val values: Sequence<DestinationUM.Content>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import androidx.compose.ui.text.buildAnnotatedString
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.account.AccountTitleUM
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.containers.FooterContainer
|
||||
|
|
@ -69,18 +68,18 @@ internal fun SendDestinationContent(
|
|||
onMemoChange = clickIntents::onRecipientMemoValueChange,
|
||||
)
|
||||
listHeaderItem(
|
||||
titleRes = when (state.accountTitleUM) {
|
||||
is AccountTitleUM.Account -> R.string.common_accounts
|
||||
else -> R.string.send_recipient_wallets_title
|
||||
titleRes = if (state.isAccountsMode == true) {
|
||||
R.string.common_accounts
|
||||
} else {
|
||||
R.string.send_recipient_wallets_title
|
||||
},
|
||||
isLoading = state.accountTitleUM == null,
|
||||
isLoading = state.isAccountsMode == null,
|
||||
isVisible = wallets.isNotEmpty() && wallets.first().isVisible && !state.isRecentHidden,
|
||||
isFirst = true,
|
||||
)
|
||||
listItem(
|
||||
list = wallets,
|
||||
isLast = recipients.any { !it.isVisible },
|
||||
accountTitleUM = state.accountTitleUM,
|
||||
isBalanceHidden = false,
|
||||
isRecentHidden = state.isRecentHidden,
|
||||
onClick = { title ->
|
||||
|
|
@ -92,7 +91,7 @@ internal fun SendDestinationContent(
|
|||
)
|
||||
listHeaderItem(
|
||||
titleRes = R.string.send_recent_transactions,
|
||||
isLoading = state.accountTitleUM == null,
|
||||
isLoading = state.isAccountsMode == null,
|
||||
isVisible = recipients.isNotEmpty() && recipients.first().isVisible && !state.isRecentHidden,
|
||||
isFirst = wallets.any { !it.isVisible },
|
||||
)
|
||||
|
|
@ -245,7 +244,6 @@ private fun LazyListScope.listItem(
|
|||
isBalanceHidden: Boolean,
|
||||
isRecentHidden: Boolean,
|
||||
onClick: (String) -> Unit,
|
||||
accountTitleUM: AccountTitleUM? = null,
|
||||
) {
|
||||
items(
|
||||
count = list.size,
|
||||
|
|
@ -259,7 +257,7 @@ private fun LazyListScope.listItem(
|
|||
ListItemWithIcon(
|
||||
title = title,
|
||||
subtitle = item.subtitle.orMaskWithStars(isBalanceHidden).resolveReference(),
|
||||
accountTitleUM = accountTitleUM,
|
||||
accountTitleUM = item.accountTitleUM,
|
||||
info = item.timestamp?.resolveReference(),
|
||||
subtitleEndOffset = item.subtitleEndOffset,
|
||||
subtitleIconRes = item.subtitleIconRes,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.send.v2.subcomponents.destination.ui.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
|
|
@ -11,6 +12,7 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
* @property userWalletId wallet id
|
||||
* @property address blockchain address
|
||||
* @property cryptoCurrency selected crypto currency
|
||||
* @property account associated account (if in accounts mode)
|
||||
*/
|
||||
@Immutable
|
||||
data class DestinationWalletUM(
|
||||
|
|
@ -18,4 +20,5 @@ data class DestinationWalletUM(
|
|||
val userWalletId: UserWalletId,
|
||||
val address: String,
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
val account: Account.CryptoPortfolio? = null,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue