Updated on 2026-08-14

This commit is contained in:
Tangem 2023-01-10 20:26:26 +03:00
commit 28c593bd60
137 changed files with 1098 additions and 607 deletions

View file

@ -1,7 +1,6 @@
package com.tangem.feature.referral
import android.os.Bundle
import android.transition.TransitionInflater
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -9,6 +8,7 @@ import androidx.compose.ui.platform.ComposeView
import androidx.core.view.WindowCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.transition.TransitionInflater
import com.tangem.feature.referral.presentation.R
import com.tangem.feature.referral.router.ReferralRouter
import com.tangem.feature.referral.ui.ReferralScreen
@ -30,7 +30,9 @@ class ReferralFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) }
viewModel.setRouter(ReferralRouter(fragmentManager = WeakReference(parentFragmentManager)))
viewModel.onScreenOpened()
return ComposeView(inflater.context).apply {
isTransitionGroup = true
setContent {
ReferralScreen(stateHolder = viewModel.uiState)
}

View file

@ -0,0 +1,16 @@
package com.tangem.feature.referral.analytics
import com.tangem.core.analytics.AnalyticsEvent
sealed class ReferralEvents(
event: String,
) : AnalyticsEvent(REFERRAL_PROGRAM_CATEGORY, event) {
object ReferralScreenOpened : ReferralEvents(event = "Referral Screen Opened")
object ClickParticipate : ReferralEvents(event = "Button - Participate")
object ClickCopy : ReferralEvents(event = "Button - Copy")
object ClickShare : ReferralEvents(event = "Button - Share")
object ClickTaC : ReferralEvents(event = "Link - TaC")
}
private const val REFERRAL_PROGRAM_CATEGORY = "Referral program"

View file

@ -4,6 +4,7 @@ internal data class ReferralStateHolder(
val headerState: HeaderState,
val referralInfoState: ReferralInfoState,
val errorSnackbar: ErrorSnackbar? = null,
val analytics: Analytics,
) {
data class HeaderState(val onBackClicked: () -> Unit)
@ -42,4 +43,10 @@ internal data class ReferralStateHolder(
val throwable: Throwable,
val onOkClicked: () -> Unit,
)
data class Analytics(
val onAgreementClicked: () -> Unit,
val onCopyClicked: () -> Unit,
val onShareClicked: () -> Unit,
)
}

View file

@ -9,17 +9,15 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.tangem.core.ui.components.appbar.AppBarWithAdditionalButtons
import com.tangem.core.ui.components.atoms.BottomSheetIndicator
import com.tangem.core.ui.components.atoms.Hand
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.referral.presentation.R
@ -32,11 +30,11 @@ import com.tangem.feature.referral.presentation.R
internal fun AgreementBottomSheetContent(url: String) {
Column(
modifier = Modifier
.background(color = MaterialTheme.colors.secondary)
.background(color = TangemTheme.colors.background.secondary)
.fillMaxWidth()
.height(LocalConfiguration.current.screenHeightDp.dp - TangemTheme.dimens.spacing16),
) {
BottomSheetIndicator()
Hand()
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
AppBarWithAdditionalButtons(text = stringResource(id = R.string.details_referral_title))
AgreementHtmlView(url = url)
@ -47,7 +45,7 @@ internal fun AgreementBottomSheetContent(url: String) {
@Composable
private fun AgreementHtmlView(url: String) {
AndroidView(
modifier = Modifier.background(MaterialTheme.colors.secondary),
modifier = Modifier.background(TangemTheme.colors.background.secondary),
factory = {
WebView(it).apply {
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)

View file

@ -6,10 +6,8 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
@ -18,8 +16,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TextColorType
import com.tangem.core.ui.res.textColor
import com.tangem.feature.referral.presentation.R
@Composable
@ -30,7 +26,7 @@ internal fun AgreementText(@StringRes firstPartResId: Int, onClicked: () -> Unit
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = TangemTheme.dimens.spacing54),
style = MaterialTheme.typography.caption.copy(textAlign = TextAlign.Center),
style = TangemTheme.typography.caption.copy(textAlign = TextAlign.Center),
maxLines = 2,
onClick = {
val clickableSpanStyle = requireNotNull(agreementText.spanStyles.getOrNull(1))
@ -44,13 +40,13 @@ internal fun AgreementText(@StringRes firstPartResId: Int, onClicked: () -> Unit
@Composable
private fun annotatedAgreementString(firstPart: String): AnnotatedString {
return buildAnnotatedString {
withStyle(SpanStyle(color = MaterialTheme.colors.textColor(type = TextColorType.TERTIARY))) {
withStyle(SpanStyle(color = TangemTheme.colors.text.tertiary)) {
append("$firstPart ")
}
withStyle(SpanStyle(color = MaterialTheme.colors.textColor(type = TextColorType.ACCENT))) {
withStyle(SpanStyle(color = TangemTheme.colors.text.accent)) {
append(stringResource(id = R.string.common_terms_and_conditions))
}
withStyle(SpanStyle(color = MaterialTheme.colors.textColor(type = TextColorType.TERTIARY))) {
withStyle(SpanStyle(color = TangemTheme.colors.text.tertiary)) {
append(" ${stringResource(id = R.string.referral_tos_suffix)}")
}
}
@ -60,7 +56,7 @@ private fun annotatedAgreementString(firstPart: String): AnnotatedString {
@Composable
fun Preview_AgreementText_InLightTheme() {
TangemTheme(isDark = false) {
Box(modifier = Modifier.background(MaterialTheme.colors.primary)) {
Box(modifier = Modifier.background(TangemTheme.colors.background.primary)) {
AgreementText(firstPartResId = R.string.referral_tos_not_enroled_prefix, onClicked = {})
}
}
@ -70,7 +66,7 @@ fun Preview_AgreementText_InLightTheme() {
@Composable
fun Preview_AgreementText_InDarkTheme() {
TangemTheme(isDark = true) {
Box(modifier = Modifier.background(MaterialTheme.colors.primary)) {
Box(modifier = Modifier.background(TangemTheme.colors.background.primary)) {
AgreementText(firstPartResId = R.string.referral_tos_not_enroled_prefix, onClicked = {})
}
}

View file

@ -3,7 +3,6 @@ package com.tangem.feature.referral.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@ -32,7 +31,7 @@ internal fun NonParticipateBottomBlock(onAgreementClicked: () -> Unit, onPartici
@Composable
fun Preview_NonParticipateBottomBlock_InLightTheme() {
TangemTheme(isDark = false) {
Column(Modifier.background(MaterialTheme.colors.primary)) {
Column(Modifier.background(TangemTheme.colors.background.primary)) {
NonParticipateBottomBlock(onAgreementClicked = {}, onParticipateClicked = {})
}
}
@ -42,7 +41,7 @@ fun Preview_NonParticipateBottomBlock_InLightTheme() {
@Composable
fun Preview_NonParticipateBottomBlock_InDarkTheme() {
TangemTheme(isDark = true) {
Column(Modifier.background(MaterialTheme.colors.primary)) {
Column(Modifier.background(TangemTheme.colors.background.primary)) {
NonParticipateBottomBlock(onAgreementClicked = {}, onParticipateClicked = {})
}
}

View file

@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@ -28,8 +27,6 @@ import androidx.core.content.ContextCompat.startActivity
import com.tangem.core.ui.components.PrimaryStartIconButton
import com.tangem.core.ui.components.SmallInfoCard
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TextColorType
import com.tangem.core.ui.res.textColor
import com.tangem.feature.referral.presentation.R
@OptIn(ExperimentalComposeUiApi::class)
@ -40,6 +37,8 @@ internal fun ParticipateBottomBlock(
shareLink: String,
onAgreementClicked: () -> Unit,
showCopySnackbar: () -> Unit,
onCopyClicked: () -> Unit,
onShareClicked: () -> Unit,
) {
Column(
modifier = Modifier
@ -55,11 +54,17 @@ internal fun ParticipateBottomBlock(
endText = pluralStringResource(
id = R.plurals.referral_wallets_purchased_count,
count = purchasedWalletCount,
purchasedWalletCount
purchasedWalletCount,
),
)
PersonalCodeCard(code = code)
AdditionalButtons(code = code, shareLink = shareLink, showCopySnackbar = showCopySnackbar)
AdditionalButtons(
code = code,
shareLink = shareLink,
showCopySnackbar = showCopySnackbar,
onCopyClicked = onCopyClicked,
onShareClicked = onShareClicked,
)
AgreementText(firstPartResId = R.string.referral_tos_enroled_prefix, onClicked = onAgreementClicked)
}
}
@ -73,7 +78,7 @@ private fun PersonalCodeCard(code: String) {
shape = RoundedCornerShape(TangemTheme.dimens.radius12),
)
.background(
color = MaterialTheme.colors.secondary,
color = TangemTheme.colors.background.secondary,
shape = RoundedCornerShape(TangemTheme.dimens.radius12),
)
.fillMaxWidth()
@ -83,21 +88,27 @@ private fun PersonalCodeCard(code: String) {
) {
Text(
text = stringResource(id = R.string.referral_promo_code_title),
color = MaterialTheme.colors.textColor(type = TextColorType.TERTIARY),
color = TangemTheme.colors.text.tertiary,
maxLines = 1,
style = MaterialTheme.typography.subtitle2,
style = TangemTheme.typography.subtitle2,
)
Text(
text = code,
color = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY1),
color = TangemTheme.colors.text.primary1,
maxLines = 1,
style = MaterialTheme.typography.h2,
style = TangemTheme.typography.h2,
)
}
}
@Composable
private fun AdditionalButtons(code: String, shareLink: String, showCopySnackbar: () -> Unit) {
private fun AdditionalButtons(
code: String,
shareLink: String,
showCopySnackbar: () -> Unit,
onCopyClicked: () -> Unit,
onShareClicked: () -> Unit,
) {
val clipboardManager = LocalClipboardManager.current
val hapticFeedback = LocalHapticFeedback.current
@ -110,6 +121,7 @@ private fun AdditionalButtons(code: String, shareLink: String, showCopySnackbar:
text = stringResource(id = R.string.common_copy),
iconResId = R.drawable.ic_copy_24,
onClicked = {
onCopyClicked.invoke()
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
clipboardManager.setText(AnnotatedString(code))
showCopySnackbar()
@ -122,6 +134,7 @@ private fun AdditionalButtons(code: String, shareLink: String, showCopySnackbar:
text = stringResource(id = R.string.common_share),
iconResId = R.drawable.ic_share_24,
onClicked = {
onShareClicked.invoke()
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
context.shareText(context.getString(R.string.referral_share_link, shareLink))
},
@ -143,13 +156,15 @@ private fun Context.shareText(text: String) {
@Composable
fun Preview_ParticipateBottomBlock_InLightTheme() {
TangemTheme(isDark = false) {
Column(Modifier.background(MaterialTheme.colors.primary)) {
Column(Modifier.background(TangemTheme.colors.background.primary)) {
ParticipateBottomBlock(
purchasedWalletCount = 3,
code = "x4JdK",
shareLink = "",
onAgreementClicked = {},
showCopySnackbar = {},
onCopyClicked = {},
onShareClicked = {},
)
}
}
@ -159,13 +174,15 @@ fun Preview_ParticipateBottomBlock_InLightTheme() {
@Composable
fun Preview_ParticipateBottomBlock_InDarkTheme() {
TangemTheme(isDark = true) {
Column(Modifier.background(MaterialTheme.colors.primary)) {
Column(Modifier.background(TangemTheme.colors.background.primary)) {
ParticipateBottomBlock(
purchasedWalletCount = 3,
code = "x4JdK",
shareLink = "",
onAgreementClicked = {},
showCopySnackbar = {},
onCopyClicked = {},
onShareClicked = {},
)
}
}

View file

@ -7,8 +7,10 @@ import androidx.compose.foundation.LocalOverscrollConfiguration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@ -21,7 +23,6 @@ import androidx.compose.material.BottomSheetState
import androidx.compose.material.BottomSheetValue
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Snackbar
import androidx.compose.material.SnackbarDuration
import androidx.compose.material.SnackbarHost
@ -56,15 +57,8 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.VerticalSpacer
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.res.ButtonColorType
import com.tangem.core.ui.res.IconColorType
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemColorPalette.Black
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TextColorType
import com.tangem.core.ui.res.buttonColor
import com.tangem.core.ui.res.iconColor
import com.tangem.core.ui.res.textColor
import com.tangem.feature.referral.models.ReferralStateHolder
import com.tangem.feature.referral.models.ReferralStateHolder.ErrorSnackbar
import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoContentState
@ -108,6 +102,7 @@ internal fun ReferralScreen(stateHolder: ReferralStateHolder) {
ReferralContent(
stateHolder = stateHolder,
onAgreementClicked = {
stateHolder.analytics.onAgreementClicked.invoke()
coroutineScope.launch {
if (bottomSheetScaffoldState.bottomSheetState.isCollapsed) {
bottomSheetScaffoldState.bottomSheetState.expand()
@ -131,14 +126,15 @@ private fun ReferralContent(stateHolder: ReferralStateHolder, onAgreementClicked
CompositionLocalProvider(LocalOverscrollConfiguration provides null) {
LazyColumn(
modifier = Modifier
.background(color = MaterialTheme.colors.primary)
.fillMaxWidth(),
.background(color = TangemTheme.colors.background.secondary)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
stickyHeader {
AppBarWithBackButton(
text = stringResource(R.string.details_referral_title),
onBackClick = stateHolder.headerState.onBackClicked,
modifier = Modifier.background(color = TangemTheme.colors.background.secondary),
)
}
item { Header() }
@ -172,10 +168,10 @@ private fun Header() {
Text(
text = stringResource(id = R.string.referral_title),
modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.spacing50)),
color = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY1),
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
maxLines = 2,
style = MaterialTheme.typography.h2,
style = TangemTheme.typography.h2,
)
VerticalSpacer(spaceResId = R.dimen.spacing16)
}
@ -196,6 +192,8 @@ private fun ReferralInfo(
shareLink = state.shareLink,
onAgreementClicked = onAgreementClicked,
showCopySnackbar = showCopySnackbar,
onCopyClicked = stateHolder.analytics.onCopyClicked,
onShareClicked = stateHolder.analytics.onShareClicked,
)
}
is ReferralInfoState.NonParticipantContent -> {
@ -262,7 +260,7 @@ private fun Condition(@DrawableRes iconResId: Int, infoBlock: @Composable () ->
Box(
modifier = Modifier
.background(
color = MaterialTheme.colors.buttonColor(type = ButtonColorType.SECONDARY),
color = TangemTheme.colors.button.secondary,
shape = RoundedCornerShape(TangemTheme.dimens.radius16),
)
.size(TangemTheme.dimens.size56),
@ -272,7 +270,7 @@ private fun Condition(@DrawableRes iconResId: Int, infoBlock: @Composable () ->
painter = painterResource(id = iconResId),
contentDescription = null,
modifier = Modifier.size(TangemTheme.dimens.size28),
tint = MaterialTheme.colors.iconColor(type = IconColorType.PRIMARY1),
tint = TangemTheme.colors.icon.primary1,
)
}
infoBlock()
@ -285,7 +283,7 @@ private fun InfoForYou(award: String, networkName: String, address: String? = nu
Text(
text = buildAnnotatedString {
append(stringResource(id = R.string.referral_point_currencies_description_prefix))
withStyle(SpanStyle(color = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY1))) {
withStyle(SpanStyle(color = TangemTheme.colors.text.primary1)) {
append(" $award ")
}
append(
@ -296,8 +294,8 @@ private fun InfoForYou(award: String, networkName: String, address: String? = nu
),
)
},
color = MaterialTheme.colors.textColor(type = TextColorType.TERTIARY),
style = MaterialTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.body2,
)
}
}
@ -306,19 +304,21 @@ private fun InfoForYou(award: String, networkName: String, address: String? = nu
private fun InfoForYourFriend(discount: String) {
ConditionInfo(title = stringResource(id = R.string.referral_point_discount_title)) {
Text(
text = buildString {
text = buildAnnotatedString {
append(stringResource(id = R.string.referral_point_discount_description_prefix))
append(
String.format(
stringResource(id = R.string.referral_point_discount_description_value),
" $discount",
),
)
withStyle(SpanStyle(color = TangemTheme.colors.text.primary1)) {
append(
String.format(
stringResource(id = R.string.referral_point_discount_description_value),
" $discount",
),
)
}
append(" ")
append(stringResource(id = R.string.referral_point_discount_description_suffix))
},
color = MaterialTheme.colors.textColor(type = TextColorType.TERTIARY),
style = MaterialTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
style = TangemTheme.typography.body2,
)
}
}
@ -328,8 +328,8 @@ private fun ConditionInfo(title: String, subtitleContent: @Composable () -> Unit
Column(verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing2)) {
Text(
text = title,
color = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY1),
style = MaterialTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
style = TangemTheme.typography.subtitle1,
)
subtitleContent()
}
@ -350,6 +350,7 @@ private fun ShimmerInfo() {
.width(TangemTheme.dimens.size102)
.height(TangemTheme.dimens.size16)
.background(TangemColorPalette.White),
// .background(Color(0xFFF8F8F8)),
)
Box(
modifier = Modifier
@ -363,23 +364,23 @@ private fun ShimmerInfo() {
// TODO() Replace component with component from ds
@Composable
private fun ErrorSnackbarHost(errorSnackbar: ErrorSnackbar?) {
private fun BoxScope.ErrorSnackbarHost(errorSnackbar: ErrorSnackbar?) {
if (errorSnackbar != null) {
val snackbarHostState by remember { mutableStateOf(SnackbarHostState()) }
val coroutineScope = rememberCoroutineScope()
SnackbarHost(
hostState = snackbarHostState,
modifier = Modifier.padding(top = TangemTheme.dimens.spacing56),
modifier = Modifier.align(Alignment.BottomCenter),
snackbar = {
Snackbar(
snackbarData = it,
modifier = Modifier.fillMaxWidth(),
actionOnNewLine = true,
shape = RoundedCornerShape(size = TangemTheme.dimens.radius8),
backgroundColor = Black,
contentColor = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY2),
actionColor = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY2),
backgroundColor = TangemColorPalette.Black,
contentColor = TangemTheme.colors.text.primary2,
actionColor = TangemTheme.colors.text.primary2,
elevation = TangemTheme.dimens.elevation3,
)
},
@ -412,7 +413,7 @@ private fun ErrorSnackbarHost(errorSnackbar: ErrorSnackbar?) {
// TODO() Replace component with component from ds
@Composable
private fun CopySnackbarHost(isCopyButtonPressed: MutableState<Boolean>) {
private fun BoxScope.CopySnackbarHost(isCopyButtonPressed: MutableState<Boolean>) {
if (isCopyButtonPressed.value) {
val snackbarHostState by remember { mutableStateOf(SnackbarHostState()) }
val coroutineScope = rememberCoroutineScope()
@ -424,13 +425,14 @@ private fun CopySnackbarHost(isCopyButtonPressed: MutableState<Boolean>) {
SnackbarHost(
hostState = snackbarHostState,
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing56, start = (width - snackbarWidth).div(2))
.align(Alignment.BottomCenter)
.padding(start = (width - snackbarWidth).div(2), bottom = dimensionResource(R.dimen.spacing12))
.fillMaxWidth(),
snackbar = {
Box(
modifier = Modifier
.onSizeChanged { snackbarSize = it.width }
.background(Black, RoundedCornerShape(size = TangemTheme.dimens.radius8))
.background(TangemColorPalette.Black, RoundedCornerShape(size = TangemTheme.dimens.radius8))
.shadow(
TangemTheme.dimens.elevation3,
RoundedCornerShape(size = TangemTheme.dimens.radius8),
@ -442,8 +444,8 @@ private fun CopySnackbarHost(isCopyButtonPressed: MutableState<Boolean>) {
) {
Text(
text = it.message,
color = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY2),
style = MaterialTheme.typography.body2,
color = TangemTheme.colors.text.primary2,
style = TangemTheme.typography.body2,
)
}
},
@ -480,6 +482,11 @@ fun Preview_ReferralScreen_Participant_InLightTheme() {
url = "",
),
errorSnackbar = null,
analytics = ReferralStateHolder.Analytics(
onAgreementClicked = {},
onCopyClicked = {},
onShareClicked = {},
),
),
)
}
@ -503,6 +510,11 @@ fun Preview_ReferralScreen_Participant_InDarkTheme() {
url = "",
),
errorSnackbar = null,
analytics = ReferralStateHolder.Analytics(
onAgreementClicked = {},
onCopyClicked = {},
onShareClicked = {},
),
),
)
}
@ -523,6 +535,11 @@ fun Preview_ReferralScreen_NonParticipant_InLightTheme() {
onParticipateClicked = {},
),
errorSnackbar = null,
analytics = ReferralStateHolder.Analytics(
onAgreementClicked = {},
onCopyClicked = {},
onShareClicked = {},
),
),
)
}
@ -543,6 +560,11 @@ fun Preview_ReferralScreen_NonParticipant_InDarkTheme() {
onParticipateClicked = {},
),
errorSnackbar = null,
analytics = ReferralStateHolder.Analytics(
onAgreementClicked = {},
onCopyClicked = {},
onShareClicked = {},
),
),
)
}
@ -557,6 +579,11 @@ fun Preview_ReferralScreen_Loading_InLightTheme() {
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
referralInfoState = ReferralInfoState.Loading,
errorSnackbar = null,
analytics = ReferralStateHolder.Analytics(
onAgreementClicked = {},
onCopyClicked = {},
onShareClicked = {},
),
),
)
}
@ -571,6 +598,11 @@ fun Preview_ReferralScreen_Loading_InDarkTheme() {
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
referralInfoState = ReferralInfoState.Loading,
errorSnackbar = null,
analytics = ReferralStateHolder.Analytics(
onAgreementClicked = {},
onCopyClicked = {},
onShareClicked = {},
),
),
)
}

View file

@ -5,6 +5,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.feature.referral.analytics.ReferralEvents
import com.tangem.feature.referral.domain.ReferralInteractor
import com.tangem.feature.referral.domain.models.DiscountType
import com.tangem.feature.referral.domain.models.ReferralData
@ -24,6 +26,7 @@ import kotlin.properties.Delegates
internal class ReferralViewModel @Inject constructor(
private val referralInteractor: ReferralInteractor,
private val dispatchers: CoroutineDispatcherProvider,
private val analyticsEventHandler: AnalyticsEventHandler,
) : ViewModel() {
var uiState: ReferralStateHolder by mutableStateOf(createInitiallyUiState())
@ -40,10 +43,19 @@ internal class ReferralViewModel @Inject constructor(
uiState = uiState.copy(headerState = ReferralStateHolder.HeaderState(onBackClicked = router::back))
}
fun onScreenOpened() {
analyticsEventHandler.send(ReferralEvents.ReferralScreenOpened)
}
private fun createInitiallyUiState() = ReferralStateHolder(
headerState = ReferralStateHolder.HeaderState(onBackClicked = { }),
referralInfoState = ReferralInfoState.Loading,
errorSnackbar = null,
analytics = ReferralStateHolder.Analytics(
onAgreementClicked = ::onAgreementClicked,
onCopyClicked = ::onCopyClicked,
onShareClicked = ::onShareClicked,
),
)
private fun loadReferralData() {
@ -56,6 +68,7 @@ internal class ReferralViewModel @Inject constructor(
}
private fun participate() {
analyticsEventHandler.send(ReferralEvents.ClickParticipate)
uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading)
viewModelScope.launch(dispatchers.main) {
runCatching(dispatchers.io) { referralInteractor.startReferral() }
@ -74,6 +87,18 @@ internal class ReferralViewModel @Inject constructor(
)
}
private fun onAgreementClicked() {
analyticsEventHandler.send(ReferralEvents.ClickTaC)
}
private fun onCopyClicked() {
analyticsEventHandler.send(ReferralEvents.ClickCopy)
}
private fun onShareClicked() {
analyticsEventHandler.send(ReferralEvents.ClickShare)
}
private fun ReferralData.convertToReferralInfoState(): ReferralInfoState = when (this) {
is ReferralData.ParticipantData -> ReferralInfoState.ParticipantContent(
award = getAwardValue(),
@ -107,9 +132,9 @@ internal class ReferralViewModel @Inject constructor(
private fun ReferralData.getDiscountValue(): String {
val discountSymbol = when (discountType) {
DiscountType.PERCENTAGE -> "%"
DiscountType.VALUE -> error("Value doesn't support")
DiscountType.VALUE -> this.getToken().symbol
}
return "$discount $discountSymbol"
return "$discount$discountSymbol"
}
private fun ReferralData.getToken() = requireNotNull(tokens.firstOrNull()) { "Token list is empty" }