Updated on 2026-08-14
This commit is contained in:
commit
adf64a5b99
21 changed files with 554 additions and 25 deletions
|
|
@ -275,7 +275,7 @@ dependencies {
|
|||
implementation(projects.features.tokenRecieve.api)
|
||||
implementation(projects.features.tokenRecieve.impl)
|
||||
implementation(projects.features.yieldSupply.api)
|
||||
implementation(projects.features.yieldSupply.api)
|
||||
implementation(projects.features.yieldSupply.impl)
|
||||
|
||||
/** AndroidX libraries */
|
||||
implementation(deps.androidx.core.ktx)
|
||||
|
|
|
|||
|
|
@ -34,9 +34,11 @@ import com.tangem.features.staking.api.StakingComponent
|
|||
import com.tangem.features.swap.SwapComponent
|
||||
import com.tangem.features.swap.v2.api.SendWithSwapComponent
|
||||
import com.tangem.features.tangempay.components.TangemPayDetailsComponent
|
||||
import com.tangem.features.tangempay.components.TangemPayOnboardingComponent
|
||||
import com.tangem.features.tokendetails.TokenDetailsComponent
|
||||
import com.tangem.features.wallet.WalletEntryComponent
|
||||
import com.tangem.features.walletconnect.components.WalletConnectEntryComponent
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyPromoComponent
|
||||
import com.tangem.tap.features.details.ui.appcurrency.api.AppCurrencySelectorComponent
|
||||
import com.tangem.tap.features.details.ui.appsettings.api.AppSettingsComponent
|
||||
import com.tangem.tap.features.details.ui.cardsettings.api.CardSettingsComponent
|
||||
|
|
@ -45,7 +47,6 @@ import com.tangem.tap.features.details.ui.resetcard.api.ResetCardComponent
|
|||
import com.tangem.tap.features.details.ui.securitymode.api.SecurityModeComponent
|
||||
import com.tangem.tap.features.welcome.component.WelcomeComponent
|
||||
import com.tangem.tap.routing.component.RoutingComponent.Child
|
||||
import com.tangem.features.tangempay.components.TangemPayOnboardingComponent
|
||||
import dagger.hilt.android.scopes.ActivityScoped
|
||||
import javax.inject.Inject
|
||||
import com.tangem.features.walletconnect.components.WalletConnectEntryComponent as RedesignedWalletConnectComponent
|
||||
|
|
@ -105,6 +106,7 @@ internal class ChildFactory @Inject constructor(
|
|||
private val sendEntryPointComponentFactory: SendEntryPointComponent.Factory,
|
||||
private val tangemPayDetailsComponentFactory: TangemPayDetailsComponent.Factory,
|
||||
private val tangemPayOnboardingComponentFactory: TangemPayOnboardingComponent.Factory,
|
||||
private val yieldSupplyPromoComponentFactory: YieldSupplyPromoComponent.Factory,
|
||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||
) {
|
||||
|
||||
|
|
@ -600,6 +602,13 @@ internal class ChildFactory @Inject constructor(
|
|||
componentFactory = tangemPayOnboardingComponentFactory,
|
||||
)
|
||||
}
|
||||
is AppRoute.YieldSupplyPromo -> {
|
||||
createComponentChild(
|
||||
context = context,
|
||||
params = YieldSupplyPromoComponent.Params(route.userWalletId, route.cryptoCurrency),
|
||||
componentFactory = yieldSupplyPromoComponentFactory,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -382,4 +382,10 @@ sealed class AppRoute(val path: String) : Route {
|
|||
data class TangemPayOnboarding(
|
||||
val deeplink: String,
|
||||
) : AppRoute(path = "/tangem_pay_onboarding/$deeplink")
|
||||
|
||||
@Serializable
|
||||
data class YieldSupplyPromo(
|
||||
val userWalletId: UserWalletId,
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
) : AppRoute(path = "/yield_supply_promo/${userWalletId.stringValue}/${cryptoCurrency.symbol}")
|
||||
}
|
||||
|
|
@ -1657,7 +1657,7 @@
|
|||
<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_title">年間%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>
|
||||
<string name="yield_module_rate_info_sheet_chart_average">平均%s</string>
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@
|
|||
<string name="common_camera_denied_alert_message">You have not given access to your camera, please adjust your privacy settings</string>
|
||||
<string name="common_cancel">Cancel</string>
|
||||
<string name="common_change">Change</string>
|
||||
<string name="common_choose_account">Choose account</string>
|
||||
<string name="common_choose_action">Choose action</string>
|
||||
<string name="common_choose_network">Choose network</string>
|
||||
<string name="common_choose_token">Choose token</string>
|
||||
|
|
@ -1266,6 +1267,14 @@
|
|||
<string name="swapping_to_title">You receive</string>
|
||||
<string name="swapping_token_list_title">Choose token</string>
|
||||
<string name="swapping_token_not_available">not available</string>
|
||||
<string name="tangempay_onboarding_get_card_button_text">Get card</string>
|
||||
<string name="tangempay_onboarding_pay_description">Add to your wallet and pay with your phone anywhere.</string>
|
||||
<string name="tangempay_onboarding_pay_title">Apple Pay & Google Pay</string>
|
||||
<string name="tangempay_onboarding_purchases_description">Use your USDC balance to pay for everyday purchases seamlessly.</string>
|
||||
<string name="tangempay_onboarding_purchases_title">Everyday purchases</string>
|
||||
<string name="tangempay_onboarding_security_description">Your card details are protected — full control in the app.</string>
|
||||
<string name="tangempay_onboarding_security_title">Built-in security</string>
|
||||
<string name="tangempay_onboarding_title">Get your free Crypto Card\nin minutes</string>
|
||||
<string name="this_is_my_wallet_title">This is my wallet</string>
|
||||
<string name="toast_balances_hidden">Balances hidden</string>
|
||||
<string name="toast_balances_shown">Balances shown</string>
|
||||
|
|
@ -1414,14 +1423,6 @@
|
|||
<string name="visa_unlock_notification_button">Unlock</string>
|
||||
<string name="visa_unlock_notification_subtitle">Scan your card to unlock access</string>
|
||||
<string name="visa_unlock_notification_title">Needed unlock</string>
|
||||
<string name="tangempay_onboarding_title">Get your free Crypto Card\nin minutes</string>
|
||||
<string name="tangempay_onboarding_security_title">Built-in security</string>
|
||||
<string name="tangempay_onboarding_security_description">Your card details are protected — full control in the app.</string>
|
||||
<string name="tangempay_onboarding_purchases_title">Everyday purchases</string>
|
||||
<string name="tangempay_onboarding_purchases_description">Use your USDC balance to pay for everyday purchases seamlessly.</string>
|
||||
<string name="tangempay_onboarding_pay_title">Apple Pay & Google Pay</string>
|
||||
<string name="tangempay_onboarding_pay_description">Add to your wallet and pay with your phone anywhere.</string>
|
||||
<string name="tangempay_onboarding_get_card_button_text">Get card</string>
|
||||
<string name="wallet_balance_blockchain_unreachable_try_later">Blockchain is unreachable. Try later</string>
|
||||
<string name="wallet_balance_missing_derivation">Scan card or ring</string>
|
||||
<string name="wallet_been_activated_message">This wallet has already been activated earlier.\nIf it was not done by you, please contact support.\nTangem never sells wallets along with pre-generated access codes.</string>
|
||||
|
|
@ -1732,8 +1733,8 @@
|
|||
<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</string>
|
||||
<string name="yield_module_promo_screen_title">Earn %s% yearly</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_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>
|
||||
<string name="yield_module_rate_info_sheet_chart_average">Avg %s</string>
|
||||
|
|
|
|||
|
|
@ -2,19 +2,22 @@ package com.tangem.core.ui.components.label
|
|||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.label.entity.LabelStyle
|
||||
import com.tangem.core.ui.components.label.entity.LabelUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
|
@ -48,8 +51,18 @@ fun Label(state: LabelUM, modifier: Modifier = Modifier) {
|
|||
},
|
||||
)
|
||||
|
||||
val iconColor by animateColorAsState(
|
||||
targetValue = when (state.style) {
|
||||
LabelStyle.ACCENT -> TangemTheme.colors.icon.accent
|
||||
LabelStyle.REGULAR -> TangemTheme.colors.icon.informative
|
||||
LabelStyle.WARNING -> TangemTheme.colors.icon.warning
|
||||
},
|
||||
)
|
||||
|
||||
AnimatedContent(targetState = state.text) { text ->
|
||||
Box(
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
modifier = modifier
|
||||
.padding(horizontal = 4.dp)
|
||||
.background(
|
||||
|
|
@ -63,6 +76,15 @@ fun Label(state: LabelUM, modifier: Modifier = Modifier) {
|
|||
style = TangemTheme.typography.caption1,
|
||||
color = textColor,
|
||||
)
|
||||
AnimatedVisibility(state.icon != null) {
|
||||
val wrappedIcon = remember(this) { requireNotNull(state.icon) }
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(wrappedIcon),
|
||||
tint = iconColor,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -73,6 +95,7 @@ fun Label(state: LabelUM, modifier: Modifier = Modifier) {
|
|||
private fun LabelPreview() {
|
||||
TangemThemePreview {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = Modifier.padding(16.dp),
|
||||
) {
|
||||
Label(
|
||||
|
|
@ -81,24 +104,39 @@ private fun LabelPreview() {
|
|||
style = LabelStyle.REGULAR,
|
||||
),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Label(
|
||||
state = LabelUM(
|
||||
text = TextReference.Str("Accent Label"),
|
||||
style = LabelStyle.ACCENT,
|
||||
),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Label(
|
||||
state = LabelUM(
|
||||
text = TextReference.Str("Warning Label"),
|
||||
style = LabelStyle.WARNING,
|
||||
),
|
||||
)
|
||||
Label(
|
||||
state = LabelUM(
|
||||
text = TextReference.Str("Regular Label"),
|
||||
style = LabelStyle.REGULAR,
|
||||
icon = R.drawable.ic_information_24,
|
||||
),
|
||||
)
|
||||
Label(
|
||||
state = LabelUM(
|
||||
text = TextReference.Str("Accent Label"),
|
||||
style = LabelStyle.ACCENT,
|
||||
icon = R.drawable.ic_information_24,
|
||||
),
|
||||
)
|
||||
Label(
|
||||
state = LabelUM(
|
||||
text = TextReference.Str("Warning Label"),
|
||||
style = LabelStyle.WARNING,
|
||||
icon = R.drawable.ic_information_24,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
package com.tangem.core.ui.components.label.entity
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
data class LabelUM(
|
||||
val text: TextReference,
|
||||
val style: LabelStyle,
|
||||
@DrawableRes val icon: Int? = null,
|
||||
val onIconClick: (() -> Unit)? = null,
|
||||
)
|
||||
|
||||
enum class LabelStyle {
|
||||
|
|
|
|||
|
|
@ -10,4 +10,13 @@ interface ComposableBottomSheetComponent {
|
|||
|
||||
@Composable
|
||||
fun BottomSheet()
|
||||
}
|
||||
|
||||
fun getEmptyComposableBottomSheetComponent() = EmptyComposableBottomSheetComponent
|
||||
|
||||
object EmptyComposableBottomSheetComponent : ComposableBottomSheetComponent {
|
||||
override fun dismiss() {}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {}
|
||||
}
|
||||
9
core/ui/src/main/res/drawable/ic_analytics_up_24.xml
Normal file
9
core/ui/src/main/res/drawable/ic_analytics_up_24.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12.058,1.75C14.248,1.75 15.968,1.75 17.312,1.931C18.688,2.116 19.781,2.503 20.639,3.361C21.497,4.22 21.884,5.312 22.069,6.688C22.25,8.032 22.25,9.752 22.25,11.942V12.058C22.25,14.248 22.25,15.968 22.069,17.312C21.884,18.688 21.497,19.781 20.639,20.639C19.781,21.497 18.688,21.884 17.312,22.069C15.968,22.25 14.248,22.25 12.058,22.25H11.942C9.752,22.25 8.032,22.25 6.688,22.069C5.312,21.884 4.22,21.497 3.361,20.639C2.503,19.781 2.116,18.688 1.931,17.312C1.75,15.968 1.75,14.248 1.75,12.058V11.942C1.75,9.752 1.75,8.032 1.931,6.688C2.116,5.312 2.503,4.22 3.361,3.361C4.22,2.503 5.312,2.116 6.688,1.931C8.032,1.75 9.752,1.75 11.942,1.75H12.058ZM7,15.25C6.586,15.25 6.25,15.586 6.25,16V18C6.25,18.414 6.586,18.75 7,18.75C7.414,18.75 7.75,18.414 7.75,18V16C7.75,15.586 7.414,15.25 7,15.25ZM12,14.25C11.586,14.25 11.25,14.586 11.25,15V18C11.25,18.414 11.586,18.75 12,18.75C12.414,18.75 12.75,18.414 12.75,18V15C12.75,14.586 12.414,14.25 12,14.25ZM17,12.25C16.586,12.25 16.25,12.586 16.25,13V18C16.25,18.414 16.586,18.75 17,18.75C17.414,18.75 17.75,18.414 17.75,18V13C17.75,12.586 17.414,12.25 17,12.25ZM15.858,5.252C15.654,5.261 15.416,5.301 15.179,5.34C15.168,5.342 15.157,5.344 15.146,5.346L13.878,5.555C13.469,5.622 13.192,6.008 13.26,6.417C13.327,6.826 13.713,7.103 14.122,7.035L14.846,6.915C12.963,9.557 9.953,10.75 6,10.75C5.586,10.75 5.25,11.086 5.25,11.5C5.25,11.914 5.586,12.25 6,12.25C10.322,12.25 13.898,10.906 16.132,7.694L16.279,8.207C16.394,8.605 16.809,8.835 17.207,8.721C17.605,8.606 17.835,8.191 17.721,7.793L17.403,6.683C17.4,6.671 17.396,6.66 17.393,6.648C17.335,6.446 17.272,6.223 17.19,6.041C17.089,5.819 16.93,5.582 16.645,5.42C16.369,5.263 16.09,5.241 15.858,5.252Z"
|
||||
android:fillColor="#0099FF"/>
|
||||
</vector>
|
||||
9
core/ui/src/main/res/drawable/ic_flash_new_24.xml
Normal file
9
core/ui/src/main/res/drawable/ic_flash_new_24.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M13.608,1.147C14.314,1.448 14.797,2.163 14.797,3.017L14.798,9.785C14.798,9.895 14.887,9.985 14.998,9.985H18.099C18.985,9.985 19.595,10.583 19.847,11.21C20.097,11.837 20.064,12.642 19.563,13.285L12.564,22.268C12.003,22.988 11.12,23.163 10.392,22.852C9.685,22.551 9.202,21.837 9.202,20.983L9.202,14.215C9.202,14.104 9.112,14.015 9.002,14.015H5.9C5.014,14.015 4.404,13.417 4.153,12.789C3.902,12.163 3.936,11.358 4.437,10.715L11.435,1.732C11.996,1.011 12.879,0.837 13.608,1.147Z"
|
||||
android:fillColor="#0099FF"/>
|
||||
</vector>
|
||||
10
core/ui/src/main/res/drawable/ic_repeat_24.xml
Normal file
10
core/ui/src/main/res/drawable/ic_repeat_24.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,0.59C18.302,0.59 23.41,5.698 23.41,12C23.41,18.302 18.302,23.41 12,23.41C5.698,23.41 0.59,18.302 0.59,12C0.59,5.698 5.698,0.59 12,0.59ZM18.057,10.834C17.616,10.857 17.277,11.233 17.299,11.674C17.375,13.168 16.842,14.685 15.702,15.825C13.794,17.733 10.829,17.937 8.693,16.438L9.295,16.381C9.734,16.339 10.057,15.948 10.016,15.509C9.973,15.069 9.581,14.746 9.142,14.788L6.631,15.028C6.191,15.071 5.868,15.462 5.91,15.901L6.15,18.413C6.192,18.853 6.584,19.175 7.023,19.133C7.463,19.09 7.785,18.701 7.743,18.262L7.688,17.688C10.454,19.691 14.342,19.448 16.834,16.957C18.307,15.484 18.995,13.52 18.896,11.593C18.874,11.152 18.498,10.811 18.057,10.834ZM16.77,4.914C16.33,4.956 16.008,5.347 16.05,5.786L16.104,6.361C13.338,4.357 9.451,4.599 6.959,7.091C5.486,8.564 4.797,10.528 4.896,12.455C4.918,12.896 5.294,13.235 5.735,13.213C6.176,13.19 6.516,12.815 6.494,12.374C6.418,10.88 6.951,9.362 8.091,8.222C9.999,6.314 12.965,6.112 15.1,7.61L14.497,7.667C14.058,7.709 13.736,8.099 13.777,8.539C13.82,8.979 14.211,9.302 14.65,9.26L17.161,9.019C17.601,8.977 17.924,8.586 17.882,8.146L17.643,5.635C17.601,5.195 17.209,4.872 16.77,4.914Z"
|
||||
android:fillColor="#0099FF"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
9
core/ui/src/main/res/drawable/ic_security_check_24.xml
Normal file
9
core/ui/src/main/res/drawable/ic_security_check_24.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M11.999,1.25C13.68,1.25 15.048,1.818 16.24,2.436C16.601,2.622 16.936,2.807 17.256,2.983C18.039,3.415 18.733,3.797 19.495,4.04C19.942,4.183 20.338,4.31 20.619,4.42C20.883,4.523 21.198,4.665 21.421,4.913C21.621,5.136 21.724,5.385 21.792,5.624C21.854,5.841 21.907,6.135 21.958,6.417C23.196,13.282 20.492,19.787 13.882,22.318C13.232,22.567 12.753,22.75 12.002,22.75C11.251,22.75 10.773,22.567 10.123,22.318C3.513,19.788 0.806,13.283 2.044,6.417C2.095,6.135 2.147,5.841 2.209,5.624C2.277,5.385 2.381,5.136 2.581,4.913C2.804,4.666 3.118,4.523 3.382,4.42C3.663,4.31 4.06,4.183 4.507,4.04C5.268,3.797 5.962,3.415 6.744,2.983L7.236,2.713C7.405,2.621 7.579,2.529 7.759,2.436C8.951,1.818 10.318,1.25 11.999,1.25ZM17.942,8.666C17.758,8.146 17.187,7.873 16.666,8.058C15.788,8.369 14.948,8.961 14.212,9.607C13.465,10.262 12.767,11.023 12.174,11.734C11.735,12.261 11.345,12.769 11.03,13.199C10.742,12.854 10.454,12.601 10.18,12.418C9.905,12.235 9.552,12 9,12C8.448,12 8,12.448 8,13C8,13.521 8.398,13.949 8.906,13.996C9.11,14.015 9.665,14.566 10.106,15.447C10.267,15.77 10.589,15.981 10.949,15.999C11.309,16.017 11.651,15.84 11.844,15.536C11.849,15.529 12.193,15.013 12.357,14.78C12.689,14.311 13.157,13.677 13.709,13.016C14.263,12.352 14.888,11.675 15.53,11.111C16.183,10.539 16.8,10.132 17.334,9.943C17.855,9.759 18.127,9.187 17.942,8.666Z"
|
||||
android:fillColor="#0099FF"/>
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.features.yield.supply.api
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
interface YieldSupplyPromoComponent : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val currency: CryptoCurrency,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, YieldSupplyPromoComponent>
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ dependencies {
|
|||
implementation(projects.core.configToggles)
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.navigation)
|
||||
|
||||
/** Common */
|
||||
implementation(projects.common.ui)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
package com.tangem.features.yield.supply.impl.promo
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.getEmptyComposableBottomSheetComponent
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyPromoComponent
|
||||
import com.tangem.features.yield.supply.impl.promo.model.YieldSupplyPromoModel
|
||||
import com.tangem.features.yield.supply.impl.promo.ui.YieldSupplyPromoContent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultYieldSupplyPromoComponent @AssistedInject constructor(
|
||||
@Assisted private val appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: YieldSupplyPromoComponent.Params,
|
||||
) : YieldSupplyPromoComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: YieldSupplyPromoModel = getOrCreateModel(params = params)
|
||||
|
||||
private val bottomSheetSlot = childSlot(
|
||||
source = model.bottomSheetNavigation,
|
||||
serializer = null,
|
||||
handleBackButton = false,
|
||||
childFactory = { _, _ -> bottomSheetChild() },
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state = model.uiState
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
|
||||
YieldSupplyPromoContent(
|
||||
yieldSupplyPromoUM = state,
|
||||
clickIntents = model,
|
||||
modifier = modifier,
|
||||
)
|
||||
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
private fun bottomSheetChild(): ComposableBottomSheetComponent = getEmptyComposableBottomSheetComponent()
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : YieldSupplyPromoComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: YieldSupplyPromoComponent.Params,
|
||||
): DefaultYieldSupplyPromoComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.features.yield.supply.impl.promo
|
||||
|
||||
internal enum class YieldSupplyPromoConfig {
|
||||
Apy,
|
||||
Action,
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.tangem.features.yield.supply.impl.promo.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.yield.supply.impl.promo.DefaultYieldSupplyPromoComponent
|
||||
import com.tangem.features.yield.supply.impl.promo.model.YieldSupplyPromoModel
|
||||
import com.tangem.features.yield.supply.api.YieldSupplyPromoComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface YieldSupplyPromoBindsModule {
|
||||
@Binds
|
||||
@Singleton
|
||||
fun provideYieldSupplyPromoComponentFactory(
|
||||
impl: DefaultYieldSupplyPromoComponent.Factory,
|
||||
): YieldSupplyPromoComponent.Factory
|
||||
}
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface YieldSupplyPromoModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(YieldSupplyPromoModel::class)
|
||||
fun provideYieldSupplyPromoModel(impl: YieldSupplyPromoModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.features.yield.supply.impl.promo.entity
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
data class YieldSupplyPromoUM(
|
||||
val tosLink: String,
|
||||
val policyLink: String,
|
||||
val title: TextReference,
|
||||
)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.features.yield.supply.impl.promo.model
|
||||
|
||||
internal interface YieldSupplyPromoClickIntents {
|
||||
|
||||
fun onBackClick()
|
||||
|
||||
fun onApyInfoClick()
|
||||
|
||||
fun onHowItWorksClick()
|
||||
|
||||
fun onStartEarningClick()
|
||||
|
||||
fun onUrlClick(url: String)
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.tangem.features.yield.supply.impl.promo.model
|
||||
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.impl.promo.YieldSupplyPromoConfig
|
||||
import com.tangem.features.yield.supply.impl.promo.entity.YieldSupplyPromoUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class YieldSupplyPromoModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val urlOpener: UrlOpener,
|
||||
private val appRouter: AppRouter,
|
||||
) : Model(), YieldSupplyPromoClickIntents {
|
||||
|
||||
val uiState: YieldSupplyPromoUM = YieldSupplyPromoUM(
|
||||
tosLink = "https://tangem.com/terms-of-service/", // TODO replace with real link
|
||||
policyLink = "https://tangem.com/privacy-policy/", // TODO replace with real link
|
||||
title = resourceReference(R.string.yield_module_promo_screen_title, wrappedList("5.3")),
|
||||
)
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<YieldSupplyPromoConfig> = SlotNavigation()
|
||||
|
||||
override fun onBackClick() {
|
||||
appRouter.pop()
|
||||
}
|
||||
|
||||
override fun onApyInfoClick() {
|
||||
bottomSheetNavigation.activate(YieldSupplyPromoConfig.Apy)
|
||||
}
|
||||
|
||||
override fun onUrlClick(url: String) {
|
||||
urlOpener.openUrl(url)
|
||||
}
|
||||
|
||||
override fun onHowItWorksClick() {
|
||||
urlOpener.openUrl("https://tangem.com/") // TODO replace with real link
|
||||
}
|
||||
|
||||
override fun onStartEarningClick() {
|
||||
bottomSheetNavigation.activate(YieldSupplyPromoConfig.Action)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
package com.tangem.features.yield.supply.impl.promo.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.LinkAnnotation
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.withLink
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.components.label.Label
|
||||
import com.tangem.core.ui.components.label.entity.LabelStyle
|
||||
import com.tangem.core.ui.components.label.entity.LabelUM
|
||||
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.promo.entity.YieldSupplyPromoUM
|
||||
import com.tangem.features.yield.supply.impl.promo.model.YieldSupplyPromoClickIntents
|
||||
import com.tangem.utils.StringsSigns
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@Composable
|
||||
internal fun YieldSupplyPromoContent(
|
||||
yieldSupplyPromoUM: YieldSupplyPromoUM,
|
||||
clickIntents: YieldSupplyPromoClickIntents,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier
|
||||
.background(color = TangemTheme.colors.background.tertiary)
|
||||
.fillMaxWidth()
|
||||
.imePadding()
|
||||
.systemBarsPadding()
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
YieldStatusAppBar(
|
||||
onBackClick = clickIntents::onBackClick,
|
||||
onHowItWorksClick = clickIntents::onHowItWorksClick,
|
||||
)
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.padding(horizontal = 20.dp),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_analytics_up_24),
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.background(TangemTheme.colors.icon.accent.copy(0.1f), CircleShape)
|
||||
.padding(12.dp)
|
||||
.size(32.dp),
|
||||
)
|
||||
SpacerH(20.dp)
|
||||
Text(
|
||||
text = yieldSupplyPromoUM.title.resolveReference(),
|
||||
style = TangemTheme.typography.h2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
SpacerH8()
|
||||
Label(
|
||||
state = LabelUM(
|
||||
text = resourceReference(R.string.yield_module_promo_screen_variable_rate_info),
|
||||
style = LabelStyle.REGULAR,
|
||||
icon = R.drawable.ic_information_24,
|
||||
onIconClick = clickIntents::onApyInfoClick,
|
||||
),
|
||||
)
|
||||
SpacerH32()
|
||||
PromoItems()
|
||||
}
|
||||
SpacerHMax()
|
||||
YieldSupplyTosText(
|
||||
tosLink = yieldSupplyPromoUM.tosLink,
|
||||
policyLink = yieldSupplyPromoUM.policyLink,
|
||||
onClick = clickIntents::onUrlClick,
|
||||
)
|
||||
PrimaryButton(
|
||||
text = stringResourceSafe(R.string.yield_module_start_earning),
|
||||
onClick = clickIntents::onStartEarningClick,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
SpacerH8()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun YieldStatusAppBar(onBackClick: () -> Unit, onHowItWorksClick: () -> Unit) {
|
||||
Row(
|
||||
modifier = Modifier.padding(vertical = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_back_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.primary1,
|
||||
modifier = Modifier.clickable(onClick = onBackClick),
|
||||
)
|
||||
SpacerWMax()
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.yield_module_promo_screen_how_it_works_button_title),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
modifier = Modifier.clickable(onClick = onHowItWorksClick),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PromoItems() {
|
||||
PromoItem(
|
||||
icon = R.drawable.ic_flash_new_24,
|
||||
title = resourceReference(R.string.yield_module_promo_screen_cash_out_title),
|
||||
subtitle = resourceReference(R.string.yield_module_promo_screen_cash_out_subtitle),
|
||||
)
|
||||
SpacerH24()
|
||||
PromoItem(
|
||||
icon = R.drawable.ic_repeat_24,
|
||||
title = resourceReference(R.string.yield_module_promo_screen_auto_balance_title),
|
||||
subtitle = resourceReference(R.string.yield_module_promo_screen_auto_balance_subtitle),
|
||||
)
|
||||
SpacerH24()
|
||||
PromoItem(
|
||||
icon = R.drawable.ic_security_check_24,
|
||||
title = resourceReference(R.string.yield_module_promo_screen_self_custodial_title),
|
||||
subtitle = resourceReference(R.string.yield_module_promo_screen_self_custodial_subtitle),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PromoItem(@DrawableRes icon: Int, title: TextReference, subtitle: TextReference) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(20.dp),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(icon),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
)
|
||||
Column(verticalArrangement = Arrangement.spacedBy(3.dp)) {
|
||||
Text(
|
||||
text = title.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
text = subtitle.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun YieldSupplyTosText(tosLink: String, policyLink: String, onClick: (String) -> Unit) {
|
||||
val tosTitle = stringResourceSafe(R.string.common_terms_of_use)
|
||||
val policyTitle = stringResourceSafe(R.string.common_privacy_policy)
|
||||
val fullString = stringResourceSafe(id = R.string.yield_module_promo_screen_terms_disclaimer, tosTitle, policyTitle)
|
||||
val tosIndex = fullString.indexOf(tosTitle)
|
||||
val policyIndex = fullString.indexOf(policyTitle)
|
||||
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
append(StringsSigns.POINT_SIGN)
|
||||
appendSpace()
|
||||
append(fullString.substring(0, tosIndex))
|
||||
withLink(
|
||||
link = LinkAnnotation.Clickable(
|
||||
tag = "TOS_TAG",
|
||||
linkInteractionListener = { onClick(tosLink) },
|
||||
),
|
||||
block = {
|
||||
appendColored(
|
||||
text = fullString.substring(tosIndex, tosIndex + tosTitle.length),
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
},
|
||||
)
|
||||
append(fullString.substring(tosIndex + tosTitle.length, policyIndex))
|
||||
withLink(
|
||||
link = LinkAnnotation.Clickable(
|
||||
tag = "POLICY_TAG",
|
||||
linkInteractionListener = { onClick(policyLink) },
|
||||
),
|
||||
block = {
|
||||
appendColored(
|
||||
text = fullString.substring(policyIndex, policyIndex + policyTitle.length),
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360, heightDp = 724)
|
||||
@Preview(showBackground = true, widthDp = 360, heightDp = 724, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun YieldSupplyPromoContent_Preview() {
|
||||
TangemThemePreview {
|
||||
YieldSupplyPromoContent(
|
||||
yieldSupplyPromoUM = YieldSupplyPromoUM(
|
||||
tosLink = "https://tangem.com/terms-of-service/",
|
||||
policyLink = "https://tangem.com/privacy-policy/",
|
||||
title = resourceReference(R.string.yield_module_promo_screen_title, wrappedList("5.3")),
|
||||
),
|
||||
clickIntents = object : YieldSupplyPromoClickIntents {
|
||||
override fun onBackClick() {}
|
||||
override fun onApyInfoClick() {}
|
||||
override fun onHowItWorksClick() {}
|
||||
override fun onStartEarningClick() {}
|
||||
override fun onUrlClick(url: String) {}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
Loading…
Add table
Add a link
Reference in a new issue