From 0dcf1ed23c8a7cce3e1af6d9fa6f11bf06ce5f52 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 26 Sep 2025 20:51:27 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../main/java/com/tangem/utils/TangemLinks.kt | 21 +++++ .../v2/feeselector/model/FeeSelectorModel.kt | 17 +--- .../subcomponents/fee/model/SendFeeModel.kt | 17 +--- .../wallet/state/model/WalletNotification.kt | 3 +- features/yield-supply/impl/build.gradle.kts | 4 + .../impl/common/YieldSupplyAlertFactory.kt | 94 +++++++++++++++++++ .../impl/main/DefaultYieldSupplyComponent.kt | 4 +- .../impl/main/model/YieldSupplyModel.kt | 19 +++- .../impl/main/ui/YieldSupplyBlockContent.kt | 14 ++- .../active/YieldSupplyActiveComponent.kt | 4 +- .../active/YieldSupplyActiveEntryComponent.kt | 2 + .../active/ui/YieldSupplyActiveContent.kt | 20 ++-- .../approve/YieldSupplyApproveComponent.kt | 3 +- .../approve/model/YieldSupplyApproveModel.kt | 26 +++-- .../YieldSupplyStartEarningComponent.kt | 9 +- .../model/YieldSupplyStartEarningModel.kt | 44 +++++++-- .../YieldSupplyStopEarningComponent.kt | 3 +- .../model/YieldSupplyStopEarningModel.kt | 26 +++-- 18 files changed, 256 insertions(+), 74 deletions(-) create mode 100644 core/utils/src/main/java/com/tangem/utils/TangemLinks.kt create mode 100644 features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/YieldSupplyAlertFactory.kt diff --git a/core/utils/src/main/java/com/tangem/utils/TangemLinks.kt b/core/utils/src/main/java/com/tangem/utils/TangemLinks.kt new file mode 100644 index 0000000000..3a1c60869e --- /dev/null +++ b/core/utils/src/main/java/com/tangem/utils/TangemLinks.kt @@ -0,0 +1,21 @@ +package com.tangem.utils + +import java.util.Locale + +object TangemLinks { + + private const val RU_LOCALE = "ru" + private const val EN_LOCALE = "en" + + private const val TANGEM_MAIN = "https://tangem.com/" + + val FEE_BLOG_LINK: String + get(): String { + val locale = if (Locale.getDefault().language == RU_LOCALE) RU_LOCALE else EN_LOCALE + return buildString { + append(TANGEM_MAIN) + append(locale) + append("/blog/post/what-is-a-transaction-fee-and-why-do-we-need-it/") + } + } +} \ No newline at end of file diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/FeeSelectorModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/FeeSelectorModel.kt index 958449221b..1b389809c0 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/FeeSelectorModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/FeeSelectorModel.kt @@ -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/" - } } \ No newline at end of file diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/SendFeeModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/SendFeeModel.kt index 5cad0c8511..d54150ffad 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/SendFeeModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/SendFeeModel.kt @@ -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/" - } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt index bc42b5dc0b..1479c155dd 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotification.kt @@ -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), ) } diff --git a/features/yield-supply/impl/build.gradle.kts b/features/yield-supply/impl/build.gradle.kts index 5eeadd29a9..2ca0284169 100644 --- a/features/yield-supply/impl/build.gradle.kts +++ b/features/yield-supply/impl/build.gradle.kts @@ -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 */ diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/YieldSupplyAlertFactory.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/YieldSupplyAlertFactory.kt new file mode 100644 index 0000000000..00958d2ec1 --- /dev/null +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/YieldSupplyAlertFactory.kt @@ -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), + ) + } +} \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/DefaultYieldSupplyComponent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/DefaultYieldSupplyComponent.kt index 1943c230d1..bfc0e7857d 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/DefaultYieldSupplyComponent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/DefaultYieldSupplyComponent.kt @@ -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, ), ) diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt index 6cfca46b35..c1d777f0e5 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt @@ -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() @@ -59,8 +61,12 @@ internal class YieldSupplyModel @Inject constructor( ), ) + val isBalanceHiddenFlow: StateFlow + 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 diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt index 3e8921209e..576beabb2c 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt @@ -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) } } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveComponent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveComponent.kt index 45f5276117..4d7abbb513 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveComponent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveComponent.kt @@ -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, + val isBalanceHiddenFlow: StateFlow, val callback: ModelCallback, ) diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveEntryComponent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveEntryComponent.kt index 4bca6d3382..59616762c7 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveEntryComponent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/YieldSupplyActiveEntryComponent.kt @@ -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, + val isBalanceHiddenFlow: StateFlow, val onDismiss: () -> Unit, ) } \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt index b6481893e7..0619e6b7a0 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveContent.kt @@ -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) } } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/YieldSupplyApproveComponent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/YieldSupplyApproveComponent.kt index 68cfde8d7f..3c1de839bb 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/YieldSupplyApproveComponent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/YieldSupplyApproveComponent.kt @@ -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() diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt index 0385e90b11..1f2e90bf5c 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt @@ -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 - } } \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/YieldSupplyStartEarningComponent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/YieldSupplyStartEarningComponent.kt index 2d6f3c615e..3d02037617 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/YieldSupplyStartEarningComponent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/YieldSupplyStartEarningComponent.kt @@ -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), diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt index a675b829ae..a82ff670c8 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt @@ -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 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 } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/YieldSupplyStopEarningComponent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/YieldSupplyStopEarningComponent.kt index 278f40bf52..0db25f5017 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/YieldSupplyStopEarningComponent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/YieldSupplyStopEarningComponent.kt @@ -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() diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt index dc462586ca..5ea64abb48 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt @@ -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 - } } \ No newline at end of file