Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-12 16:54:37 +05:00
commit 364f4e51b7
16 changed files with 170 additions and 35 deletions

View file

@ -9,4 +9,5 @@ interface OnrampIntents {
fun onBuyClick(quote: OnrampProviderWithQuote.Data)
fun openProviders()
fun onRefresh()
fun onLinkClick(link: String)
}

View file

@ -9,7 +9,10 @@ sealed class OnrampProviderBlockUM {
val providerId: String,
val paymentMethod: OnrampPaymentMethod,
val providerName: String,
val termsOfUseLink: String?,
val privacyPolicyLink: String?,
val isBestRate: Boolean,
val onLinkClick: (String) -> Unit,
val onClick: () -> Unit,
) : OnrampProviderBlockUM()
}

View file

@ -61,6 +61,7 @@ internal class OnrampAmountFieldChangeConverter(
amountFieldModel = amountFieldModel,
secondaryFieldModel = OnrampAmountSecondaryFieldUM.Content(TextReference.EMPTY),
),
buyButtonConfig = buyButtonConfig.copy(enabled = false),
providerBlockState = OnrampProviderBlockUM.Empty,
)
}

View file

@ -122,6 +122,9 @@ internal class OnrampAmountStateFactory(
providerName = providerResult.provider.info.name,
isBestRate = isBestRate,
onClick = onrampIntents::openProviders,
termsOfUseLink = providerResult.provider.info.termsOfUseLink,
privacyPolicyLink = providerResult.provider.info.privacyPolicyLink,
onLinkClick = onrampIntents::onLinkClick,
),
buyButtonConfig = currentState.buyButtonConfig.copy(
enabled = providerResult is SelectProviderResult.ProviderWithQuote,
@ -148,6 +151,9 @@ internal class OnrampAmountStateFactory(
providerName = provider.info.name,
isBestRate = isBestRate,
onClick = onrampIntents::openProviders,
termsOfUseLink = provider.info.termsOfUseLink,
privacyPolicyLink = provider.info.privacyPolicyLink,
onLinkClick = onrampIntents::onLinkClick,
)
}

View file

@ -10,6 +10,7 @@ import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.resolveReference
@ -60,6 +61,7 @@ internal class OnrampMainComponentModel @Inject constructor(
private val fetchPairsUseCase: OnrampFetchPairsUseCase,
private val amountInputManager: InputManager,
private val messageSender: UiMessageSender,
private val urlOpener: UrlOpener,
getWalletsUseCase: GetWalletsUseCase,
paramsContainer: ParamsContainer,
) : Model(), OnrampIntents {
@ -286,6 +288,8 @@ internal class OnrampMainComponentModel @Inject constructor(
}
}
override fun onLinkClick(link: String) = urlOpener.openUrl(link)
override fun onDestroy() {
modelScope.launch { clearOnrampCacheUseCase.invoke() }
quotesTaskScheduler.cancelTask()

View file

@ -0,0 +1,100 @@
package com.tangem.features.onramp.main.ui
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.ClickableText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.extensions.appendColored
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.main.entity.OnrampMainComponentUM
import com.tangem.features.onramp.main.entity.OnrampProviderBlockUM
private const val TERMS_OF_USE_KEY = "termsOfUse"
private const val PRIVACY_POLICY_KEY = "privacyPolicy"
@Composable
internal fun OnrampButtonComponent(state: OnrampMainComponentUM) {
val content = state as? OnrampMainComponentUM.Content
val providerState = content?.providerBlockState as? OnrampProviderBlockUM.Content
Column(
modifier = Modifier
.navigationBarsPadding()
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
OnrampTosText(providerState)
PrimaryButton(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = R.string.common_buy),
onClick = state.buyButtonConfig.onClick,
enabled = state.buyButtonConfig.enabled,
)
}
}
@Composable
private fun OnrampTosText(provider: OnrampProviderBlockUM.Content?) {
val termsOfUse = stringResource(R.string.common_terms_of_use)
val privacyPolicy = stringResource(R.string.common_privacy_policy)
val tosText = stringResource(R.string.onramp_legal, termsOfUse, privacyPolicy)
val clickableAnnotation = buildAnnotatedString {
append(tosText.substringBefore(termsOfUse))
pushStringAnnotation(TERMS_OF_USE_KEY, "")
appendColored(termsOfUse, TangemTheme.colors.text.accent)
pop()
append(tosText.substringAfter(termsOfUse).substringBefore(privacyPolicy))
pushStringAnnotation(PRIVACY_POLICY_KEY, "")
appendColored(privacyPolicy, TangemTheme.colors.text.accent)
pop()
}
AnimatedContent(
targetState = provider,
transitionSpec = { fadeIn().togetherWith(fadeOut()) },
label = "Onramp Legal Info Animation",
) { state ->
val termsOfUseLink = provider?.termsOfUseLink
val privacyPolicyLink = provider?.privacyPolicyLink
if (state != null && termsOfUseLink != null && privacyPolicyLink != null) {
ClickableText(
text = clickableAnnotation,
style = TangemTheme.typography.caption2.copy(
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.Center,
),
onClick = { offset ->
clickableAnnotation.getStringAnnotations(
tag = TERMS_OF_USE_KEY,
start = offset,
end = offset,
).firstOrNull()?.let {
state.onLinkClick(termsOfUseLink)
}
clickableAnnotation.getStringAnnotations(
tag = PRIVACY_POLICY_KEY,
start = offset,
end = offset,
).firstOrNull()?.let {
state.onLinkClick(privacyPolicyLink)
}
},
)
}
}
}

View file

@ -11,16 +11,13 @@ 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.res.stringResource
import com.tangem.core.ui.components.CircleShimmer
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.appbar.TangemTopAppBar
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.WindowInsetsZero
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.main.entity.OnrampMainComponentUM
@Composable
@ -49,15 +46,7 @@ internal fun OnrampMainComponentContent(state: OnrampMainComponentUM, modifier:
}
},
floatingActionButton = {
PrimaryButton(
modifier = Modifier
.navigationBarsPadding()
.padding(horizontal = TangemTheme.dimens.spacing16)
.fillMaxWidth(),
text = stringResource(id = R.string.common_buy),
onClick = state.buyButtonConfig.onClick,
enabled = state.buyButtonConfig.enabled,
)
OnrampButtonComponent(state)
},
floatingActionButtonPosition = FabPosition.Center,
)