diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 6b09dce789..a04ba073c9 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -160,6 +160,7 @@
Tap the card
Internal error: wallet manager not found
You have updated biometrics, scan your card to enter
+ To begin tracking your crypto assets and transactions, add tokens.
You have completed all of the lessons, and are now eligible to receive your 1INCH tokens
- Complete three lessons and receive %d 1INCH token to your wallet
diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt
index ddba0a20cd..1c60364fa2 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt
@@ -105,11 +105,13 @@ data class TangemDimens internal constructor(
val spacing38: Dp = 38.dp,
val spacing40: Dp = 40.dp,
val spacing44: Dp = 44.dp,
+ val spacing48: Dp = 48.dp,
val spacing50: Dp = 50.dp,
val spacing52: Dp = 52.dp,
val spacing54: Dp = 54.dp,
val spacing56: Dp = 56.dp,
val spacing92: Dp = 92.dp,
+ val spacing96: Dp = 96.dp,
val spacing154: Dp = 154.dp,
// endregion Spacing
)
\ No newline at end of file
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/error/TokenListErrorConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/error/TokenListErrorConverter.kt
index 9c11b12566..53f553015f 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/error/TokenListErrorConverter.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/error/TokenListErrorConverter.kt
@@ -11,7 +11,6 @@ internal class TokenListErrorConverter(
private val inProgressStateConverter: InProgressStateConverter,
) : Converter {
- // TODO: [REDACTED_JIRA]
override fun convert(value: TokenListError): OrganizeTokensState {
return inProgressStateConverter.convertBack(currentState())
}
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/error/TokenListSortingErrorConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/error/TokenListSortingErrorConverter.kt
index fab77e7e34..e738cdada5 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/error/TokenListSortingErrorConverter.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/error/TokenListSortingErrorConverter.kt
@@ -11,7 +11,6 @@ internal class TokenListSortingErrorConverter(
private val inProgressStateConverter: InProgressStateConverter,
) : Converter {
- // TODO: [REDACTED_JIRA]
override fun convert(value: TokenListSortingError): OrganizeTokensState {
return inProgressStateConverter.convertBack(currentState())
}
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletTokensListState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletTokensListState.kt
index cc607f9f17..1209a2da37 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletTokensListState.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletTokensListState.kt
@@ -10,18 +10,26 @@ import kotlinx.collections.immutable.persistentListOf
/**
* Wallet tokens list state
*
- * @property items content items
- * @property onOrganizeTokensClick lambda be invoked when organize tokens button is clicked
- *
[REDACTED_AUTHOR]
*/
-internal sealed class WalletTokensListState(
- open val items: ImmutableList,
- open val onOrganizeTokensClick: (() -> Unit)?,
-) {
+internal sealed class WalletTokensListState {
+
+ /** Empty token list state */
+ object Empty : WalletTokensListState()
+
+ /**
+ * Wallet content token list state
+ *
+ * @property items content items
+ * @property onOrganizeTokensClick lambda be invoked when organize tokens button is clicked
+ */
+ sealed class ContentState(
+ open val items: ImmutableList,
+ open val onOrganizeTokensClick: (() -> Unit)?,
+ ) : WalletTokensListState()
/** Loading content state */
- object Loading : WalletTokensListState(
+ object Loading : ContentState(
items = persistentListOf(
TokensListItemState.Token(state = TokenItemState.Loading(id = FIRST_LOADING_TOKEN_ID)),
TokensListItemState.Token(state = TokenItemState.Loading(id = SECOND_LOADING_TOKEN_ID)),
@@ -38,11 +46,11 @@ internal sealed class WalletTokensListState(
data class Content(
override val items: ImmutableList,
override val onOrganizeTokensClick: (() -> Unit)?,
- ) : WalletTokensListState(items, onOrganizeTokensClick)
+ ) : ContentState(items, onOrganizeTokensClick)
/** Locked content state */
object Locked :
- WalletTokensListState(
+ ContentState(
items = persistentListOf(
TokensListItemState.NetworkGroupTitle(value = TextReference.Res(id = R.string.main_tokens)),
TokensListItemState.Token(state = TokenItemState.Loading(id = LOCKED_TOKEN_ID)),
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt
index db0cee15f1..4bc618e81d 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt
@@ -22,6 +22,7 @@ import com.tangem.feature.wallet.presentation.common.WalletPreviewData
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
+import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletsList
import com.tangem.feature.wallet.presentation.wallet.ui.components.common.*
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.organizeButton
@@ -106,7 +107,10 @@ private fun WalletContent(state: WalletState.ContentState) {
contentItems(state = state, txHistoryItems = txHistoryItems, modifier = movableItemModifier)
if (state is WalletMultiCurrencyState) {
- organizeButton(onClick = state.tokensListState.onOrganizeTokensClick, modifier = itemModifier)
+ val tokensListState = state.tokensListState
+ if (tokensListState is WalletTokensListState.ContentState) {
+ organizeButton(onClick = tokensListState.onOrganizeTokensClick, modifier = itemModifier)
+ }
}
}
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/multicurrency/MultiCurrencyContent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/multicurrency/MultiCurrencyContent.kt
index bf7451e5ec..350cb95ecf 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/multicurrency/MultiCurrencyContent.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/multicurrency/MultiCurrencyContent.kt
@@ -1,11 +1,26 @@
package com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency
import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
import com.tangem.core.ui.decorations.roundedShapeItemDecoration
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
+import kotlinx.collections.immutable.ImmutableList
+
+private const val NON_CONTENT_TOKENS_LIST_KEY = "NON_CONTENT_TOKENS_LIST"
/**
* LazyList extension for [WalletTokensListState]
@@ -15,10 +30,20 @@ import com.tangem.feature.wallet.presentation.wallet.state.components.WalletToke
*
[REDACTED_AUTHOR]
*/
-@OptIn(ExperimentalFoundationApi::class)
internal fun LazyListScope.tokensListItems(state: WalletTokensListState, modifier: Modifier = Modifier) {
+ when (state) {
+ is WalletTokensListState.ContentState -> contentItems(items = state.items, modifier = modifier)
+ WalletTokensListState.Empty -> nonContentItem(modifier = modifier)
+ }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+private fun LazyListScope.contentItems(
+ items: ImmutableList,
+ modifier: Modifier = Modifier,
+) {
itemsIndexed(
- items = state.items,
+ items = items,
key = { _, item ->
when (item) {
is WalletTokensListState.TokensListItemState.NetworkGroupTitle -> item.value.hashCode()
@@ -33,9 +58,40 @@ internal fun LazyListScope.tokensListItems(state: WalletTokensListState, modifie
.animateItemPlacement()
.roundedShapeItemDecoration(
currentIndex = index,
- lastIndex = state.items.lastIndex,
+ lastIndex = items.lastIndex,
),
)
},
)
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+private fun LazyListScope.nonContentItem(modifier: Modifier = Modifier) {
+ item(
+ key = NON_CONTENT_TOKENS_LIST_KEY,
+ contentType = NON_CONTENT_TOKENS_LIST_KEY,
+ ) {
+ Column(
+ modifier = modifier
+ .animateItemPlacement()
+ .padding(top = TangemTheme.dimens.spacing96),
+ verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing16),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_empty_64),
+ contentDescription = null,
+ modifier = Modifier.size(size = TangemTheme.dimens.size64),
+ tint = TangemTheme.colors.icon.inactive,
+ )
+
+ Text(
+ text = stringResource(id = R.string.main_empty_tokens_list_message),
+ modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing48),
+ color = TangemTheme.colors.text.tertiary,
+ textAlign = TextAlign.Center,
+ style = TangemTheme.typography.caption,
+ )
+ }
+ }
}
\ No newline at end of file
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListErrorConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListErrorConverter.kt
index 4d8b4cc1f4..ac32cdb876 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListErrorConverter.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListErrorConverter.kt
@@ -12,7 +12,6 @@ internal class TokenListErrorConverter(
private val currentStateProvider: Provider,
) : Converter {
- // TODO: [REDACTED_JIRA]
override fun convert(value: TokenListError): WalletMultiCurrencyState.Content {
return requireNotNull(currentStateProvider() as? WalletMultiCurrencyState.Content).copy(
tokensListState = WalletTokensListState.Content(items = persistentListOf(), onOrganizeTokensClick = null),
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToContentItemsConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToContentItemsConverter.kt
index d20d628c57..5c8fb261e0 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToContentItemsConverter.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToContentItemsConverter.kt
@@ -27,18 +27,28 @@ internal class TokenListToContentItemsConverter(
)
override fun convert(value: TokenList): WalletTokensListState {
- return WalletTokensListState.Content(
- items = when (value) {
- is TokenList.GroupedByNetwork -> value.mapToMultiCurrencyItems()
- is TokenList.Ungrouped -> value.mapToMultiCurrencyItems()
- is TokenList.NotInitialized -> getLoadingMultiCurrencyTokens()
- },
- onOrganizeTokensClick = if (value.totalFiatBalance is TokenList.FiatBalance.Loaded) {
- clickIntents::onOrganizeTokensClick
- } else {
- null
- },
- )
+ val isEmptyList = when (value) {
+ is TokenList.GroupedByNetwork -> value.groups.isEmpty()
+ is TokenList.NotInitialized -> true
+ is TokenList.Ungrouped -> value.currencies.isEmpty()
+ }
+
+ return if (isEmptyList) {
+ WalletTokensListState.Empty
+ } else {
+ WalletTokensListState.Content(
+ items = when (value) {
+ is TokenList.GroupedByNetwork -> value.mapToMultiCurrencyItems()
+ is TokenList.Ungrouped -> value.mapToMultiCurrencyItems()
+ is TokenList.NotInitialized -> getLoadingMultiCurrencyTokens()
+ },
+ onOrganizeTokensClick = if (value.totalFiatBalance is TokenList.FiatBalance.Loaded) {
+ clickIntents::onOrganizeTokensClick
+ } else {
+ null
+ },
+ )
+ }
}
private fun TokenList.GroupedByNetwork.mapToMultiCurrencyItems(): PersistentList {
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToWalletStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToWalletStateConverter.kt
index 885c12dd52..e4e37d8e7d 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToWalletStateConverter.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToWalletStateConverter.kt
@@ -63,7 +63,9 @@ internal class TokenListToWalletStateConverter(
}
private fun WalletState.getRefreshingStatus(): Boolean {
- return if (this is WalletMultiCurrencyState.Content) {
+ return if (this is WalletMultiCurrencyState.Content &&
+ this.tokensListState is WalletTokensListState.ContentState
+ ) {
tokensListState.items.any { tokensListItemState ->
tokensListItemState is WalletTokensListState.TokensListItemState.Token &&
tokensListItemState.state is TokenItemState.Loading
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt
index 18bfbbbe34..11beecade5 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt
@@ -118,7 +118,9 @@ internal class WalletNotificationsListFactory(
}
return currentStateProvider().let { state ->
- state is WalletMultiCurrencyState.Content && state.tokensListState.items.any(isUnreachableState)
+ state is WalletMultiCurrencyState.Content &&
+ state.tokensListState is WalletTokensListState.ContentState &&
+ state.tokensListState.items.any(isUnreachableState)
}
}
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt
index 12cdb339a1..f7d4a9fb1b 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt
@@ -352,10 +352,12 @@ internal class WalletViewModel @Inject constructor(
// Check the special components
return when (this) {
is WalletMultiCurrencyState -> {
- tokensListState is WalletTokensListState.Loading ||
- tokensListState.items
+ val hasLoadingTokens = tokensListState is WalletTokensListState.ContentState &&
+ (tokensListState as WalletTokensListState.ContentState).items
.filterIsInstance()
.any { it.state is TokenItemState.Loading }
+
+ tokensListState is WalletTokensListState.Loading || hasLoadingTokens
}
is WalletSingleCurrencyState -> {
txHistoryState is TxHistoryState.Loading || marketPriceBlockState is MarketPriceBlockState.Loading
diff --git a/features/wallet/impl/src/main/res/drawable/ic_empty_64.xml b/features/wallet/impl/src/main/res/drawable/ic_empty_64.xml
new file mode 100644
index 0000000000..090f906247
--- /dev/null
+++ b/features/wallet/impl/src/main/res/drawable/ic_empty_64.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+