Updated on 2026-08-14
This commit is contained in:
parent
128faaec8d
commit
31e0591ef0
20 changed files with 1242 additions and 20 deletions
|
|
@ -8,7 +8,7 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Suppress("LargeClass")
|
||||
internal object WalletPreviewData {
|
||||
internal object WalletPreviewDataLegacy {
|
||||
|
||||
val topBarConfig by lazy { WalletTopBarConfig(onDetailsClick = {}) }
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.child.wallet.model.WalletActivationBannerType
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData.topBarConfig
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewDataLegacy.topBarConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.*
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.feature.wallet.presentation.preview
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletActionButtons
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal object WalletPreviewData {
|
||||
|
||||
val wallets by lazy {
|
||||
mapOf(
|
||||
UserWalletId(stringValue = "123") to WalletBalancePreview.content,
|
||||
UserWalletId(stringValue = "321") to WalletBalancePreview.loading,
|
||||
UserWalletId(stringValue = "24") to WalletBalancePreview.error,
|
||||
)
|
||||
}
|
||||
|
||||
val actionButtons = persistentListOf(
|
||||
WalletActionButtons.Buy({}, false).buttonUM,
|
||||
WalletActionButtons.Swap({}, false).buttonUM,
|
||||
WalletActionButtons.Sell({}, false).buttonUM,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.text.InlineTextContent
|
||||
import androidx.compose.foundation.text.appendInlineContent
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.Placeholder
|
||||
import androidx.compose.ui.text.PlaceholderVerticalAlign
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
|
||||
private const val STARS_INLINE_CONTENT_ID = "stars"
|
||||
|
||||
@Composable
|
||||
internal fun MarketsHint(isVisible: Boolean, modifier: Modifier = Modifier) {
|
||||
AnimatedVisibility(
|
||||
modifier = modifier,
|
||||
visible = isVisible,
|
||||
enter = fadeIn(animationSpec = tween(durationMillis = 300)),
|
||||
exit = fadeOut(animationSpec = tween(durationMillis = 300)),
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
text = "Swipe up to explore the market", // todo redesign main lokalise
|
||||
style = TangemTheme.typography2.bodyRegular14,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
append("Find new hidden gems ") // todo redesign main lokalise
|
||||
appendInlineContent(
|
||||
STARS_INLINE_CONTENT_ID,
|
||||
alternateText = "\uDBC0\uDDBF",
|
||||
)
|
||||
},
|
||||
inlineContent = mapOf(
|
||||
STARS_INLINE_CONTENT_ID to InlineTextContent(
|
||||
placeholder = Placeholder(
|
||||
width = TangemTheme.typography2.bodyRegular14.fontSize,
|
||||
height = TangemTheme.typography2.bodyRegular14.fontSize,
|
||||
placeholderVerticalAlign = PlaceholderVerticalAlign.Center,
|
||||
),
|
||||
children = {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_magic_default_24),
|
||||
tint = TangemTheme.colors2.text.neutral.tertiary,
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
),
|
||||
),
|
||||
style = TangemTheme.typography2.bodyRegular14,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun MarketsHint_Preview() {
|
||||
TangemThemePreviewRedesign {
|
||||
MarketsHint(
|
||||
isVisible = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.VisibilityThreshold
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideIn
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.*
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.sheetscaffold.TangemSheetState
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.core.ui.test.MarketTooltipTestTags
|
||||
import com.tangem.core.ui.utils.lineTo
|
||||
import com.tangem.core.ui.utils.moveTo
|
||||
import com.tangem.core.ui.utils.toPx
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
internal fun MarketsTooltip(
|
||||
availableHeight: Dp,
|
||||
bottomSheetState: TangemSheetState,
|
||||
isVisible: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val tooltipOffset by remember {
|
||||
derivedStateOf {
|
||||
val bottomSheetOffset = try {
|
||||
// Can throw exception during the first composition
|
||||
with(density) { bottomSheetState.requireOffset().toDp() }
|
||||
} catch (e: Exception) {
|
||||
0.dp
|
||||
}
|
||||
|
||||
bottomSheetOffset - availableHeight
|
||||
}
|
||||
}
|
||||
|
||||
var isVisibleWrapped by remember { mutableStateOf(value = false) }
|
||||
LaunchedEffect(isVisible) {
|
||||
if (isVisible) {
|
||||
delay(timeMillis = 300)
|
||||
}
|
||||
|
||||
isVisibleWrapped = isVisible
|
||||
}
|
||||
|
||||
val slideOffset = 40.dp.toPx()
|
||||
AnimatedVisibility(
|
||||
modifier = modifier
|
||||
.offset { IntOffset(x = 0, y = tooltipOffset.roundToPx()) }
|
||||
.testTag(MarketTooltipTestTags.CONTAINER),
|
||||
visible = isVisibleWrapped,
|
||||
enter = slideIn(
|
||||
animationSpec = spring(
|
||||
stiffness = Spring.StiffnessLow,
|
||||
visibilityThreshold = IntOffset.VisibilityThreshold,
|
||||
),
|
||||
initialOffset = { _ -> IntOffset(y = -slideOffset.roundToInt(), x = 0) },
|
||||
) + fadeIn(),
|
||||
exit = fadeOut(),
|
||||
) {
|
||||
MarketsTooltipContent()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun MarketsTooltipContent(modifier: Modifier = Modifier) {
|
||||
val backgroundColor = TangemTheme.colors.background.action
|
||||
val cornerRadius = CornerRadius(x = 14.dp.toPx())
|
||||
val tipDpSize = DpSize(width = 20.dp, height = 8.dp)
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.padding(bottom = tipDpSize.height)
|
||||
.drawBehind {
|
||||
val rect = size.toRect()
|
||||
val tipSize = tipDpSize.toSize()
|
||||
val tipRect = Rect(
|
||||
offset = Offset(
|
||||
x = rect.center.x - tipSize.center.x,
|
||||
y = rect.bottom,
|
||||
),
|
||||
size = tipSize,
|
||||
)
|
||||
drawRoundRect(color = backgroundColor, cornerRadius = cornerRadius)
|
||||
|
||||
val tipPath = Path().apply {
|
||||
moveTo(tipRect.topLeft)
|
||||
lineTo(tipRect.bottomCenter)
|
||||
lineTo(tipRect.topRight)
|
||||
}
|
||||
drawPath(color = backgroundColor, path = tipPath)
|
||||
}
|
||||
.padding(all = 12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.markets_tooltip_title),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.markets_tooltip_message),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun MarketsTooltip_Preview() {
|
||||
TangemThemePreviewRedesign {
|
||||
MarketsTooltipContent()
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -9,14 +9,14 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.SimpleSettingsRow
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.getDefaultRowColors
|
||||
import com.tangem.core.ui.components.getWarningRowColors
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewDataLegacy
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.ActionsBottomSheetConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.TokenActionButtonConfig
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -64,5 +64,5 @@ private fun ActionsBottomSheetContent_Light(
|
|||
}
|
||||
|
||||
private class ActionsBottomSheetContentConfigProvider : CollectionPreviewParameterProvider<ActionsBottomSheetConfig>(
|
||||
collection = listOf(WalletPreviewData.actionsBottomSheet),
|
||||
collection = listOf(WalletPreviewDataLegacy.actionsBottomSheet),
|
||||
)
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
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
|
||||
|
||||
internal fun LazyListScope.nftCollections2(state: WalletUM, itemModifier: Modifier) {
|
||||
(state as? WalletUM.Content)?.let { content ->
|
||||
item(key = "NFTCollections", contentType = "NFTCollections") {
|
||||
WalletNFTItem(
|
||||
modifier = itemModifier,
|
||||
state = content.nftState,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun LazyListScope.organizeTokens2(state: WalletUM, itemModifier: Modifier) {
|
||||
val organizeButton = state.tokensListUM.organizeButtonUM
|
||||
if (organizeButton != null) {
|
||||
item(
|
||||
key = "OrganizeTokensButton",
|
||||
contentType = "OrganizeTokensButton",
|
||||
) {
|
||||
TangemButton(
|
||||
organizeButton,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ import com.tangem.core.ui.res.LocalWindowSize
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.MainScreenTestTags
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewDataLegacy
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.common.WalletCard
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -106,7 +106,7 @@ private fun Preview_WalletsList() {
|
|||
TangemThemePreview {
|
||||
WalletsList(
|
||||
lazyListState = rememberLazyListState(),
|
||||
wallets = WalletPreviewData.wallets.values.toPersistentList(),
|
||||
wallets = WalletPreviewDataLegacy.wallets.values.toPersistentList(),
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,205 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.common
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.TextAutoSize
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.text.applyBladeBrush
|
||||
import com.tangem.core.ui.ds.button.SecondaryTangemButton
|
||||
import com.tangem.core.ui.ds.button.TangemButtonShape
|
||||
import com.tangem.core.ui.ds.button.TangemButtonUM
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingAppBarBehavior
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.rememberTangemExitUntilCollapsedScrollBehavior
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.snapToExitUntilCollapsed
|
||||
import com.tangem.core.ui.extensions.orEmpty
|
||||
import com.tangem.core.ui.extensions.orMaskWithStars
|
||||
import com.tangem.core.ui.extensions.resolveAnnotatedReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.core.ui.test.MainScreenTestTags
|
||||
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.WalletBalanceUM
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.fastForEach
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
private const val MIN_SCALE = 0.75f
|
||||
private const val MAX_SCALE = 1f
|
||||
|
||||
@Composable
|
||||
internal fun WalletBalance(
|
||||
walletBalanceUM: WalletBalanceUM,
|
||||
behavior: TangemCollapsingAppBarBehavior,
|
||||
buttons: ImmutableList<TangemButtonUM>,
|
||||
isBalanceHidden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val collapsedFraction = behavior.state.collapsedFraction
|
||||
val alpha = 1f - collapsedFraction
|
||||
val scale = alpha.coerceIn(MIN_SCALE, MAX_SCALE)
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = modifier
|
||||
.alpha(alpha)
|
||||
.scale(scale)
|
||||
.snapToExitUntilCollapsed(behavior)
|
||||
.fillMaxWidth()
|
||||
.padding(top = 64.dp)
|
||||
.statusBarsPadding(),
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(200.dp),
|
||||
) {
|
||||
Balance(
|
||||
walletBalanceUM = walletBalanceUM,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
SpacerH(TangemTheme.dimens2.x3)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
) {
|
||||
Text(
|
||||
text = walletBalanceUM.name,
|
||||
style = TangemTheme.typography2.bodyRegular14,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
)
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_tangem_24),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors2.graphic.neutral.tertiaryConstant,
|
||||
modifier = Modifier.size(TangemTheme.dimens2.x6),
|
||||
)
|
||||
}
|
||||
}
|
||||
SpacerH(TangemTheme.dimens2.x2)
|
||||
ActionButtons(buttons)
|
||||
SpacerH(TangemTheme.dimens2.x6)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Balance(walletBalanceUM: WalletBalanceUM, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
|
||||
AnimatedContent(
|
||||
targetState = walletBalanceUM,
|
||||
label = "Update the balance",
|
||||
modifier = modifier.testTag(MainScreenTestTags.WALLET_BALANCE),
|
||||
transitionSpec = {
|
||||
fadeIn(animationSpec = tween(durationMillis = 220, delayMillis = 90)) togetherWith
|
||||
fadeOut(animationSpec = tween(durationMillis = 90))
|
||||
},
|
||||
) { balanceUM ->
|
||||
when (balanceUM) {
|
||||
is WalletBalanceUM.Content -> {
|
||||
Text(
|
||||
text = balanceUM.balance.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(),
|
||||
style = TangemTheme.typography2.titleRegular44.applyBladeBrush(
|
||||
isEnabled = balanceUM.isBalanceFlickering,
|
||||
textColor = TangemTheme.colors2.text.neutral.primary,
|
||||
),
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
autoSize = TextAutoSize.StepBased(
|
||||
minFontSize = TangemTheme.typography2.bodySemibold15.fontSize,
|
||||
maxFontSize = TangemTheme.typography2.titleRegular44.fontSize,
|
||||
),
|
||||
)
|
||||
}
|
||||
is WalletBalanceUM.Error,
|
||||
is WalletBalanceUM.Loading,
|
||||
-> {
|
||||
TextShimmer(
|
||||
text = "123456",
|
||||
style = TangemTheme.typography2.titleRegular44,
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
textSizeHeight = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ActionButtons(buttons: ImmutableList<TangemButtonUM>) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
buttons.fastForEach { button ->
|
||||
key(button.text) {
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens2.x2_5),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
SecondaryTangemButton(
|
||||
iconRes = button.iconRes,
|
||||
onClick = button.onClick,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
)
|
||||
Text(
|
||||
text = button.text.orEmpty().resolveReference(),
|
||||
style = TangemTheme.typography2.bodySemibold15,
|
||||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun WalletBalance_Preview(@PreviewParameter(WalletBalancePreviewProvider::class) params: WalletBalanceUM) {
|
||||
TangemThemePreviewRedesign {
|
||||
WalletBalance(
|
||||
walletBalanceUM = params,
|
||||
behavior = rememberTangemExitUntilCollapsedScrollBehavior(),
|
||||
buttons = WalletPreviewData.actionButtons,
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class WalletBalancePreviewProvider : PreviewParameterProvider<WalletBalanceUM> {
|
||||
override val values: Sequence<WalletBalanceUM>
|
||||
get() = sequenceOf(
|
||||
WalletBalancePreview.content,
|
||||
WalletBalancePreview.content.copy(isBalanceFlickering = true),
|
||||
WalletBalancePreview.loading,
|
||||
WalletBalancePreview.error,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -12,7 +12,6 @@ import androidx.compose.foundation.indication
|
|||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.PressInteraction
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.TextAutoSize
|
||||
import androidx.compose.material3.*
|
||||
|
|
@ -45,7 +44,7 @@ import com.tangem.core.ui.res.TangemDimens
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.MainScreenTestTags
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewDataLegacy
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditionalInfo
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDropDownItems
|
||||
|
|
@ -375,22 +374,22 @@ private fun Preview_WalletCard(
|
|||
|
||||
private class WalletCardStateProvider : CollectionPreviewParameterProvider<WalletCardState>(
|
||||
collection = listOf(
|
||||
WalletPreviewData.walletCardContentState,
|
||||
WalletPreviewData.walletCardContentState.copy(
|
||||
WalletPreviewDataLegacy.walletCardContentState,
|
||||
WalletPreviewDataLegacy.walletCardContentState.copy(
|
||||
balance = "0.00",
|
||||
),
|
||||
WalletPreviewData.walletCardContentState.copy(
|
||||
WalletPreviewDataLegacy.walletCardContentState.copy(
|
||||
title = "Title",
|
||||
additionalInfo = WalletAdditionalInfo(
|
||||
hideable = false,
|
||||
content = TextReference.Str("3 cards"),
|
||||
),
|
||||
),
|
||||
WalletPreviewData.walletCardContentState.copy(
|
||||
WalletPreviewDataLegacy.walletCardContentState.copy(
|
||||
isBalanceFlickering = true,
|
||||
),
|
||||
WalletPreviewData.walletCardLoadingState,
|
||||
WalletPreviewData.walletCardErrorState,
|
||||
WalletPreviewDataLegacy.walletCardLoadingState,
|
||||
WalletPreviewDataLegacy.walletCardErrorState,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,79 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.common
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.rememberOverscrollEffect
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import com.tangem.common.ui.notifications.notifications
|
||||
import com.tangem.common.ui.notifications.notificationsCarousel
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.core.ui.components.transactions.txHistoryItems
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
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.multicurrency.tokensListItems
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.tokensListItems2
|
||||
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 kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
@Composable
|
||||
internal fun WalletListContent(
|
||||
currentWallet: WalletUM,
|
||||
isBalanceHidden: Boolean,
|
||||
listState: LazyListState,
|
||||
contentPadding: PaddingValues,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val containerColor = TangemTheme.colors2.surface.level1
|
||||
|
||||
val movableItemModifier = Modifier.padding(horizontal = TangemTheme.dimens2.x3)
|
||||
val itemModifier = movableItemModifier.padding(top = TangemTheme.dimens2.x3)
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
state = listState,
|
||||
contentPadding = contentPadding,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
overscrollEffect = rememberOverscrollEffect(),
|
||||
) {
|
||||
notifications(
|
||||
notifications = currentWallet.notifications.map { it.messageUM }
|
||||
.toPersistentList(),
|
||||
contentColor = containerColor,
|
||||
modifier = movableItemModifier,
|
||||
)
|
||||
notificationsCarousel(
|
||||
containerColor = containerColor,
|
||||
modifier = movableItemModifier,
|
||||
notifications = currentWallet.notifications.map { it.messageUM }
|
||||
.toPersistentList(),
|
||||
)
|
||||
|
||||
tangemPay(
|
||||
walletUM = currentWallet,
|
||||
isBalanceHiding = isBalanceHidden,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
|
||||
tokensListItems2(
|
||||
walletTokensListUM = currentWallet.tokensListUM,
|
||||
modifier = movableItemModifier,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
|
||||
nftCollections2(state = currentWallet, itemModifier = itemModifier)
|
||||
|
||||
organizeTokens2(state = currentWallet, itemModifier = itemModifier)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wallet content
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.common
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.pager.PagerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.ds.TangemPagerIndicator
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingAppBarBehavior
|
||||
|
||||
private const val MIN_SCALE = 0.75f
|
||||
private const val MAX_SCALE = 1f
|
||||
|
||||
@Composable
|
||||
internal fun WalletPagerIndicator(pagerState: PagerState, behavior: TangemCollapsingAppBarBehavior) {
|
||||
val collapsedFraction = behavior.state.collapsedFraction
|
||||
val alpha = MAX_SCALE - collapsedFraction
|
||||
val scale = alpha.coerceIn(MIN_SCALE, MAX_SCALE)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.graphicsLayer {
|
||||
scaleY = scale
|
||||
translationY = behavior.state.heightOffset
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.height(
|
||||
with(LocalDensity.current) {
|
||||
behavior.state.heightOffsetLimit.toDp().unaryMinus()
|
||||
},
|
||||
)
|
||||
.alpha(alpha),
|
||||
) {
|
||||
TangemPagerIndicator(
|
||||
pagerState = pagerState,
|
||||
modifier = Modifier
|
||||
.padding(top = 248.dp)
|
||||
.scale(scaleY = 1f, scaleX = scale)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,22 +3,77 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components.common
|
|||
import android.content.res.Configuration
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.ui.components.haze.hazeEffectTangem
|
||||
import com.tangem.core.ui.ds.topbar.TangemTopBar
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.TangemCollapsingAppBarBehavior
|
||||
import com.tangem.core.ui.ds.topbar.collapsing.rememberTangemExitUntilCollapsedScrollBehavior
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.LocalPowerSavingState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.core.ui.test.MainScreenTestTags
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewDataLegacy
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTopBarConfig
|
||||
import dev.chrisbanes.haze.HazeProgressive
|
||||
|
||||
private const val VISIBILITY_THRESHOLD = 0.5f
|
||||
|
||||
/**
|
||||
* Wallet screen collapsing top bar
|
||||
*
|
||||
* @param topBarConfig top bar config
|
||||
* @param walletBalance wallet balance text reference
|
||||
* @param behavior collapsing behavior
|
||||
*/
|
||||
@Composable
|
||||
internal fun WalletTopBar(
|
||||
topBarConfig: WalletTopBarConfig,
|
||||
walletBalance: TextReference?,
|
||||
behavior: TangemCollapsingAppBarBehavior,
|
||||
) {
|
||||
Surface(
|
||||
color = Color.Unspecified,
|
||||
contentColor = Color.Unspecified,
|
||||
modifier = Modifier.hazeEffectTangem {
|
||||
progressive =
|
||||
HazeProgressive.verticalGradient(startIntensity = 1f, endIntensity = 0f)
|
||||
},
|
||||
) {
|
||||
val isPowerSaving by LocalPowerSavingState.current.isPowerSavingModeEnabled.collectAsStateWithLifecycle()
|
||||
|
||||
val wrappedBalance = remember(behavior.state.collapsedFraction) {
|
||||
if (behavior.state.collapsedFraction > VISIBILITY_THRESHOLD) walletBalance else null
|
||||
}
|
||||
|
||||
TangemTopBar(
|
||||
title = wrappedBalance,
|
||||
startIconRes = R.drawable.ic_tangem_24,
|
||||
endIconRes = R.drawable.ic_more_default_24,
|
||||
onEndContentClick = topBarConfig.onDetailsClick,
|
||||
isGhostButtons = !isPowerSaving,
|
||||
modifier = Modifier
|
||||
.testTag(MainScreenTestTags.TOP_BAR),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wallet screen top bar
|
||||
*
|
||||
* @param config component config
|
||||
*/
|
||||
@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
internal fun WalletTopBar(config: WalletTopBarConfig) {
|
||||
|
|
@ -46,6 +101,21 @@ internal fun WalletTopBar(config: WalletTopBarConfig) {
|
|||
@Composable
|
||||
private fun Preview_WalletTopBar() {
|
||||
TangemThemePreview {
|
||||
WalletTopBar(config = WalletPreviewData.topBarConfig)
|
||||
WalletTopBar(config = WalletPreviewDataLegacy.topBarConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun WalletTopBar_Preview() {
|
||||
TangemThemePreviewRedesign {
|
||||
WalletTopBar(
|
||||
topBarConfig = WalletTopBarConfig(onDetailsClick = {}),
|
||||
walletBalance = stringReference("$ 8923,05"),
|
||||
behavior = rememberTangemExitUntilCollapsedScrollBehavior(),
|
||||
)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -4,6 +4,9 @@ import androidx.compose.animation.core.tween
|
|||
import androidx.compose.foundation.gestures.animateScrollBy
|
||||
import androidx.compose.foundation.lazy.LazyListLayoutInfo
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.runtime.saveable.Saver
|
||||
import androidx.compose.runtime.saveable.mapSaver
|
||||
import com.tangem.utils.extensions.mapNotNullValues
|
||||
|
||||
/**
|
||||
* Animate scroll [LazyListState].
|
||||
|
|
@ -28,4 +31,32 @@ private fun calculateOffset(layoutInfo: LazyListLayoutInfo, prevIndex: Int, newI
|
|||
|
||||
private fun LazyListLayoutInfo.getItemSizeWithSpacing(): Int {
|
||||
return viewportSize.width - afterContentPadding - beforeContentPadding + mainAxisItemSpacing
|
||||
}
|
||||
|
||||
/**
|
||||
* Saver for [LazyListState] map, where key is page index, and value is [LazyListState] of this page.
|
||||
*/
|
||||
internal fun lazyListStateMapSaver(pageCount: Int): Saver<MutableMap<Int, LazyListState>, Any> {
|
||||
return mapSaver(
|
||||
save = { map ->
|
||||
map.mapKeys { it.key.toString() }
|
||||
.mapValues { listState ->
|
||||
listState.value.firstVisibleItemIndex to listState.value.firstVisibleItemScrollOffset
|
||||
}
|
||||
},
|
||||
restore = { restoredMap ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val typedMap = restoredMap as? Map<String, Pair<Int, Int>> ?: return@mapSaver null
|
||||
|
||||
typedMap.mapKeys { it.key.toInt() }
|
||||
.mapNotNullValues { (_, value) ->
|
||||
val (index, offset) = value
|
||||
LazyListState(index, offset)
|
||||
}
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
repeat(pageCount) { putIfAbsent(it, LazyListState()) }
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M11.516,6.27C11.403,6.27 11.343,6.2 11.325,6.095C11.066,4.674 11.092,4.604 9.587,4.332C9.475,4.306 9.414,4.245 9.414,4.131C9.414,4.025 9.475,3.955 9.587,3.938C11.092,3.666 11.066,3.596 11.325,2.175C11.343,2.07 11.403,2 11.516,2C11.628,2 11.689,2.07 11.706,2.175C11.965,3.596 11.939,3.666 13.444,3.938C13.548,3.955 13.617,4.025 13.617,4.131C13.617,4.245 13.548,4.306 13.444,4.332C11.939,4.604 11.965,4.674 11.706,6.095C11.689,6.2 11.628,6.27 11.516,6.27ZM7.33,12.302C7.174,12.302 7.062,12.189 7.036,12.013C6.759,9.672 6.646,9.611 4.294,9.225C4.112,9.199 4,9.102 4,8.927C4,8.769 4.112,8.664 4.259,8.637C6.629,8.182 6.759,8.19 7.036,5.849C7.062,5.674 7.174,5.56 7.33,5.56C7.494,5.56 7.606,5.674 7.624,5.84C7.926,8.217 8.013,8.295 10.4,8.637C10.547,8.655 10.66,8.769 10.66,8.927C10.66,9.093 10.547,9.199 10.4,9.225C8.013,9.69 7.935,9.69 7.624,12.031C7.606,12.189 7.494,12.302 7.33,12.302ZM13.193,22C12.969,22 12.804,21.833 12.77,21.597C12.121,16.801 11.472,16.16 6.802,15.538C6.551,15.512 6.387,15.336 6.387,15.099C6.387,14.872 6.551,14.696 6.802,14.67C11.481,14.144 12.156,13.407 12.77,8.602C12.804,8.366 12.969,8.208 13.193,8.208C13.418,8.208 13.583,8.366 13.626,8.602C14.24,13.407 14.906,14.144 19.594,14.67C19.836,14.696 20,14.872 20,15.099C20,15.336 19.836,15.512 19.594,15.538C14.906,16.064 14.24,16.801 13.626,21.597C13.583,21.833 13.418,22 13.193,22Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
Loading…
Add table
Add a link
Reference in a new issue