Updated on 2026-08-14
This commit is contained in:
parent
96478230a0
commit
4acd7ce3b2
25 changed files with 1010 additions and 338 deletions
|
|
@ -1,60 +0,0 @@
|
|||
package com.tangem.core.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
/**
|
||||
* A composable that draws a fade effect at the bottom of the screen. Used on screens with a list of repeating
|
||||
* elements and floating button at the bottom of the screen.
|
||||
*/
|
||||
@Composable
|
||||
fun BottomFade(modifier: Modifier = Modifier, backgroundColor: Color = TangemTheme.colors.background.secondary) {
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(TangemTheme.dimens.size100 + bottomBarHeight)
|
||||
.background(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
backgroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A composable that draws a fade effect. Used on screens with a list of repeating
|
||||
* elements and floating button at the bottom of the screen.
|
||||
*/
|
||||
@Composable
|
||||
fun Fade(
|
||||
modifier: Modifier = Modifier,
|
||||
backgroundColor: Color = TangemTheme.colors.background.secondary,
|
||||
height: Dp = 32.dp,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(height)
|
||||
.background(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
backgroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
144
core/ui/src/main/java/com/tangem/core/ui/components/Fade.kt
Normal file
144
core/ui/src/main/java/com/tangem/core/ui/components/Fade.kt
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
package com.tangem.core.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.haze.hazeEffectTangem
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import dev.chrisbanes.haze.HazeProgressive
|
||||
import dev.chrisbanes.haze.HazeStyle
|
||||
import dev.chrisbanes.haze.HazeTint
|
||||
|
||||
/**
|
||||
* A composable that draws a fade effect at the bottom of the screen. Used on screens with a list of repeating
|
||||
* elements and floating button at the bottom of the screen.
|
||||
*/
|
||||
@Composable
|
||||
fun BottomFade(modifier: Modifier = Modifier, backgroundColor: Color = TangemTheme.colors.background.secondary) {
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(TangemTheme.dimens.size100 + bottomBarHeight)
|
||||
.background(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
backgroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A composable that draws a fade effect at the right end of the screen. Same as [BottomFade]
|
||||
* but with a horizontal gradient.
|
||||
*/
|
||||
@Composable
|
||||
fun HorizontalFade(modifier: Modifier = Modifier, backgroundColor: Color = TangemTheme.colors.background.secondary) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxHeight()
|
||||
.background(
|
||||
brush = Brush.horizontalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
backgroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A composable that draws a fade effect at the bottom of the screen. Same as [BottomFade]
|
||||
* but with a vertical blur.
|
||||
*/
|
||||
@Composable
|
||||
fun BottomFadeWithBlur(backgroundColor: Color, modifier: Modifier = Modifier) {
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(TangemTheme.dimens.size100 + bottomBarHeight)
|
||||
.hazeEffectTangem(
|
||||
style = HazeStyle(
|
||||
blurRadius = 20.dp,
|
||||
tint = HazeTint(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
backgroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
) {
|
||||
progressive =
|
||||
HazeProgressive.verticalGradient(startIntensity = 0f, endIntensity = 1f)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A composable that draws a fade effect at the right end of the screen. Same as [HorizontalFade]
|
||||
* but with blur.
|
||||
*/
|
||||
@Composable
|
||||
fun HorizontalFadeWithBlur(backgroundColor: Color, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxHeight()
|
||||
.hazeEffectTangem(
|
||||
style = HazeStyle(
|
||||
blurRadius = 20.dp,
|
||||
tint = HazeTint(
|
||||
brush = Brush.horizontalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
backgroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
backgroundColor = Color.Transparent,
|
||||
),
|
||||
) {
|
||||
progressive =
|
||||
HazeProgressive.horizontalGradient(startIntensity = 0f, endIntensity = 1f)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A composable that draws a fade effect. Used on screens with a list of repeating
|
||||
* elements and floating button at the bottom of the screen.
|
||||
*/
|
||||
@Composable
|
||||
fun Fade(
|
||||
modifier: Modifier = Modifier,
|
||||
backgroundColor: Color = TangemTheme.colors.background.secondary,
|
||||
height: Dp = 32.dp,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(height)
|
||||
.background(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
backgroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -8,16 +8,29 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.buttons.SecondarySmallButton
|
||||
import com.tangem.core.ui.components.buttons.SmallButtonConfig
|
||||
import com.tangem.core.ui.ds.button.*
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
@Composable
|
||||
fun UnableToLoadData(onRetryClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
UnableToLoadDataV2(onRetryClick, modifier)
|
||||
} else {
|
||||
UnableToLoadDataV1(onRetryClick, modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UnableToLoadDataV1(onRetryClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
|
|
@ -37,11 +50,43 @@ fun UnableToLoadData(onRetryClick: () -> Unit, modifier: Modifier = Modifier) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UnableToLoadDataV2(onRetryClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.markets_loading_error_title),
|
||||
style = TangemTheme.typography2.bodyRegular14,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
)
|
||||
TangemButton(
|
||||
buttonUM = TangemButtonUM(
|
||||
text = resourceReference(R.string.try_to_load_data_again_button_title),
|
||||
onClick = onRetryClick,
|
||||
type = TangemButtonType.Secondary,
|
||||
size = TangemButtonSize.X8,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, showBackground = true)
|
||||
@Composable
|
||||
private fun PreviewV2() {
|
||||
TangemThemePreviewRedesign {
|
||||
UnableToLoadDataV2(onRetryClick = {})
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview() {
|
||||
private fun PreviewV1() {
|
||||
TangemThemePreview {
|
||||
UnableToLoadData(onRetryClick = {})
|
||||
UnableToLoadDataV1(onRetryClick = {})
|
||||
}
|
||||
}
|
||||
|
|
@ -5,13 +5,7 @@ import androidx.compose.animation.animateColorAsState
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
|
|
@ -72,7 +66,7 @@ fun Chip(state: ChipUM, modifier: Modifier = Modifier) {
|
|||
@Preview(showBackground = true)
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun ChipPreview() {
|
||||
private fun ChipPreviewV() {
|
||||
TangemThemePreview {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
package com.tangem.core.ui.ds.badge
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
|
|
@ -15,18 +13,17 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.res.painterResource
|
||||
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.ds.badge.TangemBadgeSize.*
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.clickableSingle
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.ds.image.TangemIcon
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
|
|
@ -43,7 +40,7 @@ import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
|||
fun TangemBadge(badgeUM: TangemBadgeUM, modifier: Modifier = Modifier) {
|
||||
TangemBadge(
|
||||
text = badgeUM.text,
|
||||
iconRes = badgeUM.iconRes,
|
||||
tangemIconUM = badgeUM.tangemIconUM,
|
||||
size = badgeUM.size,
|
||||
shape = badgeUM.shape,
|
||||
color = badgeUM.color,
|
||||
|
|
@ -60,7 +57,7 @@ fun TangemBadge(badgeUM: TangemBadgeUM, modifier: Modifier = Modifier) {
|
|||
*
|
||||
* @param text TextReference for the badge label.
|
||||
* @param modifier Modifier to be applied to the badge.
|
||||
* @param iconRes Drawable resource ID for the icon to be displayed in the badge.
|
||||
* @param tangemIconUM Model of representation for the icon to be displayed in the badge.
|
||||
* @param size [TangemBadgeSize] defining the size of the badge.
|
||||
* @param shape [TangemBadgeShape] defining the shape of the badge.
|
||||
* @param color [TangemBadgeColor] defining the color scheme of the badge.
|
||||
|
|
@ -74,7 +71,7 @@ fun TangemBadge(badgeUM: TangemBadgeUM, modifier: Modifier = Modifier) {
|
|||
fun TangemBadge(
|
||||
modifier: Modifier = Modifier,
|
||||
text: TextReference? = null,
|
||||
@DrawableRes iconRes: Int? = null,
|
||||
tangemIconUM: TangemIconUM? = null,
|
||||
size: TangemBadgeSize = X9,
|
||||
shape: TangemBadgeShape = TangemBadgeShape.Default,
|
||||
color: TangemBadgeColor = TangemBadgeColor.Gray,
|
||||
|
|
@ -93,18 +90,12 @@ fun TangemBadge(
|
|||
.padding(size.toPaddingDp(position = iconPosition))
|
||||
.clickableSingle(enabled = onClick != null, onClick = { onClick?.invoke() }),
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = iconRes != null && iconPosition != TangemBadgeIconPosition.End,
|
||||
modifier = Modifier.size(size = size.toContentSize()),
|
||||
label = "Start Icon Visibility",
|
||||
) {
|
||||
val wrappedIconRes = remember(this) { requireNotNull(iconRes) }
|
||||
Icon(
|
||||
painter = painterResource(id = wrappedIconRes),
|
||||
contentDescription = null,
|
||||
tint = iconColor,
|
||||
)
|
||||
}
|
||||
StartIcon(
|
||||
tangemIconUM = tangemIconUM,
|
||||
iconPosition = iconPosition,
|
||||
size = size,
|
||||
iconColor = iconColor,
|
||||
)
|
||||
AnimatedVisibility(
|
||||
visible = text != null,
|
||||
label = "Text Visibility",
|
||||
|
|
@ -117,18 +108,66 @@ fun TangemBadge(
|
|||
color = getTextColor(type = type, color = color),
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = iconRes != null && iconPosition == TangemBadgeIconPosition.End,
|
||||
modifier = Modifier.size(size = size.toContentSize()),
|
||||
label = "End Icon Visibility",
|
||||
) {
|
||||
val wrappedIconRes = remember(this) { requireNotNull(iconRes) }
|
||||
Icon(
|
||||
painter = painterResource(id = wrappedIconRes),
|
||||
contentDescription = null,
|
||||
tint = iconColor,
|
||||
)
|
||||
}
|
||||
EndIcon(
|
||||
tangemIconUM = tangemIconUM,
|
||||
iconPosition = iconPosition,
|
||||
size = size,
|
||||
iconColor = iconColor,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StartIcon(
|
||||
iconPosition: TangemBadgeIconPosition,
|
||||
size: TangemBadgeSize,
|
||||
iconColor: Color,
|
||||
tangemIconUM: TangemIconUM? = null,
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = tangemIconUM != null && iconPosition != TangemBadgeIconPosition.End,
|
||||
modifier = Modifier.size(size = size.toContentSize()),
|
||||
label = "Start Icon Visibility",
|
||||
) {
|
||||
val wrappedIconRes = remember(this) { requireNotNull(tangemIconUM) }
|
||||
TangemIcon(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
tangemIconUM = when (wrappedIconRes) {
|
||||
is TangemIconUM.Currency,
|
||||
is TangemIconUM.Ident,
|
||||
is TangemIconUM.Image,
|
||||
is TangemIconUM.Url,
|
||||
-> wrappedIconRes
|
||||
is TangemIconUM.Icon -> wrappedIconRes.copy(tintReference = ColorReference2 { iconColor })
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EndIcon(
|
||||
iconPosition: TangemBadgeIconPosition,
|
||||
size: TangemBadgeSize,
|
||||
iconColor: Color,
|
||||
tangemIconUM: TangemIconUM? = null,
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = tangemIconUM != null && iconPosition == TangemBadgeIconPosition.End,
|
||||
modifier = Modifier.size(size = size.toContentSize()),
|
||||
label = "End Icon Visibility",
|
||||
) {
|
||||
val wrappedIconRes = remember(this) { requireNotNull(tangemIconUM) }
|
||||
TangemIcon(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
tangemIconUM = when (wrappedIconRes) {
|
||||
is TangemIconUM.Currency,
|
||||
is TangemIconUM.Ident,
|
||||
is TangemIconUM.Image,
|
||||
is TangemIconUM.Url,
|
||||
-> wrappedIconRes
|
||||
is TangemIconUM.Icon -> wrappedIconRes.copy(tintReference = ColorReference2 { iconColor })
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -351,7 +390,7 @@ private fun TangemBadge_Preview(@PreviewParameter(TangemBadgePreviewProvider::cl
|
|||
repeat(TangemBadgeType.entries.size) { index ->
|
||||
TangemBadge(
|
||||
text = stringReference("Title").takeIf { yIndex < 2 },
|
||||
iconRes = R.drawable.ic_information_24,
|
||||
tangemIconUM = TangemIconUM.Icon(R.drawable.ic_information_24),
|
||||
type = TangemBadgeType.entries[index],
|
||||
color = params,
|
||||
shape = TangemBadgeShape.entries[yIndex % 2],
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
package com.tangem.core.ui.ds.badge
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.core.ui.ds.badge.TangemBadgeSize.X9
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
/**
|
||||
* UI model for [TangemBadge] component
|
||||
*
|
||||
* @param text TextReference for the badge label.
|
||||
* @param iconRes Drawable resource ID for the icon to be displayed in the badge.
|
||||
* @param tangemIconUM Model of representation for the icon to be displayed in the badge.
|
||||
* @param size [TangemBadgeSize] defining the size of the badge.
|
||||
* @param shape [TangemBadgeShape] defining the shape of the badge.
|
||||
* @param color [TangemBadgeColor] defining the color scheme of the badge.
|
||||
|
|
@ -18,7 +18,7 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
*/
|
||||
class TangemBadgeUM(
|
||||
val text: TextReference,
|
||||
@DrawableRes val iconRes: Int? = null,
|
||||
val tangemIconUM: TangemIconUM? = null,
|
||||
val size: TangemBadgeSize = X9,
|
||||
val shape: TangemBadgeShape = TangemBadgeShape.Default,
|
||||
val color: TangemBadgeColor = TangemBadgeColor.Gray,
|
||||
|
|
|
|||
|
|
@ -2,12 +2,19 @@ package com.tangem.core.ui.ds.image
|
|||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.components.CircleShimmer
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.icons.identicon.IdentIcon
|
||||
|
|
@ -40,6 +47,11 @@ sealed interface TangemIconUM {
|
|||
data class Ident(
|
||||
val text: String,
|
||||
) : TangemIconUM
|
||||
|
||||
/** Image represented from network by url */
|
||||
data class Url(
|
||||
val url: String,
|
||||
) : TangemIconUM
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -72,5 +84,24 @@ fun TangemIcon(tangemIconUM: TangemIconUM, modifier: Modifier = Modifier) {
|
|||
address = tangemIconUM.text,
|
||||
modifier = modifier,
|
||||
)
|
||||
is TangemIconUM.Url -> SubcomposeAsyncImage(
|
||||
modifier = modifier,
|
||||
model = ImageRequest.Builder(context = LocalContext.current)
|
||||
.data(tangemIconUM.url)
|
||||
.crossfade(enable = true)
|
||||
.allowHardware(enable = false)
|
||||
.build(),
|
||||
loading = { CircleShimmer() },
|
||||
error = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = TangemTheme.colors2.surface.level3,
|
||||
shape = CircleShape,
|
||||
),
|
||||
)
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Box
|
|||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -27,12 +28,15 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.AsyncImage
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.CircleShimmer
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.haze.hazeForegroundEffectTangem
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.res.LocalIsInDarkTheme
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import dev.chrisbanes.haze.HazeStyle
|
||||
|
||||
|
|
@ -117,6 +121,7 @@ private fun BoxScope.BackgroundLayer(icon: TangemIconUM, blurRadius: Dp = 26.dp)
|
|||
is TangemIconUM.Icon -> SolidColorBackground(icon.tintReference(), blurRadius)
|
||||
is TangemIconUM.Ident -> Unit
|
||||
is TangemIconUM.Image -> ResBackground(icon.imageRes, blurRadius)
|
||||
is TangemIconUM.Url -> UrlColorBackground(icon.url, blurRadius)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -213,6 +218,31 @@ private fun BoxScope.SolidColorBackground(color: Color, blurRadius: Dp) {
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.UrlColorBackground(url: String, blurRadius: Dp) {
|
||||
SubcomposeAsyncImage(
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.hazeForegroundEffectTangem(style = HazeStyle(blurRadius = blurRadius, tint = null)),
|
||||
model = ImageRequest.Builder(context = LocalContext.current)
|
||||
.data(url)
|
||||
.crossfade(enable = true)
|
||||
.allowHardware(enable = false)
|
||||
.build(),
|
||||
loading = { CircleShimmer() },
|
||||
error = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = TangemTheme.colors2.surface.level3,
|
||||
shape = CircleShape,
|
||||
),
|
||||
)
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
private const val SCALE_FACTOR = 1.5f
|
||||
private const val INNER_SHADOW_COLOR_START = 0x00000000
|
||||
private const val INNER_SHADOW_COLOR_END = 0xFFFFFFFF
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import androidx.compose.ui.res.vectorResource
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.ds.badge.*
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds.row.token.TangemTokenRowUM
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -81,7 +82,7 @@ internal fun TokenRowPromoBanner(promoBannerUM: TangemTokenRowUM.PromoBannerUM.C
|
|||
shape = TangemBadgeShape.Rounded,
|
||||
color = TangemBadgeColor.Green,
|
||||
type = TangemBadgeType.Tinted,
|
||||
iconRes = R.drawable.ic_close_24,
|
||||
tangemIconUM = TangemIconUM.Icon(R.drawable.ic_close_24),
|
||||
iconPosition = TangemBadgeIconPosition.None,
|
||||
onClick = promoBannerUM.onCloseClick,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ fun TangemTab(
|
|||
val backgroundColor = if (isChecked) {
|
||||
TangemTheme.colors2.tabs.backgroundPrimary
|
||||
} else {
|
||||
TangemTheme.colors2.tabs.textPrimary
|
||||
TangemTheme.colors2.tabs.backgroundSecondary
|
||||
}
|
||||
val textColor = if (isChecked) {
|
||||
TangemTheme.colors2.tabs.textPrimary
|
||||
|
|
|
|||
9
core/ui/src/main/res/drawable/ic_arrow_back_28.xml
Normal file
9
core/ui/src/main/res/drawable/ic_arrow_back_28.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="28dp"
|
||||
android:height="28dp"
|
||||
android:viewportWidth="28"
|
||||
android:viewportHeight="28">
|
||||
<path
|
||||
android:pathData="M15.631,7.455C16.024,7.067 16.657,7.071 17.045,7.464C17.433,7.857 17.429,8.491 17.036,8.879L11.851,14L17.036,19.122C17.429,19.51 17.433,20.144 17.045,20.537C16.657,20.93 16.024,20.933 15.631,20.545L9.848,14.833C9.384,14.375 9.384,13.626 9.848,13.168L15.631,7.455Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
9
core/ui/src/main/res/drawable/ic_calendar_20.xml
Normal file
9
core/ui/src/main/res/drawable/ic_calendar_20.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M15.417,3C17.118,3 18,3.892 18,5.611V15.389C18,17.1 17.118,18 15.417,18H4.583C2.882,18 2,17.108 2,15.389V5.611C2,3.892 2.882,3 4.583,3H15.417ZM4.559,6.896C3.905,6.897 3.543,7.242 3.543,7.949V15.373C3.543,16.072 3.905,16.425 4.559,16.425H15.425C16.086,16.425 16.457,16.072 16.457,15.373V7.949C16.457,7.242 16.086,6.896 15.425,6.896H4.559ZM6.37,13.638C6.653,13.638 6.748,13.726 6.748,14.015V14.481C6.748,14.77 6.653,14.858 6.37,14.858H5.905C5.63,14.858 5.535,14.77 5.535,14.481V14.015C5.535,13.726 5.63,13.638 5.905,13.638H6.37ZM8.945,13.638C9.228,13.638 9.323,13.726 9.323,14.015V14.481C9.323,14.77 9.228,14.858 8.945,14.858H8.48C8.205,14.858 8.11,14.77 8.11,14.481V14.015C8.11,13.726 8.205,13.638 8.48,13.638H8.945ZM11.519,13.638C11.803,13.638 11.897,13.726 11.898,14.015V14.481C11.897,14.77 11.803,14.858 11.519,14.858H11.064C10.78,14.858 10.685,14.77 10.685,14.481V14.015C10.685,13.726 10.78,13.638 11.064,13.638H11.519ZM6.37,11.051C6.653,11.051 6.748,11.139 6.748,11.428V11.894C6.748,12.183 6.654,12.271 6.37,12.271H5.905C5.63,12.271 5.535,12.183 5.535,11.894V11.428C5.535,11.139 5.63,11.051 5.905,11.051H6.37ZM8.945,11.051C9.228,11.051 9.323,11.139 9.323,11.428V11.894C9.323,12.183 9.228,12.271 8.945,12.271H8.48C8.205,12.271 8.11,12.183 8.11,11.894V11.428C8.11,11.139 8.205,11.051 8.48,11.051H8.945ZM11.519,11.051C11.803,11.051 11.897,11.139 11.898,11.428V11.894C11.898,12.183 11.803,12.271 11.519,12.271H11.064C10.78,12.271 10.685,12.183 10.685,11.894V11.428C10.685,11.139 10.78,11.051 11.064,11.051H11.519ZM14.095,11.051C14.378,11.051 14.473,11.139 14.473,11.428V11.894C14.473,12.183 14.378,12.271 14.095,12.271H13.638C13.354,12.271 13.26,12.183 13.26,11.894V11.428C13.26,11.139 13.354,11.051 13.638,11.051H14.095ZM8.945,8.463C9.228,8.463 9.323,8.552 9.323,8.841V9.307C9.323,9.596 9.228,9.684 8.945,9.685H8.48C8.205,9.685 8.11,9.596 8.11,9.307V8.841C8.11,8.552 8.205,8.463 8.48,8.463H8.945ZM11.519,8.463C11.803,8.463 11.897,8.552 11.898,8.841V9.307C11.898,9.596 11.803,9.685 11.519,9.685H11.064C10.78,9.685 10.685,9.596 10.685,9.307V8.841C10.685,8.552 10.78,8.463 11.064,8.463H11.519ZM14.095,8.463C14.378,8.463 14.473,8.552 14.473,8.841V9.307C14.473,9.596 14.378,9.685 14.095,9.685H13.638C13.354,9.685 13.26,9.596 13.26,9.307V8.841C13.26,8.552 13.354,8.463 13.638,8.463H14.095Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
9
core/ui/src/main/res/drawable/ic_share_new_24.xml
Normal file
9
core/ui/src/main/res/drawable/ic_share_new_24.xml
Normal file
|
|
@ -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="M9.5,10H7.5C6.672,10 6,10.672 6,11.5V18.5C6,19.328 6.672,20 7.5,20H16.5C17.328,20 18,19.328 18,18.5V11.5C18,10.672 17.328,10 16.5,10H14.5V8H16.5C18.433,8 20,9.567 20,11.5V18.5C20,20.433 18.433,22 16.5,22H7.5C5.567,22 4,20.433 4,18.5V11.5C4,9.567 5.567,8 7.5,8H9.5V10ZM11.374,2.225C11.75,1.965 12.249,1.965 12.625,2.225L12.704,2.285L15.641,4.731C16.065,5.085 16.122,5.716 15.769,6.141C15.415,6.565 14.784,6.622 14.359,6.268L13,5.135V14C13,14.552 12.552,15 12,15C11.448,15 11,14.552 11,14V5.135L9.641,6.268C9.216,6.622 8.585,6.565 8.231,6.141C7.878,5.716 7.935,5.085 8.359,4.731L11.296,2.285L11.374,2.225Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
|
|
@ -25,9 +25,7 @@ import com.tangem.features.feed.ui.earn.state.EarnListItemUM
|
|||
|
||||
@Composable
|
||||
internal fun MostlyUsedCard(item: EarnListItemUM, onClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
|
||||
if (isRedesignEnabled) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
MostlyUsedCardV2(
|
||||
modifier = modifier,
|
||||
item = item,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,96 @@
|
|||
package com.tangem.features.feed.ui.feed.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.onFirstVisible
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.HorizontalFadeWithBlur
|
||||
import com.tangem.core.ui.components.block.TangemBlockCardColors
|
||||
import com.tangem.core.ui.components.haze.hazeSourceTangem
|
||||
import com.tangem.core.ui.extensions.conditionalCompose
|
||||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.feed.ui.feed.components.articles.ArticleCard
|
||||
import com.tangem.features.feed.ui.feed.components.articles.ShowMoreArticlesCard
|
||||
import com.tangem.features.feed.ui.feed.state.NewsSliderConfig
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
internal fun NewsSlider(newsSliderConfig: NewsSliderConfig) {
|
||||
val background = LocalMainBottomSheetColor.current.value
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
if (isRedesignEnabled) {
|
||||
NewsSliderV2(newsSliderConfig)
|
||||
} else {
|
||||
NewsSliderV1(newsSliderConfig)
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
LazyRow(
|
||||
modifier = Modifier
|
||||
.conditionalCompose(
|
||||
condition = isRedesignEnabled,
|
||||
modifier = {
|
||||
hazeSourceTangem(-1f)
|
||||
},
|
||||
)
|
||||
.background(color = background),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
state = rememberLazyListState(),
|
||||
) {
|
||||
itemsIndexed(
|
||||
items = newsSliderConfig.content,
|
||||
key = { index, _ -> index },
|
||||
contentType = { _, _ -> "article" },
|
||||
) { index, article ->
|
||||
val articleModifier = if (index == FOURTH_ITEM_INDEX) {
|
||||
Modifier.onFirstVisible(
|
||||
minFractionVisible = 0.5f,
|
||||
callback = newsSliderConfig.callbacks.onSliderScroll,
|
||||
)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
ArticleCard(
|
||||
articleConfigUM = article,
|
||||
onArticleClick = { newsSliderConfig.callbacks.onArticleClick(article.id) },
|
||||
modifier = articleModifier
|
||||
.width(228.dp)
|
||||
.heightIn(min = 172.dp)
|
||||
.fillMaxHeight(),
|
||||
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
|
||||
)
|
||||
}
|
||||
|
||||
if (newsSliderConfig.shouldShowSeeAllNewsItem) {
|
||||
item(contentType = "show_more") {
|
||||
ShowMoreArticlesCard(
|
||||
modifier = Modifier
|
||||
.width(228.dp)
|
||||
.heightIn(min = 172.dp)
|
||||
.onFirstVisible(
|
||||
minFractionVisible = 0.5f,
|
||||
callback = newsSliderConfig.callbacks.onSliderEndReached,
|
||||
),
|
||||
onClick = newsSliderConfig.callbacks.onOpenAllNews,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isRedesignEnabled) {
|
||||
HorizontalFadeWithBlur(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.heightIn(min = 172.dp)
|
||||
.fillMaxHeight()
|
||||
.width(100.dp),
|
||||
backgroundColor = background,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
package com.tangem.features.feed.ui.feed.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.onFirstVisible
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.features.feed.ui.feed.components.articles.ArticleCard
|
||||
import com.tangem.features.feed.ui.feed.components.articles.ShowMoreArticlesCard
|
||||
import com.tangem.core.ui.components.block.TangemBlockCardColors
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.feed.ui.feed.state.NewsSliderConfig
|
||||
|
||||
@Composable
|
||||
internal fun NewsSliderV1(newsSliderConfig: NewsSliderConfig) {
|
||||
LazyRow(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
state = rememberLazyListState(),
|
||||
) {
|
||||
itemsIndexed(
|
||||
items = newsSliderConfig.content,
|
||||
key = { index, _ -> index },
|
||||
contentType = { _, _ -> "article" },
|
||||
) { index, article ->
|
||||
val articleModifier = if (index == FOURTH_ITEM_INDEX) {
|
||||
Modifier.onFirstVisible(
|
||||
minFractionVisible = 0.5f,
|
||||
callback = newsSliderConfig.callbacks.onSliderScroll,
|
||||
)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
ArticleCard(
|
||||
articleConfigUM = article,
|
||||
onArticleClick = { newsSliderConfig.callbacks.onArticleClick(article.id) },
|
||||
modifier = articleModifier
|
||||
.heightIn(min = 164.dp)
|
||||
.width(216.dp),
|
||||
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
|
||||
)
|
||||
}
|
||||
|
||||
if (newsSliderConfig.shouldShowSeeAllNewsItem) {
|
||||
item(contentType = "show_more") {
|
||||
ShowMoreArticlesCard(
|
||||
modifier = Modifier
|
||||
.width(216.dp)
|
||||
.heightIn(min = 164.dp)
|
||||
.onFirstVisible(
|
||||
minFractionVisible = 0.5f,
|
||||
callback = newsSliderConfig.callbacks.onSliderEndReached,
|
||||
),
|
||||
onClick = newsSliderConfig.callbacks.onOpenAllNews,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
package com.tangem.features.feed.ui.feed.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.layout.onFirstVisible
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Constraints
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.features.feed.ui.feed.components.articles.ArticleCard
|
||||
import com.tangem.features.feed.ui.feed.components.articles.ShowMoreArticlesCard
|
||||
import com.tangem.core.ui.extensions.conditional
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.feed.ui.feed.state.NewsSliderConfig
|
||||
|
||||
private val dividerSpacerWidth = 20.dp
|
||||
|
||||
@Suppress("MagicNumber", "LongMethod")
|
||||
@Composable
|
||||
internal fun NewsSliderV2(newsSliderConfig: NewsSliderConfig) {
|
||||
val density = LocalDensity.current
|
||||
val dividerWidthPx = with(density) { 1.dp.roundToPx() }
|
||||
val spacerWidthPx = with(density) { dividerSpacerWidth.roundToPx() }
|
||||
|
||||
LazyRow(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||
state = rememberLazyListState(),
|
||||
) {
|
||||
itemsIndexed(
|
||||
items = newsSliderConfig.content,
|
||||
key = { index, _ -> index },
|
||||
contentType = { _, _ -> "article" },
|
||||
) { index, article ->
|
||||
val articleModifier = Modifier.conditional(
|
||||
condition = index == FOURTH_ITEM_INDEX,
|
||||
modifier = {
|
||||
onFirstVisible(
|
||||
minFractionVisible = 0.5f,
|
||||
callback = newsSliderConfig.callbacks.onSliderScroll,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
val shouldShowDivider = newsSliderConfig.shouldShowSeeAllNewsItem ||
|
||||
index < newsSliderConfig.content.size - 1
|
||||
|
||||
// have to use layout cause LazyRow has not fixed height and divider can not be measured
|
||||
Layout(
|
||||
modifier = Modifier,
|
||||
content = {
|
||||
ArticleCard(
|
||||
articleConfigUM = article,
|
||||
onArticleClick = { newsSliderConfig.callbacks.onArticleClick(article.id) },
|
||||
modifier = articleModifier
|
||||
.fillMaxHeight()
|
||||
.width(220.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(dividerSpacerWidth))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(1.dp)
|
||||
.background(TangemTheme.colors2.border.neutral.secondary),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(dividerSpacerWidth))
|
||||
},
|
||||
) { measurables, constraints ->
|
||||
val cardPlaceable = measurables[0].measure(constraints)
|
||||
val height = cardPlaceable.height
|
||||
|
||||
if (shouldShowDivider) {
|
||||
val leftSpacer = measurables[1].measure(Constraints.fixed(spacerWidthPx, height))
|
||||
val divider = measurables[2].measure(Constraints.fixed(dividerWidthPx, height))
|
||||
val rightSpacer = measurables[3].measure(Constraints.fixed(spacerWidthPx, height))
|
||||
val totalWidth = cardPlaceable.width + leftSpacer.width + divider.width + rightSpacer.width
|
||||
|
||||
layout(totalWidth, height) {
|
||||
cardPlaceable.place(0, 0)
|
||||
leftSpacer.place(cardPlaceable.width, 0)
|
||||
divider.place(cardPlaceable.width + leftSpacer.width, 0)
|
||||
rightSpacer.place(cardPlaceable.width + leftSpacer.width + divider.width, 0)
|
||||
}
|
||||
} else {
|
||||
layout(cardPlaceable.width, height) {
|
||||
cardPlaceable.place(0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newsSliderConfig.shouldShowSeeAllNewsItem) {
|
||||
item(contentType = "show_more") {
|
||||
ShowMoreArticlesCard(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(216.dp)
|
||||
.onFirstVisible(
|
||||
minFractionVisible = 0.5f,
|
||||
callback = newsSliderConfig.callbacks.onSliderEndReached,
|
||||
),
|
||||
onClick = newsSliderConfig.callbacks.onOpenAllNews,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,9 +13,7 @@ fun ArticleCard(
|
|||
modifier: Modifier = Modifier,
|
||||
colors: CardColors = TangemBlockCardColors,
|
||||
) {
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
|
||||
if (isRedesignEnabled) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
ArticleCardV2(
|
||||
articleConfigUM = articleConfigUM,
|
||||
onArticleClick = onArticleClick,
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ internal fun ShowMoreArticlesCardV2(modifier: Modifier = Modifier, onClick: () -
|
|||
.padding(vertical = 41.dp, horizontal = 16.dp),
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier.size(40.dp),
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_show_more_news_48),
|
||||
contentDescription = stringResourceSafe(R.string.common_show_more),
|
||||
)
|
||||
|
|
@ -134,6 +135,8 @@ internal fun ShowMoreArticlesCardV2(modifier: Modifier = Modifier, onClick: () -
|
|||
color = TangemTheme.colors2.text.neutral.primary,
|
||||
)
|
||||
|
||||
SpacerH(4.dp)
|
||||
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.news_stay_in_the_loop),
|
||||
style = TangemTheme.typography2.captionSemibold12,
|
||||
|
|
@ -150,17 +153,27 @@ private fun DefaultArticle(
|
|||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors2.surface.level2)
|
||||
.clickable { onArticleClick() }
|
||||
.padding(vertical = 16.dp, horizontal = 10.dp),
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(color = TangemTheme.colors2.surface.level3)
|
||||
.clickable(onClick = onArticleClick)
|
||||
.border(
|
||||
width = 1.dp,
|
||||
color = TangemTheme.colors2.border.neutral.primary,
|
||||
shape = RoundedCornerShape(20.dp),
|
||||
)
|
||||
.padding(16.dp),
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
RatingInfo(rating = stringReference("${articleConfigUM.score}"))
|
||||
RatingInfo(
|
||||
rating = stringReference("${articleConfigUM.score}"),
|
||||
isTrending = false,
|
||||
)
|
||||
}
|
||||
|
||||
SpacerH(8.dp)
|
||||
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = articleConfigUM.title,
|
||||
color = if (articleConfigUM.isViewed) {
|
||||
TangemTheme.colors2.text.neutral.tertiary
|
||||
|
|
@ -168,13 +181,13 @@ private fun DefaultArticle(
|
|||
TangemTheme.colors2.text.neutral.primary
|
||||
},
|
||||
style = TangemTheme.typography2.bodyRegular16,
|
||||
minLines = 3,
|
||||
maxLines = 3,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
SpacerH(8.dp)
|
||||
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 20.dp),
|
||||
text = articleConfigUM.createdAt.resolveReference(),
|
||||
style = TangemTheme.typography2.captionSemibold12,
|
||||
color = TangemTheme.colors2.text.neutral.secondary,
|
||||
|
|
@ -182,6 +195,8 @@ private fun DefaultArticle(
|
|||
maxLines = 1,
|
||||
)
|
||||
|
||||
SpacerH(8.dp)
|
||||
|
||||
Tags(tags = articleConfigUM.tags.toImmutableList())
|
||||
}
|
||||
}
|
||||
|
|
@ -269,7 +284,7 @@ private fun DayAndRatingInfo(rating: TextReference, modifier: Modifier = Modifie
|
|||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
RatingInfo(rating)
|
||||
RatingInfo(rating = rating, isTrending = true)
|
||||
|
||||
SpacerW(8.dp)
|
||||
|
||||
|
|
@ -282,10 +297,14 @@ private fun DayAndRatingInfo(rating: TextReference, modifier: Modifier = Modifie
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun RatingInfo(rating: TextReference) {
|
||||
private fun RatingInfo(rating: TextReference, isTrending: Boolean) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_wrapped_circle_star_16),
|
||||
tint = TangemTheme.colors2.fill.status.attention,
|
||||
tint = if (isTrending) {
|
||||
TangemTheme.colors2.fill.status.attention
|
||||
} else {
|
||||
TangemTheme.colors2.markers.iconGray
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
|
|
@ -293,7 +312,11 @@ private fun RatingInfo(rating: TextReference) {
|
|||
|
||||
Text(
|
||||
text = rating.resolveReference(),
|
||||
color = TangemTheme.colors2.text.status.attention,
|
||||
color = if (isTrending) {
|
||||
TangemTheme.colors2.text.status.attention
|
||||
} else {
|
||||
TangemTheme.colors2.text.neutral.secondary
|
||||
},
|
||||
style = TangemTheme.typography2.captionSemibold12,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,32 @@
|
|||
package com.tangem.features.feed.ui.feed.components.articles
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.block.BlockCard
|
||||
import com.tangem.core.ui.components.block.TangemBlockCardColors
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
@Composable
|
||||
fun TrendingLoadingArticle(modifier: Modifier = Modifier) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TrendingLoadingArticleV2(modifier)
|
||||
} else {
|
||||
TrendingLoadingArticleV1(modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TrendingLoadingArticleV1(modifier: Modifier = Modifier) {
|
||||
BlockCard(
|
||||
modifier = modifier,
|
||||
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
|
||||
|
|
@ -40,25 +54,167 @@ fun TrendingLoadingArticle(modifier: Modifier = Modifier) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TrendingLoadingArticleV2(modifier: Modifier = Modifier) {
|
||||
BlockCard(
|
||||
modifier = modifier,
|
||||
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors2.surface.level3),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
) {
|
||||
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
|
||||
SpacerH(8.dp)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(24.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
SpacerH(48.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
|
||||
SpacerH(12.dp)
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 58.dp, height = 24.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 58.dp, height = 24.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 58.dp, height = 24.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DefaultLoadingArticle(modifier: Modifier = Modifier) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
DefaultLoadingArticleV2(modifier)
|
||||
} else {
|
||||
DefaultLoadingArticleV1(modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DefaultLoadingArticleV1(modifier: Modifier = Modifier) {
|
||||
BlockCard(
|
||||
modifier = modifier,
|
||||
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
|
||||
) {
|
||||
Column(modifier = Modifier.padding(12.dp)) {
|
||||
RectangleShimmer(modifier = Modifier.size(width = 110.dp, height = 16.dp), radius = 4.dp)
|
||||
SpacerH(12.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 142.dp, height = 18.dp), radius = 4.dp)
|
||||
SpacerH(6.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 176.dp, height = 18.dp), radius = 4.dp)
|
||||
SpacerH(6.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 120.dp, height = 18.dp), radius = 4.dp)
|
||||
SpacerH(16.dp)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
) {
|
||||
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
|
||||
SpacerH(8.dp)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
SpacerH(28.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
|
||||
SpacerH(8.dp)
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
RectangleShimmer(modifier = Modifier.size(width = 72.dp, height = 24.dp), radius = 8.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 72.dp, height = 24.dp), radius = 8.dp)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 72.dp, height = 24.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 62.dp, height = 24.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 32.dp, height = 24.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DefaultLoadingArticleV2(modifier: Modifier = Modifier) {
|
||||
BlockCard(
|
||||
modifier = modifier,
|
||||
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors2.surface.level3),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
) {
|
||||
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
|
||||
SpacerH(8.dp)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
SpacerH(44.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(width = 46.dp, height = 16.dp), radius = TangemTheme.dimens2.x25)
|
||||
SpacerH(12.dp)
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 72.dp, height = 24.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 62.dp, height = 24.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 32.dp, height = 24.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TrendingLoadingArticlePreviewV1() {
|
||||
TangemThemePreview {
|
||||
TrendingLoadingArticle()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun TrendingLoadingArticlePreviewV2() {
|
||||
TangemThemePreviewRedesign {
|
||||
TrendingLoadingArticle()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun DefaultLoadingArticlePreviewV1() {
|
||||
TangemThemePreview {
|
||||
DefaultLoadingArticle()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun DefaultLoadingArticlePreviewV2() {
|
||||
TangemThemePreviewRedesign {
|
||||
DefaultLoadingArticle()
|
||||
}
|
||||
}
|
||||
|
|
@ -8,8 +8,12 @@ import androidx.compose.ui.layout.SubcomposeMeasureScope
|
|||
import androidx.compose.ui.unit.Constraints
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.label.Label
|
||||
import com.tangem.core.ui.components.label.entity.LabelLeadingContentUM
|
||||
import com.tangem.core.ui.components.label.entity.LabelUM
|
||||
import com.tangem.core.ui.ds.badge.*
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.utils.StringsSigns
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
|
|
@ -31,7 +35,25 @@ internal fun Tags(tags: ImmutableList<LabelUM>, modifier: Modifier = Modifier) {
|
|||
|
||||
val tagPlaceables = subcompose(ContentSlot.Tags) {
|
||||
tags.forEach { tag ->
|
||||
Label(state = tag)
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TangemBadge(
|
||||
text = tag.text,
|
||||
tangemIconUM = when (val content = tag.leadingContent) {
|
||||
LabelLeadingContentUM.None -> null
|
||||
is LabelLeadingContentUM.Token -> TangemIconUM.Url(content.iconUrl)
|
||||
},
|
||||
shape = TangemBadgeShape.Rounded,
|
||||
size = TangemBadgeSize.X6,
|
||||
type = TangemBadgeType.Tinted,
|
||||
color = TangemBadgeColor.Gray,
|
||||
iconPosition = when (tag.leadingContent) {
|
||||
LabelLeadingContentUM.None -> TangemBadgeIconPosition.None
|
||||
is LabelLeadingContentUM.Token -> TangemBadgeIconPosition.Start
|
||||
},
|
||||
)
|
||||
} else {
|
||||
Label(state = tag)
|
||||
}
|
||||
}
|
||||
}.map { it.measure(constraints) }
|
||||
|
||||
|
|
@ -108,12 +130,22 @@ private fun SubcomposeMeasureScope.calculateLayoutInfo(
|
|||
|
||||
@Composable
|
||||
private fun OverflowLabel(count: Int) {
|
||||
Label(
|
||||
state = LabelUM(
|
||||
if (LocalRedesignEnabled.current) {
|
||||
TangemBadge(
|
||||
text = TextReference.Str("${StringsSigns.PLUS}$count"),
|
||||
maxLines = 1,
|
||||
),
|
||||
)
|
||||
shape = TangemBadgeShape.Rounded,
|
||||
size = TangemBadgeSize.X6,
|
||||
type = TangemBadgeType.Tinted,
|
||||
color = TangemBadgeColor.Gray,
|
||||
)
|
||||
} else {
|
||||
Label(
|
||||
state = LabelUM(
|
||||
text = TextReference.Str("${StringsSigns.PLUS}$count"),
|
||||
maxLines = 1,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateRowWidth(placeables: List<Placeable>, spacingPx: Int): Int {
|
||||
|
|
|
|||
|
|
@ -1,23 +1,45 @@
|
|||
package com.tangem.features.feed.ui.news.details.components
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
|
||||
@Composable
|
||||
fun NewsDetailsPlaceholder(background: Color, modifier: Modifier = Modifier) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
NewsDetailsPlaceholderV2(background, modifier)
|
||||
} else {
|
||||
NewsDetailsPlaceholderV1(background, modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun NewsDetailsPlaceholderV1(background: Color, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxSize().background(background).padding(16.dp),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(background)
|
||||
.padding(16.dp),
|
||||
) {
|
||||
RectangleShimmer(modifier = Modifier.size(width = 112.dp, height = 20.dp))
|
||||
SpacerH(8.dp)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.fillMaxWidth().height(28.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(28.dp),
|
||||
)
|
||||
SpacerH(4.dp)
|
||||
RectangleShimmer(modifier = Modifier.size(height = 28.dp, width = 208.dp))
|
||||
|
|
@ -29,29 +51,178 @@ fun NewsDetailsPlaceholder(background: Color, modifier: Modifier = Modifier) {
|
|||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.fillMaxWidth().height(20.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp),
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 30.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.padding(end = 30.dp),
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 30.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.padding(end = 30.dp),
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 24.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.padding(end = 24.dp),
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 70.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.padding(end = 70.dp),
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 30.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.padding(end = 30.dp),
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 96.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.padding(end = 96.dp),
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.fillMaxWidth().height(20.dp).padding(end = 100.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.padding(end = 100.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun NewsDetailsPlaceholderV2(background: Color, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(background)
|
||||
.padding(16.dp),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.height(50.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(30.dp),
|
||||
) {
|
||||
Column {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 50.dp, height = 20.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
SpacerH(10.dp)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 90.dp, height = 18.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
}
|
||||
|
||||
VerticalDivider(color = TangemTheme.colors2.border.neutral.primary)
|
||||
|
||||
Column {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 50.dp, height = 20.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
SpacerH(10.dp)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 90.dp, height = 18.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SpacerH(36.dp)
|
||||
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(40.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
|
||||
SpacerH(12.dp)
|
||||
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(40.dp)
|
||||
.padding(end = 106.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
|
||||
SpacerH(36.dp)
|
||||
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 98.dp, height = 36.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier.size(width = 98.dp, height = 36.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
}
|
||||
|
||||
SpacerH(20.dp)
|
||||
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.padding(end = 22.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
SpacerH(12.dp)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.padding(end = 66.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
SpacerH(12.dp)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.padding(end = 18.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
SpacerH(12.dp)
|
||||
RectangleShimmer(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.padding(end = 46.dp),
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun NewsDetailsPlaceholderPreviewV1() {
|
||||
TangemThemePreview {
|
||||
NewsDetailsPlaceholder(background = TangemTheme.colors.background.tertiary)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun NewsDetailsPlaceholderPreviewV2() {
|
||||
TangemThemePreviewRedesign {
|
||||
NewsDetailsPlaceholder(background = TangemTheme.colors2.surface.level3)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
package com.tangem.features.feed.ui.news.details.components
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withStyle
|
||||
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.SpacerW
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
internal fun QuickRecap(content: String, modifier: Modifier = Modifier) {
|
||||
if (LocalRedesignEnabled.current) {
|
||||
QuickRecapV2(content, modifier)
|
||||
} else {
|
||||
QuickRecapV1(content, modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun QuickRecapV1(content: String, modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier.height(IntrinsicSize.Min),
|
||||
) {
|
||||
VerticalDivider(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(start = 8.dp),
|
||||
thickness = 2.dp,
|
||||
color = TangemTheme.colors.stroke.primary,
|
||||
)
|
||||
Column(modifier = Modifier.padding(start = 20.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_quick_recap_16),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
modifier = Modifier.size(20.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = stringResourceSafe(R.string.news_quick_recap),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Text(
|
||||
text = content,
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun QuickRecapV2(content: String, modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier.height(IntrinsicSize.Min)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_stars_20),
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
SpacerW(2.dp)
|
||||
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
withStyle(
|
||||
SpanStyle().copy(
|
||||
brush = Brush.linearGradient(
|
||||
GRADIENT_START to Color(LINEAR_GRADIENT_FIRST_PART),
|
||||
GRADIENT_END to Color(LINEAR_GRADIENT_SECOND_PART),
|
||||
),
|
||||
),
|
||||
) {
|
||||
append(stringResourceSafe(R.string.news_quick_recap))
|
||||
}
|
||||
},
|
||||
style = TangemTheme.typography2.bodyRegular14,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
|
||||
SpacerH(10.dp)
|
||||
|
||||
Box {
|
||||
VerticalDivider(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
thickness = 2.dp,
|
||||
color = Color(QUICK_RECAP_DIVIDER_COLOR),
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
text = content,
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val QUICK_RECAP_DIVIDER_COLOR = 0xFFA99FFF
|
||||
private const val LINEAR_GRADIENT_FIRST_PART = 0xFFA3A0FF
|
||||
private const val LINEAR_GRADIENT_SECOND_PART = 0xFFF79DFF
|
||||
private const val GRADIENT_START = 0f
|
||||
private const val GRADIENT_END = 0.5f
|
||||
|
|
@ -17,8 +17,10 @@ import com.tangem.core.ui.components.SpacerH
|
|||
import com.tangem.core.ui.components.chip.Chip
|
||||
import com.tangem.core.ui.components.chip.entity.ChipUM
|
||||
import com.tangem.core.ui.components.label.entity.LabelUM
|
||||
import com.tangem.core.ui.ds.tabs.TangemTab
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.res.LocalMainBottomSheetColor
|
||||
import com.tangem.core.ui.res.LocalRedesignEnabled
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.feed.ui.news.list.components.NewsListLazyColumn
|
||||
import com.tangem.features.feed.ui.news.list.state.NewsListState
|
||||
|
|
@ -29,6 +31,7 @@ import kotlinx.collections.immutable.toImmutableSet
|
|||
@Composable
|
||||
internal fun NewsListContent(state: NewsListUM, modifier: Modifier = Modifier) {
|
||||
val background = LocalMainBottomSheetColor.current.value
|
||||
val isRedesignEnabled = LocalRedesignEnabled.current
|
||||
val lazyListState = rememberLazyListState()
|
||||
|
||||
Column(
|
||||
|
|
@ -44,7 +47,17 @@ internal fun NewsListContent(state: NewsListUM, modifier: Modifier = Modifier) {
|
|||
items = state.filters,
|
||||
key = { it.id },
|
||||
) { filter ->
|
||||
Chip(state = filter)
|
||||
if (isRedesignEnabled) {
|
||||
TangemTab(
|
||||
text = filter.text,
|
||||
isChecked = filter.isSelected,
|
||||
onCheckedChange = {
|
||||
filter.onClick()
|
||||
},
|
||||
)
|
||||
} else {
|
||||
Chip(state = filter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,9 @@ private fun Content(
|
|||
key = ArticleConfigUM::id,
|
||||
) { article ->
|
||||
ArticleCard(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = Modifier
|
||||
.heightIn(min = 152.dp)
|
||||
.fillMaxWidth(),
|
||||
colors = TangemBlockCardColors.copy(containerColor = TangemTheme.colors.background.action),
|
||||
articleConfigUM = article,
|
||||
onArticleClick = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue