Updated on 2026-08-14
This commit is contained in:
parent
da6ee825ab
commit
2f5d6525e2
11 changed files with 362 additions and 15 deletions
|
|
@ -31,10 +31,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
|||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.containers.FooterContainer
|
||||
import com.tangem.core.ui.components.inputrow.InputRowDefault
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -118,7 +115,7 @@ private fun GiveTxPermissionBottomSheetContent(content: GiveTxPermissionBottomSh
|
|||
@Composable
|
||||
private fun ApprovalBottomSheetInfo(data: GiveTxPermissionState.ReadyForRequest) {
|
||||
FooterContainer(
|
||||
footer = stringResource(id = R.string.give_permission_policy_type_footer),
|
||||
footer = resourceReference(R.string.give_permission_policy_type_footer),
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
AmountItem(
|
||||
|
|
@ -130,7 +127,7 @@ private fun ApprovalBottomSheetInfo(data: GiveTxPermissionState.ReadyForRequest)
|
|||
}
|
||||
SpacerH16()
|
||||
FooterContainer(
|
||||
footer = data.footerText.resolveReference(),
|
||||
footer = data.footerText,
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
FeeItem(fee = data.fee)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,228 @@
|
|||
package com.tangem.common.ui.expressStatus
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
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.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressLinkUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressStatusItemState
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressStatusItemUM
|
||||
import com.tangem.common.ui.expressStatus.state.ExpressStatusUM
|
||||
import com.tangem.core.ui.components.SpacerWMax
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Block with express statuses
|
||||
*
|
||||
* @param state ui holder
|
||||
* @param modifier modifier
|
||||
* @see [Figma](https://www.figma.com/design/Vs6SkVsFnUPsSCNwlnVf5U/Android-%E2%80%93-UI?node-id=18459-26521&t=4jox7bfqUiXnm2h1-4)
|
||||
*/
|
||||
@Composable
|
||||
fun ExpressStatusBlock(state: ExpressStatusUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.padding(
|
||||
vertical = TangemTheme.dimens.spacing14,
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.padding(bottom = TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
Text(
|
||||
text = state.title.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
SpacerWMax()
|
||||
AnimatedVisibility(visible = state.link is ExpressLinkUM.Content) {
|
||||
val link = remember(this) { state.link as ExpressLinkUM.Content }
|
||||
Row(
|
||||
modifier = Modifier.clickable { link.onClick() },
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = link.icon),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.spacing16)
|
||||
.padding(end = TangemTheme.dimens.spacing2),
|
||||
)
|
||||
Text(
|
||||
text = link.text.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
state.statuses.forEachIndexed { index, item ->
|
||||
ExpressStatusStep(item, index == state.statuses.lastIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ExpressStatusStep(status: ExpressStatusItemUM, isLast: Boolean) {
|
||||
AnimatedContent(
|
||||
targetState = status,
|
||||
label = "Exchange Step Change Success",
|
||||
transitionSpec = {
|
||||
fadeIn(tween(durationMillis = 220)) togetherWith
|
||||
fadeOut(tween(durationMillis = 220))
|
||||
},
|
||||
) { content ->
|
||||
Row {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
when (content.state) {
|
||||
ExpressStatusItemState.Active -> StepInProgress()
|
||||
ExpressStatusItemState.Default -> StepDefault()
|
||||
ExpressStatusItemState.Done -> Step(
|
||||
iconRes = R.drawable.ic_check_24,
|
||||
iconColor = TangemTheme.colors.icon.primary1,
|
||||
borderColor = TangemTheme.colors.field.focused,
|
||||
)
|
||||
ExpressStatusItemState.Error -> Step(
|
||||
iconRes = R.drawable.ic_close_24,
|
||||
iconColor = TangemTheme.colors.icon.warning,
|
||||
)
|
||||
ExpressStatusItemState.Warning -> Step(
|
||||
iconRes = R.drawable.ic_close_24,
|
||||
iconColor = TangemTheme.colors.icon.attention,
|
||||
)
|
||||
}
|
||||
if (!isLast) {
|
||||
StepSeparator()
|
||||
}
|
||||
}
|
||||
val textColor = when (status.state) {
|
||||
ExpressStatusItemState.Active -> TangemTheme.colors.text.primary1
|
||||
ExpressStatusItemState.Default -> TangemTheme.colors.text.disabled
|
||||
ExpressStatusItemState.Done -> TangemTheme.colors.text.primary1
|
||||
ExpressStatusItemState.Error -> TangemTheme.colors.text.warning
|
||||
ExpressStatusItemState.Warning -> TangemTheme.colors.text.attention
|
||||
}
|
||||
Text(
|
||||
text = content.text.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = textColor,
|
||||
modifier = Modifier
|
||||
.padding(start = TangemTheme.dimens.spacing12),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StepDefault() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size20)
|
||||
.border(
|
||||
width = TangemTheme.dimens.size1_5,
|
||||
color = TangemTheme.colors.field.focused,
|
||||
shape = CircleShape,
|
||||
)
|
||||
.padding(TangemTheme.dimens.spacing2),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Step(iconColor: Color, @DrawableRes iconRes: Int, borderColor: Color = iconColor) {
|
||||
Icon(
|
||||
painter = painterResource(id = iconRes),
|
||||
contentDescription = null,
|
||||
tint = iconColor,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size20)
|
||||
.border(
|
||||
width = TangemTheme.dimens.size1_5,
|
||||
color = borderColor,
|
||||
shape = CircleShape,
|
||||
)
|
||||
.padding(TangemTheme.dimens.spacing2),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StepInProgress() {
|
||||
CircularProgressIndicator(
|
||||
color = TangemTheme.colors.icon.primary1,
|
||||
strokeWidth = TangemTheme.dimens.size2,
|
||||
modifier = Modifier
|
||||
.padding(TangemTheme.dimens.spacing2)
|
||||
.size(TangemTheme.dimens.size14),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StepSeparator() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(vertical = TangemTheme.dimens.spacing2)
|
||||
.size(
|
||||
width = TangemTheme.dimens.size1_5,
|
||||
height = TangemTheme.dimens.size10,
|
||||
)
|
||||
.background(
|
||||
color = TangemTheme.colors.field.focused,
|
||||
shape = CircleShape,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview_ExchangeStatusBlock() {
|
||||
val state = ExpressStatusUM(
|
||||
title = resourceReference(R.string.express_exchange_status_title),
|
||||
link = ExpressLinkUM.Content(
|
||||
icon = R.drawable.ic_alert_24,
|
||||
text = resourceReference(R.string.common_go_to_provider),
|
||||
onClick = {},
|
||||
),
|
||||
statuses = persistentListOf(
|
||||
ExpressStatusItemUM(text = stringReference("Done"), state = ExpressStatusItemState.Done),
|
||||
ExpressStatusItemUM(text = stringReference("Active"), state = ExpressStatusItemState.Active),
|
||||
ExpressStatusItemUM(text = stringReference("Warning"), state = ExpressStatusItemState.Warning),
|
||||
ExpressStatusItemUM(text = stringReference("Error"), state = ExpressStatusItemState.Error),
|
||||
ExpressStatusItemUM(text = stringReference("Default"), state = ExpressStatusItemState.Default),
|
||||
),
|
||||
)
|
||||
|
||||
TangemThemePreview {
|
||||
ExpressStatusBlock(state = state)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.tangem.common.ui.expressStatus
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.notifications.ExpressNotificationsUM
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
fun ExpressStatusNotificationBlock(state: NotificationUM?) {
|
||||
AnimatedContent(
|
||||
targetState = state,
|
||||
modifier = Modifier.padding(top = 12.dp),
|
||||
label = "Express Status Notification Change",
|
||||
) { notification ->
|
||||
if (notification?.config != null) {
|
||||
Notification(
|
||||
config = notification.config,
|
||||
iconTint = when (state) {
|
||||
is ExpressNotificationsUM.NeedVerification -> TangemTheme.colors.icon.attention
|
||||
is ExpressNotificationsUM.FailedByProvider -> TangemTheme.colors.icon.warning
|
||||
else -> null
|
||||
},
|
||||
containerColor = TangemTheme.colors.background.action,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.tangem.common.ui.expressStatus.state
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
/**
|
||||
* UI data holder for express status block
|
||||
*
|
||||
* @property title block title
|
||||
* @property link provider web link
|
||||
* @property statuses list of possible and active statuses
|
||||
*/
|
||||
data class ExpressStatusUM(
|
||||
val title: TextReference,
|
||||
val link: ExpressLinkUM,
|
||||
val statuses: ImmutableList<ExpressStatusItemUM>,
|
||||
)
|
||||
|
||||
/**
|
||||
* Provider web link for express status block.
|
||||
* [Empty] if no link needed
|
||||
* [Content] if link is provided and displayed
|
||||
*/
|
||||
@Stable
|
||||
sealed class ExpressLinkUM {
|
||||
data object Empty : ExpressLinkUM()
|
||||
data class Content(
|
||||
@DrawableRes val icon: Int,
|
||||
val text: TextReference,
|
||||
val onClick: () -> Unit,
|
||||
) : ExpressLinkUM()
|
||||
}
|
||||
|
||||
/**
|
||||
* Single status item in express status block
|
||||
*/
|
||||
data class ExpressStatusItemUM(
|
||||
val text: TextReference,
|
||||
val state: ExpressStatusItemState,
|
||||
)
|
||||
|
||||
/**
|
||||
* Available status states for express status block
|
||||
*/
|
||||
enum class ExpressStatusItemState {
|
||||
Active,
|
||||
Default,
|
||||
Done,
|
||||
Warning,
|
||||
Error,
|
||||
;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.common.ui.notifications
|
||||
|
||||
import com.tangem.common.ui.R
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
|
||||
object ExpressNotificationsUM {
|
||||
|
||||
data class NeedVerification(val onGoToProviderClick: () -> Unit) : NotificationUM.Warning(
|
||||
title = resourceReference(R.string.express_exchange_notification_verification_title),
|
||||
subtitle = resourceReference(R.string.express_exchange_notification_verification_text),
|
||||
iconResId = R.drawable.ic_alert_triangle_20,
|
||||
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||
text = resourceReference(R.string.common_go_to_provider),
|
||||
onClick = onGoToProviderClick,
|
||||
),
|
||||
)
|
||||
|
||||
data class FailedByProvider(val onGoToProviderClick: () -> Unit) : NotificationUM.Error(
|
||||
title = resourceReference(R.string.express_exchange_notification_failed_title),
|
||||
subtitle = resourceReference(R.string.express_exchange_notification_failed_text),
|
||||
iconResId = R.drawable.ic_alert_circle_24,
|
||||
buttonState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
|
||||
text = resourceReference(R.string.common_go_to_provider),
|
||||
onClick = onGoToProviderClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue