Updated on 2026-08-14
This commit is contained in:
parent
70c989be4e
commit
9da26433fb
3 changed files with 74 additions and 140 deletions
|
|
@ -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
|
||||
)
|
||||
|
|
@ -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,
|
||||
),
|
||||
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Boolean>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue