Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-10 12:58:21 +05:00
parent ccfc879099
commit 7d34989340
7 changed files with 102 additions and 48 deletions

View file

@ -51,6 +51,7 @@ import com.tangem.features.send.v2.send.confirm.ui.state.ConfirmUM
import com.tangem.features.send.v2.send.ui.state.ButtonsUM
import com.tangem.features.send.v2.send.ui.state.SendUM
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationUM
import com.tangem.features.send.v2.subcomponents.fee.SendFeeCheckReloadListener
import com.tangem.features.send.v2.subcomponents.fee.SendFeeCheckReloadTrigger
import com.tangem.features.send.v2.subcomponents.fee.model.checkAndCalculateSubtractedAmount
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM
@ -94,6 +95,7 @@ internal class SendConfirmModel @Inject constructor(
private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase,
private val getTxHistoryItemsUseCase: GetTxHistoryItemsUseCase,
private val sendFeeCheckReloadTrigger: SendFeeCheckReloadTrigger,
private val sendFeeCheckReloadListener: SendFeeCheckReloadListener,
private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter,
private val notificationsUpdateTrigger: NotificationsUpdateTrigger,
private val alertFactory: SendConfirmAlertFactory,
@ -445,7 +447,7 @@ internal class SendConfirmModel @Inject constructor(
}
private fun subscribeOnCheckFeeResultUpdates() {
sendFeeCheckReloadTrigger.checkReloadResultFlow.onEach { isFeeResultSuccess ->
sendFeeCheckReloadListener.checkReloadResultFlow.onEach { isFeeResultSuccess ->
if (isFeeResultSuccess) {
sendIdleTimer = SystemClock.elapsedRealtime()
_uiState.update(SendConfirmSendingStateTransformer(isSending = true))

View file

@ -26,6 +26,8 @@ import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponentParam
import com.tangem.features.send.v2.subcomponents.amount.SendAmountReduceListener
import com.tangem.features.send.v2.subcomponents.amount.analytics.SendAmountAnalyticEvents
import com.tangem.features.send.v2.subcomponents.amount.analytics.SendAmountAnalyticEvents.SelectedCurrencyType
import com.tangem.features.send.v2.subcomponents.fee.SendFeeData
import com.tangem.features.send.v2.subcomponents.fee.SendFeeReloadTrigger
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.orZero
import com.tangem.utils.isNullOrZero
@ -43,6 +45,7 @@ internal class SendAmountModel @Inject constructor(
private val router: Router,
private val getMinimumTransactionAmountSyncUseCase: GetMinimumTransactionAmountSyncUseCase,
private val sendAmountReduceListener: SendAmountReduceListener,
private val feeReloadTrigger: SendFeeReloadTrigger,
private val analyticsEventHandler: AnalyticsEventHandler,
) : Model(), AmountScreenClickIntents {
@ -174,6 +177,11 @@ internal class SendAmountModel @Inject constructor(
value = reduceTo,
),
)
feeReloadTrigger.triggerUpdate(
feeData = SendFeeData(
amount = (uiState.value as? AmountState.Data)?.amountTextField?.cryptoAmount?.value,
),
)
}
.launchIn(modelScope)
}
@ -188,6 +196,11 @@ internal class SendAmountModel @Inject constructor(
value = reduceByData,
),
)
feeReloadTrigger.triggerUpdate(
feeData = SendFeeData(
amount = (uiState.value as? AmountState.Data)?.amountTextField?.cryptoAmount?.value,
),
)
}
.launchIn(modelScope)
}

View file

@ -0,0 +1,8 @@
package com.tangem.features.send.v2.subcomponents.fee
import java.math.BigDecimal
data class SendFeeData(
val amount: BigDecimal?,
val destinationAddress: String? = null,
)

View file

@ -8,15 +8,24 @@ import javax.inject.Singleton
interface SendFeeReloadTrigger {
/** Flow triggers fee reload */
val reloadTriggerFlow: Flow<Unit>
/** Trigger fee update */
suspend fun triggerUpdate()
suspend fun triggerUpdate(feeData: SendFeeData)
}
interface SendFeeReloadListener {
/** Flow triggers fee reload */
val reloadTriggerFlow: Flow<SendFeeData>
}
interface SendFeeCheckReloadTrigger {
/** Trigger return callback with check result */
suspend fun callbackCheckResult(isSuccess: Boolean)
/** Trigger fee check reload */
suspend fun triggerCheckUpdate()
}
interface SendFeeCheckReloadListener {
/**
* Flow triggers fee check reload before transaction.
* Usually after significant time after fee was updated last time
@ -25,18 +34,16 @@ interface SendFeeCheckReloadTrigger {
/** Flow return result of fee check update */
val checkReloadResultFlow: Flow<Boolean>
/** Trigger return callback with check result */
suspend fun callbackCheckResult(isSuccess: Boolean)
/** Trigger fee check reload */
suspend fun triggerCheckUpdate()
}
@Singleton
internal class DefaultSendFeeReloadTrigger @Inject constructor() : SendFeeReloadTrigger, SendFeeCheckReloadTrigger {
internal class DefaultSendFeeReloadTrigger @Inject constructor() :
SendFeeReloadTrigger,
SendFeeReloadListener,
SendFeeCheckReloadTrigger,
SendFeeCheckReloadListener {
private val _reloadTriggerFlow = MutableSharedFlow<Unit>()
private val _reloadTriggerFlow = MutableSharedFlow<SendFeeData>()
override val reloadTriggerFlow = _reloadTriggerFlow.asSharedFlow()
private val _checkReloadTriggerFlow = MutableSharedFlow<Unit>()
@ -45,8 +52,8 @@ internal class DefaultSendFeeReloadTrigger @Inject constructor() : SendFeeReload
private val _checkReloadResultFlow = MutableSharedFlow<Boolean>()
override val checkReloadResultFlow = _checkReloadResultFlow.asSharedFlow()
override suspend fun triggerUpdate() {
_reloadTriggerFlow.emit(Unit)
override suspend fun triggerUpdate(feeData: SendFeeData) {
_reloadTriggerFlow.emit(feeData)
}
override suspend fun triggerCheckUpdate() {

View file

@ -1,27 +1,29 @@
package com.tangem.features.send.v2.subcomponents.fee.di
import com.tangem.features.send.v2.subcomponents.fee.DefaultSendFeeReloadTrigger
import com.tangem.features.send.v2.subcomponents.fee.SendFeeCheckReloadTrigger
import com.tangem.features.send.v2.subcomponents.fee.SendFeeReloadTrigger
import com.tangem.features.send.v2.subcomponents.fee.*
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
internal object SendFeeModule {
internal interface SendFeeModule {
@Provides
@Binds
@Singleton
fun provideSendFeeReloadTrigger(): SendFeeReloadTrigger {
return DefaultSendFeeReloadTrigger()
}
fun provideSendFeeReloadTrigger(impl: DefaultSendFeeReloadTrigger): SendFeeReloadTrigger
@Provides
@Binds
@Singleton
fun provideSendFeeCheckReloadTrigger(): SendFeeCheckReloadTrigger {
return DefaultSendFeeReloadTrigger()
}
fun provideSendFeeReloadListener(impl: DefaultSendFeeReloadTrigger): SendFeeReloadListener
@Binds
@Singleton
fun provideSendFeeCheckReloadTrigger(impl: DefaultSendFeeReloadTrigger): SendFeeCheckReloadTrigger
@Binds
@Singleton
fun provideSendFeeCheckReloadListener(impl: DefaultSendFeeReloadTrigger): SendFeeCheckReloadListener
}

View file

@ -14,9 +14,10 @@ import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase
import com.tangem.features.send.v2.common.NavigationUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.send.ui.state.ButtonsUM
import com.tangem.features.send.v2.subcomponents.fee.SendFeeCheckReloadListener
import com.tangem.features.send.v2.subcomponents.fee.SendFeeCheckReloadTrigger
import com.tangem.features.send.v2.subcomponents.fee.SendFeeComponentParams
import com.tangem.features.send.v2.subcomponents.fee.SendFeeReloadTrigger
import com.tangem.features.send.v2.subcomponents.fee.SendFeeReloadListener
import com.tangem.features.send.v2.subcomponents.fee.analytics.SendFeeAnalyticEvents
import com.tangem.features.send.v2.subcomponents.fee.analytics.SendFeeAnalyticEvents.GasPriceInserter
import com.tangem.features.send.v2.subcomponents.fee.model.transformers.*
@ -29,6 +30,7 @@ import com.tangem.utils.coroutines.saveIn
import com.tangem.utils.transformer.update
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import java.math.BigDecimal
import java.util.Locale
import javax.inject.Inject
@ -44,7 +46,8 @@ internal class SendFeeModel @Inject constructor(
private val urlOpener: UrlOpener,
private val analyticsEventHandler: AnalyticsEventHandler,
private val sendFeeAlertFactory: SendFeeAlertFactory,
private val feeReloadTrigger: SendFeeReloadTrigger,
private val feeReloadListener: SendFeeReloadListener,
private val feeCheckReloadListener: SendFeeCheckReloadListener,
private val feeCheckReloadTrigger: SendFeeCheckReloadTrigger,
) : Model(), SendFeeClickIntents {
@ -65,14 +68,19 @@ internal class SendFeeModel @Inject constructor(
subscribeOnFeeReloadTriggerUpdates()
subscribeOnFeeCheckReloadTriggerUpdates()
initialState()
loadFee()
feeReload()
}
fun updateState(state: FeeUM) {
_uiState.value = state
}
override fun feeReload() = loadFee()
override fun feeReload() {
loadFee(
amountValue = params.sendAmount,
destinationAddress = params.destinationAddress,
)
}
override fun onFeeSelectorClick(feeType: FeeType) {
_uiState.update(
@ -152,13 +160,18 @@ internal class SendFeeModel @Inject constructor(
}
private fun subscribeOnFeeReloadTriggerUpdates() {
feeReloadTrigger.reloadTriggerFlow
.onEach { feeReload() }
feeReloadListener.reloadTriggerFlow
.onEach { (amount, destination) ->
loadFee(
amountValue = amount ?: params.sendAmount,
destinationAddress = destination ?: params.destinationAddress,
)
}
.launchIn(modelScope)
}
private fun subscribeOnFeeCheckReloadTriggerUpdates() {
feeCheckReloadTrigger.checkReloadTriggerFlow
feeCheckReloadListener.checkReloadTriggerFlow
.onEach { checkLoadFee() }
.launchIn(modelScope)
}
@ -175,13 +188,18 @@ internal class SendFeeModel @Inject constructor(
params.callback.onFeeResult(uiState.value)
}
private fun loadFee() {
private fun loadFee(amountValue: BigDecimal, destinationAddress: String) {
modelScope.launch {
val isShowLoading = (uiState.value as? FeeUM.Content)?.feeSelectorUM !is FeeSelectorUM.Content
if (isShowLoading) {
_uiState.update(SendFeeLoadingTransformer)
}
callFeeUseCase().fold(
getFeeUseCase.invoke(
amount = amountValue,
destination = destinationAddress,
userWallet = params.userWallet,
cryptoCurrency = cryptoCurrencyStatus.currency,
).fold(
ifRight = {
_uiState.update(
SendFeeLoadedTransformer(
@ -206,7 +224,12 @@ internal class SendFeeModel @Inject constructor(
private fun checkLoadFee() {
modelScope.launch {
callFeeUseCase().fold(
getFeeUseCase.invoke(
amount = params.sendAmount,
destination = params.destinationAddress,
userWallet = params.userWallet,
cryptoCurrency = cryptoCurrencyStatus.currency,
).fold(
ifRight = {
sendFeeAlertFactory.getFeeUpdatedAlert(
newFee = it,
@ -236,20 +259,13 @@ internal class SendFeeModel @Inject constructor(
ifLeft = { feeError ->
feeCheckReloadTrigger.callbackCheckResult(false)
_uiState.update(SendFeeFailedTransformer(feeError))
sendFeeAlertFactory.getFeeUnreachableErrorState(::loadFee)
sendFeeAlertFactory.getFeeUnreachableErrorState(::feeReload)
updateFeeNotifications()
},
)
}.saveIn(feeJobHolder)
}
private suspend fun callFeeUseCase() = getFeeUseCase.invoke(
amount = params.sendAmount,
destination = params.destinationAddress,
userWallet = params.userWallet,
cryptoCurrency = cryptoCurrencyStatus.currency,
)
private fun isFeeApproximate(amountType: AmountType): Boolean {
val networkId = feeCryptoCurrencyStatus.currency.network.id
return isFeeApproximateUseCase(

View file

@ -32,6 +32,7 @@ import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
import com.tangem.domain.transaction.usecase.ValidateTransactionUseCase
import com.tangem.domain.utils.convertToSdkAmount
import com.tangem.features.send.v2.subcomponents.amount.SendAmountReduceTrigger
import com.tangem.features.send.v2.subcomponents.fee.SendFeeData
import com.tangem.features.send.v2.subcomponents.fee.SendFeeReloadTrigger
import com.tangem.features.send.v2.subcomponents.fee.model.checkAndCalculateSubtractedAmount
import com.tangem.features.send.v2.subcomponents.fee.model.checkFeeCoverage
@ -52,7 +53,7 @@ import kotlinx.coroutines.launch
import java.math.BigDecimal
import javax.inject.Inject
@Suppress("LongParameterList")
@Suppress("LongParameterList", "LargeClass")
@Stable
@ModelScoped
internal class NotificationsModel @Inject constructor(
@ -129,7 +130,12 @@ internal class NotificationsModel @Inject constructor(
feeError = feeError,
onReload = {
modelScope.launch {
sendFeeReloadTrigger.triggerUpdate()
sendFeeReloadTrigger.triggerUpdate(
feeData = SendFeeData(
amount = amountValue,
destinationAddress = destinationAddress,
),
)
}
},
onClick = ::showTokenDetails,