From ee722c5f466eaddb209bd3cf1504ac4503427eaf Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 21 Nov 2022 17:21:57 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/common/extensions/Navigation.kt | 2 + .../redux/navigation/NavigationState.kt | 1 + .../tangem/utils/coroutines/CoroutineExt.kt | 10 ++ .../referral/presentation/build.gradle.kts | 3 + .../feature/referral/ReferralFragment.kt | 27 ++++ .../referral/models/ReferralStateHolder.kt | 35 +++-- .../presentation/ReferralViewModel.kt | 11 -- .../referral/ui/NonParticipateBottomBlock.kt | 127 +++------------- .../referral/ui/ParticipateBottomBlock.kt | 137 +++++++++++++++--- .../feature/referral/ui/ReferralScreen.kt | 81 +++++------ .../referral/viewmodels/ReferralViewModel.kt | 91 ++++++++++++ 11 files changed, 327 insertions(+), 198 deletions(-) create mode 100644 core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt create mode 100644 features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt delete mode 100644 features/referral/presentation/src/main/java/com/tangem/feature/referral/presentation/ReferralViewModel.kt create mode 100644 features/referral/presentation/src/main/java/com/tangem/feature/referral/viewmodels/ReferralViewModel.kt diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt index 5e07c484b8..97575ecd31 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt @@ -6,6 +6,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentManager import com.tangem.common.extensions.VoidCallback +import com.tangem.feature.referral.ReferralFragment import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.FragmentShareTransition import com.tangem.tap.features.details.ui.appsettings.AppSettingsFragment @@ -108,5 +109,6 @@ private fun fragmentFactory(screen: AppScreen): Fragment { AppScreen.WalletDetails -> WalletDetailsFragment() AppScreen.WalletConnectSessions -> WalletConnectFragment() AppScreen.QrScan -> QrScanFragment() + AppScreen.ReferralProgram -> ReferralFragment() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt index 05ec744393..6d5993cbc0 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt @@ -22,4 +22,5 @@ enum class AppScreen( AddTokens, AddCustomToken, WalletConnectSessions, QrScan, + ReferralProgram } \ No newline at end of file diff --git a/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt b/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt new file mode 100644 index 0000000000..87097ce482 --- /dev/null +++ b/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt @@ -0,0 +1,10 @@ +package com.tangem.utils.coroutines + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext + +suspend fun runCatching(dispatcher: CoroutineDispatcher, block: suspend () -> R): Result { + return runCatching { + withContext(dispatcher) { block() } + } +} \ No newline at end of file diff --git a/features/referral/presentation/build.gradle.kts b/features/referral/presentation/build.gradle.kts index b2763c706c..226a789737 100644 --- a/features/referral/presentation/build.gradle.kts +++ b/features/referral/presentation/build.gradle.kts @@ -34,10 +34,13 @@ android { dependencies { /** Core modules */ + implementation(project(":core:utils")) implementation(project(":core:ui")) /** AndroidX */ implementation(AndroidX.appCompat) + implementation(AndroidX.fragmentKtx) + implementation(AndroidX.lifecycleViewModelKtx) /** Compose */ implementation(Compose.foundation) diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt new file mode 100644 index 0000000000..34df965d31 --- /dev/null +++ b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ReferralFragment.kt @@ -0,0 +1,27 @@ +package com.tangem.feature.referral + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.ui.platform.ComposeView +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import com.tangem.feature.referral.ui.ReferralScreen +import com.tangem.feature.referral.viewmodels.ReferralViewModel +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class ReferralFragment : Fragment() { + private val viewModel by viewModels().apply { + // TODO("[REDACTED_JIRA]") this.value.setOnBackClicked() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return ComposeView(inflater.context).apply { + setContent { + ReferralScreen(stateHolder = viewModel.uiState) + } + } + } +} \ No newline at end of file diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/models/ReferralStateHolder.kt b/features/referral/presentation/src/main/java/com/tangem/feature/referral/models/ReferralStateHolder.kt index 0f9a5666b3..e001315199 100644 --- a/features/referral/presentation/src/main/java/com/tangem/feature/referral/models/ReferralStateHolder.kt +++ b/features/referral/presentation/src/main/java/com/tangem/feature/referral/models/ReferralStateHolder.kt @@ -3,36 +3,39 @@ package com.tangem.feature.referral.models data class ReferralStateHolder( val headerState: HeaderState, val referralInfoState: ReferralInfoState, - val effects: Effects, - val agreementBottomSheetState: AgreementBottomSheetState + val errorToast: ErrorToast, ) { data class HeaderState(val onBackClicked: () -> Unit) - sealed interface ReferralInfoContentState + sealed interface ReferralInfoContentState { + val award: String + val discount: String + val url: String + } sealed interface ReferralInfoState { - data class ParticipantContent( - val award: String, + override val award: String, val address: String, - val discount: String, - val onParticipateClicked: () -> Unit, + override val discount: String, + val purchasedWalletCount: Int, + val code: String, + override val url: String, ) : ReferralInfoState, ReferralInfoContentState data class NonParticipantContent( - val award: String, - val discount: String, - val purchasedWalletCount: Int, - val code: String, - val onCopyClicked: () -> Unit, - val onShareClicked: () -> Unit, + override val award: String, + override val discount: String, + override val url: String, + val onParticipateClicked: () -> Unit, ) : ReferralInfoState, ReferralInfoContentState object Loading : ReferralInfoState } - data class Effects(val showErrorToast: Boolean) - - data class AgreementBottomSheetState(val url: String) + data class ErrorToast( + val visibility: Boolean, + val changeVisibility: () -> Unit + ) } diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/presentation/ReferralViewModel.kt b/features/referral/presentation/src/main/java/com/tangem/feature/referral/presentation/ReferralViewModel.kt deleted file mode 100644 index e106965a14..0000000000 --- a/features/referral/presentation/src/main/java/com/tangem/feature/referral/presentation/ReferralViewModel.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.feature.referral.presentation - -import androidx.lifecycle.ViewModel -import com.tangem.feature.referral.domain.ReferralInteractor -import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject - -@HiltViewModel -class ReferralViewModel @Inject constructor(referralInteractor: ReferralInteractor) : ViewModel() { - -} \ No newline at end of file diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/NonParticipateBottomBlock.kt b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/NonParticipateBottomBlock.kt index f202bd4ef6..a98b1e8a93 100644 --- a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/NonParticipateBottomBlock.kt +++ b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/NonParticipateBottomBlock.kt @@ -1,40 +1,40 @@ package com.tangem.feature.referral.ui import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -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 import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.PrimaryStartIconButton -import com.tangem.core.ui.components.SmallInfoCard +import com.tangem.core.ui.components.PrimaryEndIconButton 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 +fun NonParticipateBottomBlock(onAgreementClicked: () -> Unit, onParticipateClicked: () -> Unit) { + Column { + AgreementText( + firstPartResId = R.string.referral_tos_not_enroled_prefix, + onClicked = onAgreementClicked, + ) + PrimaryEndIconButton( + modifier = Modifier.padding(all = dimensionResource(id = R.dimen.spacing16)), + text = stringResource(id = R.string.referral_button_participate), + iconResId = R.drawable.ic_tangem, + onClicked = onParticipateClicked, + ) + } +} + @Preview(widthDp = 360, showBackground = true) @Composable fun Preview_NonParticipateBottomBlock_InLightTheme() { TangemTheme(isDark = false) { Column(Modifier.background(MaterialTheme.colors.primary)) { - NonParticipateBottomBlock( - purchasedWalletCount = 3, - code = "x4JdK", - onCopyClicked = {}, - onShareClicked = {}, - onAgreementClicked = {}, - ) + NonParticipateBottomBlock(onAgreementClicked = {}, onParticipateClicked = {}) } } } @@ -44,96 +44,7 @@ fun Preview_NonParticipateBottomBlock_InLightTheme() { fun Preview_NonParticipateBottomBlock_InDarkTheme() { TangemTheme(isDark = true) { Column(Modifier.background(MaterialTheme.colors.primary)) { - NonParticipateBottomBlock( - purchasedWalletCount = 3, - code = "x4JdK", - onCopyClicked = {}, - onShareClicked = {}, - onAgreementClicked = {}, - ) + NonParticipateBottomBlock(onAgreementClicked = {}, onParticipateClicked = {}) } } -} - -@Composable -fun NonParticipateBottomBlock( - purchasedWalletCount: Int, - code: String, - onCopyClicked: () -> Unit, - onShareClicked: () -> Unit, - onAgreementClicked: () -> Unit, -) { - Column( - modifier = Modifier - .padding( - top = dimensionResource(id = R.dimen.spacing24), - bottom = dimensionResource(id = R.dimen.spacing16), - ) - .padding(horizontal = dimensionResource(id = R.dimen.spacing16)), - verticalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.spacing16)), - ) { - SmallInfoCard( - startText = stringResource(id = R.string.referral_friends_bought_title), - endText = String.format( - stringResource(id = R.string.referral_wallets_purchased_count), - purchasedWalletCount, - ), - ) - PersonalCodeCard(code = code) - AdditionalButtons(onCopyClicked = onCopyClicked, onShareClicked = onShareClicked) - AgreementText(firstPartResId = R.string.referral_tos_enroled_prefix, onClicked = onAgreementClicked) - } -} - -@Composable -private fun PersonalCodeCard(code: String) { - Column( - modifier = Modifier - .shadow( - elevation = dimensionResource(id = R.dimen.elevation2), - shape = RoundedCornerShape(dimensionResource(id = R.dimen.radius12)), - ) - .background( - color = MaterialTheme.colors.secondary, - shape = RoundedCornerShape(dimensionResource(id = R.dimen.radius12)), - ) - .fillMaxWidth() - .padding(vertical = dimensionResource(id = R.dimen.spacing12)), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.spacing4)), - ) { - Text( - text = stringResource(id = R.string.referral_promo_code_title), - color = MaterialTheme.colors.textColor(type = TextColorType.TERTIARY), - maxLines = 1, - style = MaterialTheme.typography.subtitle2, - ) - Text( - text = code, - color = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY1), - maxLines = 1, - style = MaterialTheme.typography.h2, - ) - } -} - -@Composable -private fun AdditionalButtons(onCopyClicked: () -> Unit, onShareClicked: () -> Unit) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.spacing16)), - ) { - PrimaryStartIconButton( - modifier = Modifier.weight(1f), - text = stringResource(id = R.string.common_copy), - iconResId = R.drawable.ic_copy, - onClicked = onCopyClicked, - ) - PrimaryStartIconButton( - modifier = Modifier.weight(1f), - text = stringResource(id = R.string.common_share), - iconResId = R.drawable.ic_share, - onClicked = onShareClicked, - ) - } } \ No newline at end of file diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ParticipateBottomBlock.kt b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ParticipateBottomBlock.kt index d58527d894..775896aa6c 100644 --- a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ParticipateBottomBlock.kt +++ b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ParticipateBottomBlock.kt @@ -1,24 +1,135 @@ package com.tangem.feature.referral.ui +import android.content.Intent import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +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 import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.PrimaryEndIconButton +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 +@Composable +fun ParticipateBottomBlock( + purchasedWalletCount: Int, + code: String, + onAgreementClicked: () -> Unit, +) { + Column( + modifier = Modifier + .padding( + top = dimensionResource(id = R.dimen.spacing24), + bottom = dimensionResource(id = R.dimen.spacing16), + ) + .padding(horizontal = dimensionResource(id = R.dimen.spacing16)), + verticalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.spacing16)), + ) { + SmallInfoCard( + startText = stringResource(id = R.string.referral_friends_bought_title), + endText = String.format( + stringResource(id = R.string.referral_wallets_purchased_count), + purchasedWalletCount, + ), + ) + PersonalCodeCard(code = code) + AdditionalButtons(code = code) + AgreementText(firstPartResId = R.string.referral_tos_enroled_prefix, onClicked = onAgreementClicked) + } +} + +@Composable +private fun PersonalCodeCard(code: String) { + Column( + modifier = Modifier + .shadow( + elevation = dimensionResource(id = R.dimen.elevation2), + shape = RoundedCornerShape(dimensionResource(id = R.dimen.radius12)), + ) + .background( + color = MaterialTheme.colors.secondary, + shape = RoundedCornerShape(dimensionResource(id = R.dimen.radius12)), + ) + .fillMaxWidth() + .padding(vertical = dimensionResource(id = R.dimen.spacing12)), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.spacing4)), + ) { + Text( + text = stringResource(id = R.string.referral_promo_code_title), + color = MaterialTheme.colors.textColor(type = TextColorType.TERTIARY), + maxLines = 1, + style = MaterialTheme.typography.subtitle2, + ) + Text( + text = code, + color = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY1), + maxLines = 1, + style = MaterialTheme.typography.h2, + ) + } +} + +@Composable +private fun AdditionalButtons(code: String) { + val clipboardManager = LocalClipboardManager.current + val context = LocalContext.current + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.spacing16)), + ) { + PrimaryStartIconButton( + modifier = Modifier.weight(1f), + text = stringResource(id = R.string.common_copy), + iconResId = R.drawable.ic_copy, + onClicked = { clipboardManager.setText(AnnotatedString(code)) }, + ) + PrimaryStartIconButton( + modifier = Modifier.weight(1f), + text = stringResource(id = R.string.common_share), + iconResId = R.drawable.ic_share, + onClicked = { + val sendIntent: Intent = Intent().apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_TEXT, code) + type = "text/plain" + } + val shareIntent = Intent.createChooser(sendIntent, null) + startActivity(context, shareIntent, null) + }, + ) + } +} + @Preview(widthDp = 360, showBackground = true) @Composable fun Preview_ParticipateBottomBlock_InLightTheme() { TangemTheme(isDark = false) { Column(Modifier.background(MaterialTheme.colors.primary)) { - ParticipateBottomBlock(onAgreementClicked = {}, onParticipateClicked = {}) + ParticipateBottomBlock( + purchasedWalletCount = 3, + code = "x4JdK", + onAgreementClicked = {}, + ) } } } @@ -28,23 +139,11 @@ fun Preview_ParticipateBottomBlock_InLightTheme() { fun Preview_ParticipateBottomBlock_InDarkTheme() { TangemTheme(isDark = true) { Column(Modifier.background(MaterialTheme.colors.primary)) { - ParticipateBottomBlock(onAgreementClicked = {}, onParticipateClicked = {}) + ParticipateBottomBlock( + purchasedWalletCount = 3, + code = "x4JdK", + onAgreementClicked = {}, + ) } } -} - -@Composable -fun ParticipateBottomBlock(onAgreementClicked: () -> Unit, onParticipateClicked: () -> Unit) { - Column { - AgreementText( - firstPartResId = R.string.referral_tos_not_enroled_prefix, - onClicked = onAgreementClicked, - ) - PrimaryEndIconButton( - modifier = Modifier.padding(all = dimensionResource(id = R.dimen.spacing16)), - text = stringResource(id = R.string.referral_button_participate), - iconResId = R.drawable.ic_tangem, - onClicked = onParticipateClicked, - ) - } } \ No newline at end of file diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt index 7091674dcd..708aa9431e 100644 --- a/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt +++ b/features/referral/presentation/src/main/java/com/tangem/feature/referral/ui/ReferralScreen.kt @@ -1,5 +1,6 @@ package com.tangem.feature.referral.ui +import android.widget.Toast import androidx.annotation.DrawableRes import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -26,10 +27,12 @@ import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.rememberBottomSheetScaffoldState import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -49,6 +52,7 @@ 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.ReferralInfoContentState import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoState import com.tangem.feature.referral.presentation.R import com.valentinilk.shimmer.shimmer @@ -69,7 +73,11 @@ fun ReferralScreen(stateHolder: ReferralStateHolder) { TangemTheme { BottomSheetScaffold( - sheetContent = { AgreementBottomSheetContent(stateHolder.agreementBottomSheetState.url) }, + sheetContent = { + AgreementBottomSheetContent( + url = (stateHolder.referralInfoState as ReferralInfoContentState).url, + ) + }, scaffoldState = bottomSheetScaffoldState, sheetShape = RoundedCornerShape( topStart = dimensionResource(id = R.dimen.radius16), @@ -92,6 +100,15 @@ fun ReferralScreen(stateHolder: ReferralStateHolder) { ) }, ) + + val context = LocalContext.current + SideEffect { + if (stateHolder.errorToast.visibility) { + //TODO("[REDACTED_JIRA]") + Toast.makeText(context, "", Toast.LENGTH_LONG).show() + stateHolder.errorToast.changeVisibility() + } + } } } @@ -137,12 +154,11 @@ fun ReferralInfo(stateHolder: ReferralStateHolder, onAgreementClicked: () -> Uni when (val state = stateHolder.referralInfoState) { is ReferralInfoState.ParticipantContent -> { Conditions(state = state) - VerticalSpacer(spaceResId = R.dimen.spacing44) ParticipantBottomBlock(state = state, onAgreementClicked = onAgreementClicked) } is ReferralInfoState.NonParticipantContent -> { Conditions(state = state) - VerticalSpacer(spaceResId = R.dimen.spacing24) + VerticalSpacer(spaceResId = R.dimen.spacing44) NonParticipantBottomBlock(state = state, onAgreementClicked = onAgreementClicked) } is ReferralInfoState.Loading -> { @@ -162,14 +178,14 @@ private fun AppBar(stateHolder: ReferralStateHolder) { } @Composable -private fun Conditions(state: ReferralStateHolder.ReferralInfoContentState) { +private fun Conditions(state: ReferralInfoContentState) { ConditionForYou(state = state) VerticalSpacer(spaceResId = R.dimen.spacing32) ConditionForYourFriend(state = state) } @Composable -private fun ConditionForYou(state: ReferralStateHolder.ReferralInfoContentState) { +private fun ConditionForYou(state: ReferralInfoContentState) { Condition(iconResId = R.drawable.ic_tether) { when (state) { is ReferralInfoState.ParticipantContent -> InfoForYou(award = state.award, address = state.address) @@ -179,7 +195,7 @@ private fun ConditionForYou(state: ReferralStateHolder.ReferralInfoContentState) } @Composable -private fun ConditionForYourFriend(state: ReferralStateHolder.ReferralInfoContentState) { +private fun ConditionForYourFriend(state: ReferralInfoContentState) { Condition(iconResId = R.drawable.ic_discount) { when (state) { is ReferralInfoState.ParticipantContent -> InfoForYourFriend(discount = state.discount) @@ -306,19 +322,17 @@ private fun ShimmerInfo() { @Composable private fun ParticipantBottomBlock(state: ReferralInfoState.ParticipantContent, onAgreementClicked: () -> Unit) { ParticipateBottomBlock( + purchasedWalletCount = state.purchasedWalletCount, + code = state.code, onAgreementClicked = onAgreementClicked, - onParticipateClicked = state.onParticipateClicked, ) } @Composable private fun NonParticipantBottomBlock(state: ReferralInfoState.NonParticipantContent, onAgreementClicked: () -> Unit) { NonParticipateBottomBlock( - purchasedWalletCount = state.purchasedWalletCount, - code = state.code, - onCopyClicked = state.onCopyClicked, - onShareClicked = state.onShareClicked, onAgreementClicked = onAgreementClicked, + onParticipateClicked = state.onParticipateClicked, ) } @@ -333,12 +347,11 @@ fun Preview_ReferralScreen_Participant_InLightTheme() { award = "10 USDT", address = "ma80...zk8q2", discount = "10%", - onParticipateClicked = {}, - ), - effects = ReferralStateHolder.Effects(showErrorToast = false), - agreementBottomSheetState = ReferralStateHolder.AgreementBottomSheetState( + purchasedWalletCount = 3, + code = "x4JdK", url = "", ), + errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}), ), ) } @@ -355,13 +368,11 @@ fun Preview_ReferralScreen_Participant_InDarkTheme() { award = "10 USDT", address = "ma80...zk8q2", discount = "10%", - - onParticipateClicked = {}, - ), - effects = ReferralStateHolder.Effects(showErrorToast = false), - agreementBottomSheetState = ReferralStateHolder.AgreementBottomSheetState( + purchasedWalletCount = 3, + code = "x4JdK", url = "", ), + errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}), ), ) } @@ -377,16 +388,10 @@ fun Preview_ReferralScreen_NonParticipant_InLightTheme() { referralInfoState = ReferralInfoState.NonParticipantContent( award = "10 USDT", discount = "10%", - purchasedWalletCount = 3, - code = "x4JdK", - onCopyClicked = {}, - onShareClicked = {}, - - ), - effects = ReferralStateHolder.Effects(showErrorToast = false), - agreementBottomSheetState = ReferralStateHolder.AgreementBottomSheetState( url = "", + onParticipateClicked = {}, ), + errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}), ), ) } @@ -402,16 +407,10 @@ fun Preview_ReferralScreen_NonParticipant_InDarkTheme() { referralInfoState = ReferralInfoState.NonParticipantContent( award = "10 USDT", discount = "10%", - purchasedWalletCount = 3, - code = "x4JdK", - onCopyClicked = {}, - onShareClicked = {}, - - ), - effects = ReferralStateHolder.Effects(showErrorToast = false), - agreementBottomSheetState = ReferralStateHolder.AgreementBottomSheetState( url = "", + onParticipateClicked = {}, ), + errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}), ), ) } @@ -425,10 +424,7 @@ fun Preview_ReferralScreen_Loading_InLightTheme() { stateHolder = ReferralStateHolder( headerState = ReferralStateHolder.HeaderState(onBackClicked = {}), referralInfoState = ReferralInfoState.Loading, - effects = ReferralStateHolder.Effects(showErrorToast = false), - agreementBottomSheetState = ReferralStateHolder.AgreementBottomSheetState( - url = "", - ), + errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}), ), ) } @@ -442,10 +438,7 @@ fun Preview_ReferralScreen_Loading_InDarkTheme() { stateHolder = ReferralStateHolder( headerState = ReferralStateHolder.HeaderState(onBackClicked = {}), referralInfoState = ReferralInfoState.Loading, - effects = ReferralStateHolder.Effects(showErrorToast = false), - agreementBottomSheetState = ReferralStateHolder.AgreementBottomSheetState( - url = "", - ), + errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}), ), ) } diff --git a/features/referral/presentation/src/main/java/com/tangem/feature/referral/viewmodels/ReferralViewModel.kt b/features/referral/presentation/src/main/java/com/tangem/feature/referral/viewmodels/ReferralViewModel.kt new file mode 100644 index 0000000000..ae29377adf --- /dev/null +++ b/features/referral/presentation/src/main/java/com/tangem/feature/referral/viewmodels/ReferralViewModel.kt @@ -0,0 +1,91 @@ +package com.tangem.feature.referral.viewmodels + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.tangem.feature.referral.domain.ReferralInteractor +import com.tangem.feature.referral.domain.models.DiscountType +import com.tangem.feature.referral.domain.models.ReferralData +import com.tangem.feature.referral.models.ReferralStateHolder +import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoState +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.coroutines.runCatching +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class ReferralViewModel @Inject constructor( + private val referralInteractor: ReferralInteractor, + private val dispatchers: CoroutineDispatcherProvider, +) : ViewModel() { + + var uiState by mutableStateOf(createInitiallyUiState()) + private set + + init { + loadReferralData() + } + + fun setOnBackClicked(onBackClicked: () -> Unit) { + uiState = uiState.copy(headerState = ReferralStateHolder.HeaderState(onBackClicked = onBackClicked)) + } + + private fun createInitiallyUiState() = ReferralStateHolder( + headerState = ReferralStateHolder.HeaderState(onBackClicked = { }), + referralInfoState = ReferralInfoState.Loading, + errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = ::cancelErrorToast), + ) + + private fun loadReferralData() { + uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading) + viewModelScope.launch(dispatchers.main) { + runCatching(dispatchers.io) { referralInteractor.getReferralStatus() } + .onSuccess { uiState = uiState.copy(referralInfoState = it.convertToReferralInfoState()) } + .onFailure { uiState = uiState.copy(errorToast = uiState.errorToast.copy(visibility = true)) } + } + } + + private fun ReferralData.convertToReferralInfoState(): ReferralInfoState = when (this) { + is ReferralData.ParticipantData -> ReferralInfoState.ParticipantContent( + award = getAwardValue(), + address = referral.address, + discount = getDiscountValue(), + purchasedWalletCount = referral.walletsPurchased, + code = referral.promocode, + url = tosLink, + ) + is ReferralData.NonParticipantData -> ReferralInfoState.NonParticipantContent( + award = getAwardValue(), + discount = getDiscountValue(), + url = tosLink, + onParticipateClicked = ::onParticipateClicked, + ) + } + + private fun ReferralData.getAwardValue(): String = + "$award ${requireNotNull(tokens.firstOrNull()?.symbol) { "Token list is empty" }}" + + private fun ReferralData.getDiscountValue(): String { + val discountSymbol = when (discountType) { + DiscountType.PERCENTAGE -> "%" + DiscountType.VALUE -> throw java.lang.IllegalStateException("Value doesn't support") + } + return "$discount $discountSymbol" + } + + private fun onParticipateClicked() { + uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading) + viewModelScope.launch(dispatchers.main) { + runCatching(dispatchers.io) { referralInteractor.startReferral() } + .onSuccess { uiState = uiState.copy(referralInfoState = it.convertToReferralInfoState()) } + .onFailure { uiState = uiState.copy(errorToast = uiState.errorToast.copy(visibility = true)) } + } + } + + private fun cancelErrorToast() { + uiState = uiState.copy(errorToast = uiState.errorToast.copy(visibility = false)) + } +} \ No newline at end of file