Updated on 2026-08-14

This commit is contained in:
Tangem 2024-06-17 13:29:44 +03:00
parent e8a2b10e6f
commit c1900053f7
27 changed files with 270 additions and 107 deletions

View file

@ -9,11 +9,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.tangem.common.ui.amountScreen.ui.amountField
import com.tangem.common.ui.amountScreen.ui.buttons
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.amountScreen.preview.AmountScreenClickIntentsStub
import com.tangem.common.ui.amountScreen.preview.AmountStatePreviewData
import com.tangem.common.ui.amountScreen.ui.amountField
import com.tangem.common.ui.amountScreen.ui.buttons
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
@ -25,6 +25,8 @@ import com.tangem.core.ui.res.TangemThemePreview
*/
@Composable
fun AmountScreenContent(amountState: AmountState, isBalanceHiding: Boolean, clickIntents: AmountScreenClickIntents) {
if (amountState !is AmountState.Data) return
// Do not put fillMaxSize() in here
LazyColumn(
modifier = Modifier

View file

@ -5,21 +5,24 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.utils.Provider
import com.tangem.utils.isNullOrZero
import com.tangem.utils.transformer.Transformer
/**
* Selected currency change from crypto currency to app currency and vice versa
*
* @property cryptoCurrencyStatusProvider current cryptocurrency status provider
* @property cryptoCurrencyStatus current cryptocurrency status
* @property value is crypto currency or app currency
*/
class AmountCurrencyTransformer(
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
) : Transformer<AmountState, Boolean> {
override fun transform(prevState: AmountState, value: Boolean): AmountState {
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val value: Boolean,
) : Transformer<AmountState> {
override fun transform(prevState: AmountState): AmountState {
if (prevState !is AmountState.Data) return prevState
val amountTextField = prevState.amountTextField
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val isValidFiatRate = cryptoCurrencyStatus.value.fiatRate.isNullOrZero()
val isDoneActionEnabled = prevState.isPrimaryButtonEnabled

View file

@ -6,8 +6,10 @@ import com.tangem.utils.transformer.Transformer
/**
* Dismisses indication on pasted value
*/
class AmountPastedTriggerDismissTransformer : Transformer<AmountState, Boolean> {
override fun transform(prevState: AmountState, value: Boolean): AmountState {
class AmountPastedTriggerDismissTransformer : Transformer<AmountState> {
override fun transform(prevState: AmountState): AmountState {
if (prevState !is AmountState.Data) return prevState
return prevState.copy(
amountTextField = prevState.amountTextField.copy(
isValuePasted = false,

View file

@ -8,7 +8,6 @@ import com.tangem.common.ui.amountScreen.utils.getFiatValue
import com.tangem.common.ui.amountScreen.utils.getKeyboardAction
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.utils.Provider
import com.tangem.utils.isNullOrZero
import com.tangem.utils.transformer.Transformer
import java.math.BigDecimal
@ -16,13 +15,16 @@ import java.math.BigDecimal
/**
* Reduces amount by specific value
*
* @property cryptoCurrencyStatusProvider current cryptocurrency status provider
* @property cryptoCurrencyStatus current cryptocurrency status
* @property value reduced by value
*/
class AmountReduceByTransformer(
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
) : Transformer<AmountState, AmountReduceByTransformer.ReduceByData> {
override fun transform(prevState: AmountState, value: ReduceByData): AmountState {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val value: ReduceByData,
) : Transformer<AmountState> {
override fun transform(prevState: AmountState): AmountState {
if (prevState !is AmountState.Data) return prevState
val amountTextField = prevState.amountTextField
val cryptoDecimals = amountTextField.cryptoAmount.decimals
val fiatDecimals = amountTextField.fiatAmount.decimals

View file

@ -8,7 +8,6 @@ import com.tangem.common.ui.amountScreen.utils.getFiatValue
import com.tangem.common.ui.amountScreen.utils.getKeyboardAction
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.utils.Provider
import com.tangem.utils.isNullOrZero
import com.tangem.utils.transformer.Transformer
import java.math.BigDecimal
@ -16,13 +15,16 @@ import java.math.BigDecimal
/**
* Reduces amount to specific value
*
* @property cryptoCurrencyStatusProvider current cryptocurrency status provider
* @property cryptoCurrencyStatus current cryptocurrency status
* @property value reduced to value
*/
class AmountReduceToTransformer(
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
) : Transformer<AmountState, BigDecimal> {
override fun transform(prevState: AmountState, value: BigDecimal): AmountState {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val value: BigDecimal,
) : Transformer<AmountState> {
override fun transform(prevState: AmountState): AmountState {
if (prevState !is AmountState.Data) return prevState
val amountTextField = prevState.amountTextField
val cryptoDecimals = amountTextField.cryptoAmount.decimals
val fiatDecimals = amountTextField.fiatAmount.decimals

View file

@ -52,7 +52,7 @@ class AmountStateConverter(
val crypto = formatCryptoAmount(status.value.amount, status.currency.symbol, status.currency.decimals)
val noFeeRate = status.value.fiatRate.isNullOrZero()
return AmountState(
return AmountState.Data(
walletName = userWallet.name,
walletBalance = resourceReference(R.string.send_wallet_balance_format, wrappedList(crypto, fiat)),
tokenIconState = iconStateConverter.convert(status),

View file

@ -9,7 +9,6 @@ import com.tangem.common.ui.amountScreen.utils.getFiatValue
import com.tangem.common.ui.amountScreen.utils.getKeyboardAction
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.utils.Provider
import com.tangem.utils.isNullOrZero
import com.tangem.utils.transformer.Transformer
import java.math.BigDecimal
@ -17,14 +16,17 @@ import java.math.BigDecimal
/**
* Amount value change
*
* @property cryptoCurrencyStatusProvider current cryptocurrency status provider
* @property cryptoCurrencyStatus current cryptocurrency status
* @property value amount value
*/
class AmountFieldChangeTransformer(
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
) : Transformer<AmountState, String> {
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val value: String,
) : Transformer<AmountState> {
override fun transform(prevState: AmountState): AmountState {
if (prevState !is AmountState.Data) return prevState
override fun transform(prevState: AmountState, value: String): AmountState {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val amountTextField = prevState.amountTextField
if (value.isEmpty()) return prevState.emptyState()
@ -67,7 +69,7 @@ class AmountFieldChangeTransformer(
)
}
private fun AmountState.emptyState(): AmountState {
private fun AmountState.Data.emptyState(): AmountState.Data {
return copy(
isPrimaryButtonEnabled = false,
amountTextField = amountTextField.copy(

View file

@ -6,7 +6,6 @@ import androidx.compose.ui.text.input.KeyboardType
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.utils.Provider
import com.tangem.utils.isNullOrZero
import com.tangem.utils.transformer.Transformer
import java.math.RoundingMode
@ -14,14 +13,15 @@ import java.math.RoundingMode
/**
* Selects maximum amount value
*
* @property cryptoCurrencyStatusProvider current cryptocurrency status provider
* @property cryptoCurrencyStatus current cryptocurrency status
*/
class AmountFieldMaxAmountTransformer(
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
) : Transformer<AmountState, Unit> {
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
) : Transformer<AmountState> {
override fun transform(prevState: AmountState): AmountState {
if (prevState !is AmountState.Data) return prevState
override fun transform(prevState: AmountState, value: Unit): AmountState {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val amountTextField = prevState.amountTextField
val cryptoDecimals = amountTextField.cryptoAmount.decimals

View file

@ -5,28 +5,36 @@ import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
import com.tangem.core.ui.extensions.TextReference
import kotlinx.collections.immutable.PersistentList
/**
* Model for amount state
*
* @param isPrimaryButtonEnabled indicates if next state button enabled
* @param walletName user wallet name
* @param walletBalance user crypto currency balance in wallet
* @param tokenIconState crypto currency icon state
* @param segmentedButtonConfig currency switcher config
* @param selectedButton selected currency index
* @param isSegmentedButtonsEnabled indicates if currency switches is enabled
* @param amountTextField amount field state
* @param appCurrencyCode app currency code
*/
/** Model for amount state */
@Stable
data class AmountState(
val isPrimaryButtonEnabled: Boolean,
val walletName: String,
val walletBalance: TextReference,
val tokenIconState: TokenIconState,
val segmentedButtonConfig: PersistentList<AmountSegmentedButtonsConfig>,
val selectedButton: Int,
val isSegmentedButtonsEnabled: Boolean,
val amountTextField: AmountFieldModel,
val appCurrencyCode: String,
)
sealed class AmountState {
abstract val isPrimaryButtonEnabled: Boolean
/**
* @param isPrimaryButtonEnabled indicates if next state button enabled
* @param walletName user wallet name
* @param walletBalance user crypto currency balance in wallet
* @param tokenIconState crypto currency icon state
* @param segmentedButtonConfig currency switcher config
* @param selectedButton selected currency index
* @param isSegmentedButtonsEnabled indicates if currency switches is enabled
* @param amountTextField amount field state
* @param appCurrencyCode app currency code
*/
data class Data(
override val isPrimaryButtonEnabled: Boolean,
val walletName: String,
val walletBalance: TextReference,
val tokenIconState: TokenIconState,
val segmentedButtonConfig: PersistentList<AmountSegmentedButtonsConfig>,
val selectedButton: Int,
val isSegmentedButtonsEnabled: Boolean,
val amountTextField: AmountFieldModel,
val appCurrencyCode: String,
) : AmountState()
data class Empty(
override val isPrimaryButtonEnabled: Boolean = false,
) : AmountState()
}

View file

@ -15,7 +15,7 @@ import java.math.BigDecimal
object AmountStatePreviewData {
val amountState = AmountState(
val amountState = AmountState.Data(
isPrimaryButtonEnabled = false,
walletName = "Family Wallet",
walletBalance = stringReference("2 130,88 USDT (2 129,92 \$)"),

View file

@ -21,7 +21,7 @@ import com.tangem.utils.Strings.STARS
private const val AMOUNT_FIELD_KEY = "amountFieldKey"
internal fun LazyListScope.amountField(
amountState: AmountState,
amountState: AmountState.Data,
isBalanceHiding: Boolean,
modifier: Modifier = Modifier,
) {

View file

@ -1,5 +1,8 @@
package com.tangem.utils.transformer
interface Transformer<S, V> {
fun transform(prevState: S, value: V): S
/**
* Transforms state to updated state.
*/
interface Transformer<S> {
fun transform(prevState: S): S
}

View file

@ -56,9 +56,13 @@ dependencies {
implementation(projects.domain.staking)
implementation(projects.domain.balanceHiding)
implementation(projects.domain.balanceHiding.models)
implementation(projects.domain.appCurrency)
implementation(projects.domain.appCurrency.models)
implementation(projects.domain.legacy)
implementation(projects.domain.models)
/** Common */
implementation(projects.common)
implementation(projects.common.ui)
/** Libs */
implementation(projects.libs.crypto)

View file

@ -1,8 +1,9 @@
package com.tangem.features.staking.impl.presentation.state
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.core.ui.event.consumedEvent
import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub
import com.tangem.features.staking.impl.presentation.state.transformers.StakingScreenStateTransformer
import com.tangem.utils.transformer.Transformer
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@ -23,7 +24,7 @@ internal class StakingStateController @Inject constructor() {
mutableUiState.update(function = function)
}
fun update(transformer: StakingScreenStateTransformer) {
fun update(transformer: Transformer<StakingUiState>) {
mutableUiState.update(function = transformer::transform)
}
@ -37,7 +38,7 @@ internal class StakingStateController @Inject constructor() {
cryptoCurrencyName = "",
currentStep = StakingStep.InitialInfo,
initialInfoState = StakingStates.InitialInfoState.Empty(),
amountState = StakingStates.AmountState.Empty(),
amountState = AmountState.Empty(),
validatorState = StakingStates.ValidatorState.Empty(),
confirmStakingState = StakingStates.ConfirmStakingState.Empty(),
isBalanceHidden = false,

View file

@ -1,6 +1,7 @@
package com.tangem.features.staking.impl.presentation.state
import androidx.compose.runtime.Immutable
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.core.ui.event.StateEvent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents
@ -14,7 +15,7 @@ internal data class StakingUiState(
val cryptoCurrencyName: String,
val currentStep: StakingStep,
val initialInfoState: StakingStates.InitialInfoState,
val amountState: StakingStates.AmountState,
val amountState: AmountState,
val validatorState: StakingStates.ValidatorState,
val confirmStakingState: StakingStates.ConfirmStakingState,
val isBalanceHidden: Boolean,
@ -23,7 +24,7 @@ internal data class StakingUiState(
fun copyWrapped(
initialInfoState: StakingStates.InitialInfoState = this.initialInfoState,
amountState: StakingStates.AmountState = this.amountState,
amountState: AmountState = this.amountState,
validatorState: StakingStates.ValidatorState = this.validatorState,
confirmStakingState: StakingStates.ConfirmStakingState = this.confirmStakingState,
): StakingUiState = copy(
@ -57,17 +58,6 @@ internal sealed class StakingStates {
) : InitialInfoState()
}
/** Amount state */
sealed class AmountState : StakingStates() {
data class Data(
override val isPrimaryButtonEnabled: Boolean,
) : AmountState()
data class Empty(
override val isPrimaryButtonEnabled: Boolean = false,
) : AmountState()
}
/** Validator state */
sealed class ValidatorState : StakingStates() {
data class Data(

View file

@ -9,4 +9,14 @@ object StakingClickIntentsStub : StakingClickIntents {
override fun onNextClick() {}
override fun onPrevClick() {}
override fun onAmountValueChange(value: String) {}
override fun onAmountPasteTriggerDismiss() {}
override fun onMaxValueClick() {}
override fun onCurrencyChangeClick(isFiat: Boolean) {}
override fun onAmountNext() {}
}

View file

@ -1,10 +1,11 @@
package com.tangem.features.staking.impl.presentation.state.transformers
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.transformer.Transformer
internal class HideBalanceStateTransformer(
private val isBalanceHidden: Boolean,
) : StakingScreenStateTransformer {
) : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
return prevState.copy(isBalanceHidden = isBalanceHidden)

View file

@ -1,31 +1,52 @@
package com.tangem.features.staking.impl.presentation.state.transformers
import com.tangem.common.ui.amountScreen.converters.AmountStateConverter
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.core.ui.components.currency.tokenicon.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.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.staking.model.Yield
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.staking.impl.R
import com.tangem.features.staking.impl.presentation.state.StakingStates
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.features.staking.impl.presentation.state.StakingStep
import com.tangem.features.staking.impl.presentation.viewmodel.StakingClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.transformer.Transformer
import java.math.BigDecimal
internal class SetInitialDataStateTransformer(
private val clickIntents: StakingClickIntents,
private val yield: Yield,
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
) : StakingScreenStateTransformer {
private val userWalletProvider: Provider<UserWallet>,
private val appCurrencyProvider: Provider<AppCurrency>,
) : Transformer<StakingUiState> {
private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter)
private val amountStateConverter by lazy(LazyThreadSafetyMode.NONE) {
AmountStateConverter(
clickIntents = clickIntents,
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
appCurrencyProvider = appCurrencyProvider,
userWalletProvider = userWalletProvider,
iconStateConverter = iconStateConverter,
)
}
override fun transform(prevState: StakingUiState): StakingUiState {
return prevState.copy(
clickIntents = clickIntents,
currentStep = StakingStep.InitialInfo,
initialInfoState = createInitialInfoState(),
amountState = createInitialAmountState(),
)
}
@ -50,6 +71,10 @@ internal class SetInitialDataStateTransformer(
)
}
private fun createInitialAmountState(): AmountState {
return amountStateConverter.convert("")
}
private fun getAprRange(): TextReference {
val aprValues = yield.validators.mapNotNull { it.apr }

View file

@ -1,8 +0,0 @@
package com.tangem.features.staking.impl.presentation.state.transformers
import com.tangem.features.staking.impl.presentation.state.StakingUiState
internal interface StakingScreenStateTransformer {
fun transform(prevState: StakingUiState): StakingUiState
}

View file

@ -0,0 +1,18 @@
package com.tangem.features.staking.impl.presentation.state.transformers.amount
import com.tangem.common.ui.amountScreen.converters.field.AmountFieldChangeTransformer
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.transformer.Transformer
internal class AmountChangeStateTransformer(
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val value: String,
) : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
return prevState.copy(
amountState = AmountFieldChangeTransformer(cryptoCurrencyStatus, value).transform(prevState.amountState),
)
}
}

View file

@ -0,0 +1,17 @@
package com.tangem.features.staking.impl.presentation.state.transformers.amount
import com.tangem.common.ui.amountScreen.converters.AmountCurrencyTransformer
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.transformer.Transformer
internal class AmountCurrencyChangeStateTransformer(
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val value: Boolean,
) : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
return prevState.copy(
amountState = AmountCurrencyTransformer(cryptoCurrencyStatus, value).transform(prevState.amountState),
)
}
}

View file

@ -0,0 +1,16 @@
package com.tangem.features.staking.impl.presentation.state.transformers.amount
import com.tangem.common.ui.amountScreen.converters.field.AmountFieldMaxAmountTransformer
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.transformer.Transformer
internal class AmountMaxValueStateTransformer(
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
) : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
return prevState.copy(
amountState = AmountFieldMaxAmountTransformer(cryptoCurrencyStatus).transform(prevState.amountState),
)
}
}

View file

@ -0,0 +1,14 @@
package com.tangem.features.staking.impl.presentation.state.transformers.amount
import com.tangem.common.ui.amountScreen.converters.AmountPastedTriggerDismissTransformer
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.utils.transformer.Transformer
internal class AmountPasteDismissStateTransformer : Transformer<StakingUiState> {
override fun transform(prevState: StakingUiState): StakingUiState {
return prevState.copy(
amountState = AmountPastedTriggerDismissTransformer().transform(prevState.amountState),
)
}
}

View file

@ -1,11 +0,0 @@
package com.tangem.features.staking.impl.presentation.ui
import androidx.compose.runtime.Composable
import com.tangem.features.staking.impl.presentation.state.StakingStates
@Composable
internal fun StakingAmountContent(state: StakingStates.AmountState) {
if (state !is StakingStates.AmountState.Data) return
// TODO staking
}

View file

@ -12,11 +12,12 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.tangem.common.ui.amountScreen.AmountScreenContent
import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.staking.impl.R
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.features.staking.impl.presentation.state.StakingStep
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
@ -121,8 +122,10 @@ private fun StakingScreenContent(uiState: StakingUiState, modifier: Modifier = M
StakingStep.InitialInfo -> StakingInitialInfoContent(
state = uiState.initialInfoState,
)
StakingStep.Amount -> StakingAmountContent(
state = uiState.amountState,
StakingStep.Amount -> AmountScreenContent(
amountState = uiState.amountState,
isBalanceHiding = uiState.isBalanceHidden,
clickIntents = uiState.clickIntents,
)
StakingStep.ValidatorAndFee -> StakingValidatorAndFeeContent(
state = uiState.validatorState,

View file

@ -1,10 +1,14 @@
package com.tangem.features.staking.impl.presentation.viewmodel
internal interface StakingClickIntents {
import com.tangem.common.ui.amountScreen.AmountScreenClickIntents
internal interface StakingClickIntents : AmountScreenClickIntents {
fun onBackClick()
fun onNextClick()
fun onPrevClick()
override fun onAmountNext() = onNextClick()
}

View file

@ -4,19 +4,28 @@ import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import arrow.core.getOrElse
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.staking.model.Yield
import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase
import com.tangem.domain.tokens.model.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.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.staking.api.navigation.StakingRouter
import com.tangem.features.staking.impl.navigation.InnerStakingRouter
import com.tangem.features.staking.impl.presentation.state.StakingStateController
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.features.staking.impl.presentation.state.StakingStateRouter
import com.tangem.features.staking.impl.presentation.state.StakingUiState
import com.tangem.features.staking.impl.presentation.state.transformers.HideBalanceStateTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.SetInitialDataStateTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.amount.AmountChangeStateTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.amount.AmountCurrencyChangeStateTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.amount.AmountMaxValueStateTransformer
import com.tangem.features.staking.impl.presentation.state.transformers.amount.AmountPasteDismissStateTransformer
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.lifecycle.HiltViewModel
@ -25,12 +34,15 @@ import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.properties.Delegates
@Suppress("LongParameterList")
@HiltViewModel
internal class StakingViewModel @Inject constructor(
private val stateController: StakingStateController,
private val dispatchers: CoroutineDispatcherProvider,
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
private val getCryptoCurrencyStatusSyncUseCase: GetCryptoCurrencyStatusSyncUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getUserWalletUseCase: GetUserWalletUseCase,
savedStateHandle: SavedStateHandle,
) : ViewModel(), DefaultLifecycleObserver, StakingClickIntents {
@ -53,6 +65,8 @@ internal class StakingViewModel @Inject constructor(
private var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
private var innerRouter: InnerStakingRouter by Delegates.notNull()
private var userWallet: UserWallet by Delegates.notNull()
private val selectedAppCurrencyFlow: StateFlow<AppCurrency> = createSelectedAppCurrencyFlow()
init {
subscribeOnBalanceHiding()
@ -71,6 +85,22 @@ internal class StakingViewModel @Inject constructor(
stakingStateRouter.onBackClick()
}
override fun onAmountValueChange(value: String) {
stateController.update(AmountChangeStateTransformer(cryptoCurrencyStatus, value))
}
override fun onAmountPasteTriggerDismiss() {
stateController.update(AmountPasteDismissStateTransformer())
}
override fun onMaxValueClick() {
stateController.update(AmountMaxValueStateTransformer(cryptoCurrencyStatus))
}
override fun onCurrencyChangeClick(isFiat: Boolean) {
stateController.update(AmountCurrencyChangeStateTransformer(cryptoCurrencyStatus, isFiat))
}
fun setRouter(router: InnerStakingRouter, stateRouter: StakingStateRouter) {
innerRouter = router
this.stakingStateRouter = stateRouter
@ -78,6 +108,14 @@ internal class StakingViewModel @Inject constructor(
private fun subscribeOnCurrencyStatusUpdates() {
viewModelScope.launch {
getUserWalletUseCase(userWalletId).fold(
ifRight = { wallet ->
userWallet = wallet
},
ifLeft = {
// TODO staking error
},
)
getCryptoCurrencyStatusSyncUseCase(userWalletId, cryptoCurrencyId).fold(
ifRight = {
cryptoCurrencyStatus = it
@ -86,6 +124,8 @@ internal class StakingViewModel @Inject constructor(
clickIntents = this@StakingViewModel,
yield = yield,
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
userWalletProvider = Provider { userWallet },
appCurrencyProvider = Provider { selectedAppCurrencyFlow.value },
),
)
},
@ -106,4 +146,19 @@ internal class StakingViewModel @Inject constructor(
.flowOn(dispatchers.main)
.launchIn(viewModelScope)
}
private fun createSelectedAppCurrencyFlow(): StateFlow<AppCurrency> {
return getSelectedAppCurrencyUseCase()
.conflate()
.distinctUntilChanged()
.map { maybeAppCurrency ->
maybeAppCurrency.getOrElse { AppCurrency.Default }
}
.flowOn(dispatchers.main)
.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
initialValue = AppCurrency.Default,
)
}
}