Updated on 2026-08-14
This commit is contained in:
parent
9e98ebe77b
commit
ed9e188459
22 changed files with 451 additions and 53 deletions
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.common.ui.amountScreen.converters
|
||||
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
object AmountIgnoreReduceTransformer : Transformer<AmountState> {
|
||||
override fun transform(prevState: AmountState): AmountState {
|
||||
val state = prevState as? AmountState.Data ?: return prevState
|
||||
return state.copy(isIgnoreReduce = true)
|
||||
}
|
||||
}
|
||||
|
|
@ -62,6 +62,7 @@ class AmountReduceByTransformer(
|
|||
val isCheckFailed = isExceedBalance || isLessThanMinimumIfProvided
|
||||
return prevState.copy(
|
||||
isPrimaryButtonEnabled = !isZero && !isCheckFailed,
|
||||
reduceAmountBy = value.reduceAmountBy,
|
||||
amountTextField = amountTextField.copy(
|
||||
value = cryptoValue,
|
||||
fiatValue = fiatValue,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ class AmountFieldChangeTransformer(
|
|||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val maxEnterAmount: EnterAmountBoundary,
|
||||
private val minimumTransactionAmount: EnterAmountBoundary?,
|
||||
private val reduceAmountBy: BigDecimal = BigDecimal.ZERO,
|
||||
private val value: String,
|
||||
) : Transformer<AmountState> {
|
||||
|
||||
|
|
@ -68,7 +67,7 @@ class AmountFieldChangeTransformer(
|
|||
val isCheckFailed = isExceedBalance || isLessThanMinimumIfProvided
|
||||
return prevState.copy(
|
||||
isPrimaryButtonEnabled = !isZero && !isCheckFailed,
|
||||
reduceAmountBy = reduceAmountBy,
|
||||
reduceAmountBy = BigDecimal.ZERO,
|
||||
amountTextField = amountTextField.copy(
|
||||
value = cryptoValue,
|
||||
fiatValue = fiatValue,
|
||||
|
|
@ -76,10 +75,9 @@ class AmountFieldChangeTransformer(
|
|||
error = when {
|
||||
isExceedBalance -> resourceReference(R.string.send_validation_amount_exceeds_balance)
|
||||
isLessThanMinimumIfProvided -> {
|
||||
val minimumAmount =
|
||||
minimumTransactionAmount.amount.format {
|
||||
crypto(cryptoCurrencyStatus.currency)
|
||||
}
|
||||
val minimumAmount = minimumTransactionAmount?.amount.format {
|
||||
crypto(cryptoCurrencyStatus.currency)
|
||||
}
|
||||
|
||||
resourceReference(
|
||||
R.string.transfer_notification_invalid_minimum_transaction_amount_text,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ class AmountFieldSetMaxAmountTransformer(
|
|||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val maxAmount: EnterAmountBoundary,
|
||||
private val minAmount: EnterAmountBoundary?,
|
||||
private val reduceAmountBy: BigDecimal = BigDecimal.ZERO,
|
||||
) : Transformer<AmountState> {
|
||||
|
||||
override fun transform(prevState: AmountState): AmountState {
|
||||
|
|
@ -47,7 +46,7 @@ class AmountFieldSetMaxAmountTransformer(
|
|||
val isLessThanMinimumIfProvided = minAmount?.amount?.let { decimalCryptoValue < it } == true
|
||||
return prevState.copy(
|
||||
isPrimaryButtonEnabled = !isLessThanMinimumIfProvided,
|
||||
reduceAmountBy = reduceAmountBy,
|
||||
reduceAmountBy = BigDecimal.ZERO,
|
||||
amountTextField = amountTextField.copy(
|
||||
isValuePasted = true,
|
||||
value = cryptoValue,
|
||||
|
|
@ -55,7 +54,7 @@ class AmountFieldSetMaxAmountTransformer(
|
|||
isError = isLessThanMinimumIfProvided,
|
||||
error = when {
|
||||
isLessThanMinimumIfProvided -> {
|
||||
val minimumAmount = minAmount.amount.format { crypto(cryptoCurrencyStatus.currency) }
|
||||
val minimumAmount = minAmount?.amount.format { crypto(cryptoCurrencyStatus.currency) }
|
||||
resourceReference(
|
||||
R.string.transfer_notification_invalid_minimum_transaction_amount_text,
|
||||
wrappedList(minimumAmount, minimumAmount),
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ dependencies {
|
|||
implementation(projects.core.analytics)
|
||||
implementation(projects.core.configToggles)
|
||||
implementation(projects.core.navigation)
|
||||
api(projects.core.pagination)
|
||||
|
||||
/** Tangem SDK */
|
||||
implementation(tangemDeps.blockchain)
|
||||
|
|
@ -51,6 +52,8 @@ dependencies {
|
|||
implementation(projects.domain.settings)
|
||||
implementation(projects.domain.feedback)
|
||||
implementation(projects.domain.txhistory)
|
||||
implementation(projects.domain.balanceHiding.models)
|
||||
implementation(projects.domain.balanceHiding)
|
||||
|
||||
/** Compose libraries */
|
||||
implementation(deps.compose.foundation)
|
||||
|
|
@ -64,6 +67,7 @@ dependencies {
|
|||
/** Other dependencies */
|
||||
implementation(deps.kotlin.immutable.collections)
|
||||
implementation(deps.timber)
|
||||
implementation(deps.androidx.paging.runtime)
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.android)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package com.tangem.features.send.v2.common
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.send.v2.send.ui.state.ButtonsUM
|
||||
|
||||
@Immutable
|
||||
internal sealed class NavigationUM {
|
||||
data class Content(
|
||||
val title: TextReference,
|
||||
|
|
|
|||
|
|
@ -2,11 +2,17 @@ package com.tangem.features.send.v2.send
|
|||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.childStack
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
import com.arkivanov.decompose.value.ObserveLifecycleMode
|
||||
import com.arkivanov.decompose.value.subscribe
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
|
|
@ -14,10 +20,14 @@ 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.send.analytics.SendAnalyticEvents
|
||||
import com.tangem.features.send.v2.send.confirm.SendConfirmComponent
|
||||
import com.tangem.features.send.v2.send.confirm.ui.state.ConfirmUM
|
||||
import com.tangem.features.send.v2.send.model.SendModel
|
||||
import com.tangem.features.send.v2.send.ui.SendContent
|
||||
import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponent
|
||||
import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponentParams
|
||||
import com.tangem.features.send.v2.subcomponents.destination.SendDestinationComponent
|
||||
import com.tangem.features.send.v2.subcomponents.destination.SendDestinationComponentParams
|
||||
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationUM
|
||||
import com.tangem.features.send.v2.subcomponents.fee.SendFeeComponent
|
||||
import com.tangem.features.send.v2.subcomponents.fee.SendFeeComponentParams
|
||||
|
|
@ -26,10 +36,12 @@ import dagger.assisted.AssistedFactory
|
|||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
internal class DefaultSendComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: SendComponent.Params,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : SendComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val stackNavigation = StackNavigation<SendRoute>()
|
||||
|
|
@ -65,9 +77,44 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
|||
},
|
||||
)
|
||||
|
||||
init {
|
||||
childStack.subscribe(
|
||||
lifecycle = lifecycle,
|
||||
mode = ObserveLifecycleMode.CREATE_DESTROY,
|
||||
) { stack ->
|
||||
componentScope.launch {
|
||||
when (val activeComponent = stack.active.instance) {
|
||||
is SendConfirmComponent -> if (currentRoute.value.isEditMode) {
|
||||
analyticsEventHandler.send(SendAnalyticEvents.ConfirmationScreenOpened)
|
||||
activeComponent.updateState(model.uiState.value)
|
||||
}
|
||||
is SendAmountComponent -> {
|
||||
analyticsEventHandler.send(SendAnalyticEvents.AmountScreenOpened)
|
||||
activeComponent.updateState(model.uiState.value.amountUM)
|
||||
}
|
||||
is SendDestinationComponent -> {
|
||||
analyticsEventHandler.send(SendAnalyticEvents.AddressScreenOpened)
|
||||
activeComponent.updateState(model.uiState.value.destinationUM)
|
||||
}
|
||||
is SendFeeComponent -> {
|
||||
analyticsEventHandler.send(SendAnalyticEvents.FeeScreenOpened)
|
||||
}
|
||||
}
|
||||
currentRoute.emit(stack.active.configuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val stackState by childStack.subscribeAsState()
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
BackHandler(onBack = ::onChildBack)
|
||||
SendContent(
|
||||
state = state,
|
||||
stackState = stackState,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createChild(route: SendRoute, factoryContext: AppComponentContext) = when (route) {
|
||||
|
|
@ -75,7 +122,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
|||
is SendRoute.Destination -> getDestinationComponent(factoryContext, route)
|
||||
is SendRoute.Amount -> getAmountComponent(factoryContext, route)
|
||||
is SendRoute.Fee -> getFeeComponent(factoryContext)
|
||||
SendRoute.Confirm -> getConfirmComponent()
|
||||
SendRoute.Confirm -> getConfirmComponent(factoryContext)
|
||||
}
|
||||
|
||||
private fun getDestinationComponent(factoryContext: AppComponentContext, route: SendRoute) =
|
||||
|
|
@ -84,6 +131,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
|||
params = SendDestinationComponentParams.DestinationParams(
|
||||
state = model.uiState.value.destinationUM,
|
||||
currentRoute = currentRoute.filterIsInstance<SendRoute.Destination>(),
|
||||
isBalanceHidingFlow = model.isBalanceHiddenFlow,
|
||||
analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY,
|
||||
userWallet = model.userWallet,
|
||||
cryptoCurrency = params.currency,
|
||||
|
|
@ -97,6 +145,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
|||
params = SendAmountComponentParams.AmountParams(
|
||||
state = model.uiState.value.amountUM,
|
||||
currentRoute = currentRoute.filterIsInstance<SendRoute.Amount>(),
|
||||
isBalanceHidingFlow = model.isBalanceHiddenFlow,
|
||||
analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY,
|
||||
userWallet = model.userWallet,
|
||||
appCurrency = model.appCurrency,
|
||||
|
|
@ -132,12 +181,46 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getConfirmComponent() = getStubComponent() // todo
|
||||
private fun getConfirmComponent(factoryContext: AppComponentContext): SendConfirmComponent {
|
||||
val predefinedAmount = params.amount
|
||||
val predefinedTxId = params.transactionId
|
||||
val predefinedAddress = params.destinationAddress
|
||||
val predefinedValues =
|
||||
if (predefinedAmount != null && predefinedTxId != null && predefinedAddress != null) {
|
||||
SendConfirmComponent.Params.PredefinedValues.Content(
|
||||
amount = predefinedAmount,
|
||||
address = predefinedAddress,
|
||||
tag = params.tag,
|
||||
transactionId = predefinedTxId,
|
||||
)
|
||||
} else {
|
||||
SendConfirmComponent.Params.PredefinedValues.Empty
|
||||
}
|
||||
return SendConfirmComponent(
|
||||
appComponentContext = factoryContext,
|
||||
params = SendConfirmComponent.Params(
|
||||
state = model.uiState.value,
|
||||
userWallet = model.userWallet,
|
||||
currentRoute = currentRoute.filterIsInstance<SendRoute.Confirm>(),
|
||||
isBalanceHidingFlow = model.isBalanceHiddenFlow,
|
||||
analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY,
|
||||
cryptoCurrencyStatus = model.cryptoCurrencyStatus,
|
||||
feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus,
|
||||
appCurrency = model.appCurrency,
|
||||
callback = model,
|
||||
predefinedValues = predefinedValues,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getStubComponent() = ComposableContentComponent { }
|
||||
|
||||
private fun onChildBack() {
|
||||
if (childStack.value.active.configuration == SendRoute.Empty || childStack.value.backStack.isEmpty()) {
|
||||
val isEmptyRoute = childStack.value.active.configuration == SendRoute.Empty
|
||||
val isEmptyStack = childStack.value.backStack.isEmpty()
|
||||
val isSuccess = model.uiState.value.confirmUM is ConfirmUM.Success
|
||||
|
||||
if (isEmptyRoute || isEmptyStack || isSuccess) {
|
||||
router.pop()
|
||||
} else {
|
||||
stackNavigation.pop()
|
||||
|
|
|
|||
|
|
@ -489,7 +489,7 @@ internal class SendConfirmModel @Inject constructor(
|
|||
flow = uiState,
|
||||
flow2 = params.currentRoute,
|
||||
transform = { state, route -> state to route },
|
||||
).onEach { (state, _) ->
|
||||
).distinctUntilChanged().onEach { (state, _) ->
|
||||
val amountUM = state.amountUM as? AmountState.Data
|
||||
val confirmUM = state.confirmUM
|
||||
params.callback.onResult(
|
||||
|
|
|
|||
|
|
@ -1,49 +1,108 @@
|
|||
package com.tangem.features.send.v2.send.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.BlockchainErrorInfo
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.qrscanning.models.SourceType
|
||||
import com.tangem.domain.qrscanning.usecases.ListenToQrScanningUseCase
|
||||
import com.tangem.domain.qrscanning.usecases.ParseQrCodeUseCase
|
||||
import com.tangem.domain.tokens.GetCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
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.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.send.confirm.ui.state.ConfirmUM
|
||||
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
|
||||
import com.tangem.features.send.v2.subcomponents.destination.model.transformers.SendDestinationInitialStateTransformer
|
||||
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationUM
|
||||
import com.tangem.features.send.v2.subcomponents.fee.SendFeeComponent
|
||||
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
internal interface SendComponentCallback :
|
||||
SendAmountComponent.ModelCallback,
|
||||
SendFeeComponent.ModelCallback,
|
||||
SendDestinationComponent.ModelCallback,
|
||||
SendConfirmComponent.ModelCallback
|
||||
|
||||
@Stable
|
||||
@ModelScoped
|
||||
@Suppress("LongParameterList")
|
||||
internal class SendModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model(),
|
||||
SendDestinationComponent.ModelCallback,
|
||||
SendAmountComponent.ModelCallback,
|
||||
SendFeeComponent.ModelCallback,
|
||||
SendConfirmComponent.ModelCallback {
|
||||
private val router: Router,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val getCurrencyStatusUpdatesUseCase: GetCurrencyStatusUpdatesUseCase,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val listenToQrScanningUseCase: ListenToQrScanningUseCase,
|
||||
private val parseQrCodeUseCase: ParseQrCodeUseCase,
|
||||
private val sendConfirmAlertFactory: SendConfirmAlertFactory,
|
||||
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase,
|
||||
private val getCardInfoUseCase: GetCardInfoUseCase,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
) : Model(), SendComponentCallback {
|
||||
|
||||
private val params: SendComponent.Params = paramsContainer.require()
|
||||
private val userWalletId = params.userWalletId
|
||||
private val cryptoCurrency = params.currency
|
||||
|
||||
private val _uiState = MutableStateFlow(initialState())
|
||||
val uiState = _uiState.asStateFlow()
|
||||
|
||||
private val _isBalanceHiddenFlow = MutableStateFlow(false)
|
||||
val isBalanceHiddenFlow = _isBalanceHiddenFlow.asStateFlow()
|
||||
|
||||
var userWallet: UserWallet by Delegates.notNull()
|
||||
var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
|
||||
var feeCryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
|
||||
var appCurrency: AppCurrency = AppCurrency.Default
|
||||
var predefinedAmountValue: String? = null
|
||||
|
||||
override fun onResult(sendUM: SendUM) {
|
||||
_uiState.value = sendUM
|
||||
private var balanceHidingJobHolder = JobHolder()
|
||||
|
||||
init {
|
||||
subscribeOnBalanceHidden()
|
||||
subscribeOnQRScannerResult()
|
||||
subscribeOnCurrencyStatusUpdates()
|
||||
initAppCurrency()
|
||||
}
|
||||
|
||||
override fun onNavigationResult(navigationUM: NavigationUM) {
|
||||
_uiState.update { it.copy(navigationUM = navigationUM) }
|
||||
}
|
||||
|
||||
override fun onDestinationResult(destinationUM: DestinationUM) {
|
||||
|
|
@ -58,10 +117,146 @@ internal class SendModel @Inject constructor(
|
|||
_uiState.update { it.copy(feeUM = feeUM) }
|
||||
}
|
||||
|
||||
override fun onResult(sendUM: SendUM) {
|
||||
_uiState.update { sendUM }
|
||||
}
|
||||
|
||||
private fun initAppCurrency() {
|
||||
modelScope.launch {
|
||||
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnCurrencyStatusUpdates() {
|
||||
modelScope.launch {
|
||||
getUserWalletUseCase(params.userWalletId).fold(
|
||||
ifRight = { wallet ->
|
||||
userWallet = wallet
|
||||
|
||||
val isSingleWalletWithToken = wallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()
|
||||
val isMultiCurrency = wallet.isMultiCurrency
|
||||
getCurrenciesStatusUpdates(
|
||||
isSingleWalletWithToken = isSingleWalletWithToken,
|
||||
isMultiCurrency = isMultiCurrency,
|
||||
)
|
||||
},
|
||||
ifLeft = {
|
||||
sendConfirmAlertFactory.getGenericErrorState(::onFailedTxEmailClick)
|
||||
return@launch
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnBalanceHidden() {
|
||||
getBalanceHidingSettingsUseCase()
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.onEach {
|
||||
_isBalanceHiddenFlow.value = it.isBalanceHidden
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
.saveIn(balanceHidingJobHolder)
|
||||
}
|
||||
|
||||
private fun getCurrenciesStatusUpdates(isSingleWalletWithToken: Boolean, isMultiCurrency: Boolean) {
|
||||
getCurrencyStatus(
|
||||
isSingleWalletWithToken = isSingleWalletWithToken,
|
||||
isMultiCurrency = isMultiCurrency,
|
||||
).onEach { maybeCryptoCurrency ->
|
||||
maybeCryptoCurrency.fold(
|
||||
ifRight = { cryptoCurrencyStatus ->
|
||||
onDataLoaded(
|
||||
currencyStatus = cryptoCurrencyStatus,
|
||||
feeCurrencyStatus = getFeeCurrencyStatus(cryptoCurrencyStatus, isMultiCurrency),
|
||||
)
|
||||
},
|
||||
ifLeft = {
|
||||
sendConfirmAlertFactory.getGenericErrorState {
|
||||
onFailedTxEmailClick(it.toString())
|
||||
}
|
||||
},
|
||||
)
|
||||
}.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun getCurrencyStatus(
|
||||
isSingleWalletWithToken: Boolean,
|
||||
isMultiCurrency: Boolean,
|
||||
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
|
||||
return if (isMultiCurrency) {
|
||||
getCurrencyStatusUpdatesUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
isSingleWalletWithTokens = isSingleWalletWithToken,
|
||||
)
|
||||
} else {
|
||||
getPrimaryCurrencyStatusUpdatesUseCase(userWalletId = userWalletId)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getFeeCurrencyStatus(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
isMultiCurrency: Boolean,
|
||||
): CryptoCurrencyStatus {
|
||||
return if (isMultiCurrency) {
|
||||
getFeePaidCryptoCurrencyStatusSyncUseCase(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
).getOrNull() ?: cryptoCurrencyStatus
|
||||
} else {
|
||||
cryptoCurrencyStatus
|
||||
}
|
||||
}
|
||||
|
||||
private fun onDataLoaded(currencyStatus: CryptoCurrencyStatus, feeCurrencyStatus: CryptoCurrencyStatus) {
|
||||
cryptoCurrencyStatus = currencyStatus
|
||||
feeCryptoCurrencyStatus = feeCurrencyStatus
|
||||
|
||||
if (params.amount != null) {
|
||||
router.replaceAll(SendRoute.Confirm)
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnQRScannerResult() {
|
||||
listenToQrScanningUseCase(SourceType.SEND)
|
||||
.getOrElse { emptyFlow() }
|
||||
.onEach(::onQrCodeScanned)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun onQrCodeScanned(address: String) {
|
||||
val parsedQrCode = parseQrCodeUseCase(address, cryptoCurrency).getOrNull()
|
||||
predefinedAmountValue = parsedQrCode?.amount?.parseBigDecimal(cryptoCurrency.decimals)
|
||||
}
|
||||
|
||||
private fun onFailedTxEmailClick(errorMessage: String? = null) {
|
||||
saveBlockchainErrorUseCase(
|
||||
error = BlockchainErrorInfo(
|
||||
errorMessage = errorMessage.orEmpty(),
|
||||
blockchainId = cryptoCurrency.network.id.value,
|
||||
derivationPath = cryptoCurrency.network.derivationPath.value,
|
||||
destinationAddress = "",
|
||||
tokenSymbol = "",
|
||||
amount = "",
|
||||
fee = "",
|
||||
),
|
||||
)
|
||||
|
||||
val cardInfo = getCardInfoUseCase(userWallet.scanResponse).getOrNull() ?: return
|
||||
|
||||
modelScope.launch {
|
||||
sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(cardInfo = cardInfo))
|
||||
}
|
||||
}
|
||||
|
||||
private fun initialState(): SendUM = SendUM(
|
||||
amountUM = AmountState.Empty(),
|
||||
destinationUM = DestinationUM.Empty(),
|
||||
destinationUM = SendDestinationInitialStateTransformer(
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
).transform(DestinationUM.Empty()),
|
||||
feeUM = FeeUM.Empty(),
|
||||
confirmUM = ConfirmUM.Empty,
|
||||
navigationUM = NavigationUM.Empty,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.tangem.features.send.v2.send.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.extensions.compose.stack.Children
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.slide
|
||||
import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
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.NavigationUM
|
||||
import com.tangem.features.send.v2.send.ui.state.SendUM
|
||||
|
||||
@Composable
|
||||
internal fun SendContent(state: SendUM, stackState: ChildStack<SendRoute, ComposableContentComponent>) {
|
||||
Column(
|
||||
modifier = Modifier.Companion
|
||||
.background(color = TangemTheme.colors.background.tertiary)
|
||||
.fillMaxSize()
|
||||
.imePadding()
|
||||
.systemBarsPadding(),
|
||||
horizontalAlignment = Alignment.Companion.CenterHorizontally,
|
||||
) {
|
||||
SendAppBar(navigationUM = state.navigationUM)
|
||||
Children(
|
||||
stack = stackState,
|
||||
animation = stackAnimation(slide()),
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
it.instance.Content(Modifier.weight(1f))
|
||||
}
|
||||
SendNavigationButtons(navigationUM = state.navigationUM)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SendAppBar(navigationUM: NavigationUM) {
|
||||
val navigationUM = navigationUM as? NavigationUM.Content ?: return
|
||||
AppBarWithBackButtonAndIcon(
|
||||
text = navigationUM.title.resolveReference(),
|
||||
subtitle = navigationUM.subtitle?.resolveReference(),
|
||||
onBackClick = navigationUM.backIconClick,
|
||||
onIconClick = navigationUM.additionalIconClick,
|
||||
backIconRes = navigationUM.backIconRes,
|
||||
iconRes = navigationUM.additionalIconRes,
|
||||
backgroundColor = TangemTheme.colors.background.tertiary,
|
||||
modifier = Modifier.height(TangemTheme.dimens.size56),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.send.v2.subcomponents.amount
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
|
|
@ -20,7 +21,7 @@ internal class SendAmountBlockComponent(
|
|||
val onClick: () -> Unit,
|
||||
) : ComposableContentComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: SendAmountModel = getOrCreateModel(params = params, router = router)
|
||||
private val model: SendAmountModel = getOrCreateModel(params = params)
|
||||
|
||||
init {
|
||||
model.uiState.onEach {
|
||||
|
|
@ -32,14 +33,13 @@ internal class SendAmountBlockComponent(
|
|||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state = model.uiState.collectAsStateWithLifecycle()
|
||||
val isClickEnabled = params.blockClickEnableFlow.collectAsStateWithLifecycle()
|
||||
val isEditingDisabled = params.blockEditDisabledFlow.collectAsStateWithLifecycle()
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
val isClickEnabled by params.blockClickEnableFlow.collectAsStateWithLifecycle()
|
||||
|
||||
AmountBlock(
|
||||
amountState = state.value,
|
||||
isClickDisabled = !isClickEnabled.value,
|
||||
isEditingDisabled = isEditingDisabled.value,
|
||||
amountState = state,
|
||||
isClickDisabled = !isClickEnabled,
|
||||
isEditingDisabled = params.isPredefinedValues,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,10 +27,11 @@ internal class SendAmountComponent(
|
|||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
val isBalanceHidden by params.isBalanceHidingFlow.collectAsStateWithLifecycle()
|
||||
|
||||
AmountScreenContent(
|
||||
amountState = state,
|
||||
isBalanceHidden = false,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
clickIntents = model,
|
||||
modifier = Modifier.background(TangemTheme.colors.background.tertiary),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ internal sealed class SendAmountComponentParams {
|
|||
val callback: ModelCallback,
|
||||
val currentRoute: Flow<SendRoute.Amount>,
|
||||
val predefinedAmountValue: String?,
|
||||
val isBalanceHidingFlow: StateFlow<Boolean>,
|
||||
) : SendAmountComponentParams()
|
||||
|
||||
data class AmountBlockParams(
|
||||
|
|
@ -35,7 +36,8 @@ internal sealed class SendAmountComponentParams {
|
|||
override val userWallet: UserWallet,
|
||||
override val appCurrency: AppCurrency,
|
||||
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
val blockEditDisabledFlow: StateFlow<Boolean>,
|
||||
val blockClickEnableFlow: StateFlow<Boolean>,
|
||||
val predefinedAmountValue: String?,
|
||||
val isPredefinedValues: Boolean,
|
||||
) : SendAmountComponentParams()
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import javax.inject.Singleton
|
|||
interface SendAmountReduceTrigger {
|
||||
suspend fun triggerReduceBy(reduceBy: ReduceByData)
|
||||
suspend fun triggerReduceTo(reduceTo: BigDecimal)
|
||||
suspend fun triggerIgnoreReduce()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -21,6 +22,7 @@ interface SendAmountReduceTrigger {
|
|||
interface SendAmountReduceListener {
|
||||
val reduceToTriggerFlow: Flow<BigDecimal>
|
||||
val reduceByTriggerFlow: Flow<ReduceByData>
|
||||
val ignoreReduceTriggerFlow: Flow<Unit>
|
||||
}
|
||||
|
||||
@Singleton
|
||||
|
|
@ -29,6 +31,7 @@ internal class DefaultSendAmountReduceTrigger @Inject constructor() :
|
|||
SendAmountReduceListener {
|
||||
override val reduceToTriggerFlow = MutableSharedFlow<BigDecimal>()
|
||||
override val reduceByTriggerFlow = MutableSharedFlow<ReduceByData>()
|
||||
override val ignoreReduceTriggerFlow = MutableSharedFlow<Unit>()
|
||||
|
||||
override suspend fun triggerReduceBy(reduceBy: ReduceByData) {
|
||||
reduceByTriggerFlow.emit(reduceBy)
|
||||
|
|
@ -37,4 +40,8 @@ internal class DefaultSendAmountReduceTrigger @Inject constructor() :
|
|||
override suspend fun triggerReduceTo(reduceTo: BigDecimal) {
|
||||
reduceToTriggerFlow.emit(reduceTo)
|
||||
}
|
||||
|
||||
override suspend fun triggerIgnoreReduce() {
|
||||
ignoreReduceTriggerFlow.emit(Unit)
|
||||
}
|
||||
}
|
||||
|
|
@ -14,11 +14,14 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
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.NavigationUM
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
import com.tangem.features.send.v2.send.SendRoute
|
||||
import com.tangem.features.send.v2.send.ui.state.ButtonsUM
|
||||
import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponentParams
|
||||
import com.tangem.features.send.v2.subcomponents.amount.SendAmountReduceListener
|
||||
import com.tangem.features.send.v2.subcomponents.amount.analytics.SendAmountAnalyticEvents
|
||||
|
|
@ -60,6 +63,7 @@ internal class SendAmountModel @Inject constructor(
|
|||
initMinBoundary()
|
||||
subscribeOnAmountReduceByTriggerUpdates()
|
||||
subscribeOnAmountReduceToTriggerUpdates()
|
||||
subscribeOnAmountIgnoreReduceTriggerUpdates()
|
||||
}
|
||||
|
||||
private fun initMinBoundary() {
|
||||
|
|
@ -79,7 +83,6 @@ internal class SendAmountModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun initialState() {
|
||||
val predefinedAmountValue = (params as? SendAmountComponentParams.AmountParams)?.predefinedAmountValue
|
||||
if (uiState.value is AmountState.Empty) {
|
||||
_uiState.update {
|
||||
AmountStateConverterV2(
|
||||
|
|
@ -95,8 +98,9 @@ internal class SendAmountModel @Inject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
if (predefinedAmountValue != null) {
|
||||
onAmountValueChange(predefinedAmountValue)
|
||||
val params = params as? SendAmountComponentParams.AmountBlockParams
|
||||
if (params?.predefinedAmountValue != null) {
|
||||
onAmountValueChange(params.predefinedAmountValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -191,6 +195,12 @@ internal class SendAmountModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun subscribeOnAmountIgnoreReduceTriggerUpdates() {
|
||||
sendAmountReduceListener.ignoreReduceTriggerFlow
|
||||
.onEach { _uiState.update(AmountIgnoreReduceTransformer::transform) }
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun saveResult() {
|
||||
val params = params as? SendAmountComponentParams.AmountParams ?: return
|
||||
params.callback.onAmountResult(uiState.value)
|
||||
|
|
@ -202,7 +212,7 @@ internal class SendAmountModel @Inject constructor(
|
|||
flow = uiState,
|
||||
flow2 = params.currentRoute,
|
||||
transform = { state, route -> state to route },
|
||||
).onEach { (state, route) ->
|
||||
).distinctUntilChanged().onEach { (state, route) ->
|
||||
params.callback.onNavigationResult(
|
||||
NavigationUM.Content(
|
||||
title = resourceReference(R.string.send_amount_label),
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ internal class SendDestinationComponent(
|
|||
SendDestinationContent(state = state, clickIntents = model, isBalanceHidden = isBalanceHidden)
|
||||
}
|
||||
|
||||
|
||||
interface ModelCallback : SendNavigationModelCallback {
|
||||
fun onDestinationResult(destinationUM: DestinationUM)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -357,7 +357,7 @@ internal class SendDestinationModel @Inject constructor(
|
|||
flow = uiState,
|
||||
flow2 = params.currentRoute,
|
||||
transform = { state, route -> state to route },
|
||||
).onEach { (state, route) ->
|
||||
).distinctUntilChanged().onEach { (state, route) ->
|
||||
params.callback.onNavigationResult(
|
||||
NavigationUM.Content(
|
||||
title = resourceReference(R.string.send_recipient_label),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.features.send.v2.subcomponents.destination.model.transformers
|
||||
|
||||
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class SendDestinationPredefinedStateTransformer(
|
||||
private val address: String,
|
||||
private val memo: String?,
|
||||
) : Transformer<DestinationUM> {
|
||||
|
||||
override fun transform(prevState: DestinationUM): DestinationUM {
|
||||
val state = prevState as? DestinationUM.Content ?: return prevState
|
||||
|
||||
return state.copy(
|
||||
addressTextField = state.addressTextField.copy(value = address, isValuePasted = false),
|
||||
memoTextField = memo?.let { state.memoTextField?.copy(value = it, isValuePasted = false) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,15 +10,11 @@ internal sealed class DestinationTextFieldUM {
|
|||
/** Current value */
|
||||
abstract val value: String
|
||||
|
||||
/** Lambda be invoked when value is been changed */
|
||||
abstract val onValueChange: (String) -> Unit
|
||||
|
||||
/** Keyboard options */
|
||||
abstract val keyboardOptions: KeyboardOptions
|
||||
|
||||
data class RecipientAddress(
|
||||
override val value: String,
|
||||
override val onValueChange: (String) -> Unit,
|
||||
override val keyboardOptions: KeyboardOptions,
|
||||
val placeholder: TextReference,
|
||||
val label: TextReference,
|
||||
|
|
@ -29,7 +25,6 @@ internal sealed class DestinationTextFieldUM {
|
|||
|
||||
data class RecipientMemo(
|
||||
override val value: String,
|
||||
override val onValueChange: (String) -> Unit,
|
||||
override val keyboardOptions: KeyboardOptions,
|
||||
val placeholder: TextReference,
|
||||
val label: TextReference,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ internal sealed class DestinationUM {
|
|||
val wallets: ImmutableList<DestinationRecipientListUM>,
|
||||
val networkName: String,
|
||||
val isValidating: Boolean = false,
|
||||
val isEditingDisabled: Boolean = false,
|
||||
val isInitialized: Boolean = false,
|
||||
) : DestinationUM()
|
||||
|
||||
data class Empty(
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ internal class SendFeeAlertFactory @Inject constructor(
|
|||
return isFeeTooHigh
|
||||
}
|
||||
|
||||
fun getFeeUpdatedAlert(newFee: TransactionFee, feeUM: FeeUM, onFeeNotIncreased: () -> Unit) {
|
||||
fun getFeeUpdatedAlert(newFee: TransactionFee, feeUM: FeeUM, proceedAction: () -> Unit, stopAction: () -> Unit) {
|
||||
if (feeUM !is FeeUM.Content) return
|
||||
val feeSelectorUM = feeUM.feeSelectorUM as? FeeSelectorUM.Content ?: return
|
||||
val newFee = when (newFee) {
|
||||
|
|
@ -100,12 +100,16 @@ internal class SendFeeAlertFactory @Inject constructor(
|
|||
DialogMessage(
|
||||
message = resourceReference(id = R.string.send_notification_high_fee_title),
|
||||
dismissOnFirstAction = true,
|
||||
firstActionBuilder = { okAction() },
|
||||
secondActionBuilder = { cancelAction() },
|
||||
firstActionBuilder = {
|
||||
okAction { proceedAction(); onDismissRequest() }
|
||||
},
|
||||
secondActionBuilder = {
|
||||
cancelAction { stopAction(); onDismissRequest() }
|
||||
},
|
||||
),
|
||||
)
|
||||
} else {
|
||||
onFeeNotIncreased()
|
||||
proceedAction()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.features.send.v2.send.ui.state.ButtonsUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||
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.SendFeeCheckReloadTrigger
|
||||
import com.tangem.features.send.v2.subcomponents.fee.SendFeeComponentParams
|
||||
import com.tangem.features.send.v2.subcomponents.fee.SendFeeReloadTrigger
|
||||
|
|
@ -208,7 +208,20 @@ internal class SendFeeModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
callFeeUseCase().fold(
|
||||
ifRight = {
|
||||
feeCheckReloadTrigger.callbackCheckResult(true)
|
||||
sendFeeAlertFactory.getFeeUpdatedAlert(
|
||||
newFee = it,
|
||||
feeUM = uiState.value,
|
||||
proceedAction = {
|
||||
modelScope.launch {
|
||||
feeCheckReloadTrigger.callbackCheckResult(true)
|
||||
}
|
||||
},
|
||||
stopAction = {
|
||||
modelScope.launch {
|
||||
feeCheckReloadTrigger.callbackCheckResult(false)
|
||||
}
|
||||
},
|
||||
)
|
||||
_uiState.update(
|
||||
SendFeeLoadedTransformer(
|
||||
fees = it,
|
||||
|
|
@ -223,7 +236,7 @@ internal class SendFeeModel @Inject constructor(
|
|||
ifLeft = { feeError ->
|
||||
feeCheckReloadTrigger.callbackCheckResult(false)
|
||||
_uiState.update(SendFeeFailedTransformer(feeError))
|
||||
sendFeeAlertFactory.getFeeUnreachableErrorState(::checkLoadFee)
|
||||
sendFeeAlertFactory.getFeeUnreachableErrorState(::loadFee)
|
||||
updateFeeNotifications()
|
||||
},
|
||||
)
|
||||
|
|
@ -265,7 +278,7 @@ internal class SendFeeModel @Inject constructor(
|
|||
flow = uiState,
|
||||
flow2 = params.currentRoute,
|
||||
transform = { state, route -> state to route },
|
||||
).onEach { (state, _) ->
|
||||
).distinctUntilChanged().onEach { (state, _) ->
|
||||
params.callback.onNavigationResult(
|
||||
NavigationUM.Content(
|
||||
title = resourceReference(R.string.common_fee_selector_title),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue