Updated on 2026-08-14
This commit is contained in:
parent
f5eaca92f6
commit
dea7034aad
26 changed files with 349 additions and 716 deletions
|
|
@ -67,7 +67,6 @@ import com.tangem.features.staking.impl.navigation.InnerStakingRouter
|
|||
import com.tangem.features.staking.impl.presentation.state.*
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
|
||||
import com.tangem.features.staking.impl.presentation.state.events.StakingAlertUM
|
||||
import com.tangem.features.staking.impl.presentation.state.events.StakingEvent
|
||||
import com.tangem.features.staking.impl.presentation.state.events.StakingEventFactory
|
||||
import com.tangem.features.staking.impl.presentation.state.helpers.StakingBalanceUpdater
|
||||
import com.tangem.features.staking.impl.presentation.state.helpers.StakingFeeLoader
|
||||
|
|
@ -249,7 +248,7 @@ internal class StakingModel @Inject constructor(
|
|||
|
||||
private val stakingEventFactory: StakingEventFactory
|
||||
get() = StakingEventFactory(
|
||||
stateController = stateController,
|
||||
messageSender = messageSender,
|
||||
popBackStack = ::onBackClick,
|
||||
onFailedTxEmailClick = ::onFailedTxEmailClick,
|
||||
)
|
||||
|
|
@ -503,11 +502,7 @@ internal class StakingModel @Inject constructor(
|
|||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
)
|
||||
stateController.updateEvent(
|
||||
StakingEvent.ShowAlert(
|
||||
StakingAlertUM.FeeIncreased(stateController::dismissAlert),
|
||||
),
|
||||
)
|
||||
messageSender.send(StakingAlertUM.feeIncreased {})
|
||||
updateNotifications()
|
||||
},
|
||||
onTransactionExpired = {
|
||||
|
|
@ -571,9 +566,7 @@ internal class StakingModel @Inject constructor(
|
|||
|
||||
override fun onAmountEnterClick() {
|
||||
if (integration.preferredTargets.isEmpty()) {
|
||||
stateController.updateEvent(
|
||||
StakingEvent.ShowAlert(StakingAlertUM.NoAvailableValidators),
|
||||
)
|
||||
messageSender.send(StakingAlertUM.noAvailableValidators())
|
||||
} else {
|
||||
if (uiState.value.actionType is StakingActionCommonType.Enter) {
|
||||
stateController.updateAll(
|
||||
|
|
@ -1047,11 +1040,7 @@ internal class StakingModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun showPrimaryClickAlert() {
|
||||
stateController.updateEvent(
|
||||
StakingEvent.ShowAlert(
|
||||
StakingAlertUM.StakeMoreClickUnavailable(cryptoCurrencyStatus.currency),
|
||||
),
|
||||
)
|
||||
messageSender.send(StakingAlertUM.stakeMoreClickUnavailable(cryptoCurrencyStatus.currency))
|
||||
}
|
||||
|
||||
override fun onOpenLearnMoreAboutApproveClick() {
|
||||
|
|
|
|||
|
|
@ -3,12 +3,9 @@ package com.tangem.features.staking.impl.presentation.state
|
|||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.common.ui.navigationButtons.NavigationButtonsState
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.event.triggeredEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.features.staking.impl.presentation.state.events.StakingEvent
|
||||
import com.tangem.features.staking.impl.presentation.state.stub.StakingClickIntentsStub
|
||||
import com.tangem.features.staking.impl.presentation.state.transformers.SetButtonsStateTransformer
|
||||
import com.tangem.features.staking.impl.presentation.state.transformers.SetTitleTransformer
|
||||
|
|
@ -72,16 +69,6 @@ internal class StakingStateController @Inject constructor(
|
|||
mutableUiState.update(function = titleTransformer::transform)
|
||||
}
|
||||
|
||||
fun updateEvent(event: StakingEvent?) {
|
||||
mutableUiState.update {
|
||||
it.copy(event = event?.let { triggeredEvent(event, ::dismissAlert) } ?: consumedEvent())
|
||||
}
|
||||
}
|
||||
|
||||
fun dismissAlert() {
|
||||
mutableUiState.update { it.copy(event = consumedEvent()) }
|
||||
}
|
||||
|
||||
private fun getInitialState(): StakingUiState {
|
||||
return StakingUiState(
|
||||
title = TextReference.EMPTY,
|
||||
|
|
@ -98,7 +85,6 @@ internal class StakingStateController @Inject constructor(
|
|||
rewardsValidatorsState = StakingStates.RewardsValidatorsState.Empty(),
|
||||
confirmationState = StakingStates.ConfirmationState.Empty(),
|
||||
isBalanceHidden = false,
|
||||
event = consumedEvent(),
|
||||
bottomSheetConfig = null,
|
||||
actionType = StakingActionCommonType.Enter(skipEnterAmount = false),
|
||||
buttonsState = NavigationButtonsState.Empty,
|
||||
|
|
|
|||
|
|
@ -6,14 +6,12 @@ import com.tangem.common.ui.navigationButtons.NavigationButtonsState
|
|||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.list.RoundedListWithDividersItemData
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.domain.models.staking.PendingAction
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
|
||||
import com.tangem.features.staking.impl.presentation.state.events.StakingEvent
|
||||
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
|
@ -40,7 +38,6 @@ internal data class StakingUiState(
|
|||
val bottomSheetConfig: TangemBottomSheetConfig?,
|
||||
val actionType: StakingActionCommonType,
|
||||
val buttonsState: NavigationButtonsState,
|
||||
val event: StateEvent<StakingEvent>,
|
||||
val balanceState: BalanceState?,
|
||||
val showColdWalletInteractionIcon: Boolean,
|
||||
val shouldShowHoldToConfirmButton: Boolean,
|
||||
|
|
|
|||
|
|
@ -1,85 +1,74 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.events
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.common.ui.alerts.models.AlertUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.core.ui.message.EventMessageAction
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.features.staking.impl.R
|
||||
|
||||
@Immutable
|
||||
internal sealed class StakingAlertUM : AlertUM {
|
||||
internal object StakingAlertUM {
|
||||
|
||||
data class GenericError(
|
||||
override val onConfirmClick: () -> Unit,
|
||||
) : StakingAlertUM() {
|
||||
override val title: TextReference = resourceReference(R.string.common_error)
|
||||
override val message: TextReference = resourceReference(R.string.common_unknown_error)
|
||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_support)
|
||||
}
|
||||
fun genericError(onConfirmClick: () -> Unit): DialogMessage = DialogMessage(
|
||||
title = resourceReference(R.string.common_error),
|
||||
message = resourceReference(R.string.common_unknown_error),
|
||||
firstAction = EventMessageAction(
|
||||
title = resourceReference(id = R.string.common_support),
|
||||
onClick = onConfirmClick,
|
||||
),
|
||||
)
|
||||
|
||||
data class StakingError(
|
||||
val code: String,
|
||||
override val onConfirmClick: () -> Unit,
|
||||
) : StakingAlertUM() {
|
||||
override val title: TextReference = resourceReference(R.string.common_error)
|
||||
override val message: TextReference = resourceReference(R.string.generic_error_code, wrappedList(code))
|
||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_support)
|
||||
}
|
||||
fun stakingError(code: String, onConfirmClick: () -> Unit): DialogMessage = DialogMessage(
|
||||
title = resourceReference(R.string.common_error),
|
||||
message = resourceReference(R.string.generic_error_code, wrappedList(code)),
|
||||
firstAction = EventMessageAction(
|
||||
title = resourceReference(id = R.string.common_support),
|
||||
onClick = onConfirmClick,
|
||||
),
|
||||
)
|
||||
|
||||
data object NoAvailableValidators : StakingAlertUM() {
|
||||
override val title = resourceReference(R.string.common_error)
|
||||
override val message = resourceReference(R.string.staking_no_validators_error_message)
|
||||
override val confirmButtonText = resourceReference(R.string.common_ok)
|
||||
override val onConfirmClick = null
|
||||
}
|
||||
fun noAvailableValidators(): DialogMessage = DialogMessage(
|
||||
title = resourceReference(R.string.common_error),
|
||||
message = resourceReference(R.string.staking_no_validators_error_message),
|
||||
)
|
||||
|
||||
data class FeeIncreased(
|
||||
override val onConfirmClick: () -> Unit,
|
||||
) : StakingAlertUM() {
|
||||
override val title: TextReference? = null
|
||||
override val message: TextReference = resourceReference(id = R.string.send_notification_high_fee_title)
|
||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
||||
}
|
||||
fun feeIncreased(onConfirmClick: () -> Unit): DialogMessage = DialogMessage(
|
||||
title = null,
|
||||
message = resourceReference(id = R.string.send_notification_high_fee_title),
|
||||
firstAction = EventMessageAction(
|
||||
title = resourceReference(id = R.string.common_ok),
|
||||
onClick = onConfirmClick,
|
||||
),
|
||||
)
|
||||
|
||||
data object ValidatorsUnavailable : StakingAlertUM() {
|
||||
override val onConfirmClick: (() -> Unit)? = null
|
||||
override val title: TextReference = resourceReference(id = R.string.staking_error_no_validators_title)
|
||||
override val message: TextReference = resourceReference(id = R.string.staking_error_no_validators_message)
|
||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
||||
}
|
||||
fun validatorsUnavailable(): DialogMessage = DialogMessage(
|
||||
title = resourceReference(id = R.string.staking_error_no_validators_title),
|
||||
message = resourceReference(id = R.string.staking_error_no_validators_message),
|
||||
)
|
||||
|
||||
data class StakeMoreClickUnavailable(
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
) : StakingAlertUM() {
|
||||
override val onConfirmClick: (() -> Unit)? = null
|
||||
override val title: TextReference? = null
|
||||
override val message: TextReference = resourceReference(
|
||||
fun stakeMoreClickUnavailable(cryptoCurrency: CryptoCurrency): DialogMessage = DialogMessage(
|
||||
title = null,
|
||||
message = resourceReference(
|
||||
id = R.string.staking_stake_more_button_unavailability_reason,
|
||||
wrappedList(cryptoCurrency.name, cryptoCurrency.symbol),
|
||||
)
|
||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
data class RewardsMinimumRequirementsError(
|
||||
val cryptoCurrencyName: String,
|
||||
val cryptoAmountValue: String,
|
||||
) : StakingAlertUM() {
|
||||
override val onConfirmClick: (() -> Unit)? = null
|
||||
override val title: TextReference? = null
|
||||
override val message: TextReference = resourceReference(
|
||||
id = R.string.staking_details_min_rewards_notification,
|
||||
formatArgs = wrappedList(cryptoCurrencyName, cryptoAmountValue),
|
||||
fun rewardsMinimumRequirementsError(cryptoCurrencyName: String, cryptoAmountValue: String): DialogMessage =
|
||||
DialogMessage(
|
||||
title = null,
|
||||
message = resourceReference(
|
||||
id = R.string.staking_details_min_rewards_notification,
|
||||
formatArgs = wrappedList(cryptoCurrencyName, cryptoAmountValue),
|
||||
),
|
||||
)
|
||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
||||
}
|
||||
|
||||
data class NetworkFeeUpdated(
|
||||
override val onConfirmClick: () -> Unit,
|
||||
) : StakingAlertUM() {
|
||||
override val title: TextReference = resourceReference(R.string.staking_alert_network_fee_updated_title)
|
||||
override val message: TextReference = resourceReference(R.string.staking_alert_network_fee_updated_message)
|
||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
||||
}
|
||||
fun networkFeeUpdated(onConfirmClick: () -> Unit): DialogMessage = DialogMessage(
|
||||
title = resourceReference(R.string.staking_alert_network_fee_updated_title),
|
||||
message = resourceReference(R.string.staking_alert_network_fee_updated_message),
|
||||
firstAction = EventMessageAction(
|
||||
title = resourceReference(id = R.string.common_ok),
|
||||
onClick = onConfirmClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.events
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.common.ui.alerts.models.AlertUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
@Immutable
|
||||
internal sealed class StakingEvent {
|
||||
|
||||
data class ShowSnackBar(val text: TextReference) : StakingEvent()
|
||||
|
||||
data class ShowAlert(val alert: AlertUM) : StakingEvent()
|
||||
}
|
||||
|
|
@ -1,69 +1,63 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.events
|
||||
|
||||
import com.tangem.common.ui.alerts.TransactionErrorAlertConverter
|
||||
import com.tangem.common.ui.alerts.TransactionErrorDialogFactory
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.transaction.error.SendTransactionError
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStateController
|
||||
|
||||
internal class StakingEventFactory(
|
||||
private val stateController: StakingStateController,
|
||||
private val messageSender: UiMessageSender,
|
||||
private val popBackStack: () -> Unit,
|
||||
private val onFailedTxEmailClick: (String) -> Unit,
|
||||
private val transactionErrorDialogFactory: TransactionErrorDialogFactory = TransactionErrorDialogFactory(),
|
||||
) {
|
||||
|
||||
fun createGenericErrorAlert(error: String) {
|
||||
val alert = StakingEvent.ShowAlert(
|
||||
StakingAlertUM.GenericError(
|
||||
messageSender.send(
|
||||
StakingAlertUM.genericError(
|
||||
onConfirmClick = { onFailedTxEmailClick(error) },
|
||||
),
|
||||
)
|
||||
stateController.updateEvent(alert)
|
||||
}
|
||||
|
||||
fun createSendTransactionErrorAlert(error: SendTransactionError?) {
|
||||
val alert = error?.let {
|
||||
TransactionErrorAlertConverter(
|
||||
transactionErrorDialogFactory.create(
|
||||
error = error,
|
||||
popBackStack = popBackStack,
|
||||
onFailedTxEmailClick = onFailedTxEmailClick,
|
||||
).convert(error)
|
||||
}?.let {
|
||||
StakingEvent.ShowAlert(it)
|
||||
)
|
||||
}
|
||||
stateController.updateEvent(alert)
|
||||
alert?.let { messageSender.send(it) }
|
||||
}
|
||||
|
||||
fun createStakingErrorAlert(error: StakingError) {
|
||||
val alert = StakingEvent.ShowAlert(
|
||||
StakingAlertUM.StakingError(
|
||||
messageSender.send(
|
||||
StakingAlertUM.stakingError(
|
||||
code = error.toString(),
|
||||
onConfirmClick = { onFailedTxEmailClick(error.toString()) },
|
||||
),
|
||||
)
|
||||
stateController.updateEvent(alert)
|
||||
}
|
||||
|
||||
fun createStakingValidatorsUnavailableAlert() {
|
||||
val alert = StakingEvent.ShowAlert(alert = StakingAlertUM.ValidatorsUnavailable)
|
||||
stateController.updateEvent(alert)
|
||||
messageSender.send(StakingAlertUM.validatorsUnavailable())
|
||||
}
|
||||
|
||||
fun createStakingRewardsMinimumRequirementsErrorAlert(cryptoCurrencyName: String, cryptoAmountValue: String) {
|
||||
stateController.updateEvent(
|
||||
StakingEvent.ShowAlert(
|
||||
alert = StakingAlertUM.RewardsMinimumRequirementsError(
|
||||
cryptoCurrencyName = cryptoCurrencyName,
|
||||
cryptoAmountValue = cryptoAmountValue,
|
||||
),
|
||||
messageSender.send(
|
||||
StakingAlertUM.rewardsMinimumRequirementsError(
|
||||
cryptoCurrencyName = cryptoCurrencyName,
|
||||
cryptoAmountValue = cryptoAmountValue,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun createNetworkFeeUpdatedAlert(onConfirm: () -> Unit) {
|
||||
val alert = StakingEvent.ShowAlert(
|
||||
alert = StakingAlertUM.NetworkFeeUpdated(
|
||||
messageSender.send(
|
||||
StakingAlertUM.networkFeeUpdated(
|
||||
onConfirmClick = onConfirm,
|
||||
),
|
||||
)
|
||||
stateController.updateEvent(alert)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
package com.tangem.features.staking.impl.presentation.ui
|
||||
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import com.tangem.common.ui.alerts.models.AlertUM
|
||||
import com.tangem.core.ui.components.BasicDialog
|
||||
import com.tangem.core.ui.components.DialogButtonUM
|
||||
import com.tangem.core.ui.event.EventEffect
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.events.StakingEvent
|
||||
|
||||
@Composable
|
||||
internal fun StakingEventEffect(event: StateEvent<StakingEvent>, snackbarHostState: SnackbarHostState) {
|
||||
val resources = LocalContext.current.resources
|
||||
var alertConfig by remember { mutableStateOf<AlertUM?>(value = null) }
|
||||
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
LaunchedEffect(key1 = alertConfig) {
|
||||
keyboardController?.hide()
|
||||
}
|
||||
|
||||
alertConfig?.let {
|
||||
StakingAlert(state = it, onDismiss = { alertConfig = null })
|
||||
}
|
||||
|
||||
EventEffect(
|
||||
event = event,
|
||||
onTrigger = { value ->
|
||||
when (value) {
|
||||
is StakingEvent.ShowSnackBar -> {
|
||||
snackbarHostState.showSnackbar(message = value.text.resolveReference(resources))
|
||||
}
|
||||
is StakingEvent.ShowAlert -> {
|
||||
alertConfig = value.alert
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun StakingAlert(state: AlertUM, onDismiss: () -> Unit) {
|
||||
val confirmButton: DialogButtonUM
|
||||
val dismissButton: DialogButtonUM?
|
||||
|
||||
val onActionClick = state.onConfirmClick
|
||||
if (onActionClick != null) {
|
||||
confirmButton = DialogButtonUM(
|
||||
title = state.confirmButtonText.resolveReference(),
|
||||
onClick = {
|
||||
onActionClick()
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
|
||||
dismissButton = DialogButtonUM(
|
||||
title = stringResourceSafe(id = R.string.common_cancel),
|
||||
onClick = onDismiss,
|
||||
)
|
||||
} else {
|
||||
confirmButton = DialogButtonUM(
|
||||
title = state.confirmButtonText.resolveReference(),
|
||||
onClick = onDismiss,
|
||||
)
|
||||
dismissButton = null
|
||||
}
|
||||
|
||||
BasicDialog(
|
||||
message = state.message.resolveReference(),
|
||||
confirmButton = confirmButton,
|
||||
onDismissDialog = onDismiss,
|
||||
title = state.title?.resolveReference(),
|
||||
dismissButton = dismissButton,
|
||||
)
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@ import androidx.compose.animation.core.tween
|
|||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -39,7 +38,6 @@ import kotlinx.coroutines.flow.withIndex
|
|||
|
||||
@Composable
|
||||
internal fun StakingScreen(uiState: StakingUiState) {
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val confirmationState = uiState.confirmationState as? StakingStates.ConfirmationState.Data
|
||||
|
||||
BackHandler(onBack = uiState.clickIntents::onPrevClick)
|
||||
|
|
@ -71,11 +69,6 @@ internal fun StakingScreen(uiState: StakingUiState) {
|
|||
)
|
||||
StakingBottomSheet(bottomSheetConfig = uiState.bottomSheetConfig)
|
||||
}
|
||||
|
||||
StakingEventEffect(
|
||||
event = uiState.event,
|
||||
snackbarHostState = snackbarHostState,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue