Updated on 2026-08-14
This commit is contained in:
commit
5b832e2591
26 changed files with 584 additions and 85 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 9f34ca0ea3969b5ba6b82e1aea2fef0a44463fc8
|
||||
Subproject commit a8cf062a6bb58332458c0f5b43026e062378e5c7
|
||||
|
|
@ -134,7 +134,7 @@
|
|||
<string name="biometric_unavailable_warning">お使いの携帯電話で生体認証が無効になっているため、アプリにウォレットを保存できません。ウォレットを保存するには、携帯電話の設定で生体認証機能を有効にしてください。</string>
|
||||
<string name="bitcoin_promo_activation_error">プロモーションコードの処理中にエラーが発生しました。しばらくしてからもう一度お試しください。</string>
|
||||
<string name="bitcoin_promo_activation_error_title">アクティベーションエラー</string>
|
||||
<string name="bitcoin_promo_activation_success">プロモコードが正常に有効化されました。リワードは14日以内にあなたのアカウントに付与されます。</string>
|
||||
<string name="bitcoin_promo_activation_success">プロモーションコードが正常に有効化されました。報酬は14日以内にビットコインアカウントに入金されます。</string>
|
||||
<string name="bitcoin_promo_activation_success_title">プロモーションコードが有効になりました</string>
|
||||
<string name="bitcoin_promo_already_activated">このプロモーションコードは既に使用されているため、再度使うことはできません。</string>
|
||||
<string name="bitcoin_promo_already_activated_title">コードが利用できません</string>
|
||||
|
|
@ -180,6 +180,7 @@
|
|||
<string name="common_add">追加</string>
|
||||
<string name="common_add_to_portfolio">ポートフォリオに追加</string>
|
||||
<string name="common_add_token">トークンを追加</string>
|
||||
<string name="common_added">追加済み</string>
|
||||
<string name="common_address">アドレス</string>
|
||||
<string name="common_all">すべて</string>
|
||||
<string name="common_allow">許可する</string>
|
||||
|
|
@ -1365,7 +1366,7 @@
|
|||
<string name="user_push_notification_agreement_argument_two_subtitle">新しい機能や限定オファーへの早期アクセス。</string>
|
||||
<string name="user_push_notification_agreement_argument_two_title">機能およびニュースのアップデート</string>
|
||||
<string name="user_push_notification_agreement_header">プッシュ通知を使用しますか?</string>
|
||||
<string name="user_push_notification_banner_subtitle">プッシュ通知を有効にすると、資金が到着するとすぐに通知されます。</string>
|
||||
<string name="user_push_notification_banner_subtitle">プッシュ通知を有効にすると、ウォレットに着金したときにアラートを受信できます。</string>
|
||||
<string name="user_push_notification_banner_title">取引を見逃さない</string>
|
||||
<string name="user_wallet_list_add_button">新しいウォレットを追加</string>
|
||||
<string name="user_wallet_list_delete_hw_prompt">バックアップせずにこのウォレットを削除すると、資金に永久にアクセスできなくなります。</string>
|
||||
|
|
@ -1444,6 +1445,7 @@
|
|||
<string name="wallet_connect_subtitle">dAppsに接続する</string>
|
||||
<string name="wallet_connect_title">WalletConnect</string>
|
||||
<string name="wallet_connect_toast_awaiting_session_proposal">接続には数秒かかる場合があります</string>
|
||||
<string name="wallet_create_common_title">Tangemウォレットを作成する</string>
|
||||
<string name="wallet_create_hardware_badge">%sから</string>
|
||||
<string name="wallet_create_hardware_description">Tangemウォレットを購入ーこれは、あなたの秘密鍵をオフラインで安全に保管する物理デバイスです。</string>
|
||||
<string name="wallet_create_hardware_title">ハードウェアウォレット</string>
|
||||
|
|
@ -1759,7 +1761,8 @@
|
|||
<string name="yield_module_supply_apr">供給APR</string>
|
||||
<string name="yield_module_token_details_earn_notification_apy">APY</string>
|
||||
<string name="yield_module_token_details_earn_notification_description">あなたの資産を眠らせない — 残高を運用して利息を得ましょう。</string>
|
||||
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">保有資産から報酬を得る</string>
|
||||
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_subtitle">利息は自動的に発生します</string>
|
||||
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Aaveレンディング</string>
|
||||
<string name="yield_module_token_details_earn_notification_processing">入金の処理中</string>
|
||||
<string name="yield_module_token_details_earn_notification_title">年間%1$s%%の収益</string>
|
||||
<string name="yield_module_transfer_mode_automatic">自動</string>
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@
|
|||
<string name="biometric_unavailable_warning">Вы отключили биометрическую аутентификацию на вашем телефоне и не сможете сохранять кошельки в приложении. Для сохранения кошельков, пожалуйста, включите функцию биометрической аутентификации в настройках телефона.</string>
|
||||
<string name="bitcoin_promo_activation_error">При обработке промокода произошла ошибка. Пожалуйста, попробуйте позже.</string>
|
||||
<string name="bitcoin_promo_activation_error_title">Ошибка активации</string>
|
||||
<string name="bitcoin_promo_activation_success">Ваш промокод был успешно активирован. Награда будет зачислена на ваш счёт в течение 14 дней.</string>
|
||||
<string name="bitcoin_promo_activation_success">Ваш промокод был успешно активирован. Награда будет зачислена на ваш Bitcoin адрес в течение 14 дней.</string>
|
||||
<string name="bitcoin_promo_activation_success_title">Промокод активирован</string>
|
||||
<string name="bitcoin_promo_already_activated">Этот промокод уже был использован и не может быть активирован повторно.</string>
|
||||
<string name="bitcoin_promo_already_activated_title">Код недоступен</string>
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@
|
|||
<string name="biometric_unavailable_warning">You have disabled biometric authentication on your phone and will not be able to save wallets in the app. To save wallets, please enable the biometric authentication function in your phone settings.</string>
|
||||
<string name="bitcoin_promo_activation_error">An error occurred while processing your promo code. Please try again later.</string>
|
||||
<string name="bitcoin_promo_activation_error_title">Activation error</string>
|
||||
<string name="bitcoin_promo_activation_success">Your promo code was successfully activated. A reward will be credited to your account within 14 days.</string>
|
||||
<string name="bitcoin_promo_activation_success">Your promo code was successfully activated. The reward will be credited to your Bitcoin account within 14 days.</string>
|
||||
<string name="bitcoin_promo_activation_success_title">Promo Code Activated</string>
|
||||
<string name="bitcoin_promo_already_activated">This promo code has already been used and cannot be activated again.</string>
|
||||
<string name="bitcoin_promo_already_activated_title">Code unavailable</string>
|
||||
|
|
@ -1797,7 +1797,10 @@
|
|||
<string name="yield_module_fee_policy_sheet_description">All future %s top-ups will be supplied to Aave automatically, with the transaction fee deducted.</string>
|
||||
<string name="yield_module_fee_policy_sheet_max_fee_note">If network fees rise above maximum fee, the transaction won’t go through until they decrease. You can change this limit later.</string>
|
||||
<string name="yield_module_fee_policy_sheet_max_fee_title">Maximum fee</string>
|
||||
<string name="yield_module_fee_policy_sheet_min_amount_note">The transaction fee must stay below 4% of your deposit. Tangem will transfer funds to Aave only once your balance is large enough to meet this condition. </string>
|
||||
<string name="yield_module_fee_policy_sheet_min_amount_title">Minimal amount</string>
|
||||
<string name="yield_module_fee_policy_sheet_title">Fee policy</string>
|
||||
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangem also takes a 3% service fee on the yield earned.</string>
|
||||
<string name="yield_module_high_fee_error">Network fee is too high right now. Waiting until it falls below your limit.</string>
|
||||
<string name="yield_module_historical_returns">Historical returns</string>
|
||||
<string name="yield_module_main_view_approve_notification_description">Write description here. In one, two or three lines will be awesome. [PLACEHOLDER]</string>
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ fun Notification(
|
|||
subtitle = config.subtitle,
|
||||
subtitleColor = subtitleColor,
|
||||
showArrowIcon = isEnabled && config.shouldShowArrowIcon,
|
||||
hasCloseButton = config.onCloseClick != null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -148,6 +149,7 @@ private fun MainContent(
|
|||
titleColor: Color,
|
||||
subtitleColor: Color,
|
||||
showArrowIcon: Boolean,
|
||||
hasCloseButton: Boolean,
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(
|
||||
|
|
@ -161,10 +163,24 @@ private fun MainContent(
|
|||
|
||||
SpacerW(width = TangemTheme.dimens.spacing10)
|
||||
|
||||
TextsBlock(title = title, titleColor = titleColor, subtitle = subtitle, subtitleColor = subtitleColor)
|
||||
TextsBlock(
|
||||
title = title,
|
||||
titleColor = titleColor,
|
||||
subtitle = subtitle,
|
||||
subtitleColor = subtitleColor,
|
||||
modifier = Modifier
|
||||
.weight(1f, fill = false)
|
||||
.then(
|
||||
if (hasCloseButton && !showArrowIcon) {
|
||||
Modifier.padding(end = TangemTheme.dimens.size32)
|
||||
} else {
|
||||
Modifier
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
if (showArrowIcon) {
|
||||
SpacerWMax()
|
||||
SpacerW(width = TangemTheme.dimens.spacing8)
|
||||
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_chevron_right_24),
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@ internal class DefaultCustomTokensRepository(
|
|||
private val networkFactory: NetworkFactory,
|
||||
) : CustomTokensRepository {
|
||||
|
||||
private val excludedBlockchainsForCustom = setOf(
|
||||
Blockchain.Quai,
|
||||
Blockchain.QuaiTestnet,
|
||||
)
|
||||
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains)
|
||||
private val userTokensResponseFactory = UserTokensResponseFactory()
|
||||
private val tokenAddressConverter = TokenAddressesConverter()
|
||||
|
|
@ -268,6 +273,7 @@ internal class DefaultCustomTokensRepository(
|
|||
val scanResponse = userWallet.scanResponse
|
||||
|
||||
Blockchain.entries
|
||||
.filter { it !in excludedBlockchainsForCustom }
|
||||
.mapNotNull { blockchain ->
|
||||
val canHandleBlockchain = scanResponse.card.canHandleBlockchain(
|
||||
blockchain,
|
||||
|
|
|
|||
|
|
@ -45,19 +45,33 @@ fun CardDTO.supportedBlockchains(
|
|||
excludedBlockchains: ExcludedBlockchains,
|
||||
): List<Blockchain> {
|
||||
val supportedBlockchains = if (firmwareVersion < FirmwareVersion.MultiWalletAvailable) {
|
||||
Blockchain.fromCurve(EllipticCurve.Secp256k1).toMutableList()
|
||||
Blockchain.fromCurve(EllipticCurve.Secp256k1)
|
||||
} else if (!cardTypesResolver.isWallet2() && !cardTypesResolver.isTangemWallet()) {
|
||||
// need for old multiwallet that supports only secp256k1
|
||||
wallets.flatMap { Blockchain.fromCurve(it.curve) }.distinct().toMutableList()
|
||||
wallets.flatMap { Blockchain.fromCurve(it.curve) }.distinct()
|
||||
} else {
|
||||
// multiwallet supports all blockchains, move this logic to config
|
||||
Blockchain.entries.toMutableList()
|
||||
Blockchain.entries
|
||||
}
|
||||
return supportedBlockchains
|
||||
.filter { isTestCard == it.isTestnet() }
|
||||
.filterNot(::isBlockchainUnsupported)
|
||||
.filter { it !in excludedBlockchains }
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out blockchains that are not supported by the specific card firmware.
|
||||
* @return `false` if blockchain is not supported, `true` otherwise.
|
||||
*/
|
||||
private fun CardDTO.isBlockchainUnsupported(blockchain: Blockchain): Boolean {
|
||||
return when (blockchain) {
|
||||
Blockchain.Quai, Blockchain.QuaiTestnet -> {
|
||||
firmwareVersion <= FirmwareVersion.HDWalletAvailable
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun CardDTO.supportedTokens(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.tangem.feature.qrscanning.presentation.transformers
|
|||
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.domain.qrscanning.models.QrResultSource
|
||||
import com.tangem.domain.qrscanning.models.SourceType
|
||||
|
|
@ -22,7 +21,7 @@ internal class InitializeQrScanningStateTransformer(
|
|||
override fun transform(prevState: QrScanningState): QrScanningState {
|
||||
val message = when (source) {
|
||||
SourceType.SEND -> network?.let { resourceReference(R.string.send_qrcode_scan_info, wrappedList(it)) }
|
||||
SourceType.WALLET_CONNECT -> stringReference("Open Web3 app and chose WalletConnect option")
|
||||
SourceType.WALLET_CONNECT -> resourceReference(R.string.wc_qr_scan_hint)
|
||||
}
|
||||
|
||||
return QrScanningState(
|
||||
|
|
|
|||
|
|
@ -69,4 +69,8 @@ internal interface StakingClickIntents : AmountScreenClickIntents {
|
|||
fun showPrimaryClickAlert()
|
||||
|
||||
fun onOpenLearnMoreAboutApproveClick()
|
||||
|
||||
fun onActivateTonAccountNotificationClick()
|
||||
|
||||
fun onActivateTonAccountClick()
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.staking.impl.presentation.model
|
|||
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer
|
||||
|
|
@ -48,8 +49,11 @@ import com.tangem.domain.staking.utils.getValidatorsCount
|
|||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.CreateTransferTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetAllowanceUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.utils.convertToSdkAmount
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.features.staking.api.StakingComponent
|
||||
import com.tangem.features.staking.impl.analytics.StakingParamsInterceptor
|
||||
|
|
@ -69,10 +73,15 @@ import com.tangem.features.staking.impl.presentation.state.transformers.approval
|
|||
import com.tangem.features.staking.impl.presentation.state.transformers.confirmation.SetUpdatedAllowanceTransformer
|
||||
import com.tangem.features.staking.impl.presentation.state.transformers.notifications.AddStakingNotificationsTransformer
|
||||
import com.tangem.features.staking.impl.presentation.state.transformers.notifications.DismissStakingNotificationsStateTransformer
|
||||
import com.tangem.features.staking.impl.presentation.state.transformers.ton.CompleteInitializeBottomSheetTransformer
|
||||
import com.tangem.features.staking.impl.presentation.state.transformers.ton.SetFeeToTonInitializeBottomSheetTransformer
|
||||
import com.tangem.features.staking.impl.presentation.state.transformers.ton.ShowTonInitializeBottomSheetTransformer
|
||||
import com.tangem.features.staking.impl.presentation.state.transformers.ton.SetFeeErrorToTonInitializeBottomSheetTransformer
|
||||
import com.tangem.features.staking.impl.presentation.state.transformers.validator.ValidatorSelectChangeTransformer
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.checkAndCalculateSubtractedAmount
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.isSingleAction
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.withStubUnstakeAction
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isTon
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.TangemBlogUrlBuilder.RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP
|
||||
import com.tangem.utils.coroutines.*
|
||||
|
|
@ -122,6 +131,9 @@ internal class StakingModel @Inject constructor(
|
|||
private val getActionsUseCase: GetActionsUseCase,
|
||||
private val getYieldUseCase: GetYieldUseCase,
|
||||
private val checkAccountInitializedUseCase: CheckAccountInitializedUseCase,
|
||||
private val createTransferTransactionUseCase: CreateTransferTransactionUseCase,
|
||||
private val getFeeUseCase: GetFeeUseCase,
|
||||
private val getNetworkAddressesUseCase: GetNetworkAddressesUseCase,
|
||||
private val getActionRequirementAmountUseCase: GetActionRequirementAmountUseCase,
|
||||
private val paramsInterceptorHolder: ParamsInterceptorHolder,
|
||||
private val shareManager: ShareManager,
|
||||
|
|
@ -150,11 +162,14 @@ internal class StakingModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private var isAccountInitialized: Boolean = true
|
||||
private var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
|
||||
private var stakingActions: List<StakingAction> = emptyList()
|
||||
private var feeCryptoCurrencyStatus: CryptoCurrencyStatus? = null
|
||||
private var minimumTransactionAmount: EnterAmountBoundary? = null
|
||||
|
||||
private var tonAccountInitializeTransaction: TransactionData.Uncompiled? = null
|
||||
|
||||
private val userWallet by lazy {
|
||||
requireNotNull(
|
||||
getUserWalletUseCase(userWalletId).getOrNull(),
|
||||
|
|
@ -250,26 +265,12 @@ internal class StakingModel @Inject constructor(
|
|||
val isInitialInfoStep = value.currentStep == StakingStep.InitialInfo
|
||||
val noBalanceState = balanceState == null
|
||||
val noYieldBalanceData = cryptoCurrencyStatus.value.yieldBalance !is YieldBalance.Data
|
||||
val isAccountInitialized = checkAccountInitializedUseCase.invoke(
|
||||
userWalletId = userWalletId,
|
||||
network = cryptoCurrencyStatus.currency.network,
|
||||
).getOrElse {
|
||||
Timber.e(it)
|
||||
false
|
||||
}
|
||||
|
||||
when {
|
||||
isInitialInfoStep && noBalanceState && yield.allValidatorsFull && noYieldBalanceData -> {
|
||||
stakingEventFactory.createStakingValidatorsUnavailableAlert()
|
||||
return@launch
|
||||
}
|
||||
isInitialInfoStep && noBalanceState && !isAccountInitialized -> {
|
||||
analyticsEventHandler.send(StakingAnalyticsEvent.UnitializedAddress(
|
||||
token = cryptoCurrencyStatus.currency.symbol,
|
||||
))
|
||||
stakingEventFactory.createInitializeAccountAlert()
|
||||
return@launch
|
||||
}
|
||||
isInitialInfoStep && noBalanceState -> {
|
||||
val list = buildList {
|
||||
SetConfirmationStateInitTransformer(
|
||||
|
|
@ -763,6 +764,7 @@ internal class StakingModel @Inject constructor(
|
|||
AddStakingNotificationsTransformer(
|
||||
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
|
||||
appCurrencyProvider = Provider { appCurrency },
|
||||
isAccountInitializedProvider = Provider { isAccountInitialized },
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
currencyWarning = currencyWarning,
|
||||
currencyCheck = currencyStatus,
|
||||
|
|
@ -934,6 +936,85 @@ internal class StakingModel @Inject constructor(
|
|||
urlOpener.openUrl(RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP)
|
||||
}
|
||||
|
||||
override fun onActivateTonAccountNotificationClick() {
|
||||
modelScope.launch {
|
||||
stateController.update(
|
||||
ShowTonInitializeBottomSheetTransformer(
|
||||
onDismiss = { stateController.update(DismissBottomSheetStateTransformer) },
|
||||
),
|
||||
)
|
||||
|
||||
val tonAmount = BigDecimal(1)
|
||||
val destination = getNetworkAddressesUseCase.invokeSync(
|
||||
userWalletId = userWalletId,
|
||||
network = cryptoCurrencyStatus.currency.network,
|
||||
).getOrNull(0)?.address ?: return@launch
|
||||
|
||||
val transaction = createTransferTransactionUseCase(
|
||||
amount = tonAmount.convertToSdkAmount(cryptoCurrencyStatus),
|
||||
destination = destination,
|
||||
userWalletId = userWalletId,
|
||||
network = cryptoCurrencyStatus.currency.network,
|
||||
memo = null,
|
||||
)
|
||||
tonAccountInitializeTransaction = transaction.getOrElse {
|
||||
stateController.update(
|
||||
SetFeeErrorToTonInitializeBottomSheetTransformer(),
|
||||
)
|
||||
return@launch
|
||||
}
|
||||
|
||||
val transactionFee = getFeeUseCase(
|
||||
userWallet = userWallet,
|
||||
network = cryptoCurrencyStatus.currency.network,
|
||||
transactionData = tonAccountInitializeTransaction!!,
|
||||
)
|
||||
|
||||
transactionFee.fold(
|
||||
ifLeft = {
|
||||
stateController.update(
|
||||
SetFeeErrorToTonInitializeBottomSheetTransformer(),
|
||||
)
|
||||
},
|
||||
ifRight = {
|
||||
stateController.update(
|
||||
SetFeeToTonInitializeBottomSheetTransformer(
|
||||
appCurrencyProvider = Provider { appCurrency },
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
fee = it.normal,
|
||||
isFeeApproximate = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivateTonAccountClick() {
|
||||
modelScope.launch {
|
||||
tonAccountInitializeTransaction?.let { transaction ->
|
||||
sendTransactionUseCase.invoke(
|
||||
txData = transaction,
|
||||
userWallet = userWallet,
|
||||
network = cryptoCurrencyStatus.currency.network,
|
||||
).fold(
|
||||
ifLeft = {
|
||||
stateController.update(DismissBottomSheetStateTransformer)
|
||||
},
|
||||
ifRight = {
|
||||
stateController.update(CompleteInitializeBottomSheetTransformer(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
minimumTransactionAmount = minimumTransactionAmount,
|
||||
))
|
||||
|
||||
balanceUpdater.partialUpdateWithDelay()
|
||||
stateController.update(DismissBottomSheetStateTransformer)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun setupApprovalNeeded() {
|
||||
val approval = StakingIntegrationID.create(currencyId = cryptoCurrencyStatus.currency.id)?.approval
|
||||
?: StakingApproval.Empty
|
||||
|
|
@ -961,7 +1042,9 @@ internal class StakingModel @Inject constructor(
|
|||
)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.filter { value.currentStep == StakingStep.InitialInfo }
|
||||
.filter {
|
||||
value.currentStep == StakingStep.InitialInfo || isCaseWithUnitializedTonAccount()
|
||||
}
|
||||
.onEach { maybeStatus ->
|
||||
maybeStatus.fold(
|
||||
ifRight = { status ->
|
||||
|
|
@ -989,6 +1072,19 @@ internal class StakingModel @Inject constructor(
|
|||
}
|
||||
cryptoCurrencyStatus = status
|
||||
|
||||
val isAccountInitializedNew = checkAccountInitializedUseCase.invoke(
|
||||
userWalletId = userWalletId,
|
||||
network = cryptoCurrencyStatus.currency.network,
|
||||
).getOrElse {
|
||||
Timber.e(it)
|
||||
false
|
||||
}
|
||||
if (isAccountInitializedNew && !isAccountInitialized) {
|
||||
isAccountInitialized = true
|
||||
updateNotifications()
|
||||
}
|
||||
isAccountInitialized = isAccountInitializedNew
|
||||
|
||||
setupApprovalNeeded()
|
||||
setupIsAnyTokenStaked()
|
||||
checkIfSubtractAvailable()
|
||||
|
|
@ -1150,6 +1246,12 @@ internal class StakingModel @Inject constructor(
|
|||
.getOrElse { false }
|
||||
}
|
||||
|
||||
private fun isCaseWithUnitializedTonAccount(): Boolean {
|
||||
return value.currentStep == StakingStep.Confirmation &&
|
||||
isTon(cryptoCurrencyStatus.currency.network.rawId) &&
|
||||
!isAccountInitialized
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val WHAT_IS_STAKING_ARTICLE_URL = "https://tangem.com/en/blog/post/how-to-stake-cryptocurrency/"
|
||||
const val ALLOWANCE_UPDATE_DELAY = 10_000L
|
||||
|
|
|
|||
|
|
@ -60,6 +60,15 @@ internal object StakingNotification {
|
|||
title = resourceReference(R.string.staking_notification_low_staked_balance_title),
|
||||
subtitle = resourceReference(R.string.staking_notification_low_staked_balance_text),
|
||||
)
|
||||
|
||||
data class InitializeTonAccount(private val onInitializeClick: () -> Unit) : Info(
|
||||
title = resourceReference(R.string.staking_notification_ton_account_initialization_title),
|
||||
subtitle = resourceReference(R.string.staking_notification_ton_account_initialization_message),
|
||||
buttonsState = NotificationConfig.ButtonsState.PrimaryButtonConfig(
|
||||
text = resourceReference(R.string.common_activate),
|
||||
onClick = onInitializeClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
sealed class Info(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.bottomsheet
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||
|
||||
internal data class TonInitializeAccountBottomSheetConfig(
|
||||
val title: TextReference,
|
||||
val message: TextReference,
|
||||
val footer: TextReference,
|
||||
val onButtonClick: () -> Unit,
|
||||
val isButtonEnabled: Boolean,
|
||||
val isButtonLoading: Boolean,
|
||||
val feeState: FeeState,
|
||||
) : TangemBottomSheetConfigContent
|
||||
|
|
@ -62,13 +62,6 @@ internal sealed class StakingAlertUM : AlertUM {
|
|||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
||||
}
|
||||
|
||||
data object InitializeAccount : StakingAlertUM() {
|
||||
override val onConfirmClick: (() -> Unit)? = null
|
||||
override val title: TextReference = resourceReference(id = R.string.staking_error_no_validators_title)
|
||||
override val message: TextReference = resourceReference(id = R.string.staking_notification_ton_activate_account)
|
||||
override val confirmButtonText: TextReference = resourceReference(id = R.string.common_ok)
|
||||
}
|
||||
|
||||
data class RewardsMinimumRequirementsError(
|
||||
val cryptoCurrencyName: String,
|
||||
val cryptoAmountValue: String,
|
||||
|
|
|
|||
|
|
@ -47,11 +47,6 @@ internal class StakingEventFactory(
|
|||
stateController.updateEvent(alert)
|
||||
}
|
||||
|
||||
fun createInitializeAccountAlert() {
|
||||
val alert = StakingEvent.ShowAlert(alert = StakingAlertUM.InitializeAccount)
|
||||
stateController.updateEvent(alert)
|
||||
}
|
||||
|
||||
fun createStakingRewardsMinimumRequirementsErrorAlert(cryptoCurrencyName: String, cryptoAmountValue: String) {
|
||||
stateController.updateEvent(
|
||||
StakingEvent.ShowAlert(
|
||||
|
|
|
|||
|
|
@ -76,6 +76,11 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun partialUpdateWithDelay() {
|
||||
delay(BALANCE_UPDATE_DELAY)
|
||||
partialUpdate()
|
||||
}
|
||||
|
||||
private suspend fun fetchCurrencyStatus(delayMillis: Long = 0L) {
|
||||
delay(delayMillis)
|
||||
fetchCurrencyStatusUseCase(
|
||||
|
|
|
|||
|
|
@ -78,4 +78,8 @@ internal object StakingClickIntentsStub : StakingClickIntents {
|
|||
override fun showPrimaryClickAlert() {}
|
||||
|
||||
override fun onOpenLearnMoreAboutApproveClick() {}
|
||||
|
||||
override fun onActivateTonAccountNotificationClick() {}
|
||||
|
||||
override fun onActivateTonAccountClick() {}
|
||||
}
|
||||
|
|
@ -40,6 +40,7 @@ import java.math.BigDecimal
|
|||
internal class AddStakingNotificationsTransformer(
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val isAccountInitializedProvider: Provider<Boolean>,
|
||||
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||
private val currencyWarning: CryptoCurrencyWarning?,
|
||||
private val feeError: GetFeeError?,
|
||||
|
|
@ -90,34 +91,40 @@ internal class AddStakingNotificationsTransformer(
|
|||
BigDecimal.ZERO
|
||||
}
|
||||
|
||||
val notifications = buildList {
|
||||
// errors
|
||||
addErrorNotifications(
|
||||
prevState = prevState,
|
||||
feeError = feeError,
|
||||
sendingAmount = sendingAmount,
|
||||
onReload = prevState.clickIntents::getFee,
|
||||
feeValue = feeValue,
|
||||
)
|
||||
addStakingErrorNotifications(stakingError = stakingError, onReload = prevState.clickIntents::getFee)
|
||||
// warnings
|
||||
addWarningNotifications(
|
||||
prevState = prevState,
|
||||
amountState = amountState,
|
||||
feeState = feeState,
|
||||
sendingAmount = sendingAmount,
|
||||
isFeeCoverage = isFeeCoverage && isEnterAction && !sendingAmount.equals(minimumRequirement),
|
||||
)
|
||||
val notifications = if (isAccountInitializedProvider.invoke()) {
|
||||
buildList {
|
||||
// errors
|
||||
addErrorNotifications(
|
||||
prevState = prevState,
|
||||
feeError = feeError,
|
||||
sendingAmount = sendingAmount,
|
||||
onReload = prevState.clickIntents::getFee,
|
||||
feeValue = feeValue,
|
||||
)
|
||||
addStakingErrorNotifications(stakingError = stakingError, onReload = prevState.clickIntents::getFee)
|
||||
// warnings
|
||||
addWarningNotifications(
|
||||
prevState = prevState,
|
||||
amountState = amountState,
|
||||
feeState = feeState,
|
||||
sendingAmount = sendingAmount,
|
||||
isFeeCoverage = isFeeCoverage && isEnterAction && !sendingAmount.equals(minimumRequirement),
|
||||
)
|
||||
|
||||
stakingInfoNotificationsFactory.addInfoNotifications(
|
||||
notifications = this,
|
||||
prevState = prevState,
|
||||
sendingAmount = sendingAmount,
|
||||
actionAmount = amountValue,
|
||||
feeValue = feeValue,
|
||||
tonBalanceExtraFeeThreshold = TON_BALANCE_EXTRA_FEE_THRESHOLD,
|
||||
)
|
||||
}.toImmutableList()
|
||||
stakingInfoNotificationsFactory.addInfoNotifications(
|
||||
notifications = this,
|
||||
prevState = prevState,
|
||||
sendingAmount = sendingAmount,
|
||||
actionAmount = amountValue,
|
||||
feeValue = feeValue,
|
||||
tonBalanceExtraFeeThreshold = TON_BALANCE_EXTRA_FEE_THRESHOLD,
|
||||
)
|
||||
}.toImmutableList()
|
||||
} else {
|
||||
buildList {
|
||||
addTonInitializeAccountNotification(prevState)
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
||||
val isActualSources = with(cryptoCurrencyStatus.value) {
|
||||
sources.yieldBalanceSource.isActual() && sources.networkSource.isActual()
|
||||
|
|
@ -130,7 +137,8 @@ internal class AddStakingNotificationsTransformer(
|
|||
it is StakingNotification.Error ||
|
||||
it is NotificationUM.Error ||
|
||||
it is NotificationUM.Warning.NetworkFeeUnreachable ||
|
||||
it is StakingNotification.Warning.TransactionInProgress
|
||||
it is StakingNotification.Warning.TransactionInProgress ||
|
||||
it is StakingNotification.Warning.InitializeTonAccount
|
||||
} && isActualSources,
|
||||
),
|
||||
)
|
||||
|
|
@ -219,7 +227,6 @@ internal class AddStakingNotificationsTransformer(
|
|||
) {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val appCurrency = appCurrencyProvider()
|
||||
cryptoCurrencyStatus.currency
|
||||
|
||||
addRentExemptionNotification(
|
||||
rentWarning = currencyCheck.rentWarning,
|
||||
|
|
@ -282,6 +289,19 @@ internal class AddStakingNotificationsTransformer(
|
|||
}
|
||||
}
|
||||
|
||||
private fun MutableList<NotificationUM>.addTonInitializeAccountNotification(prevState: StakingUiState) {
|
||||
val isAccountInitialized = isAccountInitializedProvider.invoke()
|
||||
val cryptoCurrencyNetworkIdValue = cryptoCurrencyStatusProvider().currency.network.rawId
|
||||
|
||||
if (isTon(cryptoCurrencyNetworkIdValue) && !isAccountInitialized) {
|
||||
add(
|
||||
StakingNotification.Warning.InitializeTonAccount(
|
||||
onInitializeClick = prevState.clickIntents::onActivateTonAccountNotificationClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val TON_BALANCE_EXTRA_FEE_THRESHOLD = BigDecimal(0.2)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers.ton
|
||||
|
||||
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer
|
||||
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer.ReduceByData
|
||||
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class CompleteInitializeBottomSheetTransformer(
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val minimumTransactionAmount: EnterAmountBoundary?,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val prevBottomSheetConfig = prevState.bottomSheetConfig ?: return prevState
|
||||
val prevBottomSheetConfigContent =
|
||||
prevBottomSheetConfig.content as? TonInitializeAccountBottomSheetConfig ?: return prevState
|
||||
|
||||
val feeAmount = (prevBottomSheetConfigContent.feeState as? FeeState.Content)
|
||||
?.fee?.amount?.value?.multiply(BigDecimal(FEE_MULTIPLIER)) ?: return prevState
|
||||
|
||||
val confirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data ?: return prevState
|
||||
|
||||
return prevState.copy(
|
||||
amountState = AmountReduceByTransformer(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
minimumTransactionAmount = minimumTransactionAmount,
|
||||
value = ReduceByData(
|
||||
feeAmount,
|
||||
feeAmount,
|
||||
),
|
||||
).transform(prevState.amountState),
|
||||
confirmationState = confirmationState.copy(
|
||||
reduceAmountBy = feeAmount,
|
||||
),
|
||||
bottomSheetConfig = prevBottomSheetConfig.copy(
|
||||
content = prevBottomSheetConfigContent.copy(
|
||||
isButtonLoading = true,
|
||||
isButtonEnabled = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val FEE_MULTIPLIER = 1.1
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers.ton
|
||||
|
||||
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class SetFeeErrorToTonInitializeBottomSheetTransformer : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val prevBottomSheetConfig = prevState.bottomSheetConfig ?: return prevState
|
||||
val prevBottomSheetConfigContent =
|
||||
prevBottomSheetConfig.content as? TonInitializeAccountBottomSheetConfig ?: return prevState
|
||||
|
||||
return prevState.copy(
|
||||
bottomSheetConfig = prevBottomSheetConfig.copy(
|
||||
content = prevBottomSheetConfigContent.copy(
|
||||
isButtonEnabled = false,
|
||||
feeState = FeeState.Error,
|
||||
isButtonLoading = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers.ton
|
||||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class SetFeeToTonInitializeBottomSheetTransformer(
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||
private val fee: Fee,
|
||||
private val isFeeApproximate: Boolean,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val prevBottomSheetConfig = prevState.bottomSheetConfig ?: return prevState
|
||||
val prevBottomSheetConfigContent =
|
||||
prevBottomSheetConfig.content as? TonInitializeAccountBottomSheetConfig ?: return prevState
|
||||
|
||||
val isFeeConvertibleToFiat = feeCryptoCurrencyStatus?.currency?.network?.hasFiatFeeRate == true
|
||||
return prevState.copy(
|
||||
bottomSheetConfig = prevBottomSheetConfig.copy(
|
||||
content = prevBottomSheetConfigContent.copy(
|
||||
isButtonEnabled = true,
|
||||
isButtonLoading = false,
|
||||
feeState = FeeState.Content(
|
||||
fee = fee,
|
||||
rate = feeCryptoCurrencyStatus?.value?.fiatRate,
|
||||
isFeeConvertibleToFiat = isFeeConvertibleToFiat,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
isFeeApproximate = isFeeApproximate,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers.ton
|
||||
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class ShowTonInitializeBottomSheetTransformer(
|
||||
private val onDismiss: () -> Unit,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
return prevState.copy(
|
||||
bottomSheetConfig = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = onDismiss,
|
||||
content = TonInitializeAccountBottomSheetConfig(
|
||||
title = resourceReference(R.string.staking_account_initialization_title),
|
||||
message = resourceReference(R.string.staking_account_initialization_message),
|
||||
footer = resourceReference(R.string.staking_account_initialization_footer),
|
||||
onButtonClick = prevState.clickIntents::onActivateTonAccountClick,
|
||||
isButtonEnabled = false,
|
||||
feeState = FeeState.Loading,
|
||||
isButtonLoading = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -28,8 +28,10 @@ import com.tangem.features.staking.impl.presentation.state.StakingStep
|
|||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.StakingActionSelectionBottomSheetConfig
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.StakingInfoBottomSheetConfig
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||
import com.tangem.features.staking.impl.presentation.ui.bottomsheet.StakingActionSelectorBottomSheet
|
||||
import com.tangem.features.staking.impl.presentation.ui.bottomsheet.StakingInfoBottomSheet
|
||||
import com.tangem.features.staking.impl.presentation.ui.bottomsheet.TonInitializeAccountBottomSheet
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
|
@ -83,6 +85,7 @@ fun StakingBottomSheet(bottomSheetConfig: TangemBottomSheetConfig?) {
|
|||
is StakingInfoBottomSheetConfig -> StakingInfoBottomSheet(bottomSheetConfig)
|
||||
is GiveTxPermissionBottomSheetConfig -> GiveTxPermissionBottomSheet(bottomSheetConfig)
|
||||
is StakingActionSelectionBottomSheetConfig -> StakingActionSelectorBottomSheet(bottomSheetConfig)
|
||||
is TonInitializeAccountBottomSheetConfig -> TonInitializeAccountBottomSheet(bottomSheetConfig)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,158 @@
|
|||
package com.tangem.features.staking.impl.presentation.ui.bottomsheet
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButton
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.TonInitializeAccountBottomSheetConfig
|
||||
import com.tangem.features.staking.impl.presentation.ui.block.StakingFeeBlock
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Composable
|
||||
internal fun TonInitializeAccountBottomSheet(config: TangemBottomSheetConfig) {
|
||||
TangemBottomSheet<TonInitializeAccountBottomSheetConfig>(
|
||||
config = config,
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
) { content ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing16,
|
||||
)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
SpacerH(height = 16.dp)
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.img_ton_22),
|
||||
modifier = Modifier.size(56.dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
SpacerH(height = 24.dp)
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
text = content.title.resolveReference(),
|
||||
style = TangemTheme.typography.h3,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
SpacerH(height = 16.dp)
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
text = content.message.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
SpacerH(height = 24.dp)
|
||||
|
||||
StakingFeeBlock(content.feeState)
|
||||
|
||||
SpacerH(height = 12.dp)
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
text = content.footer.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
SpacerH(height = 20.dp)
|
||||
|
||||
TangemButton(
|
||||
text = stringResourceSafe(R.string.common_activate),
|
||||
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_tangem_24),
|
||||
onClick = content.onButtonClick,
|
||||
colors = TangemButtonsDefaults.primaryButtonColors,
|
||||
showProgress = content.feeState is FeeState.Loading || content.isButtonLoading,
|
||||
enabled = content.isButtonEnabled,
|
||||
size = TangemButtonSize.WideAction,
|
||||
textStyle = TangemTheme.typography.subtitle1,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
|
||||
SpacerH(height = 8.dp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_TonInitializeAccountBottomSheetContent() {
|
||||
TangemThemePreview {
|
||||
TonInitializeAccountBottomSheet(
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = {},
|
||||
content = TonInitializeAccountBottomSheetConfig(
|
||||
title = resourceReference(R.string.staking_account_initialization_title),
|
||||
message = resourceReference(R.string.staking_account_initialization_message),
|
||||
footer = resourceReference(R.string.staking_account_initialization_footer),
|
||||
onButtonClick = {},
|
||||
isButtonEnabled = true,
|
||||
isButtonLoading = false,
|
||||
feeState = FeeState.Content(
|
||||
fee = Fee.Common(
|
||||
amount = Amount(
|
||||
currencySymbol = "MATIC",
|
||||
value = BigDecimal(0.159806),
|
||||
decimals = 18,
|
||||
type = AmountType.Coin,
|
||||
),
|
||||
),
|
||||
rate = BigDecimal.ONE,
|
||||
appCurrency = AppCurrency.Default,
|
||||
isFeeApproximate = false,
|
||||
isFeeConvertibleToFiat = true,
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
// endregion Preview
|
||||
|
|
@ -241,8 +241,8 @@ internal class SwapNotificationsFactory(
|
|||
) {
|
||||
add(
|
||||
SwapNotificationUM.Info.PermissionNeeded(
|
||||
providerName = fromToken.symbol,
|
||||
fromTokenSymbol = providerName,
|
||||
providerName = providerName,
|
||||
fromTokenSymbol = fromToken.symbol,
|
||||
onApproveClick = actions.openPermissionBottomSheet,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ internal object SwapNotificationUM {
|
|||
),
|
||||
iconResId = R.drawable.ic_locked_24,
|
||||
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||
text = TextReference.Res(R.string.common_approve),
|
||||
text = TextReference.Res(R.string.give_permission_title),
|
||||
onClick = onApproveClick,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,16 +2,15 @@
|
|||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs = -Xmx6144m -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
org.gradle.parallel = true
|
||||
org.gradle.daemon = true
|
||||
android.useAndroidX = true
|
||||
org.gradle.unsafe.configuration-cache = true
|
||||
android.nonTransitiveRClass = false
|
||||
org.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
org.gradle.parallel=true
|
||||
org.gradle.workers.max=8
|
||||
org.gradle.daemon=true
|
||||
org.gradle.caching=true
|
||||
org.gradle.configuration-cache=true
|
||||
|
||||
android.useAndroidX=true
|
||||
android.nonTransitiveRClass=false
|
||||
|
||||
kotlin.incremental=true
|
||||
Loading…
Add table
Add a link
Reference in a new issue