Updated on 2026-08-14
This commit is contained in:
parent
229dc89bcb
commit
3398db66e2
13 changed files with 609 additions and 156 deletions
|
|
@ -14,7 +14,8 @@ import androidx.compose.ui.util.fastForEach
|
|||
import androidx.paging.compose.LazyPagingItems
|
||||
import androidx.paging.compose.itemContentType
|
||||
import androidx.paging.compose.itemKey
|
||||
import com.tangem.core.ui.components.transactions.empty.EmptyTransactionBlock
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.transactions.empty.EmptyTransactionBlockLegacy
|
||||
import com.tangem.core.ui.components.transactions.empty.EmptyTransactionsBlockState
|
||||
import com.tangem.core.ui.components.transactions.state.TransactionState
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
|
|
@ -45,13 +46,21 @@ fun LazyListScope.txHistoryItems(
|
|||
)
|
||||
}
|
||||
is TxHistoryState.Empty -> {
|
||||
nonContentItem(state = EmptyTransactionsBlockState.Empty(state.onExploreClick), modifier = modifier)
|
||||
nonContentItem(
|
||||
state = EmptyTransactionsBlockState.Empty(
|
||||
onExplore = state.onExploreClick,
|
||||
exploreIconResId = R.drawable.ic_arrow_top_right_24,
|
||||
),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
is TxHistoryState.Error -> {
|
||||
nonContentItem(
|
||||
state = EmptyTransactionsBlockState.FailedToLoad(
|
||||
onReload = state.onReloadClick,
|
||||
onExplore = state.onExploreClick,
|
||||
reloadIconResId = R.drawable.ic_refresh_24,
|
||||
exploreIconResId = R.drawable.ic_arrow_top_right_24,
|
||||
),
|
||||
modifier = modifier,
|
||||
)
|
||||
|
|
@ -64,7 +73,10 @@ fun LazyListScope.txHistoryItems(
|
|||
}
|
||||
|
||||
nonContentItem(
|
||||
state = EmptyTransactionsBlockState.NotImplemented(onExplore = state.onExploreClick),
|
||||
state = EmptyTransactionsBlockState.NotImplemented(
|
||||
onExplore = state.onExploreClick,
|
||||
exploreIconResId = R.drawable.ic_arrow_top_right_24,
|
||||
),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
@ -121,7 +133,7 @@ fun PendingTxsBlock(pendingTxs: ImmutableList<TransactionState>, isBalanceHidden
|
|||
|
||||
private fun LazyListScope.nonContentItem(state: EmptyTransactionsBlockState, modifier: Modifier = Modifier) {
|
||||
item(key = state::class.java, contentType = state::class.java) {
|
||||
EmptyTransactionBlock(
|
||||
EmptyTransactionBlockLegacy(
|
||||
state = state,
|
||||
modifier = modifier
|
||||
.animateItem(fadeInSpec = null, fadeOutSpec = null)
|
||||
|
|
|
|||
|
|
@ -1,65 +1,74 @@
|
|||
package com.tangem.core.ui.components.transactions.empty
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButton
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.ds.button.TangemButton
|
||||
import com.tangem.core.ui.ds.button.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.ds.button.TangemButtonShape
|
||||
import com.tangem.core.ui.ds.button.TangemButtonSize
|
||||
import com.tangem.core.ui.ds.button.TangemButtonType
|
||||
import com.tangem.core.ui.ds.button.TangemButtonUM
|
||||
import com.tangem.core.ui.ds.image.TangemIcon
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.core.ui.test.EmptyTransactionBlockTestTags
|
||||
|
||||
/**
|
||||
* Placeholder for transaction's block without content
|
||||
*
|
||||
* @param state component state
|
||||
* @param modifier modifier
|
||||
*/
|
||||
@Composable
|
||||
fun EmptyTransactionBlock(state: EmptyTransactionsBlockState, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(color = TangemTheme.colors.background.primary)
|
||||
.padding(vertical = TangemTheme.dimens.spacing24)
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = TangemTheme.dimens2.x6)
|
||||
.testTag(EmptyTransactionBlockTestTags.BLOCK),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing24),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
TangemIcon(
|
||||
tangemIconUM = TangemIconUM.Icon(
|
||||
iconRes = state.iconRes,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.tertiary },
|
||||
),
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size64)
|
||||
.size(TangemTheme.dimens2.x16)
|
||||
.testTag(EmptyTransactionBlockTestTags.ICON),
|
||||
painter = painterResource(id = state.iconRes),
|
||||
tint = TangemTheme.colors.icon.inactive,
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(TangemTheme.dimens2.x4))
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing32)
|
||||
.padding(horizontal = TangemTheme.dimens2.x8)
|
||||
.testTag(EmptyTransactionBlockTestTags.TEXT),
|
||||
textAlign = TextAlign.Center,
|
||||
text = state.text.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography2.calloutRegular15,
|
||||
color = TangemTheme.colors2.text.neutral.tertiary,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(TangemTheme.dimens2.x8))
|
||||
|
||||
Buttons(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing18)
|
||||
.padding(horizontal = TangemTheme.dimens2.x4)
|
||||
.testTag(EmptyTransactionBlockTestTags.EXPLORE_BUTTON),
|
||||
state = state.buttonsState,
|
||||
)
|
||||
|
|
@ -76,41 +85,70 @@ private fun Buttons(state: EmptyTransactionsBlockState.ButtonsState, modifier: M
|
|||
|
||||
@Composable
|
||||
private fun SingleButton(state: EmptyTransactionsBlockState.ButtonsState.SingleButton, modifier: Modifier = Modifier) {
|
||||
ActionButton(modifier = modifier, config = state.actionButtonConfig)
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
TangemButton(buttonUM = state.actionButtonConfig.toButtonUM())
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PairButtons(state: EmptyTransactionsBlockState.ButtonsState.PairButtons, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens2.x2),
|
||||
) {
|
||||
ActionButton(
|
||||
TangemButton(
|
||||
modifier = Modifier.weight(1F),
|
||||
config = state.firstButtonConfig,
|
||||
buttonUM = state.firstButtonConfig.toButtonUM(),
|
||||
)
|
||||
ActionButton(
|
||||
TangemButton(
|
||||
modifier = Modifier.weight(1F),
|
||||
config = state.secondButtonConfig,
|
||||
buttonUM = state.secondButtonConfig.toButtonUM(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ActionButtonConfig.toButtonUM(): TangemButtonUM = TangemButtonUM(
|
||||
text = text,
|
||||
tangemIconUM = TangemIconUM.Icon(iconRes = iconResId),
|
||||
type = TangemButtonType.Secondary,
|
||||
size = TangemButtonSize.X12,
|
||||
isEnabled = isEnabled,
|
||||
isLoading = isInProgress,
|
||||
onClick = onClick,
|
||||
shape = TangemButtonShape.Rounded,
|
||||
iconPosition = TangemButtonIconPosition.End,
|
||||
)
|
||||
|
||||
@Composable
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun EmptyTransactionBlockPreview(
|
||||
@PreviewParameter(EmptyTransactionBlockStateProvider::class) state: EmptyTransactionsBlockState,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
TangemThemePreviewRedesign {
|
||||
EmptyTransactionBlock(state = state)
|
||||
}
|
||||
}
|
||||
|
||||
private class EmptyTransactionBlockStateProvider : CollectionPreviewParameterProvider<EmptyTransactionsBlockState>(
|
||||
collection = listOf(
|
||||
EmptyTransactionsBlockState.Empty {},
|
||||
EmptyTransactionsBlockState.FailedToLoad(onReload = {}, onExplore = {}),
|
||||
EmptyTransactionsBlockState.NotImplemented(onExplore = {}),
|
||||
),
|
||||
)
|
||||
private class EmptyTransactionBlockStateProvider :
|
||||
CollectionPreviewParameterProvider<EmptyTransactionsBlockState>(
|
||||
collection = listOf(
|
||||
EmptyTransactionsBlockState.Empty(
|
||||
onExplore = {},
|
||||
exploreIconResId = R.drawable.ic_compass_24,
|
||||
),
|
||||
EmptyTransactionsBlockState.FailedToLoad(
|
||||
onReload = {},
|
||||
onExplore = {},
|
||||
reloadIconResId = R.drawable.ic_refresh_24,
|
||||
exploreIconResId = R.drawable.ic_compass_24,
|
||||
),
|
||||
EmptyTransactionsBlockState.NotImplemented(
|
||||
onExplore = {},
|
||||
exploreIconResId = R.drawable.ic_compass_24,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package com.tangem.core.ui.components.transactions.empty
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
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.draw.clip
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButton
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.test.EmptyTransactionBlockTestTags
|
||||
|
||||
/**
|
||||
* Placeholder for transaction's block without content
|
||||
*
|
||||
* @param state component state
|
||||
* @param modifier modifier
|
||||
*/
|
||||
@Composable
|
||||
fun EmptyTransactionBlockLegacy(state: EmptyTransactionsBlockState, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(color = TangemTheme.colors.background.primary)
|
||||
.padding(vertical = TangemTheme.dimens.spacing24)
|
||||
.testTag(EmptyTransactionBlockTestTags.BLOCK),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing24),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size64)
|
||||
.testTag(EmptyTransactionBlockTestTags.ICON),
|
||||
painter = painterResource(id = state.iconRes),
|
||||
tint = TangemTheme.colors.icon.inactive,
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing32)
|
||||
.testTag(EmptyTransactionBlockTestTags.TEXT),
|
||||
textAlign = TextAlign.Center,
|
||||
text = state.text.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
|
||||
Buttons(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing18)
|
||||
.testTag(EmptyTransactionBlockTestTags.EXPLORE_BUTTON),
|
||||
state = state.buttonsState,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Buttons(state: EmptyTransactionsBlockState.ButtonsState, modifier: Modifier = Modifier) {
|
||||
when (state) {
|
||||
is EmptyTransactionsBlockState.ButtonsState.SingleButton -> SingleButton(state = state, modifier = modifier)
|
||||
is EmptyTransactionsBlockState.ButtonsState.PairButtons -> PairButtons(state = state, modifier = modifier)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SingleButton(state: EmptyTransactionsBlockState.ButtonsState.SingleButton, modifier: Modifier = Modifier) {
|
||||
ActionButton(modifier = modifier, config = state.actionButtonConfig)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PairButtons(state: EmptyTransactionsBlockState.ButtonsState.PairButtons, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
ActionButton(
|
||||
modifier = Modifier.weight(1F),
|
||||
config = state.firstButtonConfig,
|
||||
)
|
||||
ActionButton(
|
||||
modifier = Modifier.weight(1F),
|
||||
config = state.secondButtonConfig,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun EmptyTransactionBlockLegacyPreview(
|
||||
@PreviewParameter(EmptyTransactionBlockLegacyStateProvider::class) state: EmptyTransactionsBlockState,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
EmptyTransactionBlockLegacy(state = state)
|
||||
}
|
||||
}
|
||||
|
||||
private class EmptyTransactionBlockLegacyStateProvider :
|
||||
CollectionPreviewParameterProvider<EmptyTransactionsBlockState>(
|
||||
collection = listOf(
|
||||
EmptyTransactionsBlockState.Empty(
|
||||
onExplore = {},
|
||||
exploreIconResId = R.drawable.ic_arrow_top_right_24,
|
||||
),
|
||||
EmptyTransactionsBlockState.FailedToLoad(
|
||||
onReload = {},
|
||||
onExplore = {},
|
||||
reloadIconResId = R.drawable.ic_refresh_24,
|
||||
exploreIconResId = R.drawable.ic_arrow_top_right_24,
|
||||
),
|
||||
EmptyTransactionsBlockState.NotImplemented(
|
||||
onExplore = {},
|
||||
exploreIconResId = R.drawable.ic_arrow_top_right_24,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.core.ui.components.transactions.empty
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
|
@ -21,17 +22,19 @@ sealed class EmptyTransactionsBlockState(
|
|||
data class FailedToLoad(
|
||||
val onReload: () -> Unit,
|
||||
val onExplore: () -> Unit,
|
||||
@DrawableRes val reloadIconResId: Int,
|
||||
@DrawableRes val exploreIconResId: Int,
|
||||
) : EmptyTransactionsBlockState(
|
||||
buttonsState = ButtonsState.PairButtons(
|
||||
firstButtonConfig = ActionButtonConfig(
|
||||
text = TextReference.Res(R.string.common_reload),
|
||||
iconResId = R.drawable.ic_refresh_24,
|
||||
iconResId = reloadIconResId,
|
||||
onClick = onReload,
|
||||
isEnabled = true,
|
||||
),
|
||||
secondButtonConfig = ActionButtonConfig(
|
||||
text = TextReference.Res(R.string.common_explore),
|
||||
iconResId = R.drawable.ic_arrow_top_right_24,
|
||||
iconResId = exploreIconResId,
|
||||
onClick = onExplore,
|
||||
isEnabled = true,
|
||||
),
|
||||
|
|
@ -40,11 +43,14 @@ sealed class EmptyTransactionsBlockState(
|
|||
text = TextReference.Res(R.string.transaction_history_error_failed_to_load),
|
||||
)
|
||||
|
||||
data class Empty(val onExplore: (() -> Unit)) : EmptyTransactionsBlockState(
|
||||
data class Empty(
|
||||
val onExplore: () -> Unit,
|
||||
@DrawableRes val exploreIconResId: Int,
|
||||
) : EmptyTransactionsBlockState(
|
||||
buttonsState = ButtonsState.SingleButton(
|
||||
actionButtonConfig = ActionButtonConfig(
|
||||
text = TextReference.Res(R.string.common_explore),
|
||||
iconResId = R.drawable.ic_arrow_top_right_24,
|
||||
iconResId = exploreIconResId,
|
||||
onClick = onExplore,
|
||||
isEnabled = true,
|
||||
),
|
||||
|
|
@ -53,11 +59,14 @@ sealed class EmptyTransactionsBlockState(
|
|||
text = TextReference.Res(R.string.transaction_history_empty_transactions),
|
||||
)
|
||||
|
||||
data class NotImplemented(val onExplore: () -> Unit) : EmptyTransactionsBlockState(
|
||||
data class NotImplemented(
|
||||
val onExplore: () -> Unit,
|
||||
@DrawableRes val exploreIconResId: Int,
|
||||
) : EmptyTransactionsBlockState(
|
||||
buttonsState = ButtonsState.SingleButton(
|
||||
actionButtonConfig = ActionButtonConfig(
|
||||
text = TextReference.Res(R.string.common_explore_transaction_history),
|
||||
iconResId = R.drawable.ic_arrow_top_right_24,
|
||||
iconResId = exploreIconResId,
|
||||
onClick = onExplore,
|
||||
isEnabled = true,
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue