From 9da26433fb749a19d1bd8a3ad19aed80b84de6e1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 17 May 2024 17:11:13 +0800 Subject: [PATCH] Updated on 2026-08-14 --- .../com/tangem/core/ui/res/TangemDimens.kt | 1 + .../referral/ui/ParticipateBottomBlock.kt | 39 ++-- .../feature/referral/ui/ReferralScreen.kt | 174 ++++++------------ 3 files changed, 74 insertions(+), 140 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt index 79a2e16273..447750132a 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt @@ -131,6 +131,7 @@ data class TangemDimens internal constructor( val spacing92: Dp = 92.dp, val spacing94: Dp = 94.dp, val spacing96: Dp = 96.dp, + val spacing108: Dp = 108.dp, val spacing154: Dp = 154.dp, // endregion Spacing ) \ 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 69c37e25c9..7890ba08a7 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 @@ -8,14 +8,8 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Divider -import androidx.compose.material3.Icon -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow @@ -31,12 +25,13 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import androidx.core.content.ContextCompat.startActivity -import com.tangem.core.ui.components.* -import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.core.ui.components.PrimaryStartIconButton import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview import com.tangem.feature.referral.domain.models.ExpectedAward import com.tangem.feature.referral.domain.models.ExpectedAwards import com.tangem.feature.referral.presentation.R +import kotlinx.coroutines.launch @Suppress("LongParameterList") @Composable @@ -45,8 +40,8 @@ internal fun ParticipateBottomBlock( code: String, shareLink: String, expectedAwards: ExpectedAwards?, + snackbarHostState: SnackbarHostState, onAgreementClick: () -> Unit, - onShowCopySnackbar: () -> Unit, onCopyClick: () -> Unit, onShareClick: () -> Unit, ) { @@ -63,7 +58,7 @@ internal fun ParticipateBottomBlock( AdditionalButtons( code = code, shareLink = shareLink, - onShowCopySnackbar = onShowCopySnackbar, + snackbarHostState = snackbarHostState, onCopyClick = onCopyClick, onShareClick = onShareClick, ) @@ -112,9 +107,9 @@ private fun Awards(expectedAwards: ExpectedAwards) { val elementsCountToShowInLessMode = 3 val isExpanded = remember { mutableStateOf(false) } - Divider( - color = TangemTheme.colors.stroke.primary, + HorizontalDivider( thickness = TangemTheme.dimens.size0_5, + color = TangemTheme.colors.stroke.primary, ) AwardText( startText = if (expectedAwards.expectedAwards.isNotEmpty()) { @@ -272,13 +267,16 @@ private fun PersonalCodeCard(code: String) { private fun AdditionalButtons( code: String, shareLink: String, - onShowCopySnackbar: () -> Unit, + snackbarHostState: SnackbarHostState, onCopyClick: () -> Unit, onShareClick: () -> Unit, ) { val clipboardManager = LocalClipboardManager.current val hapticFeedback = LocalHapticFeedback.current + val coroutineScope = rememberCoroutineScope() + val resources = LocalContext.current.resources + Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16), @@ -291,7 +289,13 @@ private fun AdditionalButtons( onCopyClick.invoke() hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) clipboardManager.setText(AnnotatedString(code)) - onShowCopySnackbar() + + coroutineScope.launch { + snackbarHostState.showSnackbar( + message = resources.getString(R.string.referral_promo_code_copied), + duration = SnackbarDuration.Short, + ) + } }, ) @@ -333,7 +337,7 @@ private fun ParticipateBottomBlockPreview( shareLink = data.shareLink, expectedAwards = data.expectedAwards, onAgreementClick = data.onAgreementClick, - onShowCopySnackbar = data.onShowCopySnackbar, + snackbarHostState = SnackbarHostState(), onCopyClick = data.onCopyClick, onShareClick = data.onShareClick, ) @@ -391,7 +395,6 @@ private class ParticipateBottomBlockDataProvider : CollectionPreviewParameterPro purchasedWalletCount = 0, expectedAwards = null, ), - ), ) 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 cdff31bf58..39b216fb16 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,6 +1,7 @@ package com.tangem.feature.referral.ui import android.content.res.Configuration +import android.content.res.Resources import androidx.annotation.DrawableRes import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -11,9 +12,7 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.onSizeChanged -import androidx.compose.ui.platform.LocalConfiguration -import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString @@ -22,14 +21,15 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.RectangleShimmer import com.tangem.core.ui.components.SpacerH16 import com.tangem.core.ui.components.SpacerH24 import com.tangem.core.ui.components.SpacerH32 import com.tangem.core.ui.components.appbar.AppBarWithBackButton -import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.core.ui.components.snackbar.CopiedTextSnackbar +import com.tangem.core.ui.components.snackbar.TangemSnackbar import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview import com.tangem.feature.referral.domain.models.ExpectedAward import com.tangem.feature.referral.domain.models.ExpectedAwards import com.tangem.feature.referral.models.DemoModeException @@ -50,6 +50,8 @@ internal fun ReferralScreen(stateHolder: ReferralStateHolder, modifier: Modifier var isBottomSheetVisible by remember { mutableStateOf(value = false) } val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val snackbarHostState = remember(::SnackbarHostState) + Scaffold( modifier = modifier, topBar = { @@ -58,10 +60,26 @@ internal fun ReferralScreen(stateHolder: ReferralStateHolder, modifier: Modifier onBackClick = stateHolder.headerState.onBackClicked, ) }, + snackbarHost = { + SnackbarHost( + hostState = snackbarHostState, + modifier = Modifier + .padding(horizontal = TangemTheme.dimens.spacing16) + .padding(bottom = TangemTheme.dimens.spacing108), + ) { + // TODO: use StateEvent + if (stateHolder.errorSnackbar != null) { + TangemSnackbar(data = it, actionOnNewLine = true) + } else { + CopiedTextSnackbar(it) + } + } + }, containerColor = TangemTheme.colors.background.secondary, ) { ReferralContent( stateHolder = stateHolder, + snackbarHostState = snackbarHostState, onAgreementClick = { stateHolder.analytics.onAgreementClicked.invoke() isBottomSheetVisible = true @@ -70,6 +88,26 @@ internal fun ReferralScreen(stateHolder: ReferralStateHolder, modifier: Modifier ) } + val errorSnackbar = stateHolder.errorSnackbar + val coroutineScope = rememberCoroutineScope() + val resources = LocalContext.current.resources + + SideEffect { + if (errorSnackbar != null) { + coroutineScope.launch { + val result = snackbarHostState.showSnackbar( + message = resources.getMessageForErrorSnackbar(errorSnackbar.throwable), + actionLabel = resources.getString(R.string.warning_button_ok), + duration = SnackbarDuration.Indefinite, + ) + + if (result == SnackbarResult.ActionPerformed) { + errorSnackbar.onOkClicked() + } + } + } + } + ReferralBottomSheet( sheetState = sheetState, isVisible = isBottomSheetVisible, @@ -81,11 +119,10 @@ internal fun ReferralScreen(stateHolder: ReferralStateHolder, modifier: Modifier @Composable private fun ReferralContent( stateHolder: ReferralStateHolder, + snackbarHostState: SnackbarHostState, onAgreementClick: () -> Unit, modifier: Modifier = Modifier, ) { - val isCopyButtonPressed = remember { mutableStateOf(value = false) } - Box(modifier = modifier) { LazyColumn( modifier = Modifier.fillMaxSize(), @@ -95,14 +132,11 @@ private fun ReferralContent( item { ReferralInfo( stateHolder = stateHolder, + snackbarHostState = snackbarHostState, onAgreementClick = onAgreementClick, - onShowCopySnackbar = { isCopyButtonPressed.value = true }, ) } } - - ErrorSnackbarHost(errorSnackbar = stateHolder.errorSnackbar) - CopySnackbarHost(isCopyButtonPressed = isCopyButtonPressed) } } @@ -133,8 +167,8 @@ private fun Header() { @Composable private fun ReferralInfo( stateHolder: ReferralStateHolder, + snackbarHostState: SnackbarHostState, onAgreementClick: () -> Unit, - onShowCopySnackbar: () -> Unit, ) { when (val state = stateHolder.referralInfoState) { is ReferralInfoState.ParticipantContent -> { @@ -144,8 +178,8 @@ private fun ReferralInfo( code = state.code, shareLink = state.shareLink, expectedAwards = state.expectedAwards, + snackbarHostState = snackbarHostState, onAgreementClick = onAgreementClick, - onShowCopySnackbar = onShowCopySnackbar, onCopyClick = stateHolder.analytics.onCopyClicked, onShareClick = stateHolder.analytics.onShareClicked, ) @@ -335,115 +369,11 @@ private fun ShimmerInfo() { } } -// TODO() Replace component with component from ds -@Composable -private fun BoxScope.ErrorSnackbarHost(errorSnackbar: ErrorSnackbar?) { - if (errorSnackbar != null) { - val snackbarHostState by remember { mutableStateOf(SnackbarHostState()) } - val coroutineScope = rememberCoroutineScope() - - SnackbarHost( - hostState = snackbarHostState, - modifier = Modifier.align(Alignment.BottomCenter), - snackbar = { - Snackbar( - snackbarData = it, - modifier = Modifier.fillMaxWidth(), - actionOnNewLine = true, - shape = RoundedCornerShape(size = TangemTheme.dimens.radius8), - containerColor = TangemTheme.colors.button.primary, - contentColor = TangemTheme.colors.text.primary2, - actionColor = TangemTheme.colors.text.primary2, - ) - }, - ) - - val actionLabel = stringResource(id = R.string.warning_button_ok) - val message = getMessageForErrorSnackbar(errorSnackbar) - SideEffect { - coroutineScope.launch { - val result = snackbarHostState.showSnackbar( - message = message, - actionLabel = actionLabel, - duration = SnackbarDuration.Indefinite, - ) - if (result == SnackbarResult.ActionPerformed) { - errorSnackbar.onOkClicked() - } - } - } - } -} - -// TODO() Replace component with component from ds -@Composable -private fun BoxScope.CopySnackbarHost(isCopyButtonPressed: MutableState) { - if (isCopyButtonPressed.value) { - val snackbarHostState by remember { mutableStateOf(SnackbarHostState()) } - val coroutineScope = rememberCoroutineScope() - - var snackbarSize by remember { mutableIntStateOf(value = 0) } - val width = LocalConfiguration.current.screenWidthDp.dp - val snackbarWidth = with(LocalDensity.current) { snackbarSize.toDp() } - - SnackbarHost( - hostState = snackbarHostState, - modifier = Modifier - .align(Alignment.BottomCenter) - .padding(start = (width - snackbarWidth).div(2), bottom = TangemTheme.dimens.spacing12) - .fillMaxWidth(), - snackbar = { - Box( - modifier = Modifier - .onSizeChanged { snackbarSize = it.width } - .background( - color = TangemTheme.colors.icon.primary1, - shape = RoundedCornerShape(size = TangemTheme.dimens.radius8), - ) - .padding( - horizontal = TangemTheme.dimens.spacing16, - vertical = TangemTheme.dimens.spacing14, - ), - ) { - Text( - text = it.visuals.message, - color = TangemTheme.colors.text.primary2, - style = TangemTheme.typography.body2, - ) - } - }, - ) - - val message = stringResource(id = R.string.referral_promo_code_copied) - SideEffect { - coroutineScope.launch { - snackbarHostState.showSnackbar( - message = message, - duration = SnackbarDuration.Short, - ) - isCopyButtonPressed.value = false - } - } - } -} - -@Composable -private fun getMessageForErrorSnackbar(errorSnackbar: ErrorSnackbar): String { - return when (errorSnackbar.throwable) { - is DemoModeException -> { - stringResource(id = R.string.alert_demo_feature_disabled) - } - - else -> { - if (errorSnackbar.throwable.cause != null) { - String.format( - format = stringResource(id = R.string.referral_error_failed_to_load_info_with_reason), - errorSnackbar.throwable.cause, - ) - } else { - stringResource(id = R.string.referral_error_failed_to_load_info) - } - } +private fun Resources.getMessageForErrorSnackbar(throwable: Throwable): String { + return when { + throwable is DemoModeException -> getString(R.string.alert_demo_feature_disabled) + throwable.cause != null -> getString(R.string.referral_error_failed_to_load_info_with_reason, throwable.cause) + else -> getString(R.string.referral_error_failed_to_load_info) } }