Updated on 2026-08-14
This commit is contained in:
commit
4f47d876ed
18 changed files with 221 additions and 185 deletions
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.features.send.v2.common
|
||||
|
||||
sealed class PredefinedValues {
|
||||
data object Empty : PredefinedValues()
|
||||
|
||||
sealed class Content : PredefinedValues() {
|
||||
abstract val amount: String
|
||||
abstract val address: String
|
||||
abstract val memo: String?
|
||||
|
||||
data class Deeplink(
|
||||
override val amount: String,
|
||||
override val address: String,
|
||||
override val memo: String?,
|
||||
val transactionId: String,
|
||||
) : Content()
|
||||
|
||||
data class QrCode(
|
||||
override val amount: String,
|
||||
override val address: String,
|
||||
override val memo: String?,
|
||||
) : Content()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package com.tangem.features.send.v2.common
|
||||
|
||||
import com.tangem.domain.tokens.FetchPendingTransactionsUseCase
|
||||
import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.txhistory.TxHistoryFeatureToggles
|
||||
import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter
|
||||
import com.tangem.utils.coroutines.DelayedWork
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class SendBalanceUpdater @AssistedInject constructor(
|
||||
private val fetchPendingTransactionsUseCase: FetchPendingTransactionsUseCase,
|
||||
private val updateDelayedNetworkStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||
private val getTxHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
|
||||
private val getTxHistoryItemsUseCase: GetTxHistoryItemsUseCase,
|
||||
private val txHistoryFeatureToggles: TxHistoryFeatureToggles,
|
||||
private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
@Assisted private val cryptoCurrency: CryptoCurrency,
|
||||
) {
|
||||
fun scheduleUpdates() {
|
||||
coroutineScope.launch {
|
||||
listOf(
|
||||
// we should update network to find pending tx after 1 sec
|
||||
async {
|
||||
fetchPendingTransactionsUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
networks = setOf(cryptoCurrency.network),
|
||||
)
|
||||
},
|
||||
// we should update tx history and network for new balances
|
||||
async {
|
||||
updateTxHistory()
|
||||
},
|
||||
async {
|
||||
updateNetworkStatuses()
|
||||
},
|
||||
).awaitAll()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateNetworkStatuses(delay: Long = BALANCE_UPDATE_DELAY) {
|
||||
updateDelayedNetworkStatusUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
network = cryptoCurrency.network,
|
||||
delayMillis = delay,
|
||||
refresh = true,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun updateTxHistory() {
|
||||
delay(BALANCE_UPDATE_DELAY)
|
||||
val txHistoryItemsCountEither = getTxHistoryItemsCountUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
currency = cryptoCurrency,
|
||||
)
|
||||
|
||||
txHistoryItemsCountEither.onRight {
|
||||
if (txHistoryFeatureToggles.isFeatureEnabled) {
|
||||
txHistoryContentUpdateEmitter.triggerUpdate()
|
||||
} else {
|
||||
getTxHistoryItemsUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
currency = cryptoCurrency,
|
||||
refresh = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val BALANCE_UPDATE_DELAY = 11_000L
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(cryptoCurrency: CryptoCurrency, userWallet: UserWallet): SendBalanceUpdater
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,6 @@ import com.tangem.core.ui.extensions.resolveReference
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.v2.send.SendRoute
|
||||
import com.tangem.features.send.v2.common.ui.state.NavigationUM
|
||||
import com.tangem.features.send.v2.send.ui.SendNavigationButtons
|
||||
|
||||
@Composable
|
||||
internal fun SendContent(navigationUM: NavigationUM, stackState: ChildStack<SendRoute, ComposableContentComponent>) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.features.send.v2.send.ui
|
||||
package com.tangem.features.send.v2.common.ui
|
||||
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.foundation.background
|
||||
|
|
@ -14,7 +14,7 @@ import dagger.multibindings.IntoMap
|
|||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface SendModelModule {
|
||||
internal interface CommonSendModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
|
|
@ -19,6 +19,7 @@ import com.tangem.core.decompose.model.getOrCreateModel
|
|||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.send.v2.api.SendComponent
|
||||
import com.tangem.features.send.v2.common.PredefinedValues
|
||||
import com.tangem.features.send.v2.common.ui.SendContent
|
||||
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
|
||||
import com.tangem.features.send.v2.send.analytics.SendAnalyticEvents
|
||||
|
|
@ -152,7 +153,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
|||
cryptoCurrencyStatus = model.cryptoCurrencyStatus,
|
||||
callback = model,
|
||||
isEditMode = route.isEditMode,
|
||||
predefinedAmountValue = model.predefinedAmountValue,
|
||||
predefinedValues = model.predefinedValues,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -187,14 +188,14 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
|||
val predefinedAddress = params.destinationAddress
|
||||
val predefinedValues =
|
||||
if (predefinedAmount != null && predefinedTxId != null && predefinedAddress != null) {
|
||||
SendConfirmComponent.Params.PredefinedValues.Content(
|
||||
PredefinedValues.Content.Deeplink(
|
||||
amount = predefinedAmount,
|
||||
address = predefinedAddress,
|
||||
tag = params.tag,
|
||||
memo = params.tag,
|
||||
transactionId = predefinedTxId,
|
||||
)
|
||||
} else {
|
||||
SendConfirmComponent.Params.PredefinedValues.Empty
|
||||
PredefinedValues.Empty
|
||||
}
|
||||
return SendConfirmComponent(
|
||||
appComponentContext = factoryContext,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.send.v2.common.PredefinedValues
|
||||
import com.tangem.features.send.v2.send.SendRoute
|
||||
import com.tangem.features.send.v2.send.confirm.model.SendConfirmModel
|
||||
import com.tangem.features.send.v2.send.confirm.ui.SendConfirmContent
|
||||
|
|
@ -19,10 +20,11 @@ import com.tangem.features.send.v2.send.ui.state.SendUM
|
|||
import com.tangem.features.send.v2.subcomponents.amount.SendAmountBlockComponent
|
||||
import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponentParams
|
||||
import com.tangem.features.send.v2.subcomponents.destination.SendDestinationBlockComponent
|
||||
import com.tangem.features.send.v2.subcomponents.destination.SendDestinationComponentParams
|
||||
import com.tangem.features.send.v2.subcomponents.destination.SendDestinationComponentParams.DestinationBlockParams
|
||||
import com.tangem.features.send.v2.subcomponents.fee.SendFeeBlockComponent
|
||||
import com.tangem.features.send.v2.subcomponents.fee.SendFeeComponentParams
|
||||
import com.tangem.features.send.v2.subcomponents.notifications.NotificationsComponent
|
||||
import com.tangem.features.send.v2.subcomponents.notifications.model.NotificationData
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
|
|
@ -38,15 +40,13 @@ internal class SendConfirmComponent(
|
|||
private val destinationBlockComponent =
|
||||
SendDestinationBlockComponent(
|
||||
appComponentContext = child("sendConfirmDestinationBlock"),
|
||||
params = SendDestinationComponentParams.DestinationBlockParams(
|
||||
params = DestinationBlockParams(
|
||||
state = model.uiState.value.destinationUM,
|
||||
analyticsCategoryName = params.analyticsCategoryName,
|
||||
userWalletId = params.userWallet.walletId,
|
||||
cryptoCurrency = params.cryptoCurrencyStatus.currency,
|
||||
blockClickEnableFlow = blockClickEnableFlow.asStateFlow(),
|
||||
isPredefinedValues = params.predefinedValues is Params.PredefinedValues.Content,
|
||||
predefinedAddressValue = (params.predefinedValues as? Params.PredefinedValues.Content)?.address,
|
||||
predefinedMemoValue = (params.predefinedValues as? Params.PredefinedValues.Content)?.tag,
|
||||
predefinedValues = params.predefinedValues,
|
||||
),
|
||||
onResult = model::onDestinationResult,
|
||||
onClick = model::showEditDestination,
|
||||
|
|
@ -61,8 +61,7 @@ internal class SendConfirmComponent(
|
|||
cryptoCurrencyStatus = params.cryptoCurrencyStatus,
|
||||
appCurrency = params.appCurrency,
|
||||
blockClickEnableFlow = blockClickEnableFlow.asStateFlow(),
|
||||
isPredefinedValues = params.predefinedValues is Params.PredefinedValues.Content,
|
||||
predefinedAmountValue = (params.predefinedValues as? Params.PredefinedValues.Content)?.amount,
|
||||
predefinedValues = params.predefinedValues,
|
||||
),
|
||||
onResult = model::onAmountResult,
|
||||
onClick = model::showEditAmount,
|
||||
|
|
@ -77,8 +76,8 @@ internal class SendConfirmComponent(
|
|||
cryptoCurrencyStatus = params.cryptoCurrencyStatus,
|
||||
feeCryptoCurrencyStatus = params.feeCryptoCurrencyStatus,
|
||||
appCurrency = params.appCurrency,
|
||||
sendAmount = model.enteredAmount.orZero(),
|
||||
destinationAddress = model.enteredDestination.orEmpty(),
|
||||
sendAmount = model.confirmData.enteredAmount.orZero(),
|
||||
destinationAddress = model.confirmData.enteredDestination.orEmpty(),
|
||||
blockClickEnableFlow = blockClickEnableFlow.asStateFlow(),
|
||||
),
|
||||
onResult = model::onFeeResult,
|
||||
|
|
@ -93,13 +92,15 @@ internal class SendConfirmComponent(
|
|||
cryptoCurrencyStatus = params.cryptoCurrencyStatus,
|
||||
feeCryptoCurrencyStatus = params.feeCryptoCurrencyStatus,
|
||||
appCurrency = params.appCurrency,
|
||||
destinationAddress = model.enteredDestination.orEmpty(),
|
||||
memo = model.enteredMemo,
|
||||
amountValue = model.enteredAmount.orZero(),
|
||||
reduceAmountBy = model.reduceAmountBy.orZero(),
|
||||
isIgnoreReduce = model.isIgnoreReduce,
|
||||
fee = model.fee,
|
||||
feeError = model.feeError,
|
||||
notificationData = NotificationData(
|
||||
destinationAddress = model.confirmData.enteredDestination.orEmpty(),
|
||||
memo = model.confirmData.enteredMemo,
|
||||
amountValue = model.confirmData.enteredAmount.orZero(),
|
||||
reduceAmountBy = model.confirmData.reduceAmountBy.orZero(),
|
||||
isIgnoreReduce = model.confirmData.isIgnoreReduce,
|
||||
fee = model.confirmData.fee,
|
||||
feeError = model.confirmData.feeError,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -143,17 +144,7 @@ internal class SendConfirmComponent(
|
|||
val currentRoute: Flow<SendRoute.Confirm>,
|
||||
val isBalanceHidingFlow: StateFlow<Boolean>,
|
||||
val predefinedValues: PredefinedValues,
|
||||
) {
|
||||
sealed class PredefinedValues {
|
||||
data object Empty : PredefinedValues()
|
||||
data class Content(
|
||||
val transactionId: String,
|
||||
val amount: String,
|
||||
val address: String,
|
||||
val tag: String?,
|
||||
) : PredefinedValues()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
interface ModelCallback {
|
||||
fun onResult(sendUM: SendUM)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.features.send.v2.send.confirm.model
|
||||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class ConfirmData(
|
||||
val enteredAmount: BigDecimal?,
|
||||
val reduceAmountBy: BigDecimal,
|
||||
val isIgnoreReduce: Boolean,
|
||||
val enteredDestination: String?,
|
||||
val enteredMemo: String?,
|
||||
val fee: Fee?,
|
||||
val feeError: GetFeeError?,
|
||||
)
|
||||
|
|
@ -5,7 +5,6 @@ import androidx.compose.runtime.Stable
|
|||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
|
|
@ -25,17 +24,13 @@ import com.tangem.domain.feedback.models.FeedbackEmailType
|
|||
import com.tangem.domain.settings.IsSendTapHelpEnabledUseCase
|
||||
import com.tangem.domain.settings.NeverShowTapHelpUseCase
|
||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.tokens.FetchPendingTransactionsUseCase
|
||||
import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase
|
||||
import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.usecase.CreateTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
||||
import com.tangem.domain.utils.convertToSdkAmount
|
||||
import com.tangem.features.send.v2.common.SendBalanceUpdater
|
||||
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
|
||||
import com.tangem.features.send.v2.common.ui.state.NavigationUM
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
|
|
@ -57,17 +52,13 @@ import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM
|
|||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeUM
|
||||
import com.tangem.features.send.v2.subcomponents.notifications.NotificationsUpdateTrigger
|
||||
import com.tangem.features.send.v2.subcomponents.notifications.model.NotificationData
|
||||
import com.tangem.features.txhistory.TxHistoryFeatureToggles
|
||||
import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.DelayedWork
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import com.tangem.utils.extensions.stripZeroPlainString
|
||||
import com.tangem.utils.transformer.update
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList", "LargeClass")
|
||||
|
|
@ -88,20 +79,14 @@ internal class SendConfirmModel @Inject constructor(
|
|||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
|
||||
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
|
||||
private val fetchPendingTransactionsUseCase: FetchPendingTransactionsUseCase,
|
||||
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||
private val getTxHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
|
||||
private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase,
|
||||
private val getTxHistoryItemsUseCase: GetTxHistoryItemsUseCase,
|
||||
private val sendFeeCheckReloadTrigger: SendFeeCheckReloadTrigger,
|
||||
private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter,
|
||||
private val notificationsUpdateTrigger: NotificationsUpdateTrigger,
|
||||
private val alertFactory: SendConfirmAlertFactory,
|
||||
private val sendAnalyticHelper: SendAnalyticHelper,
|
||||
private val txHistoryFeatureToggles: TxHistoryFeatureToggles,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
private val urlOpener: UrlOpener,
|
||||
private val shareManager: ShareManager,
|
||||
sendBalanceUpdaterFactory: SendBalanceUpdater.Factory,
|
||||
) : Model(), SendConfirmClickIntents {
|
||||
|
||||
private val params: SendConfirmComponent.Params = paramsContainer.require()
|
||||
|
|
@ -111,6 +96,8 @@ internal class SendConfirmModel @Inject constructor(
|
|||
private val cryptoCurrencyStatus = params.cryptoCurrencyStatus
|
||||
private val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
|
||||
private val sendBalanceUpdater = sendBalanceUpdaterFactory.create(cryptoCurrency, userWallet)
|
||||
|
||||
private val _uiState = MutableStateFlow(params.state)
|
||||
val uiState = _uiState.asStateFlow()
|
||||
|
||||
|
|
@ -123,20 +110,16 @@ internal class SendConfirmModel @Inject constructor(
|
|||
private val feeSelectorUM
|
||||
get() = feeUM?.feeSelectorUM as? FeeSelectorUM.Content
|
||||
|
||||
val enteredAmount: BigDecimal?
|
||||
get() = amountState?.amountTextField?.cryptoAmount?.value
|
||||
val reduceAmountBy: BigDecimal
|
||||
get() = amountState?.reduceAmountBy.orZero()
|
||||
val isIgnoreReduce: Boolean
|
||||
get() = amountState?.isIgnoreReduce == true
|
||||
val enteredDestination: String?
|
||||
get() = destinationUM?.addressTextField?.value
|
||||
val enteredMemo: String?
|
||||
get() = destinationUM?.memoTextField?.value
|
||||
val fee: Fee?
|
||||
get() = feeSelectorUM?.selectedFee
|
||||
val feeError: GetFeeError?
|
||||
get() = (feeUM?.feeSelectorUM as? FeeSelectorUM.Error)?.error
|
||||
val confirmData: ConfirmData
|
||||
get() = ConfirmData(
|
||||
enteredAmount = amountState?.amountTextField?.cryptoAmount?.value,
|
||||
enteredMemo = destinationUM?.memoTextField?.value,
|
||||
reduceAmountBy = amountState?.reduceAmountBy.orZero(),
|
||||
isIgnoreReduce = amountState?.isIgnoreReduce == true,
|
||||
enteredDestination = destinationUM?.addressTextField?.value,
|
||||
fee = feeSelectorUM?.selectedFee,
|
||||
feeError = (feeUM?.feeSelectorUM as? FeeSelectorUM.Error)?.error,
|
||||
)
|
||||
|
||||
private var sendIdleTimer: Long = 0L
|
||||
private var isAmountSubtractAvailable = false
|
||||
|
|
@ -234,15 +217,15 @@ internal class SendConfirmModel @Inject constructor(
|
|||
|
||||
override fun onFailedTxEmailClick(errorMessage: String) {
|
||||
val amountValue = amountState?.amountTextField?.cryptoAmount?.value
|
||||
val feeValue = fee?.amount?.value
|
||||
val feeValue = confirmData.fee?.amount?.value
|
||||
|
||||
val receivingAmount = if (amountValue != null && feeValue != null) {
|
||||
checkAndCalculateSubtractedAmount(
|
||||
isAmountSubtractAvailable = isAmountSubtractAvailable,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
amountValue = enteredAmount.orZero(),
|
||||
amountValue = confirmData.enteredAmount.orZero(),
|
||||
feeValue = feeValue,
|
||||
reduceAmountBy = reduceAmountBy,
|
||||
reduceAmountBy = confirmData.reduceAmountBy,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
@ -255,7 +238,7 @@ internal class SendConfirmModel @Inject constructor(
|
|||
errorMessage = errorMessage,
|
||||
blockchainId = cryptoCurrency.network.id.value,
|
||||
derivationPath = cryptoCurrency.network.derivationPath.value,
|
||||
destinationAddress = enteredDestination.orEmpty(),
|
||||
destinationAddress = confirmData.enteredDestination.orEmpty(),
|
||||
tokenSymbol = if (amount?.type is AmountType.Token) {
|
||||
amount.currencySymbol
|
||||
} else {
|
||||
|
|
@ -320,7 +303,7 @@ internal class SendConfirmModel @Inject constructor(
|
|||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
amountValue = amountValue,
|
||||
feeValue = feeValue,
|
||||
reduceAmountBy = reduceAmountBy.orZero(),
|
||||
reduceAmountBy = confirmData.reduceAmountBy.orZero(),
|
||||
)
|
||||
|
||||
modelScope.launch {
|
||||
|
|
@ -367,7 +350,7 @@ internal class SendConfirmModel @Inject constructor(
|
|||
ifRight = {
|
||||
updateTransactionStatus(txData)
|
||||
addTokenToWalletIfNeeded()
|
||||
scheduleUpdates()
|
||||
sendBalanceUpdater.scheduleUpdates()
|
||||
sendAnalyticHelper.sendSuccessAnalytics(cryptoCurrency, uiState.value)
|
||||
},
|
||||
)
|
||||
|
|
@ -378,7 +361,7 @@ internal class SendConfirmModel @Inject constructor(
|
|||
val wallets = destinationUM?.wallets ?: return
|
||||
|
||||
val receivingUserWallet = wallets
|
||||
.firstOrNull { it.address == enteredDestination }
|
||||
.firstOrNull { it.address == confirmData.enteredDestination }
|
||||
?: return
|
||||
|
||||
val userWalletId = receivingUserWallet.userWalletId ?: return
|
||||
|
|
@ -401,49 +384,6 @@ internal class SendConfirmModel @Inject constructor(
|
|||
_uiState.update(SendConfirmSentStateTransformer(txData, txUrl))
|
||||
}
|
||||
|
||||
private fun scheduleUpdates() {
|
||||
coroutineScope.launch {
|
||||
listOf(
|
||||
// we should update network to find pending tx after 1 sec
|
||||
async {
|
||||
fetchPendingTransactionsUseCase(userWallet.walletId, setOf(cryptoCurrency.network))
|
||||
},
|
||||
// we should update tx history and network for new balance
|
||||
async {
|
||||
updateTxHistory()
|
||||
},
|
||||
async {
|
||||
updateDelayedCurrencyStatusUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
network = cryptoCurrency.network,
|
||||
delayMillis = BALANCE_UPDATE_DELAY,
|
||||
refresh = true,
|
||||
)
|
||||
},
|
||||
).awaitAll()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateTxHistory() {
|
||||
delay(BALANCE_UPDATE_DELAY)
|
||||
val txHistoryItemsCountEither = getTxHistoryItemsCountUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
currency = cryptoCurrency,
|
||||
)
|
||||
|
||||
txHistoryItemsCountEither.onRight {
|
||||
if (txHistoryFeatureToggles.isFeatureEnabled) {
|
||||
txHistoryContentUpdateEmitter.triggerUpdate()
|
||||
} else {
|
||||
getTxHistoryItemsUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
currency = cryptoCurrency,
|
||||
refresh = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnCheckFeeResultUpdates() {
|
||||
sendFeeCheckReloadTrigger.checkReloadResultFlow.onEach { isFeeResultSuccess ->
|
||||
if (isFeeResultSuccess) {
|
||||
|
|
@ -460,13 +400,13 @@ internal class SendConfirmModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
notificationsUpdateTrigger.triggerUpdate(
|
||||
data = NotificationData(
|
||||
destinationAddress = enteredDestination.orEmpty(),
|
||||
memo = enteredMemo,
|
||||
amountValue = enteredAmount.orZero(),
|
||||
reduceAmountBy = reduceAmountBy.orZero(),
|
||||
isIgnoreReduce = isIgnoreReduce,
|
||||
fee = fee,
|
||||
feeError = feeError,
|
||||
destinationAddress = confirmData.enteredDestination.orEmpty(),
|
||||
memo = confirmData.enteredMemo,
|
||||
amountValue = confirmData.enteredAmount.orZero(),
|
||||
reduceAmountBy = confirmData.reduceAmountBy.orZero(),
|
||||
isIgnoreReduce = confirmData.isIgnoreReduce,
|
||||
fee = confirmData.fee,
|
||||
feeError = confirmData.feeError,
|
||||
),
|
||||
)
|
||||
_uiState.update {
|
||||
|
|
@ -552,6 +492,5 @@ internal class SendConfirmModel @Inject constructor(
|
|||
|
||||
private companion object {
|
||||
const val CHECK_FEE_UPDATE_DELAY = 10_000L
|
||||
const val BALANCE_UPDATE_DELAY = 11_000L
|
||||
}
|
||||
}
|
||||
|
|
@ -29,11 +29,12 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
|||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.features.send.v2.api.SendComponent
|
||||
import com.tangem.features.send.v2.common.PredefinedValues
|
||||
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
|
||||
import com.tangem.features.send.v2.common.ui.state.NavigationUM
|
||||
import com.tangem.features.send.v2.send.SendRoute
|
||||
import com.tangem.features.send.v2.send.confirm.model.SendConfirmAlertFactory
|
||||
import com.tangem.features.send.v2.send.confirm.SendConfirmComponent
|
||||
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
|
||||
import com.tangem.features.send.v2.send.confirm.model.SendConfirmAlertFactory
|
||||
import com.tangem.features.send.v2.send.ui.state.SendUM
|
||||
import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponent
|
||||
import com.tangem.features.send.v2.subcomponents.destination.SendDestinationComponent
|
||||
|
|
@ -90,7 +91,7 @@ internal class SendModel @Inject constructor(
|
|||
var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
|
||||
var feeCryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
|
||||
var appCurrency: AppCurrency = AppCurrency.Default
|
||||
var predefinedAmountValue: String? = null
|
||||
var predefinedValues: PredefinedValues = PredefinedValues.Empty
|
||||
|
||||
private var balanceHidingJobHolder = JobHolder()
|
||||
|
||||
|
|
@ -227,7 +228,11 @@ internal class SendModel @Inject constructor(
|
|||
|
||||
private fun onQrCodeScanned(address: String) {
|
||||
val parsedQrCode = parseQrCodeUseCase(address, cryptoCurrency).getOrNull()
|
||||
predefinedAmountValue = parsedQrCode?.amount?.parseBigDecimal(cryptoCurrency.decimals)
|
||||
predefinedValues = PredefinedValues.Content.QrCode(
|
||||
amount = parsedQrCode?.amount?.parseBigDecimal(cryptoCurrency.decimals).orEmpty(),
|
||||
address = parsedQrCode?.address.orEmpty(),
|
||||
memo = parsedQrCode?.memo,
|
||||
)
|
||||
}
|
||||
|
||||
private fun onFailedTxEmailClick(errorMessage: String? = null) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.common.ui.amountScreen.ui.AmountBlock
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.send.v2.common.PredefinedValues
|
||||
import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponentParams.AmountBlockParams
|
||||
import com.tangem.features.send.v2.subcomponents.amount.model.SendAmountModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
|
|
@ -39,7 +40,7 @@ internal class SendAmountBlockComponent(
|
|||
AmountBlock(
|
||||
amountState = state,
|
||||
isClickDisabled = !isClickEnabled,
|
||||
isEditingDisabled = params.isPredefinedValues,
|
||||
isEditingDisabled = params.predefinedValues is PredefinedValues.Content.Deeplink,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.common.ui.amountScreen.models.AmountState
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.send.v2.common.PredefinedValues
|
||||
import com.tangem.features.send.v2.send.SendRoute
|
||||
import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponent.ModelCallback
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -16,7 +17,7 @@ internal sealed class SendAmountComponentParams {
|
|||
abstract val userWallet: UserWallet
|
||||
abstract val appCurrency: AppCurrency
|
||||
abstract val cryptoCurrencyStatus: CryptoCurrencyStatus
|
||||
abstract val predefinedAmountValue: String?
|
||||
abstract val predefinedValues: PredefinedValues
|
||||
|
||||
data class AmountParams(
|
||||
override val state: AmountState,
|
||||
|
|
@ -24,7 +25,7 @@ internal sealed class SendAmountComponentParams {
|
|||
override val userWallet: UserWallet,
|
||||
override val appCurrency: AppCurrency,
|
||||
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
override val predefinedAmountValue: String?,
|
||||
override val predefinedValues: PredefinedValues,
|
||||
val isEditMode: Boolean,
|
||||
val callback: ModelCallback,
|
||||
val currentRoute: Flow<SendRoute.Amount>,
|
||||
|
|
@ -37,8 +38,7 @@ internal sealed class SendAmountComponentParams {
|
|||
override val userWallet: UserWallet,
|
||||
override val appCurrency: AppCurrency,
|
||||
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
override val predefinedAmountValue: String?,
|
||||
override val predefinedValues: PredefinedValues,
|
||||
val blockClickEnableFlow: StateFlow<Boolean>,
|
||||
val isPredefinedValues: Boolean,
|
||||
) : SendAmountComponentParams()
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.tokens.GetMinimumTransactionAmountSyncUseCase
|
||||
import com.tangem.features.send.v2.common.PredefinedValues
|
||||
import com.tangem.features.send.v2.common.ui.state.NavigationUM
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
import com.tangem.features.send.v2.send.SendRoute
|
||||
|
|
@ -98,7 +99,10 @@ internal class SendAmountModel @Inject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
params.predefinedAmountValue?.let(::onAmountValueChange)
|
||||
val predefinedValues = params.predefinedValues as? PredefinedValues.Content
|
||||
if (predefinedValues?.amount != null) {
|
||||
onAmountValueChange(predefinedValues.amount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.send.v2.common.PredefinedValues
|
||||
import com.tangem.features.send.v2.subcomponents.destination.model.SendDestinationModel
|
||||
import com.tangem.features.send.v2.subcomponents.destination.ui.DestinationBlock
|
||||
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationUM
|
||||
|
|
@ -38,7 +39,7 @@ internal class SendDestinationBlockComponent(
|
|||
DestinationBlock(
|
||||
destinationUM = state,
|
||||
isClickDisabled = !isClickEnabled,
|
||||
isEditingDisabled = params.isPredefinedValues,
|
||||
isEditingDisabled = params.predefinedValues is PredefinedValues.Content.Deeplink,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.send.v2.subcomponents.destination
|
|||
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.send.v2.common.PredefinedValues
|
||||
import com.tangem.features.send.v2.send.SendRoute
|
||||
import com.tangem.features.send.v2.subcomponents.destination.SendDestinationComponent.ModelCallback
|
||||
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationUM
|
||||
|
|
@ -32,8 +33,6 @@ internal sealed class SendDestinationComponentParams {
|
|||
override val userWalletId: UserWalletId,
|
||||
override val cryptoCurrency: CryptoCurrency,
|
||||
val blockClickEnableFlow: StateFlow<Boolean>,
|
||||
val predefinedAddressValue: String?,
|
||||
val predefinedMemoValue: String?,
|
||||
val isPredefinedValues: Boolean,
|
||||
val predefinedValues: PredefinedValues,
|
||||
) : SendDestinationComponentParams()
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ import com.tangem.domain.transaction.usecase.ValidateWalletMemoUseCase
|
|||
import com.tangem.domain.txhistory.usecase.GetFixedTxHistoryItemsUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.features.send.v2.common.PredefinedValues
|
||||
import com.tangem.features.send.v2.common.ui.state.NavigationUM
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
import com.tangem.features.send.v2.send.SendRoute
|
||||
|
|
@ -29,6 +30,7 @@ import com.tangem.features.send.v2.send.analytics.SendAnalyticEvents
|
|||
import com.tangem.features.send.v2.send.analytics.SendAnalyticEvents.SendScreenSource
|
||||
import com.tangem.features.send.v2.send.ui.state.ButtonsUM
|
||||
import com.tangem.features.send.v2.subcomponents.destination.SendDestinationComponentParams
|
||||
import com.tangem.features.send.v2.subcomponents.destination.SendDestinationComponentParams.DestinationBlockParams
|
||||
import com.tangem.features.send.v2.subcomponents.destination.analytics.EnterAddressSource
|
||||
import com.tangem.features.send.v2.subcomponents.destination.analytics.SendDestinationAnalyticEvents
|
||||
import com.tangem.features.send.v2.subcomponents.destination.model.transformers.*
|
||||
|
|
@ -96,19 +98,20 @@ internal class SendDestinationModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun initialState() {
|
||||
if ((uiState.value as? DestinationUM.Content)?.isInitialized == false) {
|
||||
if ((uiState.value as? DestinationUM.Content)?.isInitialized == false || uiState.value is DestinationUM.Empty) {
|
||||
_uiState.update(
|
||||
SendDestinationInitialStateTransformer(
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
isInitialized = true,
|
||||
),
|
||||
)
|
||||
val params = params as? SendDestinationComponentParams.DestinationBlockParams
|
||||
if (params?.predefinedAddressValue != null && params.predefinedMemoValue != null) {
|
||||
val params = params as? DestinationBlockParams
|
||||
val predefinedValues = params?.predefinedValues as? PredefinedValues.Content.Deeplink
|
||||
if (predefinedValues?.address != null) {
|
||||
_uiState.update(
|
||||
SendDestinationPredefinedStateTransformer(
|
||||
address = params.predefinedAddressValue,
|
||||
memo = params.predefinedMemoValue,
|
||||
address = predefinedValues.address,
|
||||
memo = predefinedValues.memo,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,19 +2,17 @@ package com.tangem.features.send.v2.subcomponents.notifications
|
|||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.send.v2.subcomponents.notifications
|
||||
import com.tangem.features.send.v2.subcomponents.notifications.model.NotificationData
|
||||
import com.tangem.features.send.v2.subcomponents.notifications.model.NotificationsModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class NotificationsComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
|
|
@ -45,12 +43,6 @@ internal class NotificationsComponent(
|
|||
val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
val appCurrency: AppCurrency,
|
||||
val destinationAddress: String,
|
||||
val memo: String?,
|
||||
val amountValue: BigDecimal,
|
||||
val reduceAmountBy: BigDecimal,
|
||||
val isIgnoreReduce: Boolean,
|
||||
val fee: Fee?,
|
||||
val feeError: GetFeeError?,
|
||||
val notificationData: NotificationData,
|
||||
)
|
||||
}
|
||||
|
|
@ -78,13 +78,7 @@ internal class NotificationsModel @Inject constructor(
|
|||
private val currency = cryptoCurrencyStatus.currency
|
||||
private val appCurrency = params.appCurrency
|
||||
|
||||
private var destinationAddress = params.destinationAddress
|
||||
private var memo = params.memo
|
||||
private var amountValue = params.amountValue
|
||||
private var reduceAmountBy = params.reduceAmountBy
|
||||
private var isIgnoreReduce = params.isIgnoreReduce
|
||||
private var fee = params.fee
|
||||
private var feeError = params.feeError
|
||||
private var notificationData = params.notificationData
|
||||
|
||||
private val _uiState = MutableStateFlow<ImmutableList<NotificationUM>>(persistentListOf())
|
||||
val uiState = _uiState.asStateFlow()
|
||||
|
|
@ -110,14 +104,7 @@ internal class NotificationsModel @Inject constructor(
|
|||
}
|
||||
|
||||
private suspend fun updateState(data: NotificationData) {
|
||||
destinationAddress = data.destinationAddress
|
||||
memo = data.memo
|
||||
amountValue = data.amountValue
|
||||
reduceAmountBy = data.reduceAmountBy
|
||||
isIgnoreReduce = data.isIgnoreReduce
|
||||
fee = data.fee
|
||||
feeError = data.feeError
|
||||
|
||||
notificationData = data
|
||||
buildNotifications()
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +113,7 @@ internal class NotificationsModel @Inject constructor(
|
|||
addFeeUnreachableNotification(
|
||||
tokenStatus = cryptoCurrencyStatus,
|
||||
coinStatus = feeCryptoCurrencyStatus,
|
||||
feeError = feeError,
|
||||
feeError = notificationData.feeError,
|
||||
onReload = {
|
||||
modelScope.launch {
|
||||
sendFeeReloadTrigger.triggerUpdate()
|
||||
|
|
@ -134,13 +121,7 @@ internal class NotificationsModel @Inject constructor(
|
|||
},
|
||||
onClick = ::showTokenDetails,
|
||||
)
|
||||
addDomainNotifications(
|
||||
destinationAddress = destinationAddress,
|
||||
memo = memo,
|
||||
amountValue = amountValue,
|
||||
reduceAmountBy = reduceAmountBy,
|
||||
fee = fee,
|
||||
)
|
||||
addDomainNotifications()
|
||||
}
|
||||
|
||||
notificationsUpdateTrigger.callbackHasError(notifications.any { it is NotificationUM.Error })
|
||||
|
|
@ -161,13 +142,7 @@ internal class NotificationsModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun MutableList<NotificationUM>.addDomainNotifications(
|
||||
destinationAddress: String,
|
||||
memo: String?,
|
||||
amountValue: BigDecimal,
|
||||
reduceAmountBy: BigDecimal,
|
||||
fee: Fee?,
|
||||
) {
|
||||
private suspend fun MutableList<NotificationUM>.addDomainNotifications() = with(notificationData) {
|
||||
val balance = cryptoCurrencyStatus.value.amount ?: return
|
||||
val feeValue = fee?.amount?.value ?: return
|
||||
val isFeeCoverage = checkFeeCoverage(
|
||||
|
|
@ -305,7 +280,7 @@ internal class NotificationsModel @Inject constructor(
|
|||
) {
|
||||
val validationError = validateTransactionUseCase(
|
||||
userWalletId = userWalletId,
|
||||
amount = amountValue.convertToSdkAmount(cryptoCurrencyStatus.currency),
|
||||
amount = enteredAmount.convertToSdkAmount(currency),
|
||||
fee = fee,
|
||||
memo = memo,
|
||||
destination = destinationAddress,
|
||||
|
|
@ -353,7 +328,7 @@ internal class NotificationsModel @Inject constructor(
|
|||
addHighFeeWarningNotification(
|
||||
enteredAmountValue = enteredAmount,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
ignoreAmountReduce = isIgnoreReduce,
|
||||
ignoreAmountReduce = notificationData.isIgnoreReduce,
|
||||
onReduceClick = { reduceBy, reduceByDiff, _ ->
|
||||
modelScope.launch {
|
||||
sendAmountReduceTrigger.triggerReduceBy(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue