Updated on 2026-08-14

This commit is contained in:
Tangem 2025-09-26 20:51:27 +05:00
parent 7b5a62d593
commit 0dcf1ed23c
18 changed files with 256 additions and 74 deletions

View file

@ -29,6 +29,7 @@ import com.tangem.features.send.v2.api.subcomponents.feeSelector.FeeSelectorRelo
import com.tangem.features.send.v2.api.subcomponents.feeSelector.analytics.CommonSendFeeAnalyticEvents
import com.tangem.features.send.v2.api.subcomponents.feeSelector.analytics.CommonSendFeeAnalyticEvents.GasPriceInserter
import com.tangem.features.send.v2.feeselector.model.transformers.*
import com.tangem.utils.TangemLinks
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.transformer.update
import kotlinx.coroutines.flow.MutableStateFlow
@ -36,7 +37,6 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import java.util.Locale
import javax.inject.Inject
@Suppress("LongParameterList")
@ -77,13 +77,7 @@ internal class FeeSelectorModel @Inject constructor(
}
fun onReadMoreClicked() {
val locale = if (Locale.getDefault().language == RU_LOCALE) RU_LOCALE else EN_LOCALE
val url = buildString {
append(FEE_READ_MORE_URL_FIRST_PART)
append(locale)
append(FEE_READ_MORE_URL_SECOND_PART)
}
urlOpener.openUrl(url)
urlOpener.openUrl(TangemLinks.FEE_BLOG_LINK)
}
private fun initAppCurrency() {
@ -245,11 +239,4 @@ internal class FeeSelectorModel @Inject constructor(
)
}
}
private companion object {
const val RU_LOCALE = "ru"
const val EN_LOCALE = "en"
const val FEE_READ_MORE_URL_FIRST_PART = "https://tangem.com/"
const val FEE_READ_MORE_URL_SECOND_PART = "/blog/post/what-is-a-transaction-fee-and-why-do-we-need-it/"
}
}

View file

@ -22,13 +22,13 @@ import com.tangem.features.send.v2.subcomponents.fee.model.transformers.*
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeType
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeUM
import com.tangem.utils.TangemLinks
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.saveIn
import com.tangem.utils.transformer.update
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import java.util.Locale
import javax.inject.Inject
@Suppress("LongParameterList")
@ -136,13 +136,7 @@ internal class SendFeeModel @Inject constructor(
}
override fun onReadMoreClick() {
val locale = if (Locale.getDefault().language == RU_LOCALE) RU_LOCALE else EN_LOCALE
val url = buildString {
append(FEE_READ_MORE_URL_FIRST_PART)
append(locale)
append(FEE_READ_MORE_URL_SECOND_PART)
}
urlOpener.openUrl(url)
urlOpener.openUrl(TangemLinks.FEE_BLOG_LINK)
}
override fun onNextClick() {
@ -297,11 +291,4 @@ internal class SendFeeModel @Inject constructor(
)
}.launchIn(modelScope)
}
private companion object {
const val RU_LOCALE = "ru"
const val EN_LOCALE = "en"
const val FEE_READ_MORE_URL_FIRST_PART = "https://tangem.com/"
const val FEE_READ_MORE_URL_SECOND_PART = "/blog/post/what-is-a-transaction-fee-and-why-do-we-need-it/"
}
}

View file

@ -141,8 +141,7 @@ sealed class WalletNotification(val config: NotificationConfig) {
data object YeildSupplyApprove : Warning(
title = resourceReference(R.string.yield_module_main_view_approve_notification_title),
// todo yield supply lokalise
subtitle = resourceReference(R.string.yield_module_main_view_approve_notification_title),
subtitle = resourceReference(R.string.yield_module_main_view_approve_notification_description),
)
}

View file

@ -42,6 +42,10 @@ dependencies {
implementation(projects.domain.transaction.models)
implementation(projects.domain.transaction)
implementation(projects.domain.yieldSupply)
implementation(projects.domain.feedback.models)
implementation(projects.domain.feedback)
implementation(projects.domain.balanceHiding.models)
implementation(projects.domain.balanceHiding)
implementation(projects.libs.crypto)
/** Compose */

View file

@ -0,0 +1,94 @@
package com.tangem.features.yield.supply.impl.common
import com.tangem.common.ui.alerts.TransactionErrorAlertConverter
import com.tangem.common.ui.alerts.models.AlertDemoModeUM
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.EventMessageAction
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
import com.tangem.domain.feedback.models.BlockchainErrorInfo
import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.transaction.error.SendTransactionError
import com.tangem.features.yield.supply.impl.R
import javax.inject.Inject
@ModelScoped
class YieldSupplyAlertFactory @Inject constructor(
private val uiMessageSender: UiMessageSender,
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase,
private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase,
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
) {
fun getGenericErrorState(onFailedTxEmailClick: () -> Unit, popBack: () -> Unit = {}) {
uiMessageSender.send(
DialogMessage(
title = resourceReference(id = R.string.send_alert_transaction_failed_title),
message = resourceReference(id = R.string.common_unknown_error),
onDismissRequest = popBack,
firstAction = EventMessageAction(
title = resourceReference(R.string.common_support),
onClick = onFailedTxEmailClick,
),
),
)
}
fun getSendTransactionErrorState(
error: SendTransactionError?,
popBack: () -> Unit,
onFailedTxEmailClick: (String) -> Unit,
) {
val transactionErrorAlertConverter = TransactionErrorAlertConverter(
popBackStack = popBack,
onFailedTxEmailClick = onFailedTxEmailClick,
)
val errorAlert = error?.let { transactionErrorAlertConverter.convert(error) } ?: return
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?) {
saveBlockchainErrorUseCase(
error = BlockchainErrorInfo(
errorMessage = errorMessage.orEmpty(),
blockchainId = cryptoCurrency?.network?.rawId.orEmpty(),
derivationPath = cryptoCurrency?.network?.derivationPath?.value.orEmpty(),
tokenSymbol = cryptoCurrency?.symbol.orEmpty(),
destinationAddress = "",
amount = "",
fee = "",
),
)
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return
sendFeedbackEmailUseCase(
type = FeedbackEmailType.TransactionSendingProblem(metaInfo),
)
}
}

View file

@ -38,8 +38,9 @@ internal class DefaultYieldSupplyComponent @AssistedInject constructor(
override fun Content(modifier: Modifier) {
val yieldSupplyUM by model.uiState.collectAsStateWithLifecycle()
val bottomSheet by bottomSheetSlot.subscribeAsState()
val isBalanceHidden by model.isBalanceHiddenFlow.collectAsStateWithLifecycle()
YieldSupplyBlockContent(yieldSupplyUM = yieldSupplyUM, modifier = modifier)
YieldSupplyBlockContent(yieldSupplyUM = yieldSupplyUM, isBalanceHidden = isBalanceHidden, modifier = modifier)
bottomSheet.child?.instance?.BottomSheet()
}
@ -50,6 +51,7 @@ internal class DefaultYieldSupplyComponent @AssistedInject constructor(
params = YieldSupplyActiveEntryComponent.Params(
userWallet = model.userWallet,
cryptoCurrencyStatusFlow = model.cryptoCurrencyStatusFlow,
isBalanceHiddenFlow = model.isBalanceHiddenFlow,
onDismiss = model.bottomSheetNavigation::dismiss,
),
)

View file

@ -10,6 +10,7 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.TxInfo
import com.tangem.domain.models.wallet.UserWallet
@ -39,6 +40,7 @@ internal class YieldSupplyModel @Inject constructor(
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
@DelayedWork private val coroutineScope: CoroutineScope,
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
) : Model(), YieldSupplyClickIntents {
private val params = paramsContainer.require<YieldSupplyComponent.Params>()
@ -59,8 +61,12 @@ internal class YieldSupplyModel @Inject constructor(
),
)
val isBalanceHiddenFlow: StateFlow<Boolean>
field = MutableStateFlow(false)
init {
subscribeOnCurrencyStatusUpdates()
subscribeOnBalanceHidden()
}
private fun subscribeOnCurrencyStatusUpdates() {
@ -80,7 +86,7 @@ internal class YieldSupplyModel @Inject constructor(
onDataLoaded(cryptoCurrencyStatus)
},
ifLeft = {
// todo error
Timber.w(it.toString())
},
)
}.launchIn(modelScope)
@ -106,6 +112,17 @@ internal class YieldSupplyModel @Inject constructor(
bottomSheetNavigation.activate(Unit)
}
private fun subscribeOnBalanceHidden() {
getBalanceHidingSettingsUseCase()
.conflate()
.distinctUntilChanged()
.onEach {
isBalanceHiddenFlow.value = it.isBalanceHidden
}
.flowOn(dispatchers.default)
.launchIn(modelScope)
}
private fun onDataLoaded(cryptoCurrencyStatus: CryptoCurrencyStatus) {
val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus
val hasActiveTransaction = cryptoCurrencyStatus.value.hasCurrentNetworkTransactions

View file

@ -33,7 +33,11 @@ import com.tangem.features.yield.supply.impl.main.entity.YieldSupplyUM
import com.tangem.utils.StringsSigns
@Composable
internal fun YieldSupplyBlockContent(yieldSupplyUM: YieldSupplyUM, modifier: Modifier = Modifier) {
internal fun YieldSupplyBlockContent(
yieldSupplyUM: YieldSupplyUM,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
AnimatedContent(
targetState = yieldSupplyUM,
modifier = modifier,
@ -41,7 +45,7 @@ internal fun YieldSupplyBlockContent(yieldSupplyUM: YieldSupplyUM, modifier: Mod
when (supplyUM) {
is YieldSupplyUM.Initial -> SupplyInitial(supplyUM)
YieldSupplyUM.Loading -> SupplyLoading()
is YieldSupplyUM.Content -> SupplyContent(supplyUM)
is YieldSupplyUM.Content -> SupplyContent(supplyUM, isBalanceHidden)
YieldSupplyUM.Processing.Enter -> SupplyProcessing(
resourceReference(R.string.yield_module_token_details_earn_notification_processing),
)
@ -100,7 +104,7 @@ private fun SupplyInitial(supplyUM: YieldSupplyUM.Initial) {
}
@Composable
private fun SupplyContent(supplyUM: YieldSupplyUM.Content) {
private fun SupplyContent(supplyUM: YieldSupplyUM.Content, isBalanceHidden: Boolean) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
@ -124,7 +128,7 @@ private fun SupplyContent(supplyUM: YieldSupplyUM.Content) {
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Text(
text = supplyUM.rewardsBalance.resolveReference(),
text = supplyUM.rewardsBalance.orMaskWithStars(isBalanceHidden).resolveReference(),
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
)
@ -224,7 +228,7 @@ private fun SupplyLoading() {
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun YieldSupplyBlockContent_Preview(@PreviewParameter(PreviewProvider::class) params: YieldSupplyUM) {
TangemThemePreview {
YieldSupplyBlockContent(params)
YieldSupplyBlockContent(params, true)
}
}

View file

@ -35,8 +35,9 @@ internal class YieldSupplyActiveComponent(
@Composable
override fun Content(modifier: Modifier) {
val state by model.uiState.collectAsStateWithLifecycle()
val isBalanceHidden by params.isBalanceHiddenFlow.collectAsStateWithLifecycle()
YieldSupplyActiveContent(state = state, modifier = Modifier)
YieldSupplyActiveContent(state = state, isBalanceHidden = isBalanceHidden, modifier = Modifier)
}
@Composable
@ -53,6 +54,7 @@ internal class YieldSupplyActiveComponent(
data class Params(
val userWallet: UserWallet,
val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
val isBalanceHiddenFlow: StateFlow<Boolean>,
val callback: ModelCallback,
)

View file

@ -75,6 +75,7 @@ internal class YieldSupplyActiveEntryComponent(
params = YieldSupplyActiveComponent.Params(
userWallet = params.userWallet,
cryptoCurrencyStatusFlow = params.cryptoCurrencyStatusFlow,
isBalanceHiddenFlow = params.isBalanceHiddenFlow,
callback = model,
),
)
@ -107,6 +108,7 @@ internal class YieldSupplyActiveEntryComponent(
data class Params(
val userWallet: UserWallet,
val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
val isBalanceHiddenFlow: StateFlow<Boolean>,
val onDismiss: () -> Unit,
)
}

View file

@ -32,7 +32,11 @@ import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.impl.subcomponents.active.entity.YieldSupplyActiveContentUM
@Composable
internal fun YieldSupplyActiveContent(state: YieldSupplyActiveContentUM, modifier: Modifier = Modifier) {
internal fun YieldSupplyActiveContent(
state: YieldSupplyActiveContentUM,
isBalanceHidden: Boolean,
modifier: Modifier = Modifier,
) {
Column(
verticalArrangement = Arrangement.spacedBy(14.dp),
modifier = modifier.padding(
@ -54,12 +58,12 @@ internal fun YieldSupplyActiveContent(state: YieldSupplyActiveContentUM, modifie
color = TangemTheme.colors.text.tertiary,
)
ResizableText(
text = state.totalEarnings.resolveReference(),
text = state.totalEarnings.orMaskWithStars(isBalanceHidden).resolveReference(),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
)
}
YieldSupplyActiveMyFunds(state = state)
YieldSupplyActiveMyFunds(state = state, isBalanceHidden = isBalanceHidden)
AnimatedVisibility(state.notificationUM != null) {
val wrappedNotification = remember(this) { requireNotNull(state.notificationUM) }
@ -73,7 +77,7 @@ internal fun YieldSupplyActiveContent(state: YieldSupplyActiveContentUM, modifie
}
@Composable
private fun YieldSupplyActiveMyFunds(state: YieldSupplyActiveContentUM) {
private fun YieldSupplyActiveMyFunds(state: YieldSupplyActiveContentUM, isBalanceHidden: Boolean) {
Column(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
@ -112,6 +116,7 @@ private fun YieldSupplyActiveMyFunds(state: YieldSupplyActiveContentUM) {
InfoRow(
title = resourceReference(R.string.yield_module_earn_sheet_transfers_title),
info = resourceReference(R.string.yield_module_transfer_mode_automatic),
isBalanceHidden = false,
)
HorizontalDivider(
thickness = 0.5.dp,
@ -120,6 +125,7 @@ private fun YieldSupplyActiveMyFunds(state: YieldSupplyActiveContentUM) {
InfoRow(
title = resourceReference(R.string.yield_module_earn_sheet_available_title),
info = state.availableBalance,
isBalanceHidden = isBalanceHidden,
)
}
}
@ -150,7 +156,7 @@ private fun DescriptionText(state: YieldSupplyActiveContentUM) {
}
@Composable
private fun InfoRow(title: TextReference, info: TextReference?) {
private fun InfoRow(title: TextReference, isBalanceHidden: Boolean, info: TextReference?) {
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.padding(horizontal = 4.dp, vertical = 12.dp),
@ -165,7 +171,7 @@ private fun InfoRow(title: TextReference, info: TextReference?) {
AnimatedContent(info) { currentInfo ->
if (currentInfo != null) {
Text(
text = currentInfo.resolveReference(),
text = currentInfo.orMaskWithStars(isBalanceHidden).resolveReference(),
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.tertiary,
)
@ -187,7 +193,7 @@ private fun YieldSupplyActiveBottomSheet_Preview(
@PreviewParameter(YieldSupplyActiveBottomSheetPreviewProvider::class) params: YieldSupplyActiveContentUM,
) {
TangemThemePreview {
YieldSupplyActiveContent(params)
YieldSupplyActiveContent(params, true)
}
}

View file

@ -14,6 +14,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.child
import com.tangem.core.decompose.model.getOrCreateModel
@ -89,7 +90,7 @@ internal class YieldSupplyApproveComponent(
PrimaryButtonIconEnd(
text = stringResourceSafe(R.string.common_confirm),
onClick = model::onClick,
iconResId = R.drawable.ic_tangem_24,
iconResId = walletInterationIcon(params.userWallet),
enabled = state.isPrimaryButtonEnabled,
modifier = Modifier
.fillMaxWidth()

View file

@ -20,6 +20,7 @@ import com.tangem.domain.transaction.usecase.GetFeeUseCase
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetContractAddressUseCase
import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM
import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer
@ -29,6 +30,7 @@ import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSu
import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsUpdateTrigger
import com.tangem.features.yield.supply.impl.subcomponents.notifications.entity.YieldSupplyNotificationData
import com.tangem.utils.StringsSigns.DOT
import com.tangem.utils.TangemLinks
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.transformer.update
import kotlinx.collections.immutable.persistentListOf
@ -50,6 +52,7 @@ internal class YieldSupplyApproveModel @Inject constructor(
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase,
private val yieldSupplyGetContractAddressUseCase: YieldSupplyGetContractAddressUseCase,
private val yieldSupplyAlertFactory: YieldSupplyAlertFactory,
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
private val params: YieldSupplyApproveComponent.Params = paramsContainer.require()
@ -98,7 +101,7 @@ internal class YieldSupplyApproveModel @Inject constructor(
}
fun onReadMoreClick() {
urlOpener.openUrl(READ_MORE_URL)
urlOpener.openUrl(TangemLinks.FEE_BLOG_LINK)
}
override fun onFeeReload() {
@ -117,9 +120,22 @@ internal class YieldSupplyApproveModel @Inject constructor(
userWallet = userWallet,
network = cryptoCurrency.network,
).fold(
ifLeft = {
Timber.e(it.toString())
ifLeft = { error ->
Timber.e(error.toString())
uiState.update(YieldSupplyTransactionReadyTransformer)
yieldSupplyAlertFactory.getSendTransactionErrorState(
error = error,
popBack = params.callback::onBackClick,
onFailedTxEmailClick = { errorMessage ->
modelScope.launch(dispatchers.default) {
yieldSupplyAlertFactory.onFailedTxEmailClick(
userWallet = userWallet,
cryptoCurrency = cryptoCurrency,
errorMessage = errorMessage,
)
}
},
)
},
ifRight = {
params.callback.onTransactionSent()
@ -223,8 +239,4 @@ internal class YieldSupplyApproveModel @Inject constructor(
}
}.launchIn(modelScope)
}
private companion object {
const val READ_MORE_URL = "https://tangem.com" // todo yield supply replace with real link
}
}

View file

@ -13,6 +13,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.child
import com.tangem.core.decompose.model.getOrCreateModel
@ -105,11 +106,17 @@ internal class YieldSupplyStartEarningComponent(
override fun Footer() {
val state by model.uiState.collectAsStateWithLifecycle()
val icon = if (state.isPrimaryButtonEnabled) {
walletInterationIcon(model.userWallet)
} else {
null
}
PrimaryButtonIconEnd(
text = stringResourceSafe(R.string.yield_module_start_earning),
onClick = model::onClick,
enabled = state.isPrimaryButtonEnabled,
iconResId = R.drawable.ic_tangem_24,
iconResId = icon,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),

View file

@ -20,6 +20,7 @@ import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyEstimateEnterFeeUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyStartEarningUseCase
import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM
import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer
@ -53,12 +54,13 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val yieldSupplyNotificationsUpdateTrigger: YieldSupplyNotificationsUpdateTrigger,
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
private val yieldSupplyAlertFactory: YieldSupplyAlertFactory,
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
private val params: YieldSupplyStartEarningComponent.Params = paramsContainer.require()
private val cryptoCurrency = params.cryptoCurrency
private var userWallet: UserWallet by Delegates.notNull()
var userWallet: UserWallet by Delegates.notNull()
val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>
field = MutableStateFlow(
@ -171,6 +173,19 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
ifLeft = { error ->
Timber.e(error.toString())
uiState.update(YieldSupplyTransactionReadyTransformer)
yieldSupplyAlertFactory.getSendTransactionErrorState(
error = error,
popBack = params.callback::onBackClick,
onFailedTxEmailClick = { errorMessage ->
modelScope.launch(dispatchers.default) {
yieldSupplyAlertFactory.onFailedTxEmailClick(
userWallet = userWallet,
cryptoCurrency = cryptoCurrency,
errorMessage = errorMessage,
)
}
},
)
},
ifRight = {
fetchCurrencyStatusUseCase(userWalletId = userWallet.walletId, cryptoCurrency.id)
@ -191,8 +206,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
},
ifLeft = {
Timber.w(it.toString())
// showAlertError() todo yield supply error alert
return@launch
showAlertError()
},
)
}
@ -230,13 +244,8 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
)
},
ifLeft = {
// todo yield supply error
// sendConfirmAlertFactory.getGenericErrorState(
// onFailedTxEmailClick = {
// onFailedTxEmailClick(it.toString())
// },
// popBack = router::pop,
// )
Timber.w(it.toString())
showAlertError()
},
)
}.launchIn(modelScope)
@ -251,6 +260,21 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
}
}
private fun showAlertError() {
yieldSupplyAlertFactory.getGenericErrorState(
onFailedTxEmailClick = {
modelScope.launch(dispatchers.default) {
yieldSupplyAlertFactory.onFailedTxEmailClick(
userWallet,
cryptoCurrency,
null,
)
}
},
popBack = params.callback::onBackClick,
)
}
private companion object {
val MAX_NETWORK_FEE: BigDecimal = BigDecimal.TEN // TODO replace with value from api
}

View file

@ -14,6 +14,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.child
import com.tangem.core.decompose.model.getOrCreateModel
@ -89,7 +90,7 @@ internal class YieldSupplyStopEarningComponent(
PrimaryButtonIconEnd(
text = stringResourceSafe(R.string.common_confirm),
onClick = model::onClick,
iconResId = R.drawable.ic_tangem_24,
iconResId = walletInterationIcon(params.userWallet),
enabled = state.isPrimaryButtonEnabled,
modifier = Modifier
.fillMaxWidth()

View file

@ -17,6 +17,7 @@ import com.tangem.domain.transaction.usecase.GetFeeUseCase
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyStopEarningUseCase
import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM
import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer
@ -26,6 +27,7 @@ import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSu
import com.tangem.features.yield.supply.impl.subcomponents.notifications.entity.YieldSupplyNotificationData
import com.tangem.features.yield.supply.impl.subcomponents.stopearning.YieldSupplyStopEarningComponent
import com.tangem.features.yield.supply.impl.subcomponents.stopearning.model.transformer.YieldSupplyStopEarningFeeContentTransformer
import com.tangem.utils.TangemLinks
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.orZero
import com.tangem.utils.transformer.update
@ -46,6 +48,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
private val yieldSupplyStopEarningUseCase: YieldSupplyStopEarningUseCase,
private val urlOpener: UrlOpener,
private val yieldSupplyNotificationsUpdateTrigger: YieldSupplyNotificationsUpdateTrigger,
private val yieldSupplyAlertFactory: YieldSupplyAlertFactory,
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
private val params: YieldSupplyStopEarningComponent.Params = paramsContainer.require()
@ -100,7 +103,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
}
fun onReadMoreClick() {
urlOpener.openUrl(READ_MORE_URL)
urlOpener.openUrl(TangemLinks.FEE_BLOG_LINK)
}
fun onClick() {
@ -113,9 +116,22 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
userWallet = userWallet,
network = cryptoCurrency.network,
).fold(
ifLeft = {
Timber.e(it.toString())
ifLeft = { error ->
Timber.e(error.toString())
uiState.update(YieldSupplyTransactionReadyTransformer)
yieldSupplyAlertFactory.getSendTransactionErrorState(
error = error,
popBack = params.callback::onBackClick,
onFailedTxEmailClick = { errorMessage ->
modelScope.launch(dispatchers.default) {
yieldSupplyAlertFactory.onFailedTxEmailClick(
userWallet = params.userWallet,
cryptoCurrency = cryptoCurrency,
errorMessage = error.toString(),
)
}
},
)
},
ifRight = {
params.callback.onTransactionSent()
@ -197,8 +213,4 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
}
}.launchIn(modelScope)
}
private companion object {
const val READ_MORE_URL = "https://tangem.com" // todo yield supply replace with real link
}
}