Updated on 2026-08-14
This commit is contained in:
parent
f5eaca92f6
commit
dea7034aad
26 changed files with 349 additions and 716 deletions
|
|
@ -1,56 +0,0 @@
|
||||||
package com.tangem.common.ui.alerts
|
|
||||||
|
|
||||||
import com.tangem.common.ui.alerts.models.AlertDemoModeUM
|
|
||||||
import com.tangem.common.ui.alerts.models.AlertTransactionErrorUM
|
|
||||||
import com.tangem.common.ui.alerts.models.AlertUM
|
|
||||||
import com.tangem.core.ui.R
|
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
|
||||||
import com.tangem.core.ui.extensions.wrappedList
|
|
||||||
import com.tangem.domain.transaction.error.SendTransactionError
|
|
||||||
import com.tangem.utils.converter.Converter
|
|
||||||
|
|
||||||
class TransactionErrorAlertConverter(
|
|
||||||
private val popBackStack: () -> Unit,
|
|
||||||
private val onFailedTxEmailClick: (String) -> Unit,
|
|
||||||
) : Converter<SendTransactionError, AlertUM?> {
|
|
||||||
override fun convert(value: SendTransactionError): AlertUM? {
|
|
||||||
return when (value) {
|
|
||||||
is SendTransactionError.DemoCardError -> AlertDemoModeUM(
|
|
||||||
onConfirmClick = popBackStack,
|
|
||||||
)
|
|
||||||
is SendTransactionError.TangemSdkError -> AlertTransactionErrorUM(
|
|
||||||
code = value.code.toString(),
|
|
||||||
cause = null,
|
|
||||||
causeTextReference = resourceReference(value.messageRes, wrappedList(value.args)),
|
|
||||||
onConfirmClick = { onFailedTxEmailClick(value.code.toString()) },
|
|
||||||
)
|
|
||||||
is SendTransactionError.BlockchainSdkError -> AlertTransactionErrorUM(
|
|
||||||
code = value.code.toString(),
|
|
||||||
cause = value.message,
|
|
||||||
onConfirmClick = { onFailedTxEmailClick("${value.code}: ${value.message.orEmpty()}") },
|
|
||||||
)
|
|
||||||
is SendTransactionError.DataError -> AlertTransactionErrorUM(
|
|
||||||
code = "",
|
|
||||||
cause = value.message,
|
|
||||||
onConfirmClick = { onFailedTxEmailClick(value.message.orEmpty()) },
|
|
||||||
)
|
|
||||||
is SendTransactionError.NetworkError -> AlertTransactionErrorUM(
|
|
||||||
code = value.code.orEmpty(),
|
|
||||||
cause = value.message.orEmpty(),
|
|
||||||
onConfirmClick = { onFailedTxEmailClick(value.message.orEmpty()) },
|
|
||||||
)
|
|
||||||
is SendTransactionError.UnknownError -> AlertTransactionErrorUM(
|
|
||||||
code = "",
|
|
||||||
cause = value.ex?.localizedMessage,
|
|
||||||
onConfirmClick = { onFailedTxEmailClick(value.ex?.localizedMessage.orEmpty()) },
|
|
||||||
)
|
|
||||||
is SendTransactionError.CreateAccountUnderfunded -> AlertTransactionErrorUM(
|
|
||||||
code = "",
|
|
||||||
cause = null,
|
|
||||||
causeTextReference = resourceReference(R.string.no_account_polkadot, wrappedList(value.amount)),
|
|
||||||
onConfirmClick = popBackStack,
|
|
||||||
)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
package com.tangem.common.ui.alerts
|
||||||
|
|
||||||
|
import com.tangem.common.ui.R
|
||||||
|
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.transaction.error.SendTransactionError
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class TransactionErrorDialogFactory @Inject constructor() {
|
||||||
|
|
||||||
|
fun create(
|
||||||
|
error: SendTransactionError,
|
||||||
|
popBackStack: () -> Unit,
|
||||||
|
onFailedTxEmailClick: (String) -> Unit,
|
||||||
|
): DialogMessage? {
|
||||||
|
return when (error) {
|
||||||
|
is SendTransactionError.DemoCardError -> demoModeDialog(popBackStack)
|
||||||
|
is SendTransactionError.TangemSdkError -> transactionErrorDialog(
|
||||||
|
causeTextReference = resourceReference(error.messageRes, wrappedList(error.args)),
|
||||||
|
code = error.code.toString(),
|
||||||
|
onConfirmClick = { onFailedTxEmailClick(error.code.toString()) },
|
||||||
|
)
|
||||||
|
is SendTransactionError.BlockchainSdkError -> transactionErrorDialog(
|
||||||
|
cause = error.message,
|
||||||
|
code = error.code.toString(),
|
||||||
|
onConfirmClick = { onFailedTxEmailClick("${error.code}: ${error.message.orEmpty()}") },
|
||||||
|
)
|
||||||
|
is SendTransactionError.DataError -> transactionErrorDialog(
|
||||||
|
cause = error.message,
|
||||||
|
code = "",
|
||||||
|
onConfirmClick = { onFailedTxEmailClick(error.message.orEmpty()) },
|
||||||
|
)
|
||||||
|
is SendTransactionError.NetworkError -> transactionErrorDialog(
|
||||||
|
cause = error.message.orEmpty(),
|
||||||
|
code = error.code.orEmpty(),
|
||||||
|
onConfirmClick = { onFailedTxEmailClick(error.message.orEmpty()) },
|
||||||
|
)
|
||||||
|
is SendTransactionError.UnknownError -> transactionErrorDialog(
|
||||||
|
cause = error.ex?.localizedMessage,
|
||||||
|
code = "",
|
||||||
|
onConfirmClick = { onFailedTxEmailClick(error.ex?.localizedMessage.orEmpty()) },
|
||||||
|
)
|
||||||
|
is SendTransactionError.CreateAccountUnderfunded -> transactionErrorDialog(
|
||||||
|
causeTextReference = resourceReference(
|
||||||
|
R.string.no_account_polkadot,
|
||||||
|
wrappedList(error.amount),
|
||||||
|
),
|
||||||
|
code = "",
|
||||||
|
onConfirmClick = popBackStack,
|
||||||
|
)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun demoModeDialog(onConfirmClick: () -> Unit): DialogMessage = DialogMessage(
|
||||||
|
title = resourceReference(id = R.string.warning_demo_mode_title),
|
||||||
|
message = resourceReference(id = R.string.warning_demo_mode_message),
|
||||||
|
firstAction = EventMessageAction(
|
||||||
|
title = resourceReference(id = R.string.common_ok),
|
||||||
|
onClick = onConfirmClick,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun transactionErrorDialog(
|
||||||
|
cause: String? = null,
|
||||||
|
causeTextReference: TextReference? = null,
|
||||||
|
code: String,
|
||||||
|
onConfirmClick: () -> Unit,
|
||||||
|
): DialogMessage = DialogMessage(
|
||||||
|
title = resourceReference(id = R.string.send_alert_transaction_failed_title),
|
||||||
|
message = resourceReference(
|
||||||
|
id = R.string.send_alert_transaction_failed_text,
|
||||||
|
formatArgs = wrappedList(causeTextReference ?: cause.orEmpty(), code),
|
||||||
|
),
|
||||||
|
firstAction = EventMessageAction(
|
||||||
|
title = resourceReference(id = R.string.common_support),
|
||||||
|
onClick = onConfirmClick,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package com.tangem.common.ui.alerts.models
|
|
||||||
|
|
||||||
import com.tangem.common.ui.R
|
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
|
||||||
|
|
||||||
data class AlertDemoModeUM(
|
|
||||||
override val onConfirmClick: () -> Unit,
|
|
||||||
) : AlertUM {
|
|
||||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
|
||||||
override val title: TextReference = resourceReference(id = R.string.warning_demo_mode_title)
|
|
||||||
override val message: TextReference = resourceReference(id = R.string.warning_demo_mode_message)
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package com.tangem.common.ui.alerts.models
|
|
||||||
|
|
||||||
import com.tangem.common.ui.R
|
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
|
||||||
import com.tangem.core.ui.extensions.wrappedList
|
|
||||||
|
|
||||||
data class AlertTransactionErrorUM(
|
|
||||||
val code: String,
|
|
||||||
val cause: String?,
|
|
||||||
val causeTextReference: TextReference? = null,
|
|
||||||
override val onConfirmClick: () -> Unit,
|
|
||||||
) : AlertUM {
|
|
||||||
override val title: TextReference = resourceReference(id = R.string.send_alert_transaction_failed_title)
|
|
||||||
override val message: TextReference = resourceReference(
|
|
||||||
id = R.string.send_alert_transaction_failed_text,
|
|
||||||
formatArgs = wrappedList(causeTextReference ?: cause.orEmpty(), code),
|
|
||||||
)
|
|
||||||
override val confirmButtonText: TextReference =
|
|
||||||
resourceReference(id = R.string.common_support)
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
package com.tangem.common.ui.alerts.models
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
interface AlertUM {
|
|
||||||
val title: TextReference?
|
|
||||||
val message: TextReference
|
|
||||||
val confirmButtonText: TextReference
|
|
||||||
val onConfirmClick: (() -> Unit)?
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
package com.tangem.features.onboarding.v2.common.ui
|
package com.tangem.features.onboarding.v2.common.ui
|
||||||
|
|
||||||
import com.tangem.common.ui.alerts.models.AlertUM
|
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
|
||||||
internal data class OnboardingDialogUM(
|
internal data class OnboardingDialogUM(
|
||||||
override val title: TextReference,
|
val title: TextReference,
|
||||||
override val message: TextReference,
|
val message: TextReference,
|
||||||
val dismissButtonText: TextReference,
|
val dismissButtonText: TextReference,
|
||||||
override val confirmButtonText: TextReference,
|
val confirmButtonText: TextReference,
|
||||||
val dismissWarningColor: Boolean = false,
|
val dismissWarningColor: Boolean = false,
|
||||||
override val onConfirmClick: () -> Unit,
|
val onConfirmClick: () -> Unit,
|
||||||
val onDismissButtonClick: () -> Unit,
|
val onDismissButtonClick: () -> Unit,
|
||||||
val onDismiss: () -> Unit,
|
val onDismiss: () -> Unit,
|
||||||
) : AlertUM
|
)
|
||||||
|
|
@ -3,7 +3,6 @@ package com.tangem.features.onramp.selecttoken.model
|
||||||
import arrow.core.getOrElse
|
import arrow.core.getOrElse
|
||||||
import com.tangem.common.routing.AppRoute
|
import com.tangem.common.routing.AppRoute
|
||||||
import com.tangem.common.routing.AppRouter
|
import com.tangem.common.routing.AppRouter
|
||||||
import com.tangem.common.ui.alerts.models.AlertDemoModeUM
|
|
||||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
|
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
|
||||||
|
|
@ -13,8 +12,8 @@ import com.tangem.core.decompose.model.Model
|
||||||
import com.tangem.core.decompose.model.ParamsContainer
|
import com.tangem.core.decompose.model.ParamsContainer
|
||||||
import com.tangem.core.decompose.ui.UiMessageSender
|
import com.tangem.core.decompose.ui.UiMessageSender
|
||||||
import com.tangem.core.navigation.url.UrlOpener
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.message.DialogMessage
|
import com.tangem.core.ui.message.DialogMessage
|
||||||
import com.tangem.core.ui.message.EventMessageAction
|
|
||||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||||
|
|
@ -159,18 +158,9 @@ internal class OnrampOperationModel @Inject constructor(
|
||||||
|
|
||||||
private fun showErrorIfDemoModeOrElse(action: () -> Unit) {
|
private fun showErrorIfDemoModeOrElse(action: () -> Unit) {
|
||||||
if (selectedUserWallet is UserWallet.Cold && isDemoCardUseCase(cardId = selectedUserWallet.cardId)) {
|
if (selectedUserWallet is UserWallet.Cold && isDemoCardUseCase(cardId = selectedUserWallet.cardId)) {
|
||||||
val alertUM = AlertDemoModeUM(onConfirmClick = {})
|
|
||||||
|
|
||||||
val message = DialogMessage(
|
val message = DialogMessage(
|
||||||
title = alertUM.title,
|
title = resourceReference(id = R.string.warning_demo_mode_title),
|
||||||
message = alertUM.message,
|
message = resourceReference(id = R.string.warning_demo_mode_message),
|
||||||
firstActionBuilder = {
|
|
||||||
EventMessageAction(
|
|
||||||
title = alertUM.confirmButtonText,
|
|
||||||
onClick = alertUM.onConfirmClick,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
secondActionBuilder = { cancelAction() },
|
|
||||||
)
|
)
|
||||||
|
|
||||||
messageSender.send(message)
|
messageSender.send(message)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.tangem.features.send.v2.common
|
package com.tangem.features.send.v2.common
|
||||||
|
|
||||||
import com.tangem.common.ui.alerts.TransactionErrorAlertConverter
|
import com.tangem.common.ui.alerts.TransactionErrorDialogFactory
|
||||||
import com.tangem.common.ui.alerts.models.AlertDemoModeUM
|
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.ui.UiMessageSender
|
import com.tangem.core.decompose.ui.UiMessageSender
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
|
@ -14,6 +13,7 @@ import javax.inject.Inject
|
||||||
@ModelScoped
|
@ModelScoped
|
||||||
internal class SendConfirmAlertFactory @Inject constructor(
|
internal class SendConfirmAlertFactory @Inject constructor(
|
||||||
private val messageSender: UiMessageSender,
|
private val messageSender: UiMessageSender,
|
||||||
|
private val transactionErrorDialogFactory: TransactionErrorDialogFactory,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun getGenericErrorState(onFailedTxEmailClick: () -> Unit, popBack: () -> Unit = {}) {
|
fun getGenericErrorState(onFailedTxEmailClick: () -> Unit, popBack: () -> Unit = {}) {
|
||||||
|
|
@ -31,34 +31,16 @@ internal class SendConfirmAlertFactory @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSendTransactionErrorState(
|
fun getSendTransactionErrorState(
|
||||||
error: SendTransactionError?,
|
error: SendTransactionError,
|
||||||
popBack: () -> Unit,
|
popBack: () -> Unit,
|
||||||
onFailedTxEmailClick: (String) -> Unit,
|
onFailedTxEmailClick: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val transactionErrorAlertConverter = TransactionErrorAlertConverter(
|
val errorDialog = transactionErrorDialogFactory.create(
|
||||||
|
error = error,
|
||||||
popBackStack = popBack,
|
popBackStack = popBack,
|
||||||
onFailedTxEmailClick = onFailedTxEmailClick,
|
onFailedTxEmailClick = onFailedTxEmailClick,
|
||||||
)
|
) ?: return
|
||||||
|
|
||||||
val errorAlert = error?.let { transactionErrorAlertConverter.convert(error) } ?: return
|
messageSender.send(errorDialog)
|
||||||
val onConfirmClick = errorAlert.onConfirmClick ?: return
|
|
||||||
|
|
||||||
messageSender.send(
|
|
||||||
DialogMessage(
|
|
||||||
title = errorAlert.title,
|
|
||||||
message = errorAlert.message,
|
|
||||||
firstActionBuilder = {
|
|
||||||
EventMessageAction(
|
|
||||||
title = errorAlert.confirmButtonText,
|
|
||||||
onClick = onConfirmClick,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
secondActionBuilder = if (errorAlert !is AlertDemoModeUM) {
|
|
||||||
{ cancelAction() }
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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.*
|
||||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
|
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.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.events.StakingEventFactory
|
||||||
import com.tangem.features.staking.impl.presentation.state.helpers.StakingBalanceUpdater
|
import com.tangem.features.staking.impl.presentation.state.helpers.StakingBalanceUpdater
|
||||||
import com.tangem.features.staking.impl.presentation.state.helpers.StakingFeeLoader
|
import com.tangem.features.staking.impl.presentation.state.helpers.StakingFeeLoader
|
||||||
|
|
@ -249,7 +248,7 @@ internal class StakingModel @Inject constructor(
|
||||||
|
|
||||||
private val stakingEventFactory: StakingEventFactory
|
private val stakingEventFactory: StakingEventFactory
|
||||||
get() = StakingEventFactory(
|
get() = StakingEventFactory(
|
||||||
stateController = stateController,
|
messageSender = messageSender,
|
||||||
popBackStack = ::onBackClick,
|
popBackStack = ::onBackClick,
|
||||||
onFailedTxEmailClick = ::onFailedTxEmailClick,
|
onFailedTxEmailClick = ::onFailedTxEmailClick,
|
||||||
)
|
)
|
||||||
|
|
@ -503,11 +502,7 @@ internal class StakingModel @Inject constructor(
|
||||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
stateController.updateEvent(
|
messageSender.send(StakingAlertUM.feeIncreased {})
|
||||||
StakingEvent.ShowAlert(
|
|
||||||
StakingAlertUM.FeeIncreased(stateController::dismissAlert),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
updateNotifications()
|
updateNotifications()
|
||||||
},
|
},
|
||||||
onTransactionExpired = {
|
onTransactionExpired = {
|
||||||
|
|
@ -571,9 +566,7 @@ internal class StakingModel @Inject constructor(
|
||||||
|
|
||||||
override fun onAmountEnterClick() {
|
override fun onAmountEnterClick() {
|
||||||
if (integration.preferredTargets.isEmpty()) {
|
if (integration.preferredTargets.isEmpty()) {
|
||||||
stateController.updateEvent(
|
messageSender.send(StakingAlertUM.noAvailableValidators())
|
||||||
StakingEvent.ShowAlert(StakingAlertUM.NoAvailableValidators),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
if (uiState.value.actionType is StakingActionCommonType.Enter) {
|
if (uiState.value.actionType is StakingActionCommonType.Enter) {
|
||||||
stateController.updateAll(
|
stateController.updateAll(
|
||||||
|
|
@ -1047,11 +1040,7 @@ internal class StakingModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showPrimaryClickAlert() {
|
override fun showPrimaryClickAlert() {
|
||||||
stateController.updateEvent(
|
messageSender.send(StakingAlertUM.stakeMoreClickUnavailable(cryptoCurrencyStatus.currency))
|
||||||
StakingEvent.ShowAlert(
|
|
||||||
StakingAlertUM.StakeMoreClickUnavailable(cryptoCurrencyStatus.currency),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenLearnMoreAboutApproveClick() {
|
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.amountScreen.models.AmountState
|
||||||
import com.tangem.common.ui.navigationButtons.NavigationButtonsState
|
import com.tangem.common.ui.navigationButtons.NavigationButtonsState
|
||||||
import com.tangem.core.navigation.url.UrlOpener
|
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.core.ui.extensions.TextReference
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
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.stub.StakingClickIntentsStub
|
||||||
import com.tangem.features.staking.impl.presentation.state.transformers.SetButtonsStateTransformer
|
import com.tangem.features.staking.impl.presentation.state.transformers.SetButtonsStateTransformer
|
||||||
import com.tangem.features.staking.impl.presentation.state.transformers.SetTitleTransformer
|
import com.tangem.features.staking.impl.presentation.state.transformers.SetTitleTransformer
|
||||||
|
|
@ -72,16 +69,6 @@ internal class StakingStateController @Inject constructor(
|
||||||
mutableUiState.update(function = titleTransformer::transform)
|
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 {
|
private fun getInitialState(): StakingUiState {
|
||||||
return StakingUiState(
|
return StakingUiState(
|
||||||
title = TextReference.EMPTY,
|
title = TextReference.EMPTY,
|
||||||
|
|
@ -98,7 +85,6 @@ internal class StakingStateController @Inject constructor(
|
||||||
rewardsValidatorsState = StakingStates.RewardsValidatorsState.Empty(),
|
rewardsValidatorsState = StakingStates.RewardsValidatorsState.Empty(),
|
||||||
confirmationState = StakingStates.ConfirmationState.Empty(),
|
confirmationState = StakingStates.ConfirmationState.Empty(),
|
||||||
isBalanceHidden = false,
|
isBalanceHidden = false,
|
||||||
event = consumedEvent(),
|
|
||||||
bottomSheetConfig = null,
|
bottomSheetConfig = null,
|
||||||
actionType = StakingActionCommonType.Enter(skipEnterAmount = false),
|
actionType = StakingActionCommonType.Enter(skipEnterAmount = false),
|
||||||
buttonsState = NavigationButtonsState.Empty,
|
buttonsState = NavigationButtonsState.Empty,
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,12 @@ import com.tangem.common.ui.navigationButtons.NavigationButtonsState
|
||||||
import com.tangem.common.ui.notifications.NotificationUM
|
import com.tangem.common.ui.notifications.NotificationUM
|
||||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||||
import com.tangem.core.ui.components.list.RoundedListWithDividersItemData
|
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.extensions.TextReference
|
||||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||||
import com.tangem.domain.models.staking.PendingAction
|
import com.tangem.domain.models.staking.PendingAction
|
||||||
import com.tangem.domain.staking.model.StakingTarget
|
import com.tangem.domain.staking.model.StakingTarget
|
||||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
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.bottomsheet.InfoType
|
||||||
import com.tangem.features.staking.impl.presentation.state.events.StakingEvent
|
|
||||||
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
|
|
@ -40,7 +38,6 @@ internal data class StakingUiState(
|
||||||
val bottomSheetConfig: TangemBottomSheetConfig?,
|
val bottomSheetConfig: TangemBottomSheetConfig?,
|
||||||
val actionType: StakingActionCommonType,
|
val actionType: StakingActionCommonType,
|
||||||
val buttonsState: NavigationButtonsState,
|
val buttonsState: NavigationButtonsState,
|
||||||
val event: StateEvent<StakingEvent>,
|
|
||||||
val balanceState: BalanceState?,
|
val balanceState: BalanceState?,
|
||||||
val showColdWalletInteractionIcon: Boolean,
|
val showColdWalletInteractionIcon: Boolean,
|
||||||
val shouldShowHoldToConfirmButton: Boolean,
|
val shouldShowHoldToConfirmButton: Boolean,
|
||||||
|
|
|
||||||
|
|
@ -1,85 +1,74 @@
|
||||||
package com.tangem.features.staking.impl.presentation.state.events
|
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.resourceReference
|
||||||
import com.tangem.core.ui.extensions.wrappedList
|
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.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.features.staking.impl.R
|
import com.tangem.features.staking.impl.R
|
||||||
|
|
||||||
@Immutable
|
internal object StakingAlertUM {
|
||||||
internal sealed class StakingAlertUM : AlertUM {
|
|
||||||
|
|
||||||
data class GenericError(
|
fun genericError(onConfirmClick: () -> Unit): DialogMessage = DialogMessage(
|
||||||
override val onConfirmClick: () -> Unit,
|
title = resourceReference(R.string.common_error),
|
||||||
) : StakingAlertUM() {
|
message = resourceReference(R.string.common_unknown_error),
|
||||||
override val title: TextReference = resourceReference(R.string.common_error)
|
firstAction = EventMessageAction(
|
||||||
override val message: TextReference = resourceReference(R.string.common_unknown_error)
|
title = resourceReference(id = R.string.common_support),
|
||||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_support)
|
onClick = onConfirmClick,
|
||||||
}
|
),
|
||||||
|
)
|
||||||
|
|
||||||
data class StakingError(
|
fun stakingError(code: String, onConfirmClick: () -> Unit): DialogMessage = DialogMessage(
|
||||||
val code: String,
|
title = resourceReference(R.string.common_error),
|
||||||
override val onConfirmClick: () -> Unit,
|
message = resourceReference(R.string.generic_error_code, wrappedList(code)),
|
||||||
) : StakingAlertUM() {
|
firstAction = EventMessageAction(
|
||||||
override val title: TextReference = resourceReference(R.string.common_error)
|
title = resourceReference(id = R.string.common_support),
|
||||||
override val message: TextReference = resourceReference(R.string.generic_error_code, wrappedList(code))
|
onClick = onConfirmClick,
|
||||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_support)
|
),
|
||||||
}
|
)
|
||||||
|
|
||||||
data object NoAvailableValidators : StakingAlertUM() {
|
fun noAvailableValidators(): DialogMessage = DialogMessage(
|
||||||
override val title = resourceReference(R.string.common_error)
|
title = resourceReference(R.string.common_error),
|
||||||
override val message = resourceReference(R.string.staking_no_validators_error_message)
|
message = resourceReference(R.string.staking_no_validators_error_message),
|
||||||
override val confirmButtonText = resourceReference(R.string.common_ok)
|
)
|
||||||
override val onConfirmClick = null
|
|
||||||
}
|
|
||||||
|
|
||||||
data class FeeIncreased(
|
fun feeIncreased(onConfirmClick: () -> Unit): DialogMessage = DialogMessage(
|
||||||
override val onConfirmClick: () -> Unit,
|
title = null,
|
||||||
) : StakingAlertUM() {
|
message = resourceReference(id = R.string.send_notification_high_fee_title),
|
||||||
override val title: TextReference? = null
|
firstAction = EventMessageAction(
|
||||||
override val message: TextReference = resourceReference(id = R.string.send_notification_high_fee_title)
|
title = resourceReference(id = R.string.common_ok),
|
||||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
onClick = onConfirmClick,
|
||||||
}
|
),
|
||||||
|
)
|
||||||
|
|
||||||
data object ValidatorsUnavailable : StakingAlertUM() {
|
fun validatorsUnavailable(): DialogMessage = DialogMessage(
|
||||||
override val onConfirmClick: (() -> Unit)? = null
|
title = resourceReference(id = R.string.staking_error_no_validators_title),
|
||||||
override val title: TextReference = resourceReference(id = R.string.staking_error_no_validators_title)
|
message = resourceReference(id = R.string.staking_error_no_validators_message),
|
||||||
override val message: TextReference = resourceReference(id = R.string.staking_error_no_validators_message)
|
)
|
||||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
data class StakeMoreClickUnavailable(
|
fun stakeMoreClickUnavailable(cryptoCurrency: CryptoCurrency): DialogMessage = DialogMessage(
|
||||||
val cryptoCurrency: CryptoCurrency,
|
title = null,
|
||||||
) : StakingAlertUM() {
|
message = resourceReference(
|
||||||
override val onConfirmClick: (() -> Unit)? = null
|
|
||||||
override val title: TextReference? = null
|
|
||||||
override val message: TextReference = resourceReference(
|
|
||||||
id = R.string.staking_stake_more_button_unavailability_reason,
|
id = R.string.staking_stake_more_button_unavailability_reason,
|
||||||
wrappedList(cryptoCurrency.name, cryptoCurrency.symbol),
|
wrappedList(cryptoCurrency.name, cryptoCurrency.symbol),
|
||||||
)
|
),
|
||||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
data class RewardsMinimumRequirementsError(
|
fun rewardsMinimumRequirementsError(cryptoCurrencyName: String, cryptoAmountValue: String): DialogMessage =
|
||||||
val cryptoCurrencyName: String,
|
DialogMessage(
|
||||||
val cryptoAmountValue: String,
|
title = null,
|
||||||
) : StakingAlertUM() {
|
message = resourceReference(
|
||||||
override val onConfirmClick: (() -> Unit)? = null
|
id = R.string.staking_details_min_rewards_notification,
|
||||||
override val title: TextReference? = null
|
formatArgs = wrappedList(cryptoCurrencyName, cryptoAmountValue),
|
||||||
override val message: TextReference = 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(
|
fun networkFeeUpdated(onConfirmClick: () -> Unit): DialogMessage = DialogMessage(
|
||||||
override val onConfirmClick: () -> Unit,
|
title = resourceReference(R.string.staking_alert_network_fee_updated_title),
|
||||||
) : StakingAlertUM() {
|
message = resourceReference(R.string.staking_alert_network_fee_updated_message),
|
||||||
override val title: TextReference = resourceReference(R.string.staking_alert_network_fee_updated_title)
|
firstAction = EventMessageAction(
|
||||||
override val message: TextReference = resourceReference(R.string.staking_alert_network_fee_updated_message)
|
title = resourceReference(id = R.string.common_ok),
|
||||||
override val confirmButtonText: TextReference = 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
|
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.staking.model.stakekit.StakingError
|
||||||
import com.tangem.domain.transaction.error.SendTransactionError
|
import com.tangem.domain.transaction.error.SendTransactionError
|
||||||
import com.tangem.features.staking.impl.presentation.state.StakingStateController
|
|
||||||
|
|
||||||
internal class StakingEventFactory(
|
internal class StakingEventFactory(
|
||||||
private val stateController: StakingStateController,
|
private val messageSender: UiMessageSender,
|
||||||
private val popBackStack: () -> Unit,
|
private val popBackStack: () -> Unit,
|
||||||
private val onFailedTxEmailClick: (String) -> Unit,
|
private val onFailedTxEmailClick: (String) -> Unit,
|
||||||
|
private val transactionErrorDialogFactory: TransactionErrorDialogFactory = TransactionErrorDialogFactory(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun createGenericErrorAlert(error: String) {
|
fun createGenericErrorAlert(error: String) {
|
||||||
val alert = StakingEvent.ShowAlert(
|
messageSender.send(
|
||||||
StakingAlertUM.GenericError(
|
StakingAlertUM.genericError(
|
||||||
onConfirmClick = { onFailedTxEmailClick(error) },
|
onConfirmClick = { onFailedTxEmailClick(error) },
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
stateController.updateEvent(alert)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createSendTransactionErrorAlert(error: SendTransactionError?) {
|
fun createSendTransactionErrorAlert(error: SendTransactionError?) {
|
||||||
val alert = error?.let {
|
val alert = error?.let {
|
||||||
TransactionErrorAlertConverter(
|
transactionErrorDialogFactory.create(
|
||||||
|
error = error,
|
||||||
popBackStack = popBackStack,
|
popBackStack = popBackStack,
|
||||||
onFailedTxEmailClick = onFailedTxEmailClick,
|
onFailedTxEmailClick = onFailedTxEmailClick,
|
||||||
).convert(error)
|
)
|
||||||
}?.let {
|
|
||||||
StakingEvent.ShowAlert(it)
|
|
||||||
}
|
}
|
||||||
stateController.updateEvent(alert)
|
alert?.let { messageSender.send(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createStakingErrorAlert(error: StakingError) {
|
fun createStakingErrorAlert(error: StakingError) {
|
||||||
val alert = StakingEvent.ShowAlert(
|
messageSender.send(
|
||||||
StakingAlertUM.StakingError(
|
StakingAlertUM.stakingError(
|
||||||
code = error.toString(),
|
code = error.toString(),
|
||||||
onConfirmClick = { onFailedTxEmailClick(error.toString()) },
|
onConfirmClick = { onFailedTxEmailClick(error.toString()) },
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
stateController.updateEvent(alert)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createStakingValidatorsUnavailableAlert() {
|
fun createStakingValidatorsUnavailableAlert() {
|
||||||
val alert = StakingEvent.ShowAlert(alert = StakingAlertUM.ValidatorsUnavailable)
|
messageSender.send(StakingAlertUM.validatorsUnavailable())
|
||||||
stateController.updateEvent(alert)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createStakingRewardsMinimumRequirementsErrorAlert(cryptoCurrencyName: String, cryptoAmountValue: String) {
|
fun createStakingRewardsMinimumRequirementsErrorAlert(cryptoCurrencyName: String, cryptoAmountValue: String) {
|
||||||
stateController.updateEvent(
|
messageSender.send(
|
||||||
StakingEvent.ShowAlert(
|
StakingAlertUM.rewardsMinimumRequirementsError(
|
||||||
alert = StakingAlertUM.RewardsMinimumRequirementsError(
|
cryptoCurrencyName = cryptoCurrencyName,
|
||||||
cryptoCurrencyName = cryptoCurrencyName,
|
cryptoAmountValue = cryptoAmountValue,
|
||||||
cryptoAmountValue = cryptoAmountValue,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createNetworkFeeUpdatedAlert(onConfirm: () -> Unit) {
|
fun createNetworkFeeUpdatedAlert(onConfirm: () -> Unit) {
|
||||||
val alert = StakingEvent.ShowAlert(
|
messageSender.send(
|
||||||
alert = StakingAlertUM.NetworkFeeUpdated(
|
StakingAlertUM.networkFeeUpdated(
|
||||||
onConfirmClick = onConfirm,
|
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.animation.togetherWith
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -39,7 +38,6 @@ import kotlinx.coroutines.flow.withIndex
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun StakingScreen(uiState: StakingUiState) {
|
internal fun StakingScreen(uiState: StakingUiState) {
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
|
||||||
val confirmationState = uiState.confirmationState as? StakingStates.ConfirmationState.Data
|
val confirmationState = uiState.confirmationState as? StakingStates.ConfirmationState.Data
|
||||||
|
|
||||||
BackHandler(onBack = uiState.clickIntents::onPrevClick)
|
BackHandler(onBack = uiState.clickIntents::onPrevClick)
|
||||||
|
|
@ -71,11 +69,6 @@ internal fun StakingScreen(uiState: StakingUiState) {
|
||||||
)
|
)
|
||||||
StakingBottomSheet(bottomSheetConfig = uiState.bottomSheetConfig)
|
StakingBottomSheet(bottomSheetConfig = uiState.bottomSheetConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
StakingEventEffect(
|
|
||||||
event = uiState.event,
|
|
||||||
snackbarHostState = snackbarHostState,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.tangem.features.swap.v2.impl.common
|
package com.tangem.features.swap.v2.impl.common
|
||||||
|
|
||||||
import com.tangem.common.ui.alerts.TransactionErrorAlertConverter
|
import com.tangem.common.ui.alerts.TransactionErrorDialogFactory
|
||||||
import com.tangem.common.ui.alerts.models.AlertDemoModeUM
|
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.ui.UiMessageSender
|
import com.tangem.core.decompose.ui.UiMessageSender
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
|
@ -25,6 +24,7 @@ internal class SwapAlertFactory @Inject constructor(
|
||||||
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase,
|
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase,
|
||||||
private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase,
|
private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase,
|
||||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||||
|
private val transactionErrorDialogFactory: TransactionErrorDialogFactory,
|
||||||
) {
|
) {
|
||||||
fun getGenericErrorState(expressError: ExpressError, onFailedTxEmailClick: () -> Unit, popBack: () -> Unit = {}) {
|
fun getGenericErrorState(expressError: ExpressError, onFailedTxEmailClick: () -> Unit, popBack: () -> Unit = {}) {
|
||||||
uiMessageSender.send(
|
uiMessageSender.send(
|
||||||
|
|
@ -44,36 +44,21 @@ internal class SwapAlertFactory @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("CanBeNonNullable")
|
||||||
fun getSendTransactionErrorState(
|
fun getSendTransactionErrorState(
|
||||||
error: SendTransactionError?,
|
error: SendTransactionError?,
|
||||||
popBack: () -> Unit,
|
popBack: () -> Unit,
|
||||||
onFailedTxEmailClick: (String) -> Unit,
|
onFailedTxEmailClick: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val transactionErrorAlertConverter = TransactionErrorAlertConverter(
|
if (error == null) return
|
||||||
|
|
||||||
|
val errorDialog = transactionErrorDialogFactory.create(
|
||||||
|
error = error,
|
||||||
popBackStack = popBack,
|
popBackStack = popBack,
|
||||||
onFailedTxEmailClick = onFailedTxEmailClick,
|
onFailedTxEmailClick = onFailedTxEmailClick,
|
||||||
)
|
) ?: return
|
||||||
|
|
||||||
val errorAlert = error?.let { transactionErrorAlertConverter.convert(error) } ?: return
|
uiMessageSender.send(errorDialog)
|
||||||
val onConfirmClick = errorAlert.onConfirmClick ?: return
|
|
||||||
|
|
||||||
uiMessageSender.send(
|
|
||||||
DialogMessage.Companion(
|
|
||||||
title = errorAlert.title,
|
|
||||||
message = errorAlert.message,
|
|
||||||
firstActionBuilder = {
|
|
||||||
EventMessageAction(
|
|
||||||
title = errorAlert.confirmButtonText,
|
|
||||||
onClick = onConfirmClick,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
secondActionBuilder = if (errorAlert !is AlertDemoModeUM) {
|
|
||||||
{ cancelAction() }
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun onFailedTxEmailClick(
|
suspend fun onFailedTxEmailClick(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.tangem.feature.swap.converters
|
package com.tangem.feature.swap.converters
|
||||||
|
|
||||||
import com.tangem.common.ui.alerts.TransactionErrorAlertConverter
|
import com.tangem.common.ui.alerts.TransactionErrorDialogFactory
|
||||||
import com.tangem.common.ui.alerts.models.AlertUM
|
import com.tangem.core.ui.message.DialogMessage
|
||||||
import com.tangem.domain.transaction.error.SendTransactionError
|
import com.tangem.domain.transaction.error.SendTransactionError
|
||||||
import com.tangem.feature.swap.domain.models.ui.SwapTransactionState
|
import com.tangem.feature.swap.domain.models.ui.SwapTransactionState
|
||||||
import com.tangem.feature.swap.models.SwapAlertUM
|
import com.tangem.feature.swap.models.SwapAlertUM
|
||||||
|
|
@ -11,24 +11,25 @@ import com.tangem.utils.converter.Converter
|
||||||
internal class SwapTransactionErrorStateConverter(
|
internal class SwapTransactionErrorStateConverter(
|
||||||
private val onDismiss: () -> Unit,
|
private val onDismiss: () -> Unit,
|
||||||
private val onSupportClick: (String) -> Unit,
|
private val onSupportClick: (String) -> Unit,
|
||||||
) : Converter<SwapTransactionState.Error, AlertUM?> {
|
private val transactionErrorDialogFactory: TransactionErrorDialogFactory = TransactionErrorDialogFactory(),
|
||||||
override fun convert(value: SwapTransactionState.Error): AlertUM? {
|
) : Converter<SwapTransactionState.Error, DialogMessage?> {
|
||||||
|
override fun convert(value: SwapTransactionState.Error): DialogMessage? {
|
||||||
return when (value) {
|
return when (value) {
|
||||||
is SwapTransactionState.Error.TransactionError -> {
|
is SwapTransactionState.Error.TransactionError -> {
|
||||||
when (val error = value.error) {
|
when (val error = value.error) {
|
||||||
is SendTransactionError.UserCancelledError -> return null
|
is SendTransactionError.UserCancelledError -> return null
|
||||||
null -> SwapAlertUM.GenericError(onDismiss)
|
null -> SwapAlertUM.genericError(onDismiss)
|
||||||
else -> TransactionErrorAlertConverter(onDismiss, onSupportClick).convert(error)
|
else -> transactionErrorDialogFactory.create(error, onDismiss, onSupportClick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is SwapTransactionState.Error.ExpressError -> {
|
is SwapTransactionState.Error.ExpressError -> {
|
||||||
SwapAlertUM.ExpressErrorAlert(
|
SwapAlertUM.expressErrorAlert(
|
||||||
message = getExpressErrorMessage(value.error),
|
message = getExpressErrorMessage(value.error),
|
||||||
onConfirmClick = { onSupportClick(value.error.code.toString()) },
|
onConfirmClick = { onSupportClick(value.error.code.toString()) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
SwapTransactionState.Error.UnknownError -> SwapAlertUM.GenericError(onDismiss)
|
SwapTransactionState.Error.UnknownError -> SwapAlertUM.genericError(onDismiss)
|
||||||
is SwapTransactionState.Error.TangemPayWithdrawalError -> SwapAlertUM.GenericError(
|
is SwapTransactionState.Error.TangemPayWithdrawalError -> SwapAlertUM.genericError(
|
||||||
onConfirmClick = { onSupportClick(value.txId) },
|
onConfirmClick = { onSupportClick(value.txId) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,21 @@ import com.tangem.core.analytics.models.Basic
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.model.Model
|
import com.tangem.core.decompose.model.Model
|
||||||
import com.tangem.core.decompose.model.ParamsContainer
|
import com.tangem.core.decompose.model.ParamsContainer
|
||||||
|
import com.tangem.core.decompose.ui.UiMessageSender
|
||||||
import com.tangem.core.navigation.url.UrlOpener
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
import com.tangem.core.ui.HoldToConfirmButtonFeatureToggles
|
import com.tangem.core.ui.HoldToConfirmButtonFeatureToggles
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
|
import com.tangem.core.ui.extensions.combinedReference
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
|
import com.tangem.core.ui.extensions.toWrappedList
|
||||||
|
import com.tangem.core.ui.extensions.wrappedList
|
||||||
|
import com.tangem.core.ui.message.DialogMessage
|
||||||
|
import com.tangem.core.ui.message.EventMessageAction
|
||||||
import com.tangem.core.ui.utils.InputNumberFormatter
|
import com.tangem.core.ui.utils.InputNumberFormatter
|
||||||
|
import com.tangem.core.ui.utils.parseBigDecimal
|
||||||
|
import com.tangem.feature.swap.converters.SwapTransactionErrorStateConverter
|
||||||
|
import com.tangem.feature.swap.models.SwapAlertUM
|
||||||
import com.tangem.datasource.local.appsflyer.AppsFlyerStore
|
import com.tangem.datasource.local.appsflyer.AppsFlyerStore
|
||||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||||
import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus
|
import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus
|
||||||
|
|
@ -165,6 +175,7 @@ internal class SwapModel @Inject constructor(
|
||||||
private val getTangemPayCustomerIdUseCase: GetTangemPayCustomerIdUseCase,
|
private val getTangemPayCustomerIdUseCase: GetTangemPayCustomerIdUseCase,
|
||||||
private val appsFlyerStore: AppsFlyerStore,
|
private val appsFlyerStore: AppsFlyerStore,
|
||||||
private val holdToConfirmButtonFeatureToggles: HoldToConfirmButtonFeatureToggles,
|
private val holdToConfirmButtonFeatureToggles: HoldToConfirmButtonFeatureToggles,
|
||||||
|
private val messageSender: UiMessageSender,
|
||||||
) : Model() {
|
) : Model() {
|
||||||
|
|
||||||
private val params = paramsContainer.require<SwapComponent.Params>()
|
private val params = paramsContainer.require<SwapComponent.Params>()
|
||||||
|
|
@ -349,7 +360,8 @@ internal class SwapModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromAccountStatus == null) {
|
if (fromAccountStatus == null) {
|
||||||
uiState = stateBuilder.addAlert(uiState = uiState, onDismiss = swapRouter::back)
|
showAlert()
|
||||||
|
swapRouter.back()
|
||||||
} else {
|
} else {
|
||||||
fromAccountCurrencyStatus = fromAccountStatus
|
fromAccountCurrencyStatus = fromAccountStatus
|
||||||
toAccountCurrencyStatus = toAccountStatus
|
toAccountCurrencyStatus = toAccountStatus
|
||||||
|
|
@ -367,7 +379,8 @@ internal class SwapModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromStatus == null) {
|
if (fromStatus == null) {
|
||||||
uiState = stateBuilder.addAlert(uiState = uiState, onDismiss = swapRouter::back)
|
showAlert()
|
||||||
|
swapRouter.back()
|
||||||
} else {
|
} else {
|
||||||
initialFromStatus = fromStatus
|
initialFromStatus = fromStatus
|
||||||
initialToStatus = toStatus
|
initialToStatus = toStatus
|
||||||
|
|
@ -1032,7 +1045,7 @@ internal class SwapModel @Inject constructor(
|
||||||
val fee = getSelectedFee()
|
val fee = getSelectedFee()
|
||||||
|
|
||||||
if (fee == null && tangemPayInput?.isWithdrawal != true) {
|
if (fee == null && tangemPayInput?.isWithdrawal != true) {
|
||||||
makeDefaultAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
showAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
delay(SWAP_IN_PROGRESS_DELAY)
|
delay(SWAP_IN_PROGRESS_DELAY)
|
||||||
startLoadingQuotesFromLastState()
|
startLoadingQuotesFromLastState()
|
||||||
|
|
@ -1058,7 +1071,7 @@ internal class SwapModel @Inject constructor(
|
||||||
when (swapTransactionState) {
|
when (swapTransactionState) {
|
||||||
is SwapTransactionState.TxSent -> {
|
is SwapTransactionState.TxSent -> {
|
||||||
if (fee == null) {
|
if (fee == null) {
|
||||||
makeDefaultAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
showAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
||||||
return@onSuccess
|
return@onSuccess
|
||||||
}
|
}
|
||||||
sendSuccessSwapEvent(
|
sendSuccessSwapEvent(
|
||||||
|
|
@ -1102,21 +1115,11 @@ internal class SwapModel @Inject constructor(
|
||||||
swapRouter.openScreen(SwapNavScreen.Success)
|
swapRouter.openScreen(SwapNavScreen.Success)
|
||||||
}
|
}
|
||||||
SwapTransactionState.DemoMode -> {
|
SwapTransactionState.DemoMode -> {
|
||||||
uiState = stateBuilder.createDemoModeAlert(
|
showDemoModeAlert()
|
||||||
uiState = uiState,
|
|
||||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
|
||||||
isReverseSwapPossible = isReverseSwapPossible(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
is SwapTransactionState.Error -> {
|
is SwapTransactionState.Error -> {
|
||||||
startLoadingQuotesFromLastState()
|
startLoadingQuotesFromLastState()
|
||||||
uiState = stateBuilder.createErrorTransactionAlert(
|
showTransactionErrorAlert(swapTransactionState)
|
||||||
uiState = uiState,
|
|
||||||
error = swapTransactionState,
|
|
||||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
|
||||||
onSupportClick = ::onFailedTxEmailClick,
|
|
||||||
isReverseSwapPossible = isReverseSwapPossible(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
is SwapTransactionState.TangemPayWithdrawalData -> {
|
is SwapTransactionState.TangemPayWithdrawalData -> {
|
||||||
processTangemPayWithdrawal(swapTransactionState = swapTransactionState)
|
processTangemPayWithdrawal(swapTransactionState = swapTransactionState)
|
||||||
|
|
@ -1125,7 +1128,7 @@ internal class SwapModel @Inject constructor(
|
||||||
}.onFailure { error ->
|
}.onFailure { error ->
|
||||||
Timber.e(error)
|
Timber.e(error)
|
||||||
startLoadingQuotesFromLastState()
|
startLoadingQuotesFromLastState()
|
||||||
makeDefaultAlert()
|
showAlert()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1217,7 +1220,7 @@ internal class SwapModel @Inject constructor(
|
||||||
}
|
}
|
||||||
val feeForPermission = when (val fee = approveDataModel.fee) {
|
val feeForPermission = when (val fee = approveDataModel.fee) {
|
||||||
TxFeeState.Empty -> {
|
TxFeeState.Empty -> {
|
||||||
makeDefaultAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
showAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
||||||
Timber.e("Fee should not be Empty")
|
Timber.e("Fee should not be Empty")
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
@ -1247,29 +1250,19 @@ internal class SwapModel @Inject constructor(
|
||||||
startLoadingQuotesFromLastState(isSilent = true)
|
startLoadingQuotesFromLastState(isSilent = true)
|
||||||
}
|
}
|
||||||
is SwapTransactionState.Error -> {
|
is SwapTransactionState.Error -> {
|
||||||
uiState = stateBuilder.createErrorTransactionAlert(
|
showTransactionErrorAlert(swapTransactionState)
|
||||||
uiState = uiState,
|
|
||||||
error = swapTransactionState,
|
|
||||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
|
||||||
onSupportClick = ::onFailedTxEmailClick,
|
|
||||||
isReverseSwapPossible = isReverseSwapPossible(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
SwapTransactionState.DemoMode -> {
|
SwapTransactionState.DemoMode -> {
|
||||||
uiState = stateBuilder.createDemoModeAlert(
|
showDemoModeAlert()
|
||||||
uiState = uiState,
|
|
||||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
|
||||||
isReverseSwapPossible = isReverseSwapPossible(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
is SwapTransactionState.TangemPayWithdrawalData -> {
|
is SwapTransactionState.TangemPayWithdrawalData -> {
|
||||||
processTangemPayWithdrawal(swapTransactionState = swapTransactionState)
|
processTangemPayWithdrawal(swapTransactionState = swapTransactionState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onFailure { makeDefaultAlert() }
|
}.onFailure { showAlert() }
|
||||||
}.onFailure { error ->
|
}.onFailure { error ->
|
||||||
Timber.e(error.message.orEmpty())
|
Timber.e(error.message.orEmpty())
|
||||||
makeDefaultAlert()
|
showAlert()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1652,12 +1645,94 @@ internal class SwapModel @Inject constructor(
|
||||||
return inputNumberFormatter.getValidatedNumberWithFixedDecimals(amount, maxDecimals)
|
return inputNumberFormatter.getValidatedNumberWithFixedDecimals(amount, maxDecimals)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeDefaultAlert() {
|
private fun showAlert(message: TextReference = resourceReference(R.string.common_unknown_error)) {
|
||||||
uiState = stateBuilder.addAlert(uiState)
|
messageSender.send(SwapAlertUM.genericError(onConfirmClick = { }, message = message))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeDefaultAlert(message: TextReference) {
|
private fun showDemoModeAlert() {
|
||||||
uiState = stateBuilder.addAlert(uiState, message)
|
messageSender.send(
|
||||||
|
DialogMessage(
|
||||||
|
title = resourceReference(id = R.string.warning_demo_mode_title),
|
||||||
|
message = resourceReference(id = R.string.warning_demo_mode_message),
|
||||||
|
firstAction = EventMessageAction(
|
||||||
|
title = resourceReference(id = R.string.common_ok),
|
||||||
|
onClick = {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showTransactionErrorAlert(
|
||||||
|
error: SwapTransactionState.Error,
|
||||||
|
onSupportClick: (String) -> Unit = ::onFailedTxEmailClick,
|
||||||
|
) {
|
||||||
|
val errorAlert = SwapTransactionErrorStateConverter(
|
||||||
|
onDismiss = {},
|
||||||
|
onSupportClick = onSupportClick,
|
||||||
|
).convert(error)
|
||||||
|
errorAlert?.let { messageSender.send(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onTangemPaySupportClick(txId: String) {
|
||||||
|
modelScope.launch {
|
||||||
|
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch
|
||||||
|
val customerId = getTangemPayCustomerIdUseCase(userWallet.walletId).getOrNull().orEmpty()
|
||||||
|
val email = FeedbackEmailType.Visa.Withdrawal(
|
||||||
|
walletMetaInfo = metaInfo,
|
||||||
|
customerId = customerId,
|
||||||
|
providerName = dataState.selectedProvider?.name.orEmpty(),
|
||||||
|
txId = txId,
|
||||||
|
)
|
||||||
|
sendFeedbackEmailUseCase(email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showSwapInfoAlert(isPriceImpact: Boolean, token: String, provider: SwapProvider) {
|
||||||
|
messageSender.send(
|
||||||
|
SwapAlertUM.informationAlert(
|
||||||
|
message = buildSwapInfoMessage(isPriceImpact, token, provider),
|
||||||
|
onConfirmClick = {},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildSwapInfoMessage(isPriceImpact: Boolean, token: String, provider: SwapProvider): TextReference {
|
||||||
|
val slippage = provider.slippage?.let { "${it.parseBigDecimal(1)}%" }
|
||||||
|
val messages = buildList {
|
||||||
|
when (provider.type) {
|
||||||
|
ExchangeProviderType.CEX -> {
|
||||||
|
if (slippage != null) {
|
||||||
|
add(
|
||||||
|
resourceReference(
|
||||||
|
id = R.string.swapping_alert_cex_description_with_slippage,
|
||||||
|
formatArgs = wrappedList(token, slippage),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
add(resourceReference(R.string.swapping_alert_cex_description, wrappedList(token)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExchangeProviderType.DEX,
|
||||||
|
ExchangeProviderType.DEX_BRIDGE,
|
||||||
|
-> {
|
||||||
|
if (isPriceImpact) {
|
||||||
|
add(resourceReference(R.string.swapping_high_price_impact_description))
|
||||||
|
add(stringReference("\n\n"))
|
||||||
|
}
|
||||||
|
if (slippage != null) {
|
||||||
|
add(
|
||||||
|
resourceReference(
|
||||||
|
id = R.string.swapping_alert_dex_description_with_slippage,
|
||||||
|
formatArgs = wrappedList(slippage),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
add(resourceReference(R.string.swapping_alert_dex_description, wrappedList(token)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return combinedReference(messages.toWrappedList())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||||
|
|
@ -1777,14 +1852,7 @@ internal class SwapModel @Inject constructor(
|
||||||
val selectedProvider = dataState.selectedProvider ?: return@UiActions
|
val selectedProvider = dataState.selectedProvider ?: return@UiActions
|
||||||
val currencySymbol = dataState.toCryptoCurrency?.currency?.symbol ?: return@UiActions
|
val currencySymbol = dataState.toCryptoCurrency?.currency?.symbol ?: return@UiActions
|
||||||
val isPriceImpact = uiState.priceImpact is PriceImpact.Value
|
val isPriceImpact = uiState.priceImpact is PriceImpact.Value
|
||||||
uiState = stateBuilder.createAlert(
|
showSwapInfoAlert(isPriceImpact, currencySymbol, selectedProvider)
|
||||||
uiState = uiState,
|
|
||||||
isPriceImpact = isPriceImpact,
|
|
||||||
token = currencySymbol,
|
|
||||||
provider = selectedProvider,
|
|
||||||
isReverseSwapPossible = isReverseSwapPossible(),
|
|
||||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
onLinkClick = urlOpener::openUrl,
|
onLinkClick = urlOpener::openUrl,
|
||||||
onSelectTokenClick = {
|
onSelectTokenClick = {
|
||||||
|
|
@ -2090,31 +2158,12 @@ internal class SwapModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onTangemPayWithdrawalError(txId: String?) {
|
private fun onTangemPayWithdrawalError(txId: String?) {
|
||||||
uiState = stateBuilder.createErrorTransactionAlert(
|
showTransactionErrorAlert(
|
||||||
uiState = uiState,
|
|
||||||
error = SwapTransactionState.Error.TangemPayWithdrawalError(txId.orEmpty()),
|
error = SwapTransactionState.Error.TangemPayWithdrawalError(txId.orEmpty()),
|
||||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
onSupportClick = ::onTangemPaySupportClick,
|
||||||
onSupportClick = {
|
|
||||||
val customerId = getTangemPayCustomerIdUseCase(userWallet.walletId).getOrNull() ?: "Unknown"
|
|
||||||
onTangemPaySupportClick(customerId = customerId, txId = txId)
|
|
||||||
},
|
|
||||||
isReverseSwapPossible = isReverseSwapPossible(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onTangemPaySupportClick(customerId: String, txId: String?) {
|
|
||||||
modelScope.launch {
|
|
||||||
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch
|
|
||||||
val email = FeedbackEmailType.Visa.Withdrawal(
|
|
||||||
walletMetaInfo = metaInfo,
|
|
||||||
customerId = customerId,
|
|
||||||
providerName = dataState.selectedProvider?.name.orEmpty(),
|
|
||||||
txId = txId.orEmpty(),
|
|
||||||
)
|
|
||||||
sendFeedbackEmailUseCase(email)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onFailedTxEmailClick(errorMessage: String) {
|
private fun onFailedTxEmailClick(errorMessage: String) {
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
val transaction = dataState.swapDataModel?.transaction
|
val transaction = dataState.swapDataModel?.transaction
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,43 @@
|
||||||
package com.tangem.feature.swap.models
|
package com.tangem.feature.swap.models
|
||||||
|
|
||||||
import com.tangem.common.ui.alerts.models.AlertUM
|
|
||||||
import com.tangem.core.ui.R
|
import com.tangem.core.ui.R
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
import com.tangem.core.ui.message.DialogMessage
|
||||||
|
import com.tangem.core.ui.message.EventMessageAction
|
||||||
|
|
||||||
sealed class SwapAlertUM : AlertUM {
|
internal object SwapAlertUM {
|
||||||
|
|
||||||
data class GenericError(
|
fun genericError(
|
||||||
override val onConfirmClick: (() -> Unit),
|
onConfirmClick: () -> Unit,
|
||||||
override val message: TextReference = resourceReference(R.string.common_unknown_error),
|
message: TextReference = resourceReference(R.string.common_unknown_error),
|
||||||
) : SwapAlertUM() {
|
): DialogMessage = DialogMessage(
|
||||||
override val title: TextReference? = null
|
title = null,
|
||||||
override val confirmButtonText: TextReference =
|
message = message,
|
||||||
resourceReference(id = R.string.common_support)
|
firstAction = EventMessageAction(
|
||||||
}
|
title = resourceReference(id = R.string.common_support),
|
||||||
|
onClick = onConfirmClick,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
data class ExpressErrorAlert(
|
fun expressErrorAlert(
|
||||||
override val message: TextReference = resourceReference(R.string.common_unknown_error),
|
message: TextReference = resourceReference(R.string.common_unknown_error),
|
||||||
override val onConfirmClick: (() -> Unit),
|
onConfirmClick: () -> Unit,
|
||||||
) : SwapAlertUM() {
|
): DialogMessage = DialogMessage(
|
||||||
override val title: TextReference? = null
|
title = null,
|
||||||
override val confirmButtonText: TextReference =
|
message = message,
|
||||||
resourceReference(id = R.string.common_support)
|
firstAction = EventMessageAction(
|
||||||
}
|
title = resourceReference(id = R.string.common_support),
|
||||||
|
onClick = onConfirmClick,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
data class InformationAlert(
|
fun informationAlert(message: TextReference, onConfirmClick: () -> Unit): DialogMessage = DialogMessage(
|
||||||
override val message: TextReference,
|
title = resourceReference(R.string.swapping_alert_title),
|
||||||
override val onConfirmClick: (() -> Unit),
|
message = message,
|
||||||
) : SwapAlertUM() {
|
firstAction = EventMessageAction(
|
||||||
override val title: TextReference = resourceReference(
|
title = resourceReference(id = R.string.common_ok),
|
||||||
R.string.swapping_alert_title,
|
onClick = onConfirmClick,
|
||||||
)
|
),
|
||||||
override val confirmButtonText: TextReference =
|
)
|
||||||
resourceReference(id = R.string.common_ok)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -7,14 +7,11 @@ import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionState
|
||||||
import com.tangem.common.ui.notifications.NotificationUM
|
import com.tangem.common.ui.notifications.NotificationUM
|
||||||
import com.tangem.common.ui.swapStoriesScreen.SwapStoriesUM
|
import com.tangem.common.ui.swapStoriesScreen.SwapStoriesUM
|
||||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||||
import com.tangem.core.ui.event.StateEvent
|
|
||||||
import com.tangem.core.ui.event.consumedEvent
|
|
||||||
import com.tangem.core.ui.extensions.TextReference
|
import com.tangem.core.ui.extensions.TextReference
|
||||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
import com.tangem.feature.swap.domain.models.ui.PriceImpact
|
import com.tangem.feature.swap.domain.models.ui.PriceImpact
|
||||||
import com.tangem.feature.swap.models.states.FeeItemState
|
import com.tangem.feature.swap.models.states.FeeItemState
|
||||||
import com.tangem.feature.swap.models.states.ProviderState
|
import com.tangem.feature.swap.models.states.ProviderState
|
||||||
import com.tangem.feature.swap.models.states.events.SwapEvent
|
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
||||||
|
|
@ -24,7 +21,6 @@ internal data class SwapStateHolder(
|
||||||
val blockchainId: String, // not the same as networkId, its local id in app
|
val blockchainId: String, // not the same as networkId, its local id in app
|
||||||
val notifications: ImmutableList<NotificationUM> = persistentListOf(),
|
val notifications: ImmutableList<NotificationUM> = persistentListOf(),
|
||||||
val isInsufficientFunds: Boolean,
|
val isInsufficientFunds: Boolean,
|
||||||
val event: StateEvent<SwapEvent> = consumedEvent(),
|
|
||||||
val changeCardsButtonState: ChangeCardsButtonState,
|
val changeCardsButtonState: ChangeCardsButtonState,
|
||||||
val providerState: ProviderState,
|
val providerState: ProviderState,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
package com.tangem.feature.swap.models.states.events
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import com.tangem.common.ui.alerts.models.AlertUM
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
internal sealed class SwapEvent {
|
|
||||||
data class ShowAlert(val alert: AlertUM) : SwapEvent()
|
|
||||||
}
|
|
||||||
|
|
@ -5,21 +5,17 @@ import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import com.tangem.common.ui.account.AccountTitleUM
|
import com.tangem.common.ui.account.AccountTitleUM
|
||||||
import com.tangem.common.ui.account.CryptoPortfolioIconConverter
|
import com.tangem.common.ui.account.CryptoPortfolioIconConverter
|
||||||
import com.tangem.common.ui.account.toUM
|
import com.tangem.common.ui.account.toUM
|
||||||
import com.tangem.common.ui.alerts.models.AlertDemoModeUM
|
|
||||||
import com.tangem.common.ui.bottomsheet.permission.state.*
|
import com.tangem.common.ui.bottomsheet.permission.state.*
|
||||||
import com.tangem.common.ui.notifications.NotificationUM
|
import com.tangem.common.ui.notifications.NotificationUM
|
||||||
import com.tangem.common.ui.swapStoriesScreen.SwapStoriesFactory
|
import com.tangem.common.ui.swapStoriesScreen.SwapStoriesFactory
|
||||||
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
|
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
|
||||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||||
import com.tangem.core.ui.event.consumedEvent
|
|
||||||
import com.tangem.core.ui.event.triggeredEvent
|
|
||||||
import com.tangem.core.ui.extensions.*
|
import com.tangem.core.ui.extensions.*
|
||||||
import com.tangem.core.ui.format.bigdecimal.anyDecimals
|
import com.tangem.core.ui.format.bigdecimal.anyDecimals
|
||||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||||
import com.tangem.core.ui.format.bigdecimal.format
|
import com.tangem.core.ui.format.bigdecimal.format
|
||||||
import com.tangem.core.ui.utils.parseBigDecimal
|
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.models.account.Account
|
import com.tangem.domain.models.account.Account
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
|
@ -29,7 +25,6 @@ import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.models.wallet.isHotWallet
|
import com.tangem.domain.models.wallet.isHotWallet
|
||||||
import com.tangem.domain.promo.models.StoryContent
|
import com.tangem.domain.promo.models.StoryContent
|
||||||
import com.tangem.domain.transaction.usecase.gasless.IsGaslessFeeSupportedForNetwork
|
import com.tangem.domain.transaction.usecase.gasless.IsGaslessFeeSupportedForNetwork
|
||||||
import com.tangem.feature.swap.converters.SwapTransactionErrorStateConverter
|
|
||||||
import com.tangem.feature.swap.converters.TokensDataConverter
|
import com.tangem.feature.swap.converters.TokensDataConverter
|
||||||
import com.tangem.feature.swap.converters.TokensDataConverterV2
|
import com.tangem.feature.swap.converters.TokensDataConverterV2
|
||||||
import com.tangem.feature.swap.domain.models.ExpressDataError
|
import com.tangem.feature.swap.domain.models.ExpressDataError
|
||||||
|
|
@ -43,12 +38,10 @@ import com.tangem.feature.swap.model.SwapNotificationsFactory
|
||||||
import com.tangem.feature.swap.model.SwapProcessDataState
|
import com.tangem.feature.swap.model.SwapProcessDataState
|
||||||
import com.tangem.feature.swap.models.*
|
import com.tangem.feature.swap.models.*
|
||||||
import com.tangem.feature.swap.models.states.*
|
import com.tangem.feature.swap.models.states.*
|
||||||
import com.tangem.feature.swap.models.states.events.SwapEvent
|
|
||||||
import com.tangem.feature.swap.presentation.R
|
import com.tangem.feature.swap.presentation.R
|
||||||
import com.tangem.feature.swap.utils.formatToUIRepresentation
|
import com.tangem.feature.swap.utils.formatToUIRepresentation
|
||||||
import com.tangem.utils.Provider
|
import com.tangem.utils.Provider
|
||||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||||
import com.tangem.utils.StringsSigns.PERCENT
|
|
||||||
import com.tangem.utils.StringsSigns.TILDE_SIGN
|
import com.tangem.utils.StringsSigns.TILDE_SIGN
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
@ -972,117 +965,6 @@ internal class StateBuilder(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createErrorTransactionAlert(
|
|
||||||
uiState: SwapStateHolder,
|
|
||||||
error: SwapTransactionState.Error,
|
|
||||||
onDismiss: () -> Unit,
|
|
||||||
onSupportClick: (String) -> Unit,
|
|
||||||
isReverseSwapPossible: Boolean,
|
|
||||||
): SwapStateHolder {
|
|
||||||
val errorAlert = SwapTransactionErrorStateConverter(
|
|
||||||
onSupportClick = onSupportClick,
|
|
||||||
onDismiss = onDismiss,
|
|
||||||
).convert(error)
|
|
||||||
return uiState.copy(
|
|
||||||
event = errorAlert?.let {
|
|
||||||
triggeredEvent(
|
|
||||||
data = SwapEvent.ShowAlert(errorAlert),
|
|
||||||
onConsume = onDismiss,
|
|
||||||
)
|
|
||||||
} ?: consumedEvent(),
|
|
||||||
changeCardsButtonState = getChangeCardsButtonState(isReverseSwapPossible),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createDemoModeAlert(
|
|
||||||
uiState: SwapStateHolder,
|
|
||||||
onDismiss: () -> Unit,
|
|
||||||
isReverseSwapPossible: Boolean,
|
|
||||||
): SwapStateHolder {
|
|
||||||
return uiState.copy(
|
|
||||||
event = triggeredEvent(
|
|
||||||
data = SwapEvent.ShowAlert(AlertDemoModeUM(onDismiss)),
|
|
||||||
onConsume = onDismiss,
|
|
||||||
),
|
|
||||||
changeCardsButtonState = getChangeCardsButtonState(isReverseSwapPossible),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
|
||||||
fun createAlert(
|
|
||||||
uiState: SwapStateHolder,
|
|
||||||
isPriceImpact: Boolean,
|
|
||||||
token: String,
|
|
||||||
provider: SwapProvider,
|
|
||||||
onDismiss: () -> Unit,
|
|
||||||
isReverseSwapPossible: Boolean,
|
|
||||||
): SwapStateHolder {
|
|
||||||
val slippage = provider.slippage?.let { "${it.parseBigDecimal(1)}$PERCENT" }
|
|
||||||
val combinedMessage = buildList {
|
|
||||||
when (provider.type) {
|
|
||||||
ExchangeProviderType.CEX -> {
|
|
||||||
if (slippage != null) {
|
|
||||||
add(
|
|
||||||
resourceReference(
|
|
||||||
id = R.string.swapping_alert_cex_description_with_slippage,
|
|
||||||
formatArgs = wrappedList(token, slippage),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
add(resourceReference(R.string.swapping_alert_cex_description, wrappedList(token)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExchangeProviderType.DEX,
|
|
||||||
ExchangeProviderType.DEX_BRIDGE,
|
|
||||||
-> {
|
|
||||||
if (isPriceImpact) {
|
|
||||||
add(resourceReference(R.string.swapping_high_price_impact_description))
|
|
||||||
add(stringReference("\n\n"))
|
|
||||||
}
|
|
||||||
if (slippage != null) {
|
|
||||||
add(
|
|
||||||
resourceReference(
|
|
||||||
id = R.string.swapping_alert_dex_description_with_slippage,
|
|
||||||
formatArgs = wrappedList(slippage),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
add(resourceReference(R.string.swapping_alert_dex_description, wrappedList(token)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return uiState.copy(
|
|
||||||
event = triggeredEvent(
|
|
||||||
SwapEvent.ShowAlert(
|
|
||||||
SwapAlertUM.InformationAlert(
|
|
||||||
message = combinedReference(combinedMessage.toWrappedList()),
|
|
||||||
onConfirmClick = onDismiss,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onConsume = onDismiss,
|
|
||||||
),
|
|
||||||
changeCardsButtonState = getChangeCardsButtonState(isReverseSwapPossible),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addAlert(
|
|
||||||
uiState: SwapStateHolder,
|
|
||||||
message: TextReference = resourceReference(R.string.common_unknown_error),
|
|
||||||
onDismiss: () -> Unit = { clearAlert(uiState) },
|
|
||||||
): SwapStateHolder {
|
|
||||||
return uiState.copy(
|
|
||||||
event = triggeredEvent(
|
|
||||||
SwapEvent.ShowAlert(
|
|
||||||
SwapAlertUM.GenericError(onDismiss, message),
|
|
||||||
),
|
|
||||||
onConsume = onDismiss,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearAlert(uiState: SwapStateHolder): SwapStateHolder = uiState.copy(event = consumedEvent())
|
|
||||||
|
|
||||||
fun addNotification(uiState: SwapStateHolder, message: TextReference?, onClick: () -> Unit): SwapStateHolder {
|
fun addNotification(uiState: SwapStateHolder, message: TextReference?, onClick: () -> Unit): SwapStateHolder {
|
||||||
return uiState.copy(
|
return uiState.copy(
|
||||||
notifications = notificationsFactory.getGeneralErrorStateNotifications(
|
notifications = notificationsFactory.getGeneralErrorStateNotifications(
|
||||||
|
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
package com.tangem.feature.swap.ui
|
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
|
||||||
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.feature.swap.models.states.events.SwapEvent
|
|
||||||
import com.tangem.feature.swap.presentation.R
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
internal fun SwapEventEffect(event: StateEvent<SwapEvent>) {
|
|
||||||
var alertConfig by remember { mutableStateOf<AlertUM?>(value = null) }
|
|
||||||
|
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
|
||||||
LaunchedEffect(key1 = alertConfig) {
|
|
||||||
keyboardController?.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
alertConfig?.let {
|
|
||||||
SwapAlert(state = it, onDismiss = { alertConfig = null })
|
|
||||||
}
|
|
||||||
|
|
||||||
EventEffect(
|
|
||||||
event = event,
|
|
||||||
onTrigger = { value ->
|
|
||||||
when (value) {
|
|
||||||
is SwapEvent.ShowAlert -> {
|
|
||||||
alertConfig = value.alert
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
internal fun SwapAlert(state: AlertUM, onDismiss: () -> Unit) {
|
|
||||||
val confirmButton = DialogButtonUM(
|
|
||||||
title = state.confirmButtonText.resolveReference(),
|
|
||||||
onClick = {
|
|
||||||
state.onConfirmClick?.invoke()
|
|
||||||
onDismiss()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
val dismissButton = DialogButtonUM(
|
|
||||||
title = stringResourceSafe(id = R.string.common_cancel),
|
|
||||||
onClick = onDismiss,
|
|
||||||
)
|
|
||||||
|
|
||||||
BasicDialog(
|
|
||||||
message = state.message.resolveReference(),
|
|
||||||
confirmButton = confirmButton,
|
|
||||||
onDismissDialog = onDismiss,
|
|
||||||
title = state.title?.resolveReference(),
|
|
||||||
dismissButton = dismissButton,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -117,10 +117,6 @@ internal fun SwapScreenContent(
|
||||||
textAlign = TextAlign.Start,
|
textAlign = TextAlign.Start,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SwapEventEffect(
|
|
||||||
event = state.event,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.tangem.features.yield.supply.impl.common
|
package com.tangem.features.yield.supply.impl.common
|
||||||
|
|
||||||
import com.tangem.common.ui.alerts.TransactionErrorAlertConverter
|
import com.tangem.common.ui.alerts.TransactionErrorDialogFactory
|
||||||
import com.tangem.common.ui.alerts.models.AlertDemoModeUM
|
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.ui.UiMessageSender
|
import com.tangem.core.decompose.ui.UiMessageSender
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
|
@ -24,6 +23,7 @@ class YieldSupplyAlertFactory @Inject constructor(
|
||||||
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase,
|
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase,
|
||||||
private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase,
|
private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase,
|
||||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||||
|
private val transactionErrorDialogFactory: TransactionErrorDialogFactory,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun getGenericErrorState(onFailedTxEmailClick: () -> Unit, popBack: () -> Unit = {}) {
|
fun getGenericErrorState(onFailedTxEmailClick: () -> Unit, popBack: () -> Unit = {}) {
|
||||||
|
|
@ -41,35 +41,17 @@ class YieldSupplyAlertFactory @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSendTransactionErrorState(
|
fun getSendTransactionErrorState(
|
||||||
error: SendTransactionError?,
|
error: SendTransactionError,
|
||||||
popBack: () -> Unit,
|
popBack: () -> Unit,
|
||||||
onFailedTxEmailClick: (String) -> Unit,
|
onFailedTxEmailClick: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val transactionErrorAlertConverter = TransactionErrorAlertConverter(
|
val errorDialog = transactionErrorDialogFactory.create(
|
||||||
|
error = error,
|
||||||
popBackStack = popBack,
|
popBackStack = popBack,
|
||||||
onFailedTxEmailClick = onFailedTxEmailClick,
|
onFailedTxEmailClick = onFailedTxEmailClick,
|
||||||
)
|
) ?: return
|
||||||
|
|
||||||
val errorAlert = error?.let { transactionErrorAlertConverter.convert(error) } ?: return
|
uiMessageSender.send(errorDialog)
|
||||||
val onConfirmClick = errorAlert.onConfirmClick ?: return
|
|
||||||
|
|
||||||
uiMessageSender.send(
|
|
||||||
DialogMessage.Companion(
|
|
||||||
title = errorAlert.title,
|
|
||||||
message = errorAlert.message,
|
|
||||||
firstActionBuilder = {
|
|
||||||
EventMessageAction(
|
|
||||||
title = errorAlert.confirmButtonText,
|
|
||||||
onClick = onConfirmClick,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
secondActionBuilder = if (errorAlert !is AlertDemoModeUM) {
|
|
||||||
{ cancelAction() }
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun onFailedTxEmailClick(userWallet: UserWallet, cryptoCurrency: CryptoCurrency?, errorMessage: String?) {
|
suspend fun onFailedTxEmailClick(userWallet: UserWallet, cryptoCurrency: CryptoCurrency?, errorMessage: String?) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue