diff --git a/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageUM.kt b/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageUM.kt index acaabc9b54..2e05ad0f27 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageUM.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/ds/message/TangemMessageUM.kt @@ -42,12 +42,14 @@ data class TangemMessageUM( * @param text TextReference for the button label. * @param type TangemButtonType defining the style type of the button. * @param iconRes Drawable resource ID for the icon to be displayed in the button (optional). + * @param isLoading Boolean indicating whether the button should show a loading state. * @param onClick Lambda to be invoked when the button is clicked. */ data class TangemMessageButtonUM( val text: TextReference, val type: TangemButtonType, @DrawableRes val iconRes: Int? = null, + val isLoading: Boolean = false, val onClick: () -> Unit, ) { /** Creates a TangemButtonUM representation of this message button. */ @@ -58,6 +60,7 @@ data class TangemMessageButtonUM( iconRes = iconRes, iconPosition = TangemButtonIconPosition.End, type = type, + isLoading = isLoading, onClick = onClick, ) } \ No newline at end of file diff --git a/features/tangempay/main/impl/src/main/kotlin/com/tangem/features/tangempay/component/DefaultTangemPayMainBlockComponent.kt b/features/tangempay/main/impl/src/main/kotlin/com/tangem/features/tangempay/component/DefaultTangemPayMainBlockComponent.kt index 716d22e5f7..e2b4e2f930 100644 --- a/features/tangempay/main/impl/src/main/kotlin/com/tangem/features/tangempay/component/DefaultTangemPayMainBlockComponent.kt +++ b/features/tangempay/main/impl/src/main/kotlin/com/tangem/features/tangempay/component/DefaultTangemPayMainBlockComponent.kt @@ -3,7 +3,9 @@ package com.tangem.features.tangempay.component import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.ui.Modifier import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.ui.res.LocalRedesignEnabled import com.tangem.features.tangempay.entity.TangemPayMainUM +import com.tangem.features.tangempay.ui.TangemPayMainBlockContent import com.tangem.features.tangempay.ui.TangemPayMainBlockItem import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -26,7 +28,11 @@ internal class DefaultTangemPayMainBlockComponent @AssistedInject constructor( key = TANGEM_PAY_ACCOUNT_CONTENT_TYPE, contentType = TANGEM_PAY_ACCOUNT_CONTENT_TYPE, ) { - TangemPayMainBlockItem(state, isBalanceHidden, modifier) + if (LocalRedesignEnabled.current) { + TangemPayMainBlockContent(state, isBalanceHidden, modifier) + } else { + TangemPayMainBlockItem(state, isBalanceHidden, modifier) + } } } diff --git a/features/tangempay/main/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayMainBlockContent.kt b/features/tangempay/main/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayMainBlockContent.kt index e95dcc262b..54da2fa3ec 100644 --- a/features/tangempay/main/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayMainBlockContent.kt +++ b/features/tangempay/main/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayMainBlockContent.kt @@ -2,123 +2,199 @@ package com.tangem.features.tangempay.ui import android.content.res.Configuration import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon -import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.layoutId import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import androidx.compose.ui.unit.dp import com.tangem.core.ui.components.CircleShimmer -import com.tangem.core.ui.components.RectangleShimmer -import com.tangem.core.ui.components.SpacerWMax -import com.tangem.core.ui.components.block.BlockCard -import com.tangem.core.ui.components.inputrow.InputRowImageBase +import com.tangem.core.ui.components.TextShimmer import com.tangem.core.ui.components.text.applyBladeBrush +import com.tangem.core.ui.ds.row.TangemRowContainer +import com.tangem.core.ui.ds.row.TangemRowLayoutId import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.core.ui.res.TangemThemePreviewRedesign import com.tangem.features.tangempay.entity.TangemPayMainUM import com.tangem.features.tangempay.main.impl.R import com.tangem.utils.StringsSigns.DASH_SIGN -private const val DISABLED_ALPHA = 0.6F +private const val DISABLED_ALPHA = 0.5F @Composable -internal fun TangemPayMainBlockItem(state: TangemPayMainUM, isBalanceHidden: Boolean, modifier: Modifier = Modifier) { +internal fun TangemPayMainBlockContent( + state: TangemPayMainUM, + isBalanceHidden: Boolean, + modifier: Modifier = Modifier, +) { when (state) { is TangemPayMainUM.Empty -> Unit - is TangemPayMainUM.Loading -> TangemPayMainLoadingItem(modifier) - is TangemPayMainUM.UnderReview -> TangemPayMainUnderReviewItem(state, modifier) - is TangemPayMainUM.IssuingCard -> TangemPayMainIssuingCardItem(state, modifier) - is TangemPayMainUM.FailedToIssue -> TangemPayMainFailedIssueItem(state, modifier) - is TangemPayMainUM.Content -> TangemPayMainBlockContent(state, isBalanceHidden, modifier) - is TangemPayMainUM.TemporaryUnavailable -> TangemPayMainTempUnavailableItem(modifier) - is TangemPayMainUM.SyncNeeded -> TangemPayMainSyncNeededItem(modifier) - is TangemPayMainUM.ExposedDevice -> TangemPayMainExposedDeviceItem(modifier) + is TangemPayMainUM.Loading -> TangemPayMainLoading(modifier) + is TangemPayMainUM.UnderReview -> TangemPayStateRow( + subtitle = state.subtitle, + modifier = modifier, + onClick = state.onClick, + ) + is TangemPayMainUM.IssuingCard -> TangemPayStateRow( + subtitle = resourceReference(R.string.tangempay_issuing_your_card), + modifier = modifier, + onClick = state.onClick, + ) + is TangemPayMainUM.FailedToIssue -> TangemPayStateRow( + subtitle = resourceReference(R.string.tangempay_failed_to_issue_card), + modifier = modifier, + showError = true, + onClick = state.onClick, + ) + is TangemPayMainUM.Content -> TangemPayMainContent(state, isBalanceHidden, modifier) + is TangemPayMainUM.TemporaryUnavailable -> TangemPayStateRow( + subtitle = stringReference(DASH_SIGN), + modifier = modifier, + isEnabled = false, + ) + is TangemPayMainUM.SyncNeeded -> TangemPayStateRow( + subtitle = resourceReference(R.string.tangempay_payment_account_sync_needed), + modifier = modifier, + isEnabled = false, + ) + is TangemPayMainUM.ExposedDevice -> TangemPayStateRow( + subtitle = resourceReference(R.string.tangem_pay_rooted_device_subtitle), + modifier = modifier, + ) } } @Composable -private fun TangemPayMainBlockContent( - state: TangemPayMainUM.Content, +private fun TangemPayMainContent( + payMainUM: TangemPayMainUM.Content, isBalanceHidden: Boolean, modifier: Modifier = Modifier, ) { - Surface( - modifier = modifier, - shape = TangemTheme.shapes.roundedCornersXMedium, - color = TangemTheme.colors.background.primary, - onClick = state.onClick, + TangemRowContainer( + modifier = modifier + .clip(RoundedCornerShape(size = 18.dp)) + .background(TangemTheme.colors2.surface.level3) + .clickableSingle(onClick = payMainUM.onClick), ) { - Row( + Image( + painter = painterResource(R.drawable.img_visa_36), + contentDescription = null, modifier = Modifier - .fillMaxWidth() - .height(IntrinsicSize.Min) - .padding(horizontal = 12.dp, vertical = 16.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp), - ) { - Image( - painter = painterResource(R.drawable.img_visa_36), - contentDescription = null, - modifier = Modifier.size(36.dp), - ) + .layoutId(TangemRowLayoutId.HEAD) + .size(TangemTheme.dimens2.x10) + .padding(end = TangemTheme.dimens2.x2), + ) + Text( + text = stringResourceSafe(R.string.tangempay_payment_account), + color = TangemTheme.colors2.text.neutral.primary, + style = TangemTheme.typography2.bodySemibold16, + modifier = Modifier.layoutId(TangemRowLayoutId.START_TOP), + ) + Text( + text = payMainUM.subtitle.resolveReference(), + color = TangemTheme.colors2.text.neutral.secondary, + style = TangemTheme.typography2.captionSemibold12, + modifier = Modifier.layoutId(TangemRowLayoutId.START_BOTTOM), + ) + TangemPayFiatAmount( + text = payMainUM.balance.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(), + isBalanceFlickering = payMainUM.isBalanceFlickering, + isBalanceFromCache = payMainUM.shouldShowOnlyCacheWarning, + modifier = Modifier.layoutId(TangemRowLayoutId.END_TOP), + ) + Text( + text = payMainUM.balanceSubtitle.resolveReference(), + color = TangemTheme.colors2.text.neutral.secondary, + style = TangemTheme.typography2.captionSemibold12, + modifier = Modifier.layoutId(TangemRowLayoutId.END_BOTTOM), + ) + } +} - Column( - modifier = Modifier.weight(1f), - verticalArrangement = Arrangement.spacedBy(2.dp), - ) { - Text( - text = stringResourceSafe(R.string.tangempay_payment_account), - style = TangemTheme.typography.subtitle2, - color = TangemTheme.colors.text.primary1, - ) - Text( - text = state.subtitle.resolveReference(), - style = TangemTheme.typography.caption2, - color = TangemTheme.colors.text.tertiary, - ) - } - Column( - modifier = Modifier.fillMaxHeight(), - verticalArrangement = Arrangement.spacedBy(2.dp), - horizontalAlignment = Alignment.End, - ) { - TangemPayFiatAmount( - text = state.balance.resolveReference(), - isBalanceFlickering = state.isBalanceFlickering, - isBalanceFromCache = state.shouldShowOnlyCacheWarning, - isBalanceHidden = isBalanceHidden, - ) - Text( - text = state.balanceSubtitle.resolveReference(), - style = TangemTheme.typography.caption2, - color = TangemTheme.colors.text.tertiary, - textAlign = TextAlign.End, - ) - } +@Composable +private fun TangemPayStateRow( + subtitle: TextReference, + modifier: Modifier = Modifier, + onClick: (() -> Unit)? = null, + showError: Boolean = false, + isEnabled: Boolean = true, +) { + TangemRowContainer( + modifier = modifier + .clip(RoundedCornerShape(size = 18.dp)) + .background(TangemTheme.colors2.surface.level3) + .conditional(onClick != null && isEnabled) { clickableSingle(onClick = requireNotNull(onClick)) }, + ) { + Image( + painter = painterResource(R.drawable.img_visa_36), + contentDescription = null, + modifier = Modifier + .layoutId(TangemRowLayoutId.HEAD) + .size(TangemTheme.dimens2.x10) + .padding(end = TangemTheme.dimens2.x2) + .conditionalCompose(!isEnabled) { + alpha(DISABLED_ALPHA) + }, + ) + Text( + text = stringResourceSafe(R.string.tangempay_payment_account), + color = if (isEnabled) { + TangemTheme.colors2.text.neutral.primary + } else { + TangemTheme.colors2.text.status.disabled + }, + style = TangemTheme.typography2.bodySemibold16, + modifier = Modifier.layoutId(TangemRowLayoutId.START_TOP), + ) + Text( + text = subtitle.resolveReference(), + color = if (isEnabled) { + TangemTheme.colors2.text.neutral.secondary + } else { + TangemTheme.colors2.text.status.disabled + }, + style = TangemTheme.typography2.captionSemibold12, + modifier = Modifier.layoutId(TangemRowLayoutId.START_BOTTOM), + ) + AnimatedVisibility( + visible = showError, + enter = fadeIn(), + exit = fadeOut(), + label = "Error Icon Animation", + modifier = Modifier + .layoutId(TangemRowLayoutId.TAIL) + .size(TangemTheme.dimens2.x4), + ) { + Icon( + painter = painterResource(R.drawable.ic_alert_24), + tint = TangemTheme.colors2.graphic.status.warning, + contentDescription = null, + ) } } } @Composable private fun TangemPayFiatAmount( - text: String, + text: AnnotatedString, isBalanceFlickering: Boolean, isBalanceFromCache: Boolean, - isBalanceHidden: Boolean, modifier: Modifier = Modifier, ) { Row( @@ -134,17 +210,17 @@ private fun TangemPayFiatAmount( Icon( modifier = Modifier.size(12.dp), painter = painterResource(R.drawable.ic_error_sync_24), - tint = TangemTheme.colors.icon.inactive, + tint = TangemTheme.colors2.graphic.neutral.secondary, contentDescription = null, ) } } Text( - text = text.orMaskWithStars(isBalanceHidden), - style = TangemTheme.typography.body2.applyBladeBrush( + text = text, + style = TangemTheme.typography2.bodySemibold16.applyBladeBrush( isEnabled = isBalanceFlickering, - textColor = TangemTheme.colors.text.primary1, + textColor = TangemTheme.colors2.text.neutral.primary, ), textAlign = TextAlign.End, ) @@ -152,189 +228,63 @@ private fun TangemPayFiatAmount( } @Composable -private fun TangemPayMainUnderReviewItem(state: TangemPayMainUM.UnderReview, modifier: Modifier = Modifier) { - BlockCard( +private fun TangemPayMainLoading(modifier: Modifier = Modifier) { + TangemRowContainer( modifier = modifier - .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) - .background(TangemTheme.colors.background.primary), - onClick = state.onClick, + .clip(RoundedCornerShape(size = 18.dp)) + .background(TangemTheme.colors2.surface.level3), ) { - InputRowImageBase( + CircleShimmer( modifier = Modifier - .padding( - all = TangemTheme.dimens.spacing12, - ), - subtitle = resourceReference(R.string.tangempay_payment_account), - caption = state.subtitle, - subtitleColor = TangemTheme.colors.text.primary1, - captionColor = TangemTheme.colors.text.tertiary, - iconResWebp = R.drawable.img_visa_36, + .layoutId(TangemRowLayoutId.HEAD) + .padding(end = TangemTheme.dimens2.x2) + .size(TangemTheme.dimens2.x10), ) - } -} - -@Composable -private fun TangemPayMainTempUnavailableItem(modifier: Modifier = Modifier) { - BlockCard( - modifier = modifier - .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) - .background(TangemTheme.colors.background.primary), - enabled = false, - ) { - InputRowImageBase( - modifier = Modifier.padding(all = TangemTheme.dimens.spacing12), - subtitle = resourceReference(R.string.tangempay_payment_account), - caption = TextReference.Str(DASH_SIGN), - subtitleColor = TangemTheme.colors.text.tertiary, - captionColor = TangemTheme.colors.text.tertiary, - iconResWebp = R.drawable.img_visa_36, - ) - } -} - -@Composable -private fun TangemPayMainIssuingCardItem(state: TangemPayMainUM.IssuingCard, modifier: Modifier = Modifier) { - BlockCard( - modifier = modifier - .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) - .background(TangemTheme.colors.background.primary), - onClick = state.onClick, - ) { - InputRowImageBase( + TextShimmer( + style = TangemTheme.typography2.bodySemibold16, + radius = TangemTheme.dimens2.x25, modifier = Modifier - .padding(all = TangemTheme.dimens.spacing12), - subtitle = resourceReference(R.string.tangempay_payment_account), - caption = resourceReference(R.string.tangempay_issuing_your_card), - subtitleColor = TangemTheme.colors.text.primary1, - captionColor = TangemTheme.colors.text.tertiary, - iconResWebp = R.drawable.img_visa_36, + .layoutId(TangemRowLayoutId.START_TOP) + .width(TangemTheme.dimens2.x25), ) - } -} - -@Composable -private fun TangemPayMainFailedIssueItem(state: TangemPayMainUM.FailedToIssue, modifier: Modifier = Modifier) { - BlockCard( - modifier = modifier - .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) - .background(TangemTheme.colors.background.primary), - onClick = state.onClick, - ) { - InputRowImageBase( + TextShimmer( + style = TangemTheme.typography2.captionSemibold12, + radius = TangemTheme.dimens2.x25, modifier = Modifier - .padding( - all = TangemTheme.dimens.spacing12, - ), - subtitle = TextReference.Res(R.string.tangempay_payment_account), - caption = TextReference.Res(R.string.tangempay_failed_to_issue_card), - subtitleColor = TangemTheme.colors.text.primary1, - captionColor = TangemTheme.colors.text.tertiary, - iconResWebp = com.tangem.core.ui.R.drawable.img_visa_36, - iconEndRes = R.drawable.ic_alert_24, - endIconTint = TangemTheme.colors.icon.warning, + .layoutId(TangemRowLayoutId.START_BOTTOM) + .width(TangemTheme.dimens2.x11), ) - } -} - -@Composable -private fun TangemPayMainSyncNeededItem(modifier: Modifier = Modifier) { - BlockCard( - modifier = modifier - .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) - .background(TangemTheme.colors.background.primary), - enabled = false, - ) { - InputRowImageBase( - modifier = Modifier.padding( - all = TangemTheme.dimens.spacing12, - ), - subtitle = resourceReference(R.string.tangempay_payment_account), - caption = resourceReference(R.string.tangempay_payment_account_sync_needed), - subtitleColor = TangemTheme.colors.text.tertiary, - captionColor = TangemTheme.colors.text.tertiary, - iconResWebp = R.drawable.img_visa_36, - ) - } -} - -@Composable -private fun TangemPayMainExposedDeviceItem(modifier: Modifier = Modifier) { - BlockCard( - modifier = modifier - .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) - .background(TangemTheme.colors.background.primary) - .alpha(DISABLED_ALPHA), - enabled = false, - ) { - InputRowImageBase( + TextShimmer( + style = TangemTheme.typography2.bodyRegular16, + radius = TangemTheme.dimens2.x25, modifier = Modifier - .padding( - all = TangemTheme.dimens.spacing12, - ), - subtitle = resourceReference(R.string.tangempay_payment_account), - caption = resourceReference(R.string.tangem_pay_rooted_device_subtitle), - subtitleColor = TangemTheme.colors.text.primary1, - captionColor = TangemTheme.colors.text.tertiary, - iconResWebp = R.drawable.img_visa_36, - endIconTint = TangemTheme.colors.icon.warning, + .layoutId(TangemRowLayoutId.END_TOP) + .width(TangemTheme.dimens2.x20), + ) + TextShimmer( + style = TangemTheme.typography2.bodyRegular16, + radius = TangemTheme.dimens2.x25, + modifier = Modifier + .layoutId(TangemRowLayoutId.END_BOTTOM) + .width(TangemTheme.dimens2.x11), ) } } +// region Preview +@Preview(showBackground = true, widthDp = 360) +@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable -private fun TangemPayMainLoadingItem(modifier: Modifier = Modifier) { - Row( - modifier = modifier - .fillMaxWidth() - .background(color = TangemTheme.colors.background.primary, shape = TangemTheme.shapes.roundedCornersXMedium) - .padding(horizontal = 12.dp, vertical = 16.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - CircleShimmer(modifier = Modifier.size(36.dp)) - Column( - modifier = Modifier.padding(start = 12.dp), - verticalArrangement = Arrangement.spacedBy(2.dp), - ) { - RectangleShimmer( - modifier = Modifier - .padding(vertical = 4.dp) - .sizeIn(minWidth = 70.dp, minHeight = 12.dp), - ) - RectangleShimmer( - modifier = Modifier - .padding(vertical = 2.dp) - .sizeIn(minWidth = 52.dp, minHeight = 12.dp), - ) - } - SpacerWMax() - Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { - RectangleShimmer( - modifier = Modifier - .padding(vertical = 4.dp) - .sizeIn(minWidth = 40.dp, minHeight = 12.dp), - ) - RectangleShimmer( - modifier = Modifier - .padding(vertical = 2.dp) - .sizeIn(minWidth = 40.dp, minHeight = 12.dp), - ) - } - } -} - -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -@Preview -@Composable -private fun TangemPayMainItemsPreview( - @PreviewParameter(TangemPayMainUMPreviewParameterProvider::class) +private fun TangemPayMainBlockContent_Preview( + @PreviewParameter(TangemPayMainBlockContentPreviewParameterProvider::class) state: TangemPayMainUM, ) { - TangemThemePreview { - TangemPayMainBlockItem(state = state, isBalanceHidden = false) + TangemThemePreviewRedesign { + TangemPayMainBlockContent(state = state, isBalanceHidden = false) } } -private class TangemPayMainUMPreviewParameterProvider : CollectionPreviewParameterProvider( +private class TangemPayMainBlockContentPreviewParameterProvider : CollectionPreviewParameterProvider( collection = listOf( TangemPayMainUM.Loading, TangemPayMainUM.SyncNeeded, @@ -352,4 +302,5 @@ private class TangemPayMainUMPreviewParameterProvider : CollectionPreviewParamet shouldShowOnlyCacheWarning = true, ), ), -) \ No newline at end of file +) +// endregion \ No newline at end of file diff --git a/features/tangempay/main/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayMainBlockContentLegacy.kt b/features/tangempay/main/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayMainBlockContentLegacy.kt new file mode 100644 index 0000000000..e95dcc262b --- /dev/null +++ b/features/tangempay/main/impl/src/main/kotlin/com/tangem/features/tangempay/ui/TangemPayMainBlockContentLegacy.kt @@ -0,0 +1,355 @@ +package com.tangem.features.tangempay.ui + +import android.content.res.Configuration +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.components.CircleShimmer +import com.tangem.core.ui.components.RectangleShimmer +import com.tangem.core.ui.components.SpacerWMax +import com.tangem.core.ui.components.block.BlockCard +import com.tangem.core.ui.components.inputrow.InputRowImageBase +import com.tangem.core.ui.components.text.applyBladeBrush +import com.tangem.core.ui.extensions.* +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.features.tangempay.entity.TangemPayMainUM +import com.tangem.features.tangempay.main.impl.R +import com.tangem.utils.StringsSigns.DASH_SIGN + +private const val DISABLED_ALPHA = 0.6F + +@Composable +internal fun TangemPayMainBlockItem(state: TangemPayMainUM, isBalanceHidden: Boolean, modifier: Modifier = Modifier) { + when (state) { + is TangemPayMainUM.Empty -> Unit + is TangemPayMainUM.Loading -> TangemPayMainLoadingItem(modifier) + is TangemPayMainUM.UnderReview -> TangemPayMainUnderReviewItem(state, modifier) + is TangemPayMainUM.IssuingCard -> TangemPayMainIssuingCardItem(state, modifier) + is TangemPayMainUM.FailedToIssue -> TangemPayMainFailedIssueItem(state, modifier) + is TangemPayMainUM.Content -> TangemPayMainBlockContent(state, isBalanceHidden, modifier) + is TangemPayMainUM.TemporaryUnavailable -> TangemPayMainTempUnavailableItem(modifier) + is TangemPayMainUM.SyncNeeded -> TangemPayMainSyncNeededItem(modifier) + is TangemPayMainUM.ExposedDevice -> TangemPayMainExposedDeviceItem(modifier) + } +} + +@Composable +private fun TangemPayMainBlockContent( + state: TangemPayMainUM.Content, + isBalanceHidden: Boolean, + modifier: Modifier = Modifier, +) { + Surface( + modifier = modifier, + shape = TangemTheme.shapes.roundedCornersXMedium, + color = TangemTheme.colors.background.primary, + onClick = state.onClick, + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .height(IntrinsicSize.Min) + .padding(horizontal = 12.dp, vertical = 16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + Image( + painter = painterResource(R.drawable.img_visa_36), + contentDescription = null, + modifier = Modifier.size(36.dp), + ) + + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(2.dp), + ) { + Text( + text = stringResourceSafe(R.string.tangempay_payment_account), + style = TangemTheme.typography.subtitle2, + color = TangemTheme.colors.text.primary1, + ) + Text( + text = state.subtitle.resolveReference(), + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + ) + } + Column( + modifier = Modifier.fillMaxHeight(), + verticalArrangement = Arrangement.spacedBy(2.dp), + horizontalAlignment = Alignment.End, + ) { + TangemPayFiatAmount( + text = state.balance.resolveReference(), + isBalanceFlickering = state.isBalanceFlickering, + isBalanceFromCache = state.shouldShowOnlyCacheWarning, + isBalanceHidden = isBalanceHidden, + ) + Text( + text = state.balanceSubtitle.resolveReference(), + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.tertiary, + textAlign = TextAlign.End, + ) + } + } + } +} + +@Composable +private fun TangemPayFiatAmount( + text: String, + isBalanceFlickering: Boolean, + isBalanceFromCache: Boolean, + isBalanceHidden: Boolean, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically, + ) { + AnimatedVisibility(isBalanceFromCache) { + Row( + modifier = Modifier.padding(horizontal = 4.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp), + ) { + Icon( + modifier = Modifier.size(12.dp), + painter = painterResource(R.drawable.ic_error_sync_24), + tint = TangemTheme.colors.icon.inactive, + contentDescription = null, + ) + } + } + + Text( + text = text.orMaskWithStars(isBalanceHidden), + style = TangemTheme.typography.body2.applyBladeBrush( + isEnabled = isBalanceFlickering, + textColor = TangemTheme.colors.text.primary1, + ), + textAlign = TextAlign.End, + ) + } +} + +@Composable +private fun TangemPayMainUnderReviewItem(state: TangemPayMainUM.UnderReview, modifier: Modifier = Modifier) { + BlockCard( + modifier = modifier + .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) + .background(TangemTheme.colors.background.primary), + onClick = state.onClick, + ) { + InputRowImageBase( + modifier = Modifier + .padding( + all = TangemTheme.dimens.spacing12, + ), + subtitle = resourceReference(R.string.tangempay_payment_account), + caption = state.subtitle, + subtitleColor = TangemTheme.colors.text.primary1, + captionColor = TangemTheme.colors.text.tertiary, + iconResWebp = R.drawable.img_visa_36, + ) + } +} + +@Composable +private fun TangemPayMainTempUnavailableItem(modifier: Modifier = Modifier) { + BlockCard( + modifier = modifier + .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) + .background(TangemTheme.colors.background.primary), + enabled = false, + ) { + InputRowImageBase( + modifier = Modifier.padding(all = TangemTheme.dimens.spacing12), + subtitle = resourceReference(R.string.tangempay_payment_account), + caption = TextReference.Str(DASH_SIGN), + subtitleColor = TangemTheme.colors.text.tertiary, + captionColor = TangemTheme.colors.text.tertiary, + iconResWebp = R.drawable.img_visa_36, + ) + } +} + +@Composable +private fun TangemPayMainIssuingCardItem(state: TangemPayMainUM.IssuingCard, modifier: Modifier = Modifier) { + BlockCard( + modifier = modifier + .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) + .background(TangemTheme.colors.background.primary), + onClick = state.onClick, + ) { + InputRowImageBase( + modifier = Modifier + .padding(all = TangemTheme.dimens.spacing12), + subtitle = resourceReference(R.string.tangempay_payment_account), + caption = resourceReference(R.string.tangempay_issuing_your_card), + subtitleColor = TangemTheme.colors.text.primary1, + captionColor = TangemTheme.colors.text.tertiary, + iconResWebp = R.drawable.img_visa_36, + ) + } +} + +@Composable +private fun TangemPayMainFailedIssueItem(state: TangemPayMainUM.FailedToIssue, modifier: Modifier = Modifier) { + BlockCard( + modifier = modifier + .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) + .background(TangemTheme.colors.background.primary), + onClick = state.onClick, + ) { + InputRowImageBase( + modifier = Modifier + .padding( + all = TangemTheme.dimens.spacing12, + ), + subtitle = TextReference.Res(R.string.tangempay_payment_account), + caption = TextReference.Res(R.string.tangempay_failed_to_issue_card), + subtitleColor = TangemTheme.colors.text.primary1, + captionColor = TangemTheme.colors.text.tertiary, + iconResWebp = com.tangem.core.ui.R.drawable.img_visa_36, + iconEndRes = R.drawable.ic_alert_24, + endIconTint = TangemTheme.colors.icon.warning, + ) + } +} + +@Composable +private fun TangemPayMainSyncNeededItem(modifier: Modifier = Modifier) { + BlockCard( + modifier = modifier + .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) + .background(TangemTheme.colors.background.primary), + enabled = false, + ) { + InputRowImageBase( + modifier = Modifier.padding( + all = TangemTheme.dimens.spacing12, + ), + subtitle = resourceReference(R.string.tangempay_payment_account), + caption = resourceReference(R.string.tangempay_payment_account_sync_needed), + subtitleColor = TangemTheme.colors.text.tertiary, + captionColor = TangemTheme.colors.text.tertiary, + iconResWebp = R.drawable.img_visa_36, + ) + } +} + +@Composable +private fun TangemPayMainExposedDeviceItem(modifier: Modifier = Modifier) { + BlockCard( + modifier = modifier + .clip(RoundedCornerShape(size = TangemTheme.dimens.radius14)) + .background(TangemTheme.colors.background.primary) + .alpha(DISABLED_ALPHA), + enabled = false, + ) { + InputRowImageBase( + modifier = Modifier + .padding( + all = TangemTheme.dimens.spacing12, + ), + subtitle = resourceReference(R.string.tangempay_payment_account), + caption = resourceReference(R.string.tangem_pay_rooted_device_subtitle), + subtitleColor = TangemTheme.colors.text.primary1, + captionColor = TangemTheme.colors.text.tertiary, + iconResWebp = R.drawable.img_visa_36, + endIconTint = TangemTheme.colors.icon.warning, + ) + } +} + +@Composable +private fun TangemPayMainLoadingItem(modifier: Modifier = Modifier) { + Row( + modifier = modifier + .fillMaxWidth() + .background(color = TangemTheme.colors.background.primary, shape = TangemTheme.shapes.roundedCornersXMedium) + .padding(horizontal = 12.dp, vertical = 16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + CircleShimmer(modifier = Modifier.size(36.dp)) + Column( + modifier = Modifier.padding(start = 12.dp), + verticalArrangement = Arrangement.spacedBy(2.dp), + ) { + RectangleShimmer( + modifier = Modifier + .padding(vertical = 4.dp) + .sizeIn(minWidth = 70.dp, minHeight = 12.dp), + ) + RectangleShimmer( + modifier = Modifier + .padding(vertical = 2.dp) + .sizeIn(minWidth = 52.dp, minHeight = 12.dp), + ) + } + SpacerWMax() + Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { + RectangleShimmer( + modifier = Modifier + .padding(vertical = 4.dp) + .sizeIn(minWidth = 40.dp, minHeight = 12.dp), + ) + RectangleShimmer( + modifier = Modifier + .padding(vertical = 2.dp) + .sizeIn(minWidth = 40.dp, minHeight = 12.dp), + ) + } + } +} + +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview +@Composable +private fun TangemPayMainItemsPreview( + @PreviewParameter(TangemPayMainUMPreviewParameterProvider::class) + state: TangemPayMainUM, +) { + TangemThemePreview { + TangemPayMainBlockItem(state = state, isBalanceHidden = false) + } +} + +private class TangemPayMainUMPreviewParameterProvider : CollectionPreviewParameterProvider( + collection = listOf( + TangemPayMainUM.Loading, + TangemPayMainUM.SyncNeeded, + TangemPayMainUM.TemporaryUnavailable, + TangemPayMainUM.ExposedDevice, + TangemPayMainUM.FailedToIssue(onClick = {}), + TangemPayMainUM.UnderReview(subtitle = resourceReference(R.string.tangempay_kyc_in_progress), onClick = {}), + TangemPayMainUM.IssuingCard(onClick = {}), + TangemPayMainUM.Content( + subtitle = TextReference.Str("*1234"), + isBalanceFlickering = true, + balance = TextReference.Str("$ 101.56"), + balanceSubtitle = TextReference.Str("USDC"), + onClick = {}, + shouldShowOnlyCacheWarning = true, + ), + ), +) \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt index 22f857a5f1..a40b3e413a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt @@ -16,12 +16,11 @@ import com.tangem.core.decompose.context.child import com.tangem.core.decompose.context.childByContext import com.tangem.core.decompose.model.getOrCreateModel import com.tangem.core.ui.DesignFeatureToggles -import com.tangem.features.promobanners.api.NewPromoBannersFeatureToggles -import com.tangem.features.promobanners.api.PromoBannersBlockComponent import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.decompose.ComposableDialogComponent +import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.domain.tokens.model.details.TokenAction import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent import com.tangem.feature.wallet.child.tokenActions.TokenActionsComponent @@ -32,13 +31,14 @@ import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen2 import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.KycRejectedComponent import com.tangem.feature.walletsettings.component.RenameWalletComponent -import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.features.biometry.AskBiometryComponent import com.tangem.features.feed.entry.components.FeedEntryComponent +import com.tangem.features.promobanners.api.NewPromoBannersFeatureToggles +import com.tangem.features.promobanners.api.PromoBannersBlockComponent import com.tangem.features.pushnotifications.api.PushNotificationsBottomSheetComponent import com.tangem.features.pushnotifications.api.PushNotificationsParams -import com.tangem.features.tangempay.component.TangemPayMainBlockComponent import com.tangem.features.send.v2.api.NetworkSelectionComponent +import com.tangem.features.tangempay.component.TangemPayMainBlockComponent import com.tangem.features.tokenreceive.TokenReceiveComponent import com.tangem.features.yield.supply.api.YieldSupplyDepositedWarningComponent import dagger.assisted.Assisted @@ -231,6 +231,7 @@ internal class WalletComponent @AssistedInject constructor( if (designFeatureToggles.isRedesignEnabled) { WalletScreen2( state = uiState, + tangemPayComponent = tangemPayMainBlockComponent, bottomSheetContent = { BottomSheetContent( bottomSheetState = bottomSheetState, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt index 16187090af..44b3aa8329 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt @@ -17,6 +17,7 @@ import com.tangem.feature.wallet.presentation.common.WalletPreviewDataLegacy.top import com.tangem.feature.wallet.presentation.preview.WalletBalancePreview import com.tangem.feature.wallet.presentation.preview.WalletPreviewData import com.tangem.feature.wallet.presentation.wallet.state.model.* +import com.tangem.features.tangempay.entity.TangemPayMainUM import kotlinx.collections.immutable.persistentListOf internal object WalletScreenPreviewData { @@ -167,7 +168,7 @@ internal object WalletScreenPreviewData { isFlickering = false, onItemClick = {}, ), - tangemPayState = TangemPayState.Loading, + tangemPayMainUM = TangemPayMainUM.Loading, ) private val walletEmpty = WalletUM.Content( @@ -182,7 +183,7 @@ internal object WalletScreenPreviewData { notificationsCarousel = persistentListOf(), tokensListUM = WalletTokensListUM.Empty(onEmptyClick = {}), nftState = WalletNFTItemUM.Hidden, - tangemPayState = TangemPayState.Empty, + tangemPayMainUM = TangemPayMainUM.Empty, ) private val walletAccountDefault = walletDefault.copy( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt index 32b3a72da1..96f7c46639 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/WalletWarningsAnalyticsSender.kt @@ -168,6 +168,8 @@ internal class WalletWarningsAnalyticsSender @Inject constructor( WalletNotificationUM.SomeNetworksUnreachable, is WalletNotificationUM.UsedOutdatedData, is WalletNotificationUM.CloreMigration, + is WalletNotificationUM.TangemPayRefreshNeeded, + WalletNotificationUM.TangemPayUnreachable, -> null } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsFactory.kt index 51f3323547..8ce6b1a9c0 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/GetWalletNotificationsFactory.kt @@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.domain import com.tangem.common.ui.userwallet.ext.walletInterationIcon import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.ui.ds.message.TangemMessageEffect +import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer import com.tangem.domain.card.CardTypesResolver import com.tangem.domain.card.common.util.cardTypesResolver @@ -10,12 +11,15 @@ import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.hotwallet.GetAccessCodeSkippedUseCase import com.tangem.domain.models.StatusSource import com.tangem.domain.models.TotalFiatBalance +import com.tangem.domain.models.account.AccountStatus +import com.tangem.domain.models.account.PaymentAccountStatusValue import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.isMultiCurrency import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents +import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.account.AccountDependencies import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotificationUM import com.tangem.hot.sdk.model.HotWalletId @@ -56,6 +60,10 @@ internal class GetWalletNotificationsFactory @Inject constructor( val totalFiatBalance = accountList.totalFiatBalance val flattenCurrencies = accountList.flattenCurrencies() + val paymentAccountStatus = accountList.accountStatuses + .filterIsInstance() + .firstOrNull() + buildList { addUsedOutdatedDataNotification(totalFiatBalance) @@ -82,6 +90,14 @@ internal class GetWalletNotificationsFactory @Inject constructor( isNeedToBackup = isNeedToBackup, clickIntents = clickIntents, ) + + if (paymentAccountStatus != null) { + addTangemPayWarnings( + status = paymentAccountStatus, + userWallet = userWallet, + walletClickIntents = clickIntents, + ) + } }.sortedBy { it.type.ordinal }.toImmutableList() } } @@ -200,6 +216,34 @@ internal class GetWalletNotificationsFactory @Inject constructor( ) } + private fun MutableList.addTangemPayWarnings( + status: AccountStatus.Payment, + userWallet: UserWallet, + walletClickIntents: WalletClickIntents, + ) { + val notification = when (status.value) { + is PaymentAccountStatusValue.Error.NotSynced -> WalletNotificationUM.TangemPayRefreshNeeded( + buttonText = when (userWallet) { + is UserWallet.Cold -> resourceReference(id = R.string.home_button_scan) + is UserWallet.Hot -> resourceReference(id = R.string.tangempay_sync_needed_restore_access) + }, + onRefreshClick = { walletClickIntents.onRefreshPayToken(userWallet) }, + shouldShowProgress = false, + ) + is PaymentAccountStatusValue.NotCreated -> null // TODO(Main redesign) + is PaymentAccountStatusValue.Error.Unavailable -> WalletNotificationUM.TangemPayUnreachable + is PaymentAccountStatusValue.Error.CardIssueFailed, + is PaymentAccountStatusValue.Error.ExposedDevice, + is PaymentAccountStatusValue.IssuingCard, + is PaymentAccountStatusValue.Loaded, + is PaymentAccountStatusValue.Loading, + is PaymentAccountStatusValue.Locked, + is PaymentAccountStatusValue.UnderReview, + -> null + } + notification?.let(::add) + } + private fun MutableList.addNoAccountWarning(cryptoCurrencyStatus: CryptoCurrencyStatus?) { val noAccountStatus = cryptoCurrencyStatus?.value as? CryptoCurrencyStatus.NoAccount if (noAccountStatus != null) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt index f3644ec928..fdefd1e7bf 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletNotificationUM.kt @@ -7,10 +7,7 @@ import com.tangem.core.ui.ds.image.TangemIconUM import com.tangem.core.ui.ds.message.TangemMessageButtonUM import com.tangem.core.ui.ds.message.TangemMessageEffect import com.tangem.core.ui.ds.message.TangemMessageUM -import com.tangem.core.ui.extensions.pluralReference -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.stringReference -import com.tangem.core.ui.extensions.wrappedList +import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.wallet.impl.R import kotlinx.collections.immutable.persistentListOf @@ -297,6 +294,43 @@ internal sealed class WalletNotificationUM(val messageUM: TangemMessageUM, val t ), type = WalletNotificationType.Warning, ) + + data class TangemPayRefreshNeeded( + private val onRefreshClick: () -> Unit, + private val buttonText: TextReference, + private val shouldShowProgress: Boolean, + ) : WalletNotificationUM( + messageUM = TangemMessageUM( + id = "TangemPayRefreshNeeded", + title = resourceReference(id = R.string.tangempay_payment_account_sync_needed), + subtitle = resourceReference(id = R.string.tangempay_use_tangem_device_to_restore_payment_account), + buttonsUM = persistentListOf( + TangemMessageButtonUM( + text = buttonText, + iconRes = R.drawable.ic_tangem_24, + onClick = onRefreshClick, + type = TangemButtonType.Primary, + isLoading = shouldShowProgress, + ), + ), + messageEffect = TangemMessageEffect.Card, + isCentered = true, + ), + type = WalletNotificationType.Warning, + ) + + data object TangemPayUnreachable : WalletNotificationUM( + messageUM = TangemMessageUM( + id = "TangemPayUnreachable", + title = resourceReference(id = R.string.tangempay_temporarily_unavailable), + subtitle = resourceReference(id = R.string.tangempay_service_unreachable_try_later), + iconUM = TangemIconUM.Icon( + iconRes = R.drawable.ic_attention_default_24, + tintReference = { TangemTheme.colors2.graphic.status.attention }, + ), + ), + type = WalletNotificationType.Warning, + ) // endregion // region Promo diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletUM.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletUM.kt index a225e271a3..fd25cf396e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletUM.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletUM.kt @@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.model import androidx.compose.runtime.Immutable import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig import com.tangem.core.ui.ds.button.TangemButtonUM +import com.tangem.features.tangempay.entity.TangemPayMainUM import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf @@ -23,7 +24,7 @@ internal sealed interface WalletUM { val type: WalletType - val tangemPayState: TangemPayState + val tangemPayMainUM: TangemPayMainUM data class Content( override val pullToRefreshConfig: PullToRefreshConfig, @@ -34,7 +35,7 @@ internal sealed interface WalletUM { override val tokensListUM: WalletTokensListUM, override val nftState: WalletNFTItemUM, override val type: WalletType, - override val tangemPayState: TangemPayState, + override val tangemPayMainUM: TangemPayMainUM, ) : WalletUM data class Locked( @@ -47,6 +48,6 @@ internal sealed interface WalletUM { override val pullToRefreshConfig = PullToRefreshConfig(false, {}) override val tokensListUM: WalletTokensListUM = WalletTokensListUM.Locked override val nftState: WalletNFTItemUM = WalletNFTItemUM.Hidden - override val tangemPayState: TangemPayState = TangemPayState.Empty + override val tangemPayMainUM: TangemPayMainUM = TangemPayMainUM.Empty } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt index 4c3d0689dc..27046856a0 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/SetTokenListTransformer.kt @@ -7,16 +7,13 @@ import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.staking.model.StakingAvailability import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.presentation.wallet.state.model.* -import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.MultiWalletBalanceUMTransformer -import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.MultiWalletCardStateConverter -import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TangemPayMainBlockConverter -import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.TokenListStateConverter -import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.WalletTokensListUMConverter +import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.* import com.tangem.feature.wallet.presentation.wallet.state.utils.enableButtons -import com.tangem.utils.logging.TangemLogger import com.tangem.features.tangempay.entity.TangemPayMainUM +import com.tangem.utils.logging.TangemLogger import java.math.BigDecimal +@Suppress("LongParameterList") internal class SetTokenListTransformer( private val params: TokenConverterParams, private val userWallet: UserWallet, @@ -26,10 +23,14 @@ internal class SetTokenListTransformer( private val stakingAvailabilityMap: Map = emptyMap(), private val shouldShowMainPromo: Boolean, private val isAccountsModeEnabled: Boolean, + private val isRedesignEnabled: Boolean, ) : WalletStateTransformer(userWallet.walletId) { private val tangemPayConverter by lazy { - TangemPayMainBlockConverter(tangemPayClickIntents = clickIntents) + TangemPayMainBlockConverter( + tangemPayClickIntents = clickIntents, + isRedesignEnabled = isRedesignEnabled, + ) } override fun transform(prevState: WalletState): WalletState { @@ -59,6 +60,7 @@ internal class SetTokenListTransformer( is WalletUM.Content -> { walletUM.copy( walletsBalanceUM = walletUM.walletsBalanceUM.toLoadedState2(), + tangemPayMainUM = walletUM.tangemPayMainUM.toLoadedState(), tokensListUM = toLoadedState(), buttons = walletUM.enableButtons(), ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TangemPayMainBlockConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TangemPayMainBlockConverter.kt index 41b74bc551..1ce25e26ac 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TangemPayMainBlockConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TangemPayMainBlockConverter.kt @@ -1,10 +1,13 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter +import androidx.compose.ui.text.SpanStyle import com.tangem.common.ui.R import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.format.bigdecimal.fiat import com.tangem.core.ui.format.bigdecimal.format +import com.tangem.core.ui.format.bigdecimal.formatStyled +import com.tangem.core.ui.res.TangemTheme import com.tangem.domain.models.StatusSource import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.PaymentAccountStatusValue @@ -21,6 +24,7 @@ private const val POLYGON_CHAIN_ID = 137 internal class TangemPayMainBlockConverter( private val tangemPayClickIntents: TangemPayIntents, + private val isRedesignEnabled: Boolean, ) : Converter { @Suppress("LongMethod", "CyclomaticComplexMethod") override fun convert(value: AccountStatus.Payment): TangemPayMainUM { @@ -102,9 +106,21 @@ internal class TangemPayMainBlockConverter( private fun getBalanceText(currencyCode: String, balance: BigDecimal): TextReference { val currency = Currency.getInstance(currencyCode) - val formattedBalance = balance.format { - fiat(fiatCurrencyCode = currency.currencyCode, fiatCurrencySymbol = currency.symbol) + val formattedBalance = if (isRedesignEnabled) { + balance.formatStyled { + fiat( + fiatCurrencyCode = currency.currencyCode, + fiatCurrencySymbol = currency.symbol, + spanStyleReference = { SpanStyle(color = TangemTheme.colors2.text.neutral.secondary) }, + ) + } + } else { + stringReference( + balance.format { + fiat(fiatCurrencyCode = currency.currencyCode, fiatCurrencySymbol = currency.symbol) + }, + ) } - return stringReference(formattedBalance) + return formattedBalance } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt index cb033c72d5..1b1be5d304 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/utils/WalletLoadingStateFactory.kt @@ -69,7 +69,7 @@ internal class WalletLoadingStateFactory( is UserWallet.Cold -> WalletType.Cold is UserWallet.Hot -> WalletType.Hot }, - tangemPayState = TangemPayState.Empty, + tangemPayMainUM = TangemPayMainUM.Empty, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicAccountListSubscriber.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicAccountListSubscriber.kt index 463dd73e6e..54b8d8deb9 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicAccountListSubscriber.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/subscribers/BasicAccountListSubscriber.kt @@ -17,9 +17,9 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTokenListErrorTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTokenListTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.TokenConverterParams +import com.tangem.utils.logging.TangemLogger import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged -import com.tangem.utils.logging.TangemLogger import java.math.BigDecimal /** @@ -103,6 +103,7 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() { stakingAvailabilityMap = stakingAvailabilityMap, shouldShowMainPromo = shouldShowMainPromo, isAccountsModeEnabled = isAccountMode, + isRedesignEnabled = true, ), ) } @@ -165,6 +166,7 @@ internal abstract class BasicAccountListSubscriber : BasicWalletSubscriber() { stakingAvailabilityMap = stakingAvailabilityMap, shouldShowMainPromo = shouldShowMainPromo, isAccountsModeEnabled = false, + isRedesignEnabled = false, ), ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt index 27ff0395e6..cfa0ea99a6 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen2.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.pager.HorizontalPager @@ -68,6 +69,8 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.common.Wallet import com.tangem.feature.wallet.presentation.wallet.ui.components.common.WalletPagerIndicator import com.tangem.feature.wallet.presentation.wallet.ui.components.common.WalletTopBar import com.tangem.feature.wallet.presentation.wallet.ui.utils.lazyListStateMapSaver +import com.tangem.features.tangempay.component.TangemPayMainBlockComponent +import com.tangem.features.tangempay.entity.TangemPayMainUM import kotlinx.coroutines.launch import kotlin.math.abs @@ -77,6 +80,7 @@ private const val MARKET_HINT_THRESHOLD = 0.5f @Composable internal fun WalletScreen2( state: WalletScreenState, + tangemPayComponent: TangemPayMainBlockComponent, bottomSheetContent: @Composable (() -> Unit), bottomSheetHeaderHeightProvider: () -> Dp, onBottomSheetStateChange: (BottomSheetState) -> Unit, @@ -104,6 +108,7 @@ internal fun WalletScreen2( WalletContent2( state = state, walletsPagerState = walletsPagerState, + tangemPayComponent = tangemPayComponent, behavior = behavior, bottomSheetContent = bottomSheetContent, bottomSheetHeaderHeightProvider = bottomSheetHeaderHeightProvider, @@ -128,6 +133,7 @@ internal fun WalletScreen2( private fun WalletContent2( state: WalletScreenState, walletsPagerState: PagerState, + tangemPayComponent: TangemPayMainBlockComponent, behavior: TangemCollapsingAppBarBehavior, bottomSheetHeaderHeightProvider: () -> Dp, onBottomSheetStateChange: (BottomSheetState) -> Unit, @@ -257,6 +263,7 @@ private fun WalletContent2( currentWallet = currentWallet, listState = listState, isBalanceHidden = state.isHidingMode, + tangemPayComponent = tangemPayComponent, contentPadding = contentPadding, modifier = Modifier .fillMaxSize() @@ -565,6 +572,14 @@ private fun WalletScreen2_Preview(@PreviewParameter(WalletScreen2PreviewProvider TangemThemePreviewRedesign { WalletScreen2( state = data, + tangemPayComponent = object : TangemPayMainBlockComponent { + override fun LazyListScope.tangemPayMainContent( + state: TangemPayMainUM, + isBalanceHidden: Boolean, + modifier: Modifier, + ) { + } + }, bottomSheetContent = { Text("Markets Content") }, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletItemBlocks.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletItemBlocks.kt index 56506408ef..bc67c35655 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletItemBlocks.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletItemBlocks.kt @@ -3,9 +3,9 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.ui.Modifier import com.tangem.core.ui.ds.button.TangemButton -import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletUM -import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.TangemPayMainScreenBlock +import com.tangem.features.tangempay.component.TangemPayMainBlockComponent +import com.tangem.features.tangempay.entity.TangemPayMainUM internal fun LazyListScope.nftCollections2(state: WalletUM, itemModifier: Modifier) { (state as? WalletUM.Content)?.let { content -> @@ -33,17 +33,13 @@ internal fun LazyListScope.organizeTokens2(state: WalletUM, itemModifier: Modifi } } -internal fun LazyListScope.tangemPay(walletUM: WalletUM, isBalanceHiding: Boolean, modifier: Modifier = Modifier) { - if (walletUM is WalletState.MultiCurrency) { - item( - key = "TangemPayMainScreenBlock", - contentType = walletUM.tangemPayState::class.java, - ) { - TangemPayMainScreenBlock( - state = walletUM.tangemPayState, - isBalanceHidden = isBalanceHiding, - modifier = modifier, - ) - } +internal fun LazyListScope.tangemPay( + tangemPayComponent: TangemPayMainBlockComponent, + tangemPayUM: TangemPayMainUM, + isBalanceHidden: Boolean, + modifier: Modifier = Modifier, +) { + with(tangemPayComponent) { + tangemPayMainContent(modifier = modifier, state = tangemPayUM, isBalanceHidden = isBalanceHidden) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletContent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletContent.kt index 6217c6f14f..5a17a286bc 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletContent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/common/WalletContent.kt @@ -23,6 +23,7 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency import com.tangem.feature.wallet.presentation.wallet.ui.components.nftCollections2 import com.tangem.feature.wallet.presentation.wallet.ui.components.organizeTokens2 import com.tangem.feature.wallet.presentation.wallet.ui.components.tangemPay +import com.tangem.features.tangempay.component.TangemPayMainBlockComponent import kotlinx.collections.immutable.toPersistentList @Composable @@ -30,6 +31,7 @@ internal fun WalletListContent( currentWallet: WalletUM, isBalanceHidden: Boolean, listState: LazyListState, + tangemPayComponent: TangemPayMainBlockComponent, contentPadding: PaddingValues, modifier: Modifier = Modifier, ) { @@ -57,8 +59,9 @@ internal fun WalletListContent( ) tangemPay( - walletUM = currentWallet, - isBalanceHiding = isBalanceHidden, + tangemPayComponent = tangemPayComponent, + tangemPayUM = currentWallet.tangemPayMainUM, + isBalanceHidden = isBalanceHidden, modifier = itemModifier, )