Updated on 2026-08-14
This commit is contained in:
commit
d91a0ec820
19 changed files with 841 additions and 20 deletions
|
|
@ -280,7 +280,7 @@
|
|||
<string name="common_origin_ring">Primärring</string>
|
||||
<string name="common_passphrase">Passphrase</string>
|
||||
<string name="common_paste">Einfügen</string>
|
||||
<string name="common_privacy_policy">Datenschutzbestimmungen</string>
|
||||
<string name="common_privacy_policy">Datenschutzrichtlinie</string>
|
||||
<string name="common_range">%1$s-%2$s</string>
|
||||
<string name="common_range_with_space">%1$s — %2$s</string>
|
||||
<string name="common_read_more">Weiterlesen</string>
|
||||
|
|
@ -317,6 +317,7 @@
|
|||
<string name="common_supported_networks">Unterstützte Netzwerke</string>
|
||||
<string name="common_swap">Tauschen</string>
|
||||
<string name="common_tangem">Tangem</string>
|
||||
<string name="common_tangem_wallet">Tangem Wallet</string>
|
||||
<string name="common_terms_and_conditions">Allgemeine Geschäftsbedingungen</string>
|
||||
<string name="common_terms_of_use">Nutzungsbedingungen</string>
|
||||
<string name="common_today">Heute</string>
|
||||
|
|
@ -418,7 +419,7 @@
|
|||
<string name="express_exchange_by">Getauscht von %s</string>
|
||||
<string name="express_exchange_notification_failed_text">Besuche die Website des Anbieters, um dein Geld zurückzuerhalten</string>
|
||||
<string name="express_exchange_notification_failed_title">Fehler beim Vorgang durch Anbieter</string>
|
||||
<string name="express_exchange_notification_long_transaction_time_text">Dein Wechsel dauert länger als erwartet. Wende Dich für Hilfe bitte an den Support Deines Anbieters.</string>
|
||||
<string name="express_exchange_notification_long_transaction_time_text">Dein Swap dauert länger als üblich, aber Dein Geld ist absolut sicher und wird geliefert. Bei Fragen kannst Du Dich an das Support-Team des Anbieters wenden.</string>
|
||||
<string name="express_exchange_notification_long_transaction_time_title">Lange Transaktionszeit</string>
|
||||
<string name="express_exchange_notification_refund_text">Der Transaktionsbetrag wurde aufgrund von OKX- oder Bridge-Regeln in %1$s auf deine Wallet zurückerstattet. %2$s</string>
|
||||
<string name="express_exchange_notification_refund_title">Der Betrag wurde in %1$s (%2$s Netzwerk) zurückerstattet.</string>
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@
|
|||
<string name="common_camera_denied_alert_message">カメラへのアクセスを許可していません。プライバシー設定を調整してください。</string>
|
||||
<string name="common_cancel">キャンセル</string>
|
||||
<string name="common_change">変更</string>
|
||||
<string name="common_choose_account">アカウントを選択</string>
|
||||
<string name="common_choose_action">アクションを選択</string>
|
||||
<string name="common_choose_network">ネットワークを選択</string>
|
||||
<string name="common_choose_token">トークンを選択</string>
|
||||
|
|
@ -1247,6 +1248,14 @@
|
|||
<string name="swapping_to_title">受け取る</string>
|
||||
<string name="swapping_token_list_title">トークンを選択</string>
|
||||
<string name="swapping_token_not_available">利用不可</string>
|
||||
<string name="tangempay_onboarding_get_card_button_text">カードをGET</string>
|
||||
<string name="tangempay_onboarding_pay_description">ウォレットに追加して、どこでもスマートフォンで支払いができます。</string>
|
||||
<string name="tangempay_onboarding_pay_title">Apple Pay & Google Pay</string>
|
||||
<string name="tangempay_onboarding_purchases_description">USDC残高を使用して、毎日のお買い物をシームレスに支払います。</string>
|
||||
<string name="tangempay_onboarding_purchases_title">日常の買い物</string>
|
||||
<string name="tangempay_onboarding_security_description">カードの詳細は保護されており、アプリ内で完全に制御できます。</string>
|
||||
<string name="tangempay_onboarding_security_title">内蔵セキュリティ</string>
|
||||
<string name="tangempay_onboarding_title">無料のCryptoカード\nを数分で入手しましょう</string>
|
||||
<string name="this_is_my_wallet_title">これは私のウォレットです</string>
|
||||
<string name="toast_balances_hidden">残高非表示</string>
|
||||
<string name="toast_balances_shown">残高表示</string>
|
||||
|
|
@ -1634,7 +1643,6 @@
|
|||
<string name="yield_module_earn_sheet_current_apy_title">現在のAPY</string>
|
||||
<string name="yield_module_earn_sheet_my_funds_title">私の資金</string>
|
||||
<string name="yield_module_earn_sheet_provider_description">あなたの%1$sはAaveに預けられ、利息が付きます。あなたは%2$sトークンを保有しており、これは残高を表し、時間の経過とともに増加します。入金すると、資金はAaveに預け入れられ、取引手数料を差し引いた利息が付きます。</string>
|
||||
<string name="yield_module_earn_sheet_status_active">アクティブ</string>
|
||||
<string name="yield_module_earn_sheet_title">利回りを得る</string>
|
||||
<string name="yield_module_earn_sheet_total_earnings_title">総収益</string>
|
||||
<string name="yield_module_earn_sheet_transfers_title">Aaveへの送金</string>
|
||||
|
|
@ -1656,7 +1664,7 @@
|
|||
<string name="yield_module_promo_screen_how_it_works_button_title">使い方</string>
|
||||
<string name="yield_module_promo_screen_self_custodial_subtitle">Aaveは世界中で何百万人もの人々に信頼されています。総貸付額は104億ドルです。</string>
|
||||
<string name="yield_module_promo_screen_self_custodial_title">分散型・自己管理型</string>
|
||||
<string name="yield_module_promo_screen_terms_disclaimer">サービスを使用することにより、プロバイダーに同意したものとみなされます</string>
|
||||
<string name="yield_module_promo_screen_terms_disclaimer">サービスを利用することにより、プロバイダー\n %1$sおよび%2$sに同意したことになります</string>
|
||||
<string name="yield_module_promo_screen_title">年間%s%%の収益</string>
|
||||
<string name="yield_module_promo_screen_variable_rate_info">Aave • 変動金利</string>
|
||||
<string name="yield_module_provider">Aave</string>
|
||||
|
|
@ -1670,6 +1678,7 @@
|
|||
<string name="yield_module_start_earning_sheet_description">%sはAaveに供給され、すぐに利用可能になります</string>
|
||||
<string name="yield_module_start_earning_sheet_fee_policy">手数料ポリシーを見る</string>
|
||||
<string name="yield_module_start_earning_sheet_next_deposits">次回の入金は自動的にAaveに供給されます。</string>
|
||||
<string name="yield_module_status_active">アクティブ</string>
|
||||
<string name="yield_module_stop_earning">収益を停止する</string>
|
||||
<string name="yield_module_stop_earning_sheet_description">オフにすると、Aaveから資金が引き出され、ウォレットの%sに戻され、報酬の獲得が停止されます。</string>
|
||||
<string name="yield_module_stop_earning_sheet_fee_note">出金金額からネットワーク手数料が差し引かれます。</string>
|
||||
|
|
|
|||
|
|
@ -1623,6 +1623,7 @@
|
|||
<string name="wc_alert_wrong_card_title">We\'ve got some kind of problem</string>
|
||||
<string name="wc_all_dapps_disconnected">All dApps disconnected</string>
|
||||
<string name="wc_allow_to_spend">Allow to spend</string>
|
||||
<string name="wc_approve_description">By approving, you allow dApp or Smart contract to use tokens in future transactions.</string>
|
||||
<string name="wc_common_address">Address</string>
|
||||
<string name="wc_common_connect">Connect</string>
|
||||
<string name="wc_common_loading">Loading</string>
|
||||
|
|
@ -1711,7 +1712,6 @@
|
|||
<string name="yield_module_earn_sheet_current_apy_title">Current APY</string>
|
||||
<string name="yield_module_earn_sheet_my_funds_title">My Funds</string>
|
||||
<string name="yield_module_earn_sheet_provider_description">Your %1$s is now deposited in Aave and earning interest. You hold a%2$s token, which represents your balance and grows over time. When you top up, funds go to Aave to earn interest, minus a transaction fee.</string>
|
||||
<string name="yield_module_earn_sheet_status_active">Active</string>
|
||||
<string name="yield_module_earn_sheet_title">Earn</string>
|
||||
<string name="yield_module_earn_sheet_total_earnings_title">Total earnings</string>
|
||||
<string name="yield_module_earn_sheet_transfers_title">Transfers to Aave</string>
|
||||
|
|
@ -1733,7 +1733,7 @@
|
|||
<string name="yield_module_promo_screen_how_it_works_button_title">How it works?</string>
|
||||
<string name="yield_module_promo_screen_self_custodial_subtitle">Aave is trusted by millions worldwide. Total lended value is $10.4B.</string>
|
||||
<string name="yield_module_promo_screen_self_custodial_title">Decentralized and self-custodial</string>
|
||||
<string name="yield_module_promo_screen_terms_disclaimer">By using service, you agree with provider %1$s and %2$s</string>
|
||||
<string name="yield_module_promo_screen_terms_disclaimer">By using service, you agree with provider\n%1$s and %2$s</string>
|
||||
<string name="yield_module_promo_screen_title">Earn %s%% yearly</string>
|
||||
<string name="yield_module_promo_screen_variable_rate_info">Aave • Variable Interest Rate</string>
|
||||
<string name="yield_module_provider">Aave</string>
|
||||
|
|
@ -1747,6 +1747,8 @@
|
|||
<string name="yield_module_start_earning_sheet_description">Your %s will be supplied to Aave and will stay instantly available</string>
|
||||
<string name="yield_module_start_earning_sheet_fee_policy">See fee policy</string>
|
||||
<string name="yield_module_start_earning_sheet_next_deposits">Your next deposits will be automatically supplied to Aave.</string>
|
||||
<string name="yield_module_status_active">Active</string>
|
||||
<string name="yield_module_status_paused">Paused</string>
|
||||
<string name="yield_module_stop_earning">Stop earning</string>
|
||||
<string name="yield_module_stop_earning_sheet_description">Turning off will withdraw your funds from Aave, return them to %s in your wallet, and stop earning rewards.</string>
|
||||
<string name="yield_module_stop_earning_sheet_fee_note">The network fee will be deducted from the amount you withdraw.</string>
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@ package com.tangem.core.ui.components.containers
|
|||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -17,14 +18,14 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
*
|
||||
* @param modifier of component
|
||||
* @param footer text
|
||||
* @param footerTopPadding padding between footer and field
|
||||
* @param paddingValues padding between footer and field
|
||||
* @param content field content
|
||||
*/
|
||||
@Composable
|
||||
fun FooterContainer(
|
||||
modifier: Modifier = Modifier,
|
||||
footer: TextReference? = null,
|
||||
footerTopPadding: Dp = TangemTheme.dimens.spacing8,
|
||||
paddingValues: PaddingValues = PaddingValues(top = 8.dp),
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
|
|
@ -36,7 +37,7 @@ fun FooterContainer(
|
|||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
modifier = Modifier
|
||||
.padding(top = footerTopPadding),
|
||||
.padding(paddingValues),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.core.ui.decompose
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Stable
|
||||
interface ComposableModularContentComponent {
|
||||
|
||||
@Composable
|
||||
fun Title()
|
||||
|
||||
@Composable
|
||||
fun Content(modifier: Modifier)
|
||||
|
||||
@Composable
|
||||
fun Footer()
|
||||
}
|
||||
|
||||
fun getEmptyComposableModularContentComponent() = EmptyComposableModularContentComponent
|
||||
|
||||
object EmptyComposableModularContentComponent : ComposableModularContentComponent {
|
||||
@Composable
|
||||
override fun Title() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Footer() {
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
18
core/ui/src/main/res/drawable/ic_aave_36.xml
Normal file
18
core/ui/src/main/res/drawable/ic_aave_36.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="36dp"
|
||||
android:height="36dp"
|
||||
android:viewportWidth="36"
|
||||
android:viewportHeight="36">
|
||||
<path
|
||||
android:pathData="M18,36C27.941,36 36,27.941 36,18C36,8.059 27.941,0 18,0C8.059,0 0,8.059 0,18C0,27.941 8.059,36 18,36Z"
|
||||
android:fillColor="#9391F7"/>
|
||||
<path
|
||||
android:pathData="M14.654,18.878C16.197,18.627 17.245,17.173 16.995,15.629C16.744,14.086 15.29,13.038 13.746,13.288C12.203,13.539 11.155,14.993 11.405,16.537C11.656,18.08 13.11,19.128 14.654,18.878Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M22.054,18.878C23.597,18.627 24.646,17.173 24.395,15.629C24.145,14.086 22.69,13.038 21.147,13.288C19.603,13.539 18.555,14.993 18.806,16.537C19.056,18.08 20.51,19.128 22.054,18.878Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M17.895,4.395C10.208,4.395 3.975,10.747 3.977,18.58H7.533C7.533,12.71 12.135,7.95 17.895,7.95C23.655,7.95 28.258,12.71 28.258,18.58H31.814C31.815,10.747 25.583,4.395 17.895,4.395Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
|
|
@ -1,13 +1,16 @@
|
|||
package com.tangem.domain.yield.supply.usecase
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyEnterCallData
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.transaction.FeeRepository
|
||||
import com.tangem.domain.transaction.error.FeeErrorResolver
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.utils.extensions.isSingleItem
|
||||
|
||||
class YieldSupplyEstimateEnterFeeUseCase(
|
||||
private val feeRepository: FeeRepository,
|
||||
|
|
@ -18,19 +21,36 @@ class YieldSupplyEstimateEnterFeeUseCase(
|
|||
cryptoCurrency: CryptoCurrency,
|
||||
transactionDataList: List<TransactionData.Uncompiled>,
|
||||
): Either<GetFeeError, List<TransactionData.Uncompiled>> = Either.catch {
|
||||
transactionDataList.mapIndexed { index, transaction ->
|
||||
val fee = feeRepository.calculateFee(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionData = transaction,
|
||||
).normal
|
||||
val withCalculatedFee = transactionDataList.filter {
|
||||
(it.extras as? EthereumTransactionExtras)?.callData !is EthereumYieldSupplyEnterCallData
|
||||
}.map { transaction ->
|
||||
transaction.copy(
|
||||
fee = feeRepository.calculateFee(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionData = transaction,
|
||||
).normal,
|
||||
)
|
||||
}
|
||||
|
||||
if (index == transactionDataList.lastIndex) { // todo yield supply replace with check for contract
|
||||
transaction.copy(fee = fee.fixFee(cryptoCurrency))
|
||||
val withEstimatedCalculatedFee = transactionDataList.filter {
|
||||
(it.extras as? EthereumTransactionExtras)?.callData is EthereumYieldSupplyEnterCallData
|
||||
}.map { transaction ->
|
||||
if (transactionDataList.isSingleItem()) {
|
||||
transaction.copy(
|
||||
fee = feeRepository.calculateFee(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionData = transaction,
|
||||
).normal,
|
||||
)
|
||||
} else {
|
||||
transaction.copy(fee = fee)
|
||||
transaction.copy(fee = withCalculatedFee.first().fee?.fixFee(cryptoCurrency))
|
||||
}
|
||||
}
|
||||
|
||||
// Transactions order must be preserved
|
||||
withCalculatedFee + withEstimatedCalculatedFee
|
||||
}.mapLeft(feeErrorResolver::resolve)
|
||||
|
||||
private fun Fee.fixFee(cryptoCurrency: CryptoCurrency) = when (this) {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ dependencies {
|
|||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.transaction.models)
|
||||
implementation(projects.domain.transaction)
|
||||
implementation(projects.domain.yieldSupply)
|
||||
|
||||
/** Compose */
|
||||
implementation(deps.compose.foundation)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.features.yield.supply.impl.common.entity
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
internal sealed class YieldSupplyFeeUM {
|
||||
data object Loading : YieldSupplyFeeUM()
|
||||
data object Error : YieldSupplyFeeUM()
|
||||
data class Content(
|
||||
val transactionDataList: ImmutableList<TransactionData.Uncompiled>,
|
||||
val feeValue: TextReference,
|
||||
) : YieldSupplyFeeUM()
|
||||
}
|
||||
|
||||
internal data class YieldSupplyActionUM(
|
||||
val title: TextReference,
|
||||
val subtitle: TextReference,
|
||||
val footer: TextReference,
|
||||
val currencyIconState: CurrencyIconState,
|
||||
val yieldSupplyFeeUM: YieldSupplyFeeUM,
|
||||
val isPrimaryButtonEnabled: Boolean,
|
||||
)
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
package com.tangem.features.yield.supply.impl.common.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.components.containers.FooterContainer
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM
|
||||
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM
|
||||
import com.tangem.utils.StringsSigns
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Composable
|
||||
internal fun YieldSupplyActionContent(
|
||||
yieldSupplyActionUM: YieldSupplyActionUM,
|
||||
modifier: Modifier = Modifier,
|
||||
iconContent: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier.padding(bottom = 16.dp, start = 16.dp, end = 16.dp),
|
||||
) {
|
||||
iconContent()
|
||||
SpacerH24()
|
||||
Text(
|
||||
text = yieldSupplyActionUM.title.resolveReference(),
|
||||
style = TangemTheme.typography.h3,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
SpacerH8()
|
||||
Text(
|
||||
text = yieldSupplyActionUM.subtitle.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
SpacerH24()
|
||||
FooterContainer(
|
||||
footer = yieldSupplyActionUM.footer,
|
||||
paddingValues = PaddingValues(
|
||||
start = 12.dp,
|
||||
end = 12.dp,
|
||||
top = 8.dp,
|
||||
),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.common_network_fee_title),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
SpacerWMax()
|
||||
when (val fee = yieldSupplyActionUM.yieldSupplyFeeUM) {
|
||||
is YieldSupplyFeeUM.Content -> Text(
|
||||
text = fee.feeValue.resolveReference(),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
YieldSupplyFeeUM.Error -> Text(
|
||||
text = stringResourceSafe(R.string.common_fee_error),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.attention,
|
||||
)
|
||||
YieldSupplyFeeUM.Loading -> {
|
||||
TextShimmer(
|
||||
style = TangemTheme.typography.body1,
|
||||
text = stringResourceSafe(R.string.common_fee_error),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 344)
|
||||
@Preview(showBackground = true, widthDp = 344, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun YieldSupplyActionContent_Preview(
|
||||
@PreviewParameter(YieldSupplyActionContentPreviewProvider::class) params: YieldSupplyActionUM,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
YieldSupplyActionContent(
|
||||
yieldSupplyActionUM = params,
|
||||
modifier = Modifier.background(TangemTheme.colors.background.tertiary),
|
||||
) {
|
||||
CurrencyIcon(
|
||||
state = CurrencyIconState.Loading,
|
||||
shouldDisplayNetwork = false,
|
||||
iconSize = 48.dp,
|
||||
modifier = Modifier.size(48.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class YieldSupplyActionContentPreviewProvider : PreviewParameterProvider<YieldSupplyActionUM> {
|
||||
override val values: Sequence<YieldSupplyActionUM>
|
||||
get() = sequenceOf(
|
||||
YieldSupplyActionUM(
|
||||
title = resourceReference(R.string.yield_module_start_earning),
|
||||
subtitle = resourceReference(
|
||||
R.string.yield_module_start_earning_sheet_description,
|
||||
wrappedList("USDT"),
|
||||
),
|
||||
footer = combinedReference(
|
||||
resourceReference(R.string.yield_module_start_earning_sheet_next_deposits),
|
||||
stringReference(StringsSigns.WHITE_SPACE),
|
||||
resourceReference(R.string.yield_module_start_earning_sheet_fee_policy),
|
||||
),
|
||||
currencyIconState = CurrencyIconState.Loading,
|
||||
yieldSupplyFeeUM = YieldSupplyFeeUM.Content(
|
||||
transactionDataList = persistentListOf(),
|
||||
feeValue = stringReference("0.00020 ETH • \$0.99"),
|
||||
),
|
||||
isPrimaryButtonEnabled = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package com.tangem.features.yield.supply.impl.subcomponents.startearning
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
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.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.PrimaryButtonIconEnd
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.decompose.ComposableModularContentComponent
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.impl.common.ui.YieldSupplyActionContent
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.startearning.model.YieldSupplyStartEarningModel
|
||||
|
||||
internal class YieldSupplyStartEarningComponent(
|
||||
private val appComponentContext: AppComponentContext,
|
||||
private val params: Params,
|
||||
) : ComposableModularContentComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: YieldSupplyStartEarningModel = getOrCreateModel(params = params)
|
||||
|
||||
@Composable
|
||||
override fun Title() {
|
||||
TangemModalBottomSheetTitle(
|
||||
endIconRes = R.drawable.ic_close_24,
|
||||
onEndClick = params.callback::onBackClick,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
YieldSupplyActionContent(
|
||||
yieldSupplyActionUM = state,
|
||||
modifier = modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(80.dp)
|
||||
.padding(vertical = 1.dp),
|
||||
) {
|
||||
CurrencyIcon(
|
||||
state = state.currencyIconState,
|
||||
shouldDisplayNetwork = false,
|
||||
iconSize = 48.dp,
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.clip(RoundedCornerShape(48.dp))
|
||||
.align(Alignment.CenterStart),
|
||||
)
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_aave_36),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors.background.tertiary, RoundedCornerShape(51.dp))
|
||||
.padding(3.dp)
|
||||
.size(48.dp)
|
||||
.align(Alignment.CenterEnd),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Footer() {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
PrimaryButtonIconEnd(
|
||||
text = stringResourceSafe(R.string.yield_module_start_earning),
|
||||
onClick = model::onClick,
|
||||
enabled = state.isPrimaryButtonEnabled,
|
||||
iconResId = R.drawable.ic_tangem_24,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
val callback: ModelCallback,
|
||||
)
|
||||
|
||||
interface ModelCallback {
|
||||
fun onBackClick()
|
||||
fun onFeePolicyClick()
|
||||
fun onTransactionSent()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.tangem.features.yield.supply.impl.subcomponents.startearning
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.childStack
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableModularContentComponent
|
||||
import com.tangem.core.ui.decompose.getEmptyComposableModularContentComponent
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.startearning.model.YieldSupplyStartEarningEntryModel
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.startearning.ui.YieldSupplyStartEarningBottomSheet
|
||||
|
||||
internal class YieldSupplyStartEarningEntryComponent(
|
||||
private val appComponentContext: AppComponentContext,
|
||||
private val params: Params,
|
||||
) : ComposableBottomSheetComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val stackNavigation = StackNavigation<YieldSupplyStartEarningRoute>()
|
||||
|
||||
private val innerRouter = InnerRouter<YieldSupplyStartEarningRoute>(
|
||||
stackNavigation = stackNavigation,
|
||||
popCallback = { onChildBack() },
|
||||
)
|
||||
|
||||
private val model: YieldSupplyStartEarningEntryModel = getOrCreateModel(params = params, router = innerRouter)
|
||||
|
||||
private val innerStack = childStack(
|
||||
key = "startEarningStack",
|
||||
source = stackNavigation,
|
||||
serializer = null,
|
||||
initialConfiguration = YieldSupplyStartEarningRoute.Action,
|
||||
handleBackButton = true,
|
||||
childFactory = { configuration, factoryContext ->
|
||||
createChild(
|
||||
configuration,
|
||||
childByContext(
|
||||
componentContext = factoryContext,
|
||||
router = innerRouter,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
override fun dismiss() {
|
||||
params.onDismiss(false)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val stackState by innerStack.subscribeAsState()
|
||||
|
||||
YieldSupplyStartEarningBottomSheet(
|
||||
stackState = stackState,
|
||||
onDismiss = ::dismiss,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createChild(
|
||||
route: YieldSupplyStartEarningRoute,
|
||||
factoryContext: AppComponentContext,
|
||||
): ComposableModularContentComponent = when (route) {
|
||||
YieldSupplyStartEarningRoute.FeePolicy -> getEmptyComposableModularContentComponent() // todo fee policy
|
||||
YieldSupplyStartEarningRoute.Action -> YieldSupplyStartEarningComponent(
|
||||
appComponentContext = factoryContext,
|
||||
params = YieldSupplyStartEarningComponent.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrency = params.cryptoCurrency,
|
||||
callback = model,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun onChildBack() {
|
||||
if (innerStack.value.backStack.isEmpty()) {
|
||||
dismiss()
|
||||
} else {
|
||||
stackNavigation.pop()
|
||||
}
|
||||
}
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
val onDismiss: (Boolean) -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.features.yield.supply.impl.subcomponents.startearning
|
||||
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
|
||||
internal sealed class YieldSupplyStartEarningRoute : Route {
|
||||
data object Action : YieldSupplyStartEarningRoute()
|
||||
data object FeePolicy : YieldSupplyStartEarningRoute()
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.features.yield.supply.impl.subcomponents.startearning.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.startearning.model.YieldSupplyStartEarningEntryModel
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.startearning.model.YieldSupplyStartEarningModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface YieldSupplyStartEarningModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(YieldSupplyStartEarningModel::class)
|
||||
fun provideYieldSupplyStartEarningModel(impl: YieldSupplyStartEarningModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(YieldSupplyStartEarningEntryModel::class)
|
||||
fun provideYieldSupplyStartEarningEntryModel(impl: YieldSupplyStartEarningEntryModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.yield.supply.impl.subcomponents.startearning.entity
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
@Immutable
|
||||
internal sealed class YieldSupplyStartEarningContentUM : TangemBottomSheetConfigContent {
|
||||
|
||||
data class Main(
|
||||
val currencyIconState: CurrencyIconState,
|
||||
val fee: Fee?,
|
||||
) : YieldSupplyStartEarningContentUM()
|
||||
|
||||
data class FeePolicy(
|
||||
val title: TextReference,
|
||||
) : YieldSupplyStartEarningContentUM()
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.features.yield.supply.impl.subcomponents.startearning.model
|
||||
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.startearning.YieldSupplyStartEarningComponent
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.startearning.YieldSupplyStartEarningEntryComponent
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.startearning.YieldSupplyStartEarningRoute
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class YieldSupplyStartEarningEntryModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val router: Router,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model(), YieldSupplyStartEarningComponent.ModelCallback {
|
||||
|
||||
private val params = paramsContainer.require<YieldSupplyStartEarningEntryComponent.Params>()
|
||||
|
||||
override fun onBackClick() {
|
||||
router.pop()
|
||||
}
|
||||
|
||||
override fun onFeePolicyClick() {
|
||||
router.push(YieldSupplyStartEarningRoute.FeePolicy)
|
||||
}
|
||||
|
||||
override fun onTransactionSent() {
|
||||
params.onDismiss(true)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
package com.tangem.features.yield.supply.impl.subcomponents.startearning.model
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchain.common.TransactionSender
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.extensions.combinedReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
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.entity.YieldSupplyActionUM
|
||||
import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.startearning.YieldSupplyStartEarningComponent
|
||||
import com.tangem.utils.StringsSigns.DOT
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@ModelScoped
|
||||
internal class YieldSupplyStartEarningModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
paramsContainer: ParamsContainer,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
|
||||
private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase,
|
||||
private val sendTransactionUseCase: SendTransactionUseCase,
|
||||
private val yieldSupplyStartEarningUseCase: YieldSupplyStartEarningUseCase,
|
||||
private val yieldSupplyEstimateEnterFeeUseCase: YieldSupplyEstimateEnterFeeUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
) : Model() {
|
||||
|
||||
private val params: YieldSupplyStartEarningComponent.Params = paramsContainer.require()
|
||||
|
||||
private val cryptoCurrency = params.cryptoCurrency
|
||||
private var userWallet: UserWallet by Delegates.notNull()
|
||||
|
||||
private val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>
|
||||
field = MutableStateFlow(
|
||||
CryptoCurrencyStatus(
|
||||
currency = cryptoCurrency,
|
||||
value = CryptoCurrencyStatus.Loading,
|
||||
),
|
||||
)
|
||||
private val feeCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>
|
||||
field = MutableStateFlow(
|
||||
CryptoCurrencyStatus(
|
||||
currency = cryptoCurrency,
|
||||
value = CryptoCurrencyStatus.Loading,
|
||||
),
|
||||
)
|
||||
|
||||
val uiState: StateFlow<YieldSupplyActionUM>
|
||||
field: MutableStateFlow<YieldSupplyActionUM> = MutableStateFlow(
|
||||
YieldSupplyActionUM(
|
||||
title = resourceReference(R.string.yield_module_start_earning),
|
||||
subtitle = resourceReference(
|
||||
R.string.yield_module_start_earning_sheet_description,
|
||||
wrappedList(cryptoCurrency.symbol),
|
||||
),
|
||||
footer = combinedReference(
|
||||
resourceReference(R.string.yield_module_start_earning_sheet_next_deposits),
|
||||
resourceReference(R.string.yield_module_start_earning_sheet_fee_policy),
|
||||
),
|
||||
currencyIconState = CryptoCurrencyToIconStateConverter().convert(params.cryptoCurrency),
|
||||
yieldSupplyFeeUM = YieldSupplyFeeUM.Loading,
|
||||
isPrimaryButtonEnabled = false,
|
||||
),
|
||||
)
|
||||
|
||||
private val cryptoCurrencyStatus
|
||||
get() = cryptoCurrencyStatusFlow.value
|
||||
private var appCurrency = AppCurrency.Default
|
||||
|
||||
init {
|
||||
modelScope.launch {
|
||||
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
|
||||
subscribeOnCurrencyStatusUpdates()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun onLoadFee() {
|
||||
if (cryptoCurrencyStatus.value is CryptoCurrencyStatus.Loading) return
|
||||
|
||||
val transactionListData = yieldSupplyStartEarningUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
).getOrNull() ?: return
|
||||
|
||||
val updatedTransactionList = yieldSupplyEstimateEnterFeeUseCase.invoke(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
transactionDataList = transactionListData,
|
||||
).getOrNull() ?: return
|
||||
|
||||
val feeSum = updatedTransactionList.sumOf {
|
||||
it.fee?.amount?.value ?: BigDecimal.ZERO
|
||||
}
|
||||
|
||||
val crypto = feeSum.format { crypto(feeCryptoCurrencyStatusFlow.value.currency) }
|
||||
val fiatFeeValue = cryptoCurrencyStatus.value.fiatRate?.let { rate ->
|
||||
feeSum.multiply(rate)
|
||||
}
|
||||
|
||||
val fiat = fiatFeeValue.format { fiat(appCurrency.code, appCurrency.symbol) }
|
||||
|
||||
uiState.update {
|
||||
if (cryptoCurrencyStatus.value is CryptoCurrencyStatus.Loading) {
|
||||
it.copy(yieldSupplyFeeUM = YieldSupplyFeeUM.Loading)
|
||||
} else {
|
||||
it.copy(
|
||||
isPrimaryButtonEnabled = true, // todo yield supply check for notifications
|
||||
yieldSupplyFeeUM = YieldSupplyFeeUM.Content(
|
||||
transactionDataList = updatedTransactionList.toPersistentList(),
|
||||
feeValue = combinedReference(
|
||||
stringReference(crypto),
|
||||
stringReference(" $DOT "),
|
||||
stringReference(fiat),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onClick() {
|
||||
val yieldSupplyFeeUM = uiState.value.yieldSupplyFeeUM as? YieldSupplyFeeUM.Content ?: return
|
||||
|
||||
uiState.update { it.copy(isPrimaryButtonEnabled = false) }
|
||||
modelScope.launch(dispatchers.default) {
|
||||
sendTransactionUseCase.invoke(
|
||||
txsData = yieldSupplyFeeUM.transactionDataList,
|
||||
userWallet = userWallet,
|
||||
network = cryptoCurrency.network,
|
||||
sendMode = TransactionSender.MultipleTransactionSendMode.DEFAULT,
|
||||
).fold(
|
||||
ifLeft = {
|
||||
Timber.e(it.toString())
|
||||
uiState.update { it.copy(isPrimaryButtonEnabled = true) }
|
||||
},
|
||||
ifRight = {
|
||||
params.callback.onTransactionSent()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnCurrencyStatusUpdates() {
|
||||
modelScope.launch {
|
||||
getUserWalletUseCase(params.userWalletId).fold(
|
||||
ifRight = { wallet ->
|
||||
userWallet = wallet
|
||||
getCurrenciesStatusUpdates()
|
||||
},
|
||||
ifLeft = {
|
||||
Timber.w(it.toString())
|
||||
// showAlertError() todo yield supply error alert
|
||||
return@launch
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCurrenciesStatusUpdates() {
|
||||
getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet(
|
||||
userWalletId = params.userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
isSingleWalletWithTokens = false,
|
||||
).onEach { maybeCryptoCurrency ->
|
||||
maybeCryptoCurrency.fold(
|
||||
ifRight = { cryptoCurrencyStatus ->
|
||||
onDataLoaded(
|
||||
currencyStatus = cryptoCurrencyStatus,
|
||||
feeCurrencyStatus = getFeePaidCryptoCurrencyStatusSyncUseCase(
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
).getOrNull() ?: cryptoCurrencyStatus,
|
||||
)
|
||||
},
|
||||
ifLeft = {
|
||||
// todo yield supply error
|
||||
// sendConfirmAlertFactory.getGenericErrorState(
|
||||
// onFailedTxEmailClick = {
|
||||
// onFailedTxEmailClick(it.toString())
|
||||
// },
|
||||
// popBack = router::pop,
|
||||
// )
|
||||
},
|
||||
)
|
||||
}.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun onDataLoaded(currencyStatus: CryptoCurrencyStatus, feeCurrencyStatus: CryptoCurrencyStatus) {
|
||||
cryptoCurrencyStatusFlow.update { currencyStatus }
|
||||
feeCryptoCurrencyStatusFlow.update { feeCurrencyStatus }
|
||||
|
||||
modelScope.launch {
|
||||
onLoadFee()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.tangem.features.yield.supply.impl.subcomponents.startearning.ui
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetWithFooter
|
||||
import com.tangem.core.ui.decompose.ComposableModularContentComponent
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.yield.supply.impl.subcomponents.startearning.YieldSupplyStartEarningRoute
|
||||
|
||||
@Composable
|
||||
internal fun YieldSupplyStartEarningBottomSheet(
|
||||
stackState: ChildStack<YieldSupplyStartEarningRoute, ComposableModularContentComponent>,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
TangemModalBottomSheetWithFooter<TangemBottomSheetConfigContent.Empty>(
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = onDismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
title = {
|
||||
AnimatedContent(
|
||||
stackState.active.instance,
|
||||
) { currentState ->
|
||||
currentState.Title()
|
||||
}
|
||||
},
|
||||
footer = {
|
||||
AnimatedContent(
|
||||
stackState.active.instance,
|
||||
) { currentState ->
|
||||
currentState.Footer()
|
||||
}
|
||||
},
|
||||
content = {
|
||||
AnimatedContent(
|
||||
stackState.active.instance,
|
||||
) { currentState ->
|
||||
currentState.Content(modifier = Modifier)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -5,7 +5,8 @@
|
|||
# https://github.com/tangem/tangem-sdk-android/
|
||||
# https://github.com/tangem/vico
|
||||
|
||||
tangemBlockchainSdk = "develop-1229"
|
||||
tangemBlockchainSdk = "develop-1230"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-561"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
tangemVico = "2.0.0-alpha.25-tangem12"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue