diff --git a/app/src/main/java/com/tangem/tap/routing/ProxyAppRouter.kt b/app/src/main/java/com/tangem/tap/routing/ProxyAppRouter.kt index 5007213b9b..cdebe55b4a 100644 --- a/app/src/main/java/com/tangem/tap/routing/ProxyAppRouter.kt +++ b/app/src/main/java/com/tangem/tap/routing/ProxyAppRouter.kt @@ -82,7 +82,6 @@ internal class ProxyAppRouter( override fun defaultCompletionHandler(isSuccess: Boolean, errorMessage: String) { if (!isSuccess) { - Timber.tag("ASDASD").d(errorMessage) analyticsExceptionHandler.sendException(ExceptionAnalyticsEvent(RuntimeException(errorMessage))) Timber.w(errorMessage) diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/AmountScreenContent.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/AmountScreenContent.kt index bdb765bbbf..823ad1ce3d 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/AmountScreenContent.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/AmountScreenContent.kt @@ -30,8 +30,6 @@ fun AmountScreenContent( clickIntents: AmountScreenClickIntents, modifier: Modifier = Modifier, ) { - if (amountState !is AmountState.Data) return - // Do not put fillMaxSize() in here LazyColumn( modifier = modifier @@ -49,7 +47,7 @@ fun AmountScreenContent( onCurrencyChange = clickIntents::onCurrencyChangeClick, onMaxAmountClick = clickIntents::onMaxValueClick, ) - } else { + } else if (amountState is AmountState.Data) { amountField( amountState = amountState, isBalanceHidden = isBalanceHidden, diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountBoundaryUpdateTransformer.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountBoundaryUpdateTransformer.kt new file mode 100644 index 0000000000..a689b4501a --- /dev/null +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountBoundaryUpdateTransformer.kt @@ -0,0 +1,46 @@ +package com.tangem.common.ui.amountScreen.converters.field + +import com.tangem.common.ui.R +import com.tangem.common.ui.amountScreen.models.AmountState +import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.wrappedList +import com.tangem.core.ui.format.bigdecimal.crypto +import com.tangem.core.ui.format.bigdecimal.fiat +import com.tangem.core.ui.format.bigdecimal.format +import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.utils.transformer.Transformer + +/** + * Updates amount boundaries and revalidates current amount state + * + * @property cryptoCurrencyStatus current cryptocurrency status + * @property maxEnterAmount new maximum enter amount boundary + * @property appCurrency current app currency + * @property isRedesignEnabled whether redesign mode is enabled + */ +class AmountBoundaryUpdateTransformer( + private val cryptoCurrencyStatus: CryptoCurrencyStatus, + private val maxEnterAmount: EnterAmountBoundary, + private val appCurrency: AppCurrency, + private val isRedesignEnabled: Boolean, +) : Transformer { + + override fun transform(prevState: AmountState): AmountState { + if (prevState !is AmountState.Data) return prevState + + val fiat = maxEnterAmount.fiatAmount.format { fiat(appCurrency.code, appCurrency.symbol) } + val crypto = maxEnterAmount.amount.format { crypto(cryptoCurrencyStatus.currency) } + + val availableBalance = if (isRedesignEnabled) { + resourceReference(R.string.common_balance, wrappedList(crypto)) + } else { + resourceReference(R.string.common_crypto_fiat_format, wrappedList(crypto, fiat)) + } + + return prevState.copy( + availableBalance = availableBalance, + ) + } +} \ No newline at end of file diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldConverter.kt index ce11f41fce..f19fad6bb4 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/field/AmountFieldConverter.kt @@ -100,8 +100,8 @@ class AmountFieldConverterV2( val cryptoAmount = cryptoDecimal.convertToAmount(cryptoCurrencyStatus.currency) val fiatRate = cryptoCurrencyStatus.value.fiatRate val (fiatValue, fiatDecimal) = when { - fiatRate.isNullOrZero() -> "" to null value.isEmpty() -> "" to BigDecimal.ZERO + fiatRate.isNullOrZero() -> "" to null else -> { val fiatDecimal = fiatRate?.multiply(cryptoDecimal) val fiatValue = fiatDecimal?.parseBigDecimal(FIAT_DECIMALS).orEmpty() diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/models/AmountState.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/models/AmountState.kt index b5eab4301d..cc23669f47 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/models/AmountState.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/models/AmountState.kt @@ -12,6 +12,7 @@ import java.math.BigDecimal sealed class AmountState { abstract val isPrimaryButtonEnabled: Boolean + abstract val isRedesignEnabled: Boolean /** * @param isPrimaryButtonEnabled indicates if next state button enabled @@ -29,6 +30,7 @@ sealed class AmountState { */ data class Data( override val isPrimaryButtonEnabled: Boolean, + override val isRedesignEnabled: Boolean, val title: TextReference, val availableBalance: TextReference, val tokenName: TextReference, @@ -41,10 +43,10 @@ sealed class AmountState { val isEditingDisabled: Boolean = false, val reduceAmountBy: BigDecimal = BigDecimal.ZERO, val isIgnoreReduce: Boolean = false, - val isRedesignEnabled: Boolean, ) : AmountState() data class Empty( override val isPrimaryButtonEnabled: Boolean = false, + override val isRedesignEnabled: Boolean, ) : AmountState() } \ No newline at end of file diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/preview/AmountStatePreviewData.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/preview/AmountStatePreviewData.kt index ab6ead2229..99c11a9a14 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/preview/AmountStatePreviewData.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/preview/AmountStatePreviewData.kt @@ -19,7 +19,7 @@ import java.math.BigDecimal object AmountStatePreviewData { - val emptyState = AmountState.Empty() + val emptyState = AmountState.Empty(isRedesignEnabled = true) val amountState = AmountState.Data( isPrimaryButtonEnabled = false, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt index d38c5b42a8..4f091935b8 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt @@ -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.core.ui.extensions.resourceReference +import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.send.v2.api.SendComponent import com.tangem.features.send.v2.common.CommonSendRoute import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents @@ -57,14 +58,19 @@ internal class DefaultSendComponent @AssistedInject constructor( popCallback = { onChildBack() }, ) + private val model: SendModel = getOrCreateModel(params = params, router = innerRouter) + private val initialRoute = if (params.amount == null) { - CommonSendRoute.Destination(isEditMode = false) + if (model.uiState.value.isRedesignEnabled) { + CommonSendRoute.Amount(isEditMode = false) + } else { + CommonSendRoute.Destination(isEditMode = false) + } } else { CommonSendRoute.Empty } - private val currentRoute = MutableStateFlow(initialRoute) - private val model: SendModel = getOrCreateModel(params = params, router = innerRouter) + private val currentRoute = MutableStateFlow(initialRoute) private val childStack = childStack( key = "sendInnerStack", @@ -155,9 +161,14 @@ internal class DefaultSendComponent @AssistedInject constructor( callback = model, onBackClick = ::onChildBack, onNextClick = { + val nextRoute = if (model.uiState.value.isRedesignEnabled) { + CommonSendRoute.Confirm + } else { + CommonSendRoute.Amount(isEditMode = false) + } innerRouter.safeNextClick( currentRoute = route, - nextRoute = CommonSendRoute.Amount(isEditMode = false), + nextRoute = nextRoute, popBack = ::onChildBack, childStack = childStack, ) @@ -169,50 +180,54 @@ internal class DefaultSendComponent @AssistedInject constructor( factoryContext: AppComponentContext, route: CommonSendRoute, ): ComposableContentComponent { - val cryptoCurrencyStatus = model.cryptoCurrencyStatus - return if (cryptoCurrencyStatus != null) { - SendAmountComponent( - appComponentContext = factoryContext, - params = SendAmountComponentParams.AmountParams( - state = model.uiState.value.amountUM, - currentRoute = currentRoute.filterIsInstance(), - isBalanceHidingFlow = model.isBalanceHiddenFlow, - analyticsCategoryName = analyticCategoryName, - userWallet = model.userWallet, - appCurrency = model.appCurrency, - cryptoCurrencyStatus = cryptoCurrencyStatus, - callback = model, - predefinedValues = model.predefinedValues, - onBackClick = { - if (route.isEditMode) { + return SendAmountComponent( + appComponentContext = factoryContext, + params = SendAmountComponentParams.AmountParams( + state = model.uiState.value.amountUM, + currentRoute = currentRoute.filterIsInstance(), + isBalanceHidingFlow = model.isBalanceHiddenFlow, + analyticsCategoryName = analyticCategoryName, + appCurrency = model.appCurrency, + userWalletId = params.userWalletId, + cryptoCurrency = params.currency, + cryptoCurrencyStatusFlow = model.cryptoCurrencyStatusFlow, + callback = model, + predefinedValues = model.predefinedValues, + onBackClick = { + if (route.isEditMode) { + onChildBack() + } else { + analyticsEventHandler.send( + CommonSendAnalyticEvents.CloseButtonClicked( + categoryName = analyticCategoryName, + source = SendScreenSource.Amount, + isFromSummary = false, + isValid = model.uiState.value.amountUM.isPrimaryButtonEnabled, + ), + ) + if (model.uiState.value.isRedesignEnabled) { onChildBack() } else { - analyticsEventHandler.send( - CommonSendAnalyticEvents.CloseButtonClicked( - categoryName = analyticCategoryName, - source = SendScreenSource.Amount, - isFromSummary = false, - isValid = model.uiState.value.amountUM.isPrimaryButtonEnabled, - ), - ) router.pop() } - }, - onNextClick = { - innerRouter.safeNextClick( - currentRoute = route, - nextRoute = CommonSendRoute.Confirm, - popBack = ::onChildBack, - childStack = childStack, - ) - }, - isRedesignEnabled = model.uiState.value.isRedesignEnabled, - ), - ) - } else { - model.showAlertError() - getStubComponent() - } + } + }, + onNextClick = { + val nextRoute = if (model.uiState.value.isRedesignEnabled) { + CommonSendRoute.Destination(isEditMode = false) + } else { + CommonSendRoute.Confirm + } + innerRouter.safeNextClick( + currentRoute = route, + nextRoute = nextRoute, + popBack = ::onChildBack, + childStack = childStack, + ) + }, + isRedesignEnabled = model.uiState.value.isRedesignEnabled, + ), + ) } @Suppress("ComplexCondition") @@ -220,8 +235,8 @@ internal class DefaultSendComponent @AssistedInject constructor( val state = model.uiState.value val sendAmount = (state.amountUM as? AmountState.Data)?.amountTextField?.cryptoAmount?.value val destinationAddress = (state.destinationUM as? DestinationUM.Content)?.addressTextField?.value - val cryptoCurrencyStatus = model.cryptoCurrencyStatus - val feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus + val cryptoCurrencyStatus = model.cryptoCurrencyStatusFlow.value + val feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatusFlow.value return if (sendAmount != null && destinationAddress != null && feeCryptoCurrencyStatus != null && cryptoCurrencyStatus != null @@ -251,10 +266,12 @@ internal class DefaultSendComponent @AssistedInject constructor( } private fun getConfirmComponent(factoryContext: AppComponentContext): ComposableContentComponent { - val cryptoCurrencyStatus = model.cryptoCurrencyStatus - val feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus + val cryptoCurrencyStatus = model.cryptoCurrencyStatusFlow.value + val feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatusFlow.value - return if (cryptoCurrencyStatus != null && feeCryptoCurrencyStatus != null) { + return if (cryptoCurrencyStatus.value != CryptoCurrencyStatus.Loading && + feeCryptoCurrencyStatus.value != CryptoCurrencyStatus.Loading + ) { SendConfirmComponent( appComponentContext = factoryContext, params = SendConfirmComponent.Params( @@ -265,6 +282,8 @@ internal class DefaultSendComponent @AssistedInject constructor( analyticsCategoryName = analyticCategoryName, cryptoCurrencyStatus = cryptoCurrencyStatus, feeCryptoCurrencyStatus = feeCryptoCurrencyStatus, + cryptoCurrencyStatusFlow = model.cryptoCurrencyStatusFlow, + feeCryptoCurrencyStatusFlow = model.feeCryptoCurrencyStatusFlow, appCurrency = model.appCurrency, callback = model, predefinedValues = model.predefinedValues, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/SendConfirmComponent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/SendConfirmComponent.kt index 0145507ff8..22b3e7293e 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/SendConfirmComponent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/SendConfirmComponent.kt @@ -31,6 +31,7 @@ import com.tangem.features.send.v2.subcomponents.fee.SendFeeComponentParams import com.tangem.features.send.v2.subcomponents.notifications.DefaultSendNotificationsComponent import com.tangem.utils.extensions.orZero import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.StateFlow internal class SendConfirmComponent( appComponentContext: AppComponentContext, @@ -62,11 +63,13 @@ internal class SendConfirmComponent( state = model.uiState.value.amountUM, analyticsCategoryName = params.analyticsCategoryName, userWallet = params.userWallet, - cryptoCurrencyStatus = params.cryptoCurrencyStatus, appCurrency = params.appCurrency, blockClickEnableFlow = blockClickEnableFlow.asStateFlow(), predefinedValues = params.predefinedValues, isRedesignEnabled = model.uiState.value.isRedesignEnabled, + userWalletId = params.userWallet.walletId, + cryptoCurrency = params.cryptoCurrencyStatus.currency, + cryptoCurrencyStatusFlow = params.cryptoCurrencyStatusFlow, ), onResult = model::onAmountResult, onClick = model::showEditAmount, @@ -145,6 +148,8 @@ internal class SendConfirmComponent( val userWallet: UserWallet, val cryptoCurrencyStatus: CryptoCurrencyStatus, val feeCryptoCurrencyStatus: CryptoCurrencyStatus, + val cryptoCurrencyStatusFlow: StateFlow, + val feeCryptoCurrencyStatusFlow: StateFlow, val appCurrency: AppCurrency, val callback: ModelCallback, val currentRoute: Flow, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt index a61ec8f1e6..2ea110f6a2 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt @@ -92,7 +92,6 @@ internal class SendModel @Inject constructor( ) : Model(), SendComponentCallback { private val params: SendComponent.Params = paramsContainer.require() - private val userWalletId = params.userWalletId private val cryptoCurrency = params.currency private val _uiState = MutableStateFlow(initialState()) @@ -101,9 +100,23 @@ internal class SendModel @Inject constructor( private val _isBalanceHiddenFlow = MutableStateFlow(false) val isBalanceHiddenFlow = _isBalanceHiddenFlow.asStateFlow() + private val _cryptoCurrencyStatusFlow = MutableStateFlow( + CryptoCurrencyStatus( + params.currency, + value = CryptoCurrencyStatus.Loading, + ), + ) + val cryptoCurrencyStatusFlow = _cryptoCurrencyStatusFlow.asStateFlow() + + private val _feeCryptoCurrencyStatusFlow = MutableStateFlow( + CryptoCurrencyStatus( + params.currency, + value = CryptoCurrencyStatus.Loading, + ), + ) + val feeCryptoCurrencyStatusFlow = _feeCryptoCurrencyStatusFlow.asStateFlow() + var userWallet: UserWallet by Delegates.notNull() - var cryptoCurrencyStatus: CryptoCurrencyStatus? = null - var feeCryptoCurrencyStatus: CryptoCurrencyStatus? = null var appCurrency: AppCurrency = AppCurrency.Default var predefinedValues: PredefinedValues = PredefinedValues.Empty @@ -279,16 +292,16 @@ internal class SendModel @Inject constructor( ): Flow> { return when { isSingleWalletWithToken -> getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet( - userWalletId = userWalletId, + userWalletId = params.userWalletId, currencyId = cryptoCurrency.id, isSingleWalletWithTokens = true, ) isMultiCurrency -> getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet( - userWalletId = userWalletId, + userWalletId = params.userWalletId, currencyId = cryptoCurrency.id, isSingleWalletWithTokens = false, ) - else -> getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWalletId = userWalletId) + else -> getSingleCryptoCurrencyStatusUseCase.invokeSingleWallet(userWalletId = params.userWalletId) } } @@ -298,7 +311,7 @@ internal class SendModel @Inject constructor( ): CryptoCurrencyStatus { return if (isMultiCurrency) { getFeePaidCryptoCurrencyStatusSyncUseCase( - userWalletId = userWalletId, + userWalletId = params.userWalletId, cryptoCurrencyStatus = cryptoCurrencyStatus, ).getOrNull() ?: cryptoCurrencyStatus } else { @@ -307,8 +320,8 @@ internal class SendModel @Inject constructor( } private fun onDataLoaded(currencyStatus: CryptoCurrencyStatus, feeCurrencyStatus: CryptoCurrencyStatus) { - cryptoCurrencyStatus = currencyStatus - feeCryptoCurrencyStatus = feeCurrencyStatus + _cryptoCurrencyStatusFlow.value = currencyStatus + _feeCryptoCurrencyStatusFlow.value = feeCurrencyStatus if (params.amount != null) { router.replaceAll(CommonSendRoute.Confirm) @@ -360,7 +373,7 @@ internal class SendModel @Inject constructor( } private fun initialState(): SendUM = SendUM( - amountUM = AmountState.Empty(), + amountUM = AmountState.Empty(isRedesignEnabled = sendFeatureToggles.isSendRedesignEnabled), destinationUM = SendDestinationInitialStateTransformer( cryptoCurrency = cryptoCurrency, isRedesignEnabled = sendFeatureToggles.isSendRedesignEnabled, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/SendAmountComponentParams.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/SendAmountComponentParams.kt index a13dcf3ef1..419dc6ced6 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/SendAmountComponentParams.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/SendAmountComponentParams.kt @@ -2,8 +2,10 @@ package com.tangem.features.send.v2.subcomponents.amount import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.send.v2.common.CommonSendRoute import com.tangem.features.send.v2.common.PredefinedValues import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponent.ModelCallback @@ -14,20 +16,22 @@ internal sealed class SendAmountComponentParams { abstract val state: AmountState abstract val analyticsCategoryName: String - abstract val userWallet: UserWallet + abstract val userWalletId: UserWalletId abstract val appCurrency: AppCurrency - abstract val cryptoCurrencyStatus: CryptoCurrencyStatus abstract val predefinedValues: PredefinedValues abstract val isRedesignEnabled: Boolean + abstract val cryptoCurrency: CryptoCurrency + abstract val cryptoCurrencyStatusFlow: StateFlow data class AmountParams( override val state: AmountState, override val analyticsCategoryName: String, - override val userWallet: UserWallet, + override val userWalletId: UserWalletId, override val appCurrency: AppCurrency, - override val cryptoCurrencyStatus: CryptoCurrencyStatus, override val predefinedValues: PredefinedValues, override val isRedesignEnabled: Boolean, + override val cryptoCurrency: CryptoCurrency, + override val cryptoCurrencyStatusFlow: StateFlow, val callback: ModelCallback, val currentRoute: Flow, val isBalanceHidingFlow: StateFlow, @@ -38,11 +42,13 @@ internal sealed class SendAmountComponentParams { data class AmountBlockParams( override val state: AmountState, override val analyticsCategoryName: String, - override val userWallet: UserWallet, override val appCurrency: AppCurrency, - override val cryptoCurrencyStatus: CryptoCurrencyStatus, + override val userWalletId: UserWalletId, override val predefinedValues: PredefinedValues, override val isRedesignEnabled: Boolean, + override val cryptoCurrency: CryptoCurrency, + override val cryptoCurrencyStatusFlow: StateFlow, + val userWallet: UserWallet, val blockClickEnableFlow: StateFlow, ) : SendAmountComponentParams() } \ No newline at end of file diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/model/SendAmountModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/model/SendAmountModel.kt index d60c1b6b81..dc008c3246 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/model/SendAmountModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/amount/model/SendAmountModel.kt @@ -1,10 +1,13 @@ package com.tangem.features.send.v2.subcomponents.amount.model import androidx.compose.runtime.Stable +import arrow.core.getOrElse import com.tangem.common.ui.amountScreen.AmountScreenClickIntents import com.tangem.common.ui.amountScreen.converters.* import com.tangem.common.ui.amountScreen.converters.field.AmountFieldChangeTransformer import com.tangem.common.ui.amountScreen.converters.field.AmountFieldSetMaxAmountTransformer +import com.tangem.common.ui.amountScreen.converters.field.AmountBoundaryUpdateTransformer +import com.tangem.common.ui.amountScreen.converters.MaxEnterAmountConverter import com.tangem.common.ui.amountScreen.models.AmountParameters import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary @@ -14,9 +17,14 @@ import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.WrappedList import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.stringReference +import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase +import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.GetMinimumTransactionAmountSyncUseCase +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.SendFeatureToggles import com.tangem.features.send.v2.common.PredefinedValues import com.tangem.features.send.v2.common.ui.state.NavigationUM @@ -36,6 +44,7 @@ import com.tangem.utils.transformer.update import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import javax.inject.Inject +import kotlin.properties.Delegates @Suppress("LongParameterList") @Stable @@ -49,33 +58,59 @@ internal class SendAmountModel @Inject constructor( private val sendAmountUpdateQRListener: SendAmountUpdateQRListener, private val analyticsEventHandler: AnalyticsEventHandler, private val sendFeatureToggles: SendFeatureToggles, + private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, + private val getUserWalletUseCase: GetUserWalletUseCase, ) : Model(), AmountScreenClickIntents { private val params: SendAmountComponentParams = paramsContainer.require() + private var appCurrency: AppCurrency = AppCurrency.Default + private var userWallet: UserWallet? = null private val _uiState = MutableStateFlow(params.state) val uiState = _uiState.asStateFlow() private val analyticsCategoryName = params.analyticsCategoryName - private val userWallet = params.userWallet - private val cryptoCurrencyStatus = params.cryptoCurrencyStatus + private var cryptoCurrencyStatus: CryptoCurrencyStatus = CryptoCurrencyStatus( + currency = params.cryptoCurrency, + value = CryptoCurrencyStatus.Loading, + ) private var minAmountBoundary: EnterAmountBoundary? = null - private var maxAmountBoundary: EnterAmountBoundary = MaxEnterAmountConverter().convert(cryptoCurrencyStatus) + private var maxAmountBoundary: EnterAmountBoundary by Delegates.notNull() init { configAmountNavigation() - initMinBoundary() - subscribeOnAmountReduceByTriggerUpdates() - subscribeOnAmountReduceToTriggerUpdates() - subscribeOnAmountIgnoreReduceTriggerUpdates() - subscribeOnAmountUpdateQRTriggerUpdates() + initAppCurrency() + subscribeOnCryptoCurrencyStatusFlow() + } + + private fun initAppCurrency() { + modelScope.launch { + userWallet = getUserWalletUseCase(params.userWalletId).getOrNull() + appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default } + } + } + + private fun subscribeOnCryptoCurrencyStatusFlow() { + params.cryptoCurrencyStatusFlow + .onEach { newCryptoCurrencyStatus -> + cryptoCurrencyStatus = newCryptoCurrencyStatus + maxAmountBoundary = MaxEnterAmountConverter().convert(cryptoCurrencyStatus) + if (uiState.value is AmountState.Empty) { + subscribeOnAmountReduceByTriggerUpdates() + subscribeOnAmountReduceToTriggerUpdates() + subscribeOnAmountIgnoreReduceTriggerUpdates() + subscribeOnAmountUpdateQRTriggerUpdates() + } + initMinBoundary() + } + .launchIn(modelScope) } private fun initMinBoundary() { modelScope.launch { minAmountBoundary = getMinimumTransactionAmountSyncUseCase( - userWalletId = userWallet.walletId, + userWalletId = params.userWalletId, cryptoCurrencyStatus = cryptoCurrencyStatus, ).getOrNull()?.let { EnterAmountBoundary( @@ -84,23 +119,37 @@ internal class SendAmountModel @Inject constructor( ) } - initialState() + if (uiState.value is AmountState.Data) { + _uiState.update( + AmountBoundaryUpdateTransformer( + cryptoCurrencyStatus = cryptoCurrencyStatus, + maxEnterAmount = maxAmountBoundary, + appCurrency = appCurrency, + isRedesignEnabled = sendFeatureToggles.isSendRedesignEnabled, + ), + ) + } else { + initialState() + } } } private fun initialState() { - if (uiState.value is AmountState.Empty) { + if (uiState.value is AmountState.Empty && userWallet != null) { _uiState.update { AmountStateConverterV2( clickIntents = this, - appCurrency = params.appCurrency, + appCurrency = appCurrency, cryptoCurrencyStatus = cryptoCurrencyStatus, maxEnterAmount = maxAmountBoundary, iconStateConverter = CryptoCurrencyToIconStateConverter(), isRedesignEnabled = sendFeatureToggles.isSendRedesignEnabled, ).convert( AmountParameters( - title = stringReference(userWallet.name), + title = resourceReference( + R.string.send_from_wallet_name, + WrappedList(listOf(userWallet?.name.orEmpty())), // TODO [REDACTED_TASK_KEY] + ), value = "", ), ) @@ -242,7 +291,7 @@ internal class SendAmountModel @Inject constructor( NavigationUM.Content( title = resourceReference(R.string.send_amount_label), subtitle = null, - backIconRes = if (route.isEditMode) { + backIconRes = if (route.isEditMode || params.isRedesignEnabled) { R.drawable.ic_back_24 } else { R.drawable.ic_close_24 @@ -260,15 +309,19 @@ internal class SendAmountModel @Inject constructor( params.onNextClick() }, ), - prevButton = ButtonsUM.PrimaryButtonUM( - text = TextReference.EMPTY, - iconResId = R.drawable.ic_back_24, - isEnabled = true, - onClick = { - saveResult() - params.onBackClick() - }, - ).takeIf { route.isEditMode.not() }, + prevButton = if (params.isRedesignEnabled) { + null + } else { + ButtonsUM.PrimaryButtonUM( + text = TextReference.EMPTY, + iconResId = R.drawable.ic_back_24, + isEnabled = true, + onClick = { + saveResult() + params.onBackClick() + }, + ).takeIf { route.isEditMode.not() } + }, secondaryPairButtonsUM = null, ), ) diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt index 6bd184f1fc..2cefea736b 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt @@ -8,6 +8,7 @@ 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.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.models.network.CryptoCurrencyAddress import com.tangem.domain.qrscanning.models.SourceType @@ -293,6 +294,7 @@ internal class SendDestinationModel @Inject constructor( params.callback.onDestinationResult(uiState.value) } + @Suppress("LongMethod") private fun configDestinationNavigation() { val params = params as? SendDestinationComponentParams.DestinationParams ?: return combine( @@ -305,7 +307,7 @@ internal class SendDestinationModel @Inject constructor( NavigationUM.Content( title = params.title, subtitle = null, - backIconRes = if (route.isEditMode) { + backIconRes = if (route.isEditMode || isRedesignEnabled) { R.drawable.ic_back_24 } else { R.drawable.ic_close_24 @@ -345,7 +347,19 @@ internal class SendDestinationModel @Inject constructor( params.onNextClick() }, ), - prevButton = null, + prevButton = if (isRedesignEnabled) { + ButtonsUM.PrimaryButtonUM( + text = TextReference.EMPTY, + iconResId = R.drawable.ic_back_24, + isEnabled = true, + onClick = { + saveResult() + params.onBackClick() + }, + ) + } else { + null + }, secondaryPairButtonsUM = null, ), ) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt index 328bf590dd..ed6fbd3a57 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateController.kt @@ -78,7 +78,7 @@ internal class StakingStateController @Inject constructor( cryptoCurrencyBlockchainId = "", currentStep = StakingStep.InitialInfo, initialInfoState = StakingStates.InitialInfoState.Empty(), - amountState = AmountState.Empty(), + amountState = AmountState.Empty(isRedesignEnabled = false), validatorState = StakingStates.ValidatorState.Empty(), rewardsValidatorsState = StakingStates.RewardsValidatorsState.Empty(), confirmationState = StakingStates.ConfirmationState.Empty(),