Updated on 2026-08-14
This commit is contained in:
parent
1943ed248c
commit
dd186d6fbc
44 changed files with 499 additions and 270 deletions
|
|
@ -12,8 +12,7 @@ import com.tangem.feature.wallet.presentation.organizetokens.DraggableItem
|
|||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensListState
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
|
@ -255,7 +254,7 @@ internal object WalletPreviewData {
|
|||
}
|
||||
|
||||
val multicurrencyWalletScreenState by lazy {
|
||||
WalletStateHolder.MultiCurrencyContent(
|
||||
WalletMultiCurrencyState.Content(
|
||||
onBackClick = {},
|
||||
topBarConfig = walletTopBarConfig,
|
||||
walletsListConfig = walletListConfig,
|
||||
|
|
@ -326,7 +325,7 @@ internal object WalletPreviewData {
|
|||
}
|
||||
|
||||
val singleWalletScreenState by lazy {
|
||||
WalletStateHolder.SingleCurrencyContent(
|
||||
WalletSingleCurrencyState.Content(
|
||||
onBackClick = {},
|
||||
topBarConfig = walletTopBarConfig,
|
||||
walletsListConfig = walletListConfig,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Loading wallet state
|
||||
*
|
||||
* @property onBackClick Lambda be invoked when back button is clicked
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal data class WalletLoading(override val onBackClick: () -> Unit) : WalletStateHolder() {
|
||||
|
||||
override val topBarConfig = WalletTopBarConfig(onScanCardClick = {}, onMoreClick = {})
|
||||
|
||||
override val walletsListConfig = WalletsListConfig(
|
||||
selectedWalletIndex = 0,
|
||||
wallets = persistentListOf(
|
||||
WalletCardState.Loading(
|
||||
id = UserWalletId(stringValue = ""),
|
||||
title = "",
|
||||
additionalInfo = "",
|
||||
imageResId = null,
|
||||
),
|
||||
),
|
||||
onWalletChange = {},
|
||||
)
|
||||
|
||||
override val pullToRefreshConfig = WalletPullToRefreshConfig(isRefreshing = false, onRefresh = {})
|
||||
|
||||
override val notifications: ImmutableList<WalletNotification> = persistentListOf()
|
||||
|
||||
override val bottomSheetConfig = null
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
/**
|
||||
* Locked wallet state
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal sealed interface WalletLockedState {
|
||||
|
||||
/** Lambda be invoked when unlock wallet notification is clicked */
|
||||
val onUnlockWalletsNotificationClick: () -> Unit
|
||||
|
||||
/** Lambda be invoked when unlock wallet button is clicked */
|
||||
val onUnlockClick: () -> Unit
|
||||
|
||||
/** Lambda be invoked when scan button is clicked */
|
||||
val onScanClick: () -> Unit
|
||||
|
||||
/** Bottom sheet visibility */
|
||||
val isBottomSheetShow: Boolean
|
||||
|
||||
/** Lambda be invoked when bottom sheet is dismissed */
|
||||
val onBottomSheetDismiss: () -> Unit
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Multi currency wallet state
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal sealed class WalletMultiCurrencyState : WalletStateHolder() {
|
||||
|
||||
/** Tokens list state */
|
||||
abstract val tokensListState: WalletTokensListState
|
||||
|
||||
data class Content(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val walletsListConfig: WalletsListConfig,
|
||||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
override val notifications: ImmutableList<WalletNotification>,
|
||||
override val bottomSheetConfig: WalletBottomSheetConfig?,
|
||||
override val tokensListState: WalletTokensListState,
|
||||
) : WalletMultiCurrencyState()
|
||||
|
||||
data class Locked(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val walletsListConfig: WalletsListConfig,
|
||||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
override val onUnlockWalletsNotificationClick: () -> Unit,
|
||||
override val onUnlockClick: () -> Unit,
|
||||
override val onScanClick: () -> Unit,
|
||||
override val isBottomSheetShow: Boolean = false,
|
||||
override val onBottomSheetDismiss: () -> Unit = {},
|
||||
) : WalletMultiCurrencyState(), WalletLockedState {
|
||||
|
||||
override val notifications = persistentListOf(
|
||||
WalletNotification.UnlockWallets(onUnlockWalletsNotificationClick),
|
||||
)
|
||||
|
||||
override val bottomSheetConfig = WalletBottomSheetConfig(
|
||||
isShow = isBottomSheetShow,
|
||||
onDismissRequest = onBottomSheetDismiss,
|
||||
content = WalletBottomSheetConfig.BottomSheetContentConfig.UnlockWallets(
|
||||
onUnlockClick = onUnlockClick,
|
||||
onScanClick = onScanClick,
|
||||
),
|
||||
)
|
||||
|
||||
override val tokensListState: WalletTokensListState = WalletTokensListState.Locked
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Single currency wallet content state
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal sealed class WalletSingleCurrencyState : WalletStateHolder() {
|
||||
|
||||
/** Manage buttons */
|
||||
abstract val buttons: ImmutableList<ActionButtonConfig>
|
||||
|
||||
/** Market price block state */
|
||||
abstract val marketPriceBlockState: MarketPriceBlockState?
|
||||
|
||||
/** Transactions history state */
|
||||
abstract val txHistoryState: WalletTxHistoryState
|
||||
|
||||
data class Content(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val walletsListConfig: WalletsListConfig,
|
||||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
override val notifications: ImmutableList<WalletNotification>,
|
||||
override val bottomSheetConfig: WalletBottomSheetConfig?,
|
||||
override val buttons: ImmutableList<ActionButtonConfig>,
|
||||
override val marketPriceBlockState: MarketPriceBlockState,
|
||||
override val txHistoryState: WalletTxHistoryState,
|
||||
) : WalletSingleCurrencyState()
|
||||
|
||||
data class Locked(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val walletsListConfig: WalletsListConfig,
|
||||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
override val buttons: ImmutableList<ActionButtonConfig>,
|
||||
override val onUnlockWalletsNotificationClick: () -> Unit,
|
||||
override val onUnlockClick: () -> Unit,
|
||||
override val onScanClick: () -> Unit,
|
||||
override val isBottomSheetShow: Boolean = false,
|
||||
override val onBottomSheetDismiss: () -> Unit = {},
|
||||
val onExploreClick: () -> Unit,
|
||||
) : WalletSingleCurrencyState(), WalletLockedState {
|
||||
|
||||
override val notifications = persistentListOf(
|
||||
WalletNotification.UnlockWallets(onUnlockWalletsNotificationClick),
|
||||
)
|
||||
|
||||
override val bottomSheetConfig = WalletBottomSheetConfig(
|
||||
isShow = isBottomSheetShow,
|
||||
onDismissRequest = onBottomSheetDismiss,
|
||||
content = WalletBottomSheetConfig.BottomSheetContentConfig.UnlockWallets(
|
||||
onUnlockClick = onUnlockClick,
|
||||
onScanClick = onScanClick,
|
||||
),
|
||||
)
|
||||
|
||||
override val marketPriceBlockState = null
|
||||
|
||||
override val txHistoryState: WalletTxHistoryState = WalletTxHistoryState.Locked(onExploreClick)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +1,32 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletLockedContentState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Wallet screen state holder
|
||||
*
|
||||
* @property onBackClick lambda be invoked when back button is clicked
|
||||
* @property topBarConfig top bar config
|
||||
* @property walletsListConfig wallets list config
|
||||
* @property pullToRefreshConfig pull to refresh config
|
||||
* @property notifications notifications
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal sealed class WalletStateHolder(
|
||||
open val onBackClick: () -> Unit,
|
||||
open val topBarConfig: WalletTopBarConfig,
|
||||
open val walletsListConfig: WalletsListConfig,
|
||||
open val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
open val notifications: ImmutableList<WalletNotification>,
|
||||
open val bottomSheetConfig: WalletBottomSheetConfig? = null,
|
||||
) {
|
||||
internal sealed class WalletStateHolder {
|
||||
|
||||
/** Lambda be invoked when back button is clicked */
|
||||
abstract val onBackClick: () -> Unit
|
||||
|
||||
/** Top bar config */
|
||||
abstract val topBarConfig: WalletTopBarConfig
|
||||
|
||||
/** Wallets list config */
|
||||
abstract val walletsListConfig: WalletsListConfig
|
||||
|
||||
/** Pull to refresh config */
|
||||
abstract val pullToRefreshConfig: WalletPullToRefreshConfig
|
||||
|
||||
/** Notifications */
|
||||
abstract val notifications: ImmutableList<WalletNotification>
|
||||
|
||||
/** Bottom sheet config */
|
||||
abstract val bottomSheetConfig: WalletBottomSheetConfig?
|
||||
|
||||
fun copySealed(
|
||||
onBackClick: () -> Unit = this.onBackClick,
|
||||
|
|
@ -38,151 +37,67 @@ internal sealed class WalletStateHolder(
|
|||
bottomSheet: WalletBottomSheetConfig? = this.bottomSheetConfig,
|
||||
): WalletStateHolder {
|
||||
return when (this) {
|
||||
is MultiCurrencyContent -> this.copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
notifications = notifications,
|
||||
bottomSheetConfig = bottomSheet,
|
||||
)
|
||||
is SingleCurrencyContent -> this.copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
notifications = notifications,
|
||||
bottomSheetConfig = bottomSheet,
|
||||
)
|
||||
is UnlockWalletContent -> this.copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
)
|
||||
is Loading -> copy(onBackClick = onBackClick)
|
||||
is WalletLoading -> {
|
||||
copy(onBackClick = onBackClick)
|
||||
}
|
||||
is WalletMultiCurrencyState.Content -> {
|
||||
copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
notifications = notifications,
|
||||
bottomSheetConfig = bottomSheet,
|
||||
)
|
||||
}
|
||||
is WalletMultiCurrencyState.Locked -> {
|
||||
if (bottomSheet != null) {
|
||||
copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
isBottomSheetShow = bottomSheet.isShow,
|
||||
onBottomSheetDismiss = bottomSheet.onDismissRequest,
|
||||
)
|
||||
} else {
|
||||
copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
)
|
||||
}
|
||||
}
|
||||
is WalletSingleCurrencyState.Content -> {
|
||||
copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
notifications = notifications,
|
||||
bottomSheetConfig = bottomSheet,
|
||||
)
|
||||
}
|
||||
is WalletSingleCurrencyState.Locked -> {
|
||||
if (bottomSheet != null) {
|
||||
copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
isBottomSheetShow = bottomSheet.isShow,
|
||||
onBottomSheetDismiss = bottomSheet.onDismissRequest,
|
||||
)
|
||||
} else {
|
||||
copy(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multi currency wallet content state
|
||||
*
|
||||
* @property onBackClick lambda be invoked when back button is clicked
|
||||
* @property topBarConfig top bar config
|
||||
* @property walletsListConfig wallets list config
|
||||
* @property pullToRefreshConfig pull to refresh config
|
||||
* @property tokensListState token list state
|
||||
* @property notifications notifications
|
||||
*/
|
||||
data class MultiCurrencyContent(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val walletsListConfig: WalletsListConfig,
|
||||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
override val notifications: ImmutableList<WalletNotification>,
|
||||
override val bottomSheetConfig: WalletBottomSheetConfig? = null,
|
||||
val tokensListState: WalletTokensListState,
|
||||
) : WalletStateHolder(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
notifications = notifications,
|
||||
bottomSheetConfig = bottomSheetConfig,
|
||||
)
|
||||
|
||||
/**
|
||||
* Single currency wallet content state
|
||||
*
|
||||
* @property onBackClick lambda be invoked when back button is clicked
|
||||
* @property topBarConfig top bar config
|
||||
* @property walletsListConfig wallets list config
|
||||
* @property pullToRefreshConfig pull to refresh config
|
||||
* @property notifications notifications
|
||||
* @property buttons manage buttons
|
||||
* @property marketPriceBlockState market price block state
|
||||
* @property txHistoryState transactions history state
|
||||
*/
|
||||
data class SingleCurrencyContent(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val walletsListConfig: WalletsListConfig,
|
||||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
override val notifications: ImmutableList<WalletNotification>,
|
||||
override val bottomSheetConfig: WalletBottomSheetConfig? = null,
|
||||
val buttons: ImmutableList<ActionButtonConfig>,
|
||||
val marketPriceBlockState: MarketPriceBlockState,
|
||||
val txHistoryState: WalletTxHistoryState,
|
||||
) : WalletStateHolder(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
notifications = notifications,
|
||||
bottomSheetConfig = bottomSheetConfig,
|
||||
)
|
||||
|
||||
/**
|
||||
* Unlock wallet content state
|
||||
*
|
||||
* @property onBackClick lambda be invoked when back button is clicked
|
||||
* @property topBarConfig top bar config
|
||||
* @property walletsListConfig wallets list config
|
||||
* @property pullToRefreshConfig pull to refresh config
|
||||
* @property lockedContentState locked content state
|
||||
* @property onUnlockWalletsNotificationClick lambda be invoked when unlock wallets notification is clicked
|
||||
* @property onBottomSheetDismissRequest lambda be invoked when bottom sheet is dismissed
|
||||
* @property onUnlockClick lambda be invoked when unlock button is clicked
|
||||
* @property onScanClick lambda be invoked when scan card button is clicked
|
||||
*/
|
||||
data class UnlockWalletContent(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val walletsListConfig: WalletsListConfig,
|
||||
override val pullToRefreshConfig: WalletPullToRefreshConfig,
|
||||
val lockedContentState: WalletLockedContentState,
|
||||
val onUnlockWalletsNotificationClick: () -> Unit,
|
||||
val onBottomSheetDismissRequest: () -> Unit,
|
||||
val onUnlockClick: () -> Unit,
|
||||
val onScanClick: () -> Unit,
|
||||
) : WalletStateHolder(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
pullToRefreshConfig = pullToRefreshConfig,
|
||||
notifications = persistentListOf(WalletNotification.UnlockWallets(onUnlockWalletsNotificationClick)),
|
||||
bottomSheetConfig = WalletBottomSheetConfig(
|
||||
isShow = false,
|
||||
onDismissRequest = onBottomSheetDismissRequest,
|
||||
content = WalletBottomSheetConfig.BottomSheetContentConfig.UnlockWallets(
|
||||
onUnlockClick = onUnlockClick,
|
||||
onScanClick = onScanClick,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
/**
|
||||
* Loading state
|
||||
*
|
||||
* @property onBackClick lambda be invoked when back button is clicked
|
||||
*/
|
||||
data class Loading(override val onBackClick: () -> Unit) : WalletStateHolder(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = WalletTopBarConfig(onScanCardClick = {}, onMoreClick = {}),
|
||||
walletsListConfig = WalletsListConfig(
|
||||
selectedWalletIndex = 0,
|
||||
wallets = persistentListOf(
|
||||
WalletCardState.Loading(
|
||||
id = UserWalletId(stringValue = ""),
|
||||
title = "",
|
||||
additionalInfo = "",
|
||||
imageResId = null,
|
||||
),
|
||||
),
|
||||
onWalletChange = {},
|
||||
),
|
||||
pullToRefreshConfig = WalletPullToRefreshConfig(isRefreshing = false, onRefresh = {}),
|
||||
notifications = persistentListOf(),
|
||||
bottomSheetConfig = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
package com.tangem.feature.wallet.presentation.wallet.state.components
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
package com.tangem.feature.wallet.presentation.wallet.state.components
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.content
|
||||
package com.tangem.feature.wallet.presentation.wallet.state.components
|
||||
|
||||
/**
|
||||
* Wallet locked content state.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
package com.tangem.feature.wallet.presentation.wallet.state.components
|
||||
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
package com.tangem.feature.wallet.presentation.wallet.state.components
|
||||
|
||||
import com.tangem.core.ui.components.notifications.NotificationState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
package com.tangem.feature.wallet.presentation.wallet.state.components
|
||||
|
||||
/**
|
||||
* Wallet screen top bar config
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.content
|
||||
package com.tangem.feature.wallet.presentation.wallet.state.components
|
||||
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
package com.tangem.feature.wallet.presentation.wallet.state.components
|
||||
|
||||
/**
|
||||
* Wallet screen top bar config
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.content
|
||||
package com.tangem.feature.wallet.presentation.wallet.state.components
|
||||
|
||||
import androidx.paging.PagingData
|
||||
import com.tangem.core.ui.components.transactions.TransactionState
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
package com.tangem.feature.wallet.presentation.wallet.state.components
|
||||
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
|
|
@ -24,12 +24,14 @@ import com.tangem.utils.converter.Converter
|
|||
internal class WalletLoadedTokensListConverter(
|
||||
private val currentStateProvider: Provider<WalletStateHolder>,
|
||||
cardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
isLockedWalletProvider: Provider<Boolean>,
|
||||
clickIntents: WalletClickIntents,
|
||||
) : Converter<LoadedTokensListModel, WalletStateHolder> {
|
||||
|
||||
private val tokenListStateConverter = TokenListToWalletStateConverter(
|
||||
currentStateProvider = currentStateProvider,
|
||||
cardTypeResolverProvider = cardTypeResolverProvider,
|
||||
isLockedWalletProvider = isLockedWalletProvider,
|
||||
isWalletContentHidden = false, // TODO: [REDACTED_JIRA]
|
||||
fiatCurrencyCode = "USD", // TODO: [REDACTED_JIRA]
|
||||
fiatCurrencySymbol = "$", // TODO: [REDACTED_JIRA]
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.factory
|
||||
|
||||
import androidx.paging.PagingData
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
|
||||
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.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletSkeletonStateConverter.SkeletonModel
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
|
@ -26,45 +29,59 @@ import kotlinx.coroutines.flow.flow
|
|||
*/
|
||||
internal class WalletSkeletonStateConverter(
|
||||
private val clickIntents: WalletClickIntents,
|
||||
) : Converter<List<UserWallet>, WalletStateHolder> {
|
||||
) : Converter<SkeletonModel, WalletStateHolder> {
|
||||
|
||||
override fun convert(value: List<UserWallet>): WalletStateHolder {
|
||||
val cardTypeResolver = requireNotNull(value.firstOrNull()).scanResponse.cardTypesResolver
|
||||
override fun convert(value: SkeletonModel): WalletStateHolder {
|
||||
val wallet = requireNotNull(value.wallets.getOrNull(value.selectedWalletIndex)) { "Empty wallet list" }
|
||||
val cardTypeResolver = wallet.scanResponse.cardTypesResolver
|
||||
|
||||
return if (cardTypeResolver.isMultiwalletAllowed()) {
|
||||
createMultiCurrencyState(value)
|
||||
} else {
|
||||
createSingleCurrencyState(value, cardTypeResolver)
|
||||
return when {
|
||||
cardTypeResolver.isMultiwalletAllowed() -> createMultiCurrencyState(value)
|
||||
!cardTypeResolver.isMultiwalletAllowed() -> createSingleCurrencyState(value, cardTypeResolver)
|
||||
else -> error("Illegal wallet state: $wallet")
|
||||
}
|
||||
}
|
||||
|
||||
private fun createMultiCurrencyState(wallets: List<UserWallet>): WalletStateHolder.MultiCurrencyContent {
|
||||
return WalletStateHolder.MultiCurrencyContent(
|
||||
/**
|
||||
* Create [WalletMultiCurrencyState.Content].
|
||||
* Tokens and notifications are updated asynchronously.
|
||||
*
|
||||
* @param value converted value
|
||||
*/
|
||||
private fun createMultiCurrencyState(value: SkeletonModel): WalletMultiCurrencyState.Content {
|
||||
return WalletMultiCurrencyState.Content(
|
||||
onBackClick = clickIntents::onBackClick,
|
||||
topBarConfig = createTopBarConfig(),
|
||||
walletsListConfig = createWalletsListConfig(wallets),
|
||||
walletsListConfig = createWalletsListConfig(value),
|
||||
pullToRefreshConfig = createPullToRefreshConfig(),
|
||||
tokensListState = WalletTokensListState.Content(
|
||||
items = persistentListOf(),
|
||||
onOrganizeTokensClick = clickIntents::onOrganizeTokensClick,
|
||||
onOrganizeTokensClick = null,
|
||||
),
|
||||
notifications = persistentListOf(),
|
||||
bottomSheetConfig = null,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create [WalletSingleCurrencyState.Content].
|
||||
* Transactions, notifications and market price are updated asynchronously.
|
||||
*
|
||||
* @param value converted value
|
||||
* @param cardTypeResolver card type resolver
|
||||
*/
|
||||
private fun createSingleCurrencyState(
|
||||
wallets: List<UserWallet>,
|
||||
value: SkeletonModel,
|
||||
cardTypeResolver: CardTypesResolver,
|
||||
): WalletStateHolder.SingleCurrencyContent {
|
||||
return WalletStateHolder.SingleCurrencyContent(
|
||||
): WalletSingleCurrencyState.Content {
|
||||
return WalletSingleCurrencyState.Content(
|
||||
onBackClick = clickIntents::onBackClick,
|
||||
topBarConfig = createTopBarConfig(),
|
||||
walletsListConfig = createWalletsListConfig(wallets),
|
||||
walletsListConfig = createWalletsListConfig(value),
|
||||
pullToRefreshConfig = createPullToRefreshConfig(),
|
||||
notifications = persistentListOf(),
|
||||
bottomSheetConfig = null,
|
||||
buttons = WalletPreviewData.singleWalletScreenState.buttons, // TODO: create buttons
|
||||
buttons = getButtons(),
|
||||
marketPriceBlockState = MarketPriceBlockState.Loading(
|
||||
currencyName = cardTypeResolver.getBlockchain().currency,
|
||||
),
|
||||
|
|
@ -81,10 +98,10 @@ internal class WalletSkeletonStateConverter(
|
|||
)
|
||||
}
|
||||
|
||||
private fun createWalletsListConfig(wallets: List<UserWallet>): WalletsListConfig {
|
||||
private fun createWalletsListConfig(value: SkeletonModel): WalletsListConfig {
|
||||
return WalletsListConfig(
|
||||
selectedWalletIndex = 0,
|
||||
wallets = wallets.map { wallet ->
|
||||
selectedWalletIndex = value.selectedWalletIndex,
|
||||
wallets = value.wallets.map { wallet ->
|
||||
val cardTypeResolver = wallet.scanResponse.cardTypesResolver
|
||||
WalletCardState.Loading(
|
||||
id = wallet.walletId,
|
||||
|
|
@ -103,4 +120,22 @@ internal class WalletSkeletonStateConverter(
|
|||
private fun createPullToRefreshConfig(): WalletPullToRefreshConfig {
|
||||
return WalletPullToRefreshConfig(isRefreshing = false, onRefresh = clickIntents::onRefreshSwipe)
|
||||
}
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
private fun getButtons(): ImmutableList<ActionButtonConfig> {
|
||||
return persistentListOf(
|
||||
WalletManageButton.Buy(onClick = {}),
|
||||
WalletManageButton.Send(onClick = {}),
|
||||
WalletManageButton.Receive(onClick = {}),
|
||||
WalletManageButton.Exchange(onClick = {}),
|
||||
WalletManageButton.CopyAddress(onClick = {}),
|
||||
)
|
||||
.map(WalletManageButton::config)
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
data class SkeletonModel(
|
||||
val wallets: List<UserWallet>,
|
||||
val selectedWalletIndex: Int,
|
||||
)
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state.factory
|
|||
import androidx.paging.PagingData
|
||||
import arrow.core.Either
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
|
|
@ -10,26 +11,34 @@ import com.tangem.domain.txhistory.error.TxHistoryListError
|
|||
import com.tangem.domain.txhistory.error.TxHistoryStateError
|
||||
import com.tangem.domain.txhistory.model.TxHistoryItem
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletBottomSheetConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletLoading
|
||||
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.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBottomSheetConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletLoadedTokensListConverter.LoadedTokensListModel
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory.WalletLoadedTxHistoryConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.factory.txhistory.WalletLoadingTxHistoryConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* Main factory for creating [WalletStateHolder]
|
||||
*
|
||||
* @property currentStateProvider current ui state provider
|
||||
* @param currentCardTypeResolverProvider current card type resolver
|
||||
* @property currentCardTypeResolverProvider current card type resolver
|
||||
* @property isLockedWalletProvider current wallet is locked or not
|
||||
* @property clickIntents screen click intents
|
||||
*/
|
||||
internal class WalletStateFactory(
|
||||
private val currentStateProvider: Provider<WalletStateHolder>,
|
||||
currentCardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
private val currentCardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
private val isLockedWalletProvider: Provider<Boolean>,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
) {
|
||||
|
||||
|
|
@ -39,6 +48,7 @@ internal class WalletStateFactory(
|
|||
WalletLoadedTokensListConverter(
|
||||
currentStateProvider = currentStateProvider,
|
||||
cardTypeResolverProvider = currentCardTypeResolverProvider,
|
||||
isLockedWalletProvider = isLockedWalletProvider,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
}
|
||||
|
|
@ -59,9 +69,13 @@ internal class WalletStateFactory(
|
|||
)
|
||||
}
|
||||
|
||||
fun getInitialState(): WalletStateHolder = WalletStateHolder.Loading(onBackClick = clickIntents::onBackClick)
|
||||
fun getInitialState(): WalletStateHolder = WalletLoading(onBackClick = clickIntents::onBackClick)
|
||||
|
||||
fun getSkeletonState(wallets: List<UserWallet>): WalletStateHolder = skeletonConverter.convert(wallets)
|
||||
fun getSkeletonState(wallets: List<UserWallet>, index: Int): WalletStateHolder {
|
||||
return skeletonConverter.convert(
|
||||
value = WalletSkeletonStateConverter.SkeletonModel(wallets = wallets, selectedWalletIndex = index),
|
||||
)
|
||||
}
|
||||
|
||||
fun getStateByTokensList(
|
||||
tokenListEither: Either<TokenListError, TokenList>,
|
||||
|
|
@ -111,4 +125,45 @@ internal class WalletStateFactory(
|
|||
): WalletStateHolder {
|
||||
return loadedTxHistoryConverter.convert(txHistoryEither)
|
||||
}
|
||||
|
||||
fun getLockedState(): WalletStateHolder {
|
||||
val cardTypeResolver = currentCardTypeResolverProvider()
|
||||
val state = currentStateProvider()
|
||||
return if (cardTypeResolver.isMultiwalletAllowed()) {
|
||||
WalletMultiCurrencyState.Locked(
|
||||
onBackClick = state.onBackClick,
|
||||
topBarConfig = state.topBarConfig,
|
||||
walletsListConfig = state.walletsListConfig,
|
||||
pullToRefreshConfig = state.pullToRefreshConfig,
|
||||
onUnlockWalletsNotificationClick = clickIntents::onUnlockWalletNotificationClick,
|
||||
onUnlockClick = clickIntents::onUnlockWalletClick,
|
||||
onScanClick = clickIntents::onScanCardClick,
|
||||
)
|
||||
} else {
|
||||
WalletSingleCurrencyState.Locked(
|
||||
onBackClick = state.onBackClick,
|
||||
topBarConfig = state.topBarConfig,
|
||||
walletsListConfig = state.walletsListConfig,
|
||||
pullToRefreshConfig = state.pullToRefreshConfig,
|
||||
buttons = getButtons(),
|
||||
onUnlockWalletsNotificationClick = clickIntents::onUnlockWalletNotificationClick,
|
||||
onUnlockClick = clickIntents::onUnlockWalletClick,
|
||||
onScanClick = clickIntents::onScanCardClick,
|
||||
onExploreClick = clickIntents::onExploreClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
private fun getButtons(): ImmutableList<ActionButtonConfig> {
|
||||
return persistentListOf(
|
||||
WalletManageButton.Buy(onClick = {}),
|
||||
WalletManageButton.Send(onClick = {}),
|
||||
WalletManageButton.Receive(onClick = {}),
|
||||
WalletManageButton.Exchange(onClick = {}),
|
||||
WalletManageButton.CopyAddress(onClick = {}),
|
||||
)
|
||||
.map(WalletManageButton::config)
|
||||
.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
|
@ -8,9 +8,10 @@ import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
|||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.txhistory.error.TxHistoryListError
|
||||
import com.tangem.domain.txhistory.model.TxHistoryItem
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletManageButton
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -62,8 +63,8 @@ internal class WalletLoadedTxHistoryConverter(
|
|||
|
||||
private fun WalletStateHolder.copySingleCurrencyContent(
|
||||
txHistoryState: WalletTxHistoryState,
|
||||
): WalletStateHolder.SingleCurrencyContent {
|
||||
return WalletStateHolder.SingleCurrencyContent(
|
||||
): WalletSingleCurrencyState {
|
||||
return WalletSingleCurrencyState.Content(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
|||
import com.tangem.core.ui.components.transactions.TransactionState
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.txhistory.error.TxHistoryStateError
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletManageButton
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletManageButton
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -69,8 +70,8 @@ internal class WalletLoadingTxHistoryConverter(
|
|||
|
||||
private fun WalletStateHolder.copySingleCurrencyContent(
|
||||
txHistoryState: WalletTxHistoryState,
|
||||
): WalletStateHolder.SingleCurrencyContent {
|
||||
return WalletStateHolder.SingleCurrencyContent(
|
||||
): WalletSingleCurrencyState {
|
||||
return WalletSingleCurrencyState.Content(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import androidx.paging.*
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.core.ui.components.transactions.TransactionState
|
||||
import com.tangem.domain.txhistory.model.TxHistoryItem
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState.TxHistoryItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTxHistoryState.TxHistoryItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.extensions.isToday
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter
|
|||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
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.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTxHistoryState
|
||||
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
|
||||
|
|
@ -57,7 +59,7 @@ internal fun WalletScreen(state: WalletStateHolder) {
|
|||
.padding(paddingValues = scaffoldPaddings)
|
||||
.pullRefresh(pullRefreshState),
|
||||
) {
|
||||
val txHistoryItems = if (state is WalletStateHolder.SingleCurrencyContent &&
|
||||
val txHistoryItems = if (state is WalletSingleCurrencyState &&
|
||||
state.txHistoryState is WalletTxHistoryState.ContentState
|
||||
) {
|
||||
(state.txHistoryState as? WalletTxHistoryState.ContentState)?.items?.collectAsLazyPagingItems()
|
||||
|
|
@ -80,7 +82,7 @@ internal fun WalletScreen(state: WalletStateHolder) {
|
|||
WalletsList(config = state.walletsListConfig, lazyListState = walletsListState)
|
||||
}
|
||||
|
||||
if (state is WalletStateHolder.SingleCurrencyContent) {
|
||||
if (state is WalletSingleCurrencyState) {
|
||||
controlButtons(
|
||||
configs = state.buttons,
|
||||
modifier = movableItemModifier.padding(top = betweenItemsPadding),
|
||||
|
|
@ -89,13 +91,13 @@ internal fun WalletScreen(state: WalletStateHolder) {
|
|||
|
||||
notifications(configs = state.notifications, modifier = itemModifier)
|
||||
|
||||
if (state is WalletStateHolder.SingleCurrencyContent) {
|
||||
if (state is WalletSingleCurrencyState.Content) {
|
||||
marketPriceBlock(state = state.marketPriceBlockState, modifier = itemModifier)
|
||||
}
|
||||
|
||||
contentItems(state = state, txHistoryItems = txHistoryItems, modifier = movableItemModifier)
|
||||
|
||||
if (state is WalletStateHolder.MultiCurrencyContent) {
|
||||
if (state is WalletMultiCurrencyState) {
|
||||
organizeButton(onClick = state.tokensListState.onOrganizeTokensClick, modifier = itemModifier)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletsListConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletsListConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.common.WalletCard
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import com.tangem.core.ui.components.SecondaryButtonIconStart
|
|||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletBottomSheetConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBottomSheetConfig
|
||||
|
||||
/**
|
||||
* Wallet bottom sheet with detail notification information
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import com.tangem.core.ui.components.ResizableText
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
|
||||
|
||||
private const val DOTS = "•••"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,11 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components.common
|
|||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletLoading
|
||||
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.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.tokensListItems
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurrency.txHistoryItems
|
||||
|
||||
|
|
@ -23,10 +26,9 @@ internal fun LazyListScope.contentItems(
|
|||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
when (state) {
|
||||
is WalletStateHolder.MultiCurrencyContent -> tokensListItems(state.tokensListState, modifier)
|
||||
is WalletStateHolder.SingleCurrencyContent -> txHistoryItems(state.txHistoryState, txHistoryItems, modifier)
|
||||
is WalletStateHolder.Loading,
|
||||
is WalletStateHolder.UnlockWalletContent,
|
||||
is WalletMultiCurrencyState -> tokensListItems(state.tokensListState, modifier)
|
||||
is WalletSingleCurrencyState -> txHistoryItems(state.txHistoryState, txHistoryItems, modifier)
|
||||
is WalletLoading,
|
||||
-> Unit
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ import androidx.compose.foundation.lazy.LazyListScope
|
|||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletsListConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletsListConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.utils.ScrollOffsetCollector
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletTopBarConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTopBarConfig
|
||||
|
||||
/**
|
||||
* Wallet screen top bar
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrenc
|
|||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletContentItemDecoration
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.feature.wallet.presentation.common.component.NetworkGroupItem
|
||||
import com.tangem.feature.wallet.presentation.common.component.TokenItem
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||
|
||||
/**
|
||||
* Multi-currency content item
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import androidx.paging.compose.itemsIndexed
|
|||
import com.tangem.core.ui.components.transactions.empty.EmptyTransactionBlock
|
||||
import com.tangem.core.ui.components.transactions.empty.EmptyTransactionsBlockState
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletContentItemDecoration
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.ui.components.singlecurren
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.components.transactions.Transaction
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTxHistoryState
|
||||
|
||||
/**
|
||||
* Single currency content item
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState.TxHistoryItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTxHistoryState.TxHistoryItemState
|
||||
|
||||
/**
|
||||
* Transactions block group title
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTxHistoryState.TxHistoryItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTxHistoryState.TxHistoryItemState
|
||||
|
||||
/**
|
||||
* Transactions block title
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.core.ui.utils.BigDecimalFormatter.formatFiatAmount
|
|||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class FiatBalanceToWalletCardConverter(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.utils
|
||||
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ package com.tangem.feature.wallet.presentation.wallet.utils
|
|||
|
||||
import com.tangem.common.Provider
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
|
|
@ -14,7 +15,7 @@ internal class TokenListErrorToWalletStateConverter(
|
|||
// TODO: [REDACTED_JIRA]
|
||||
override fun convert(value: TokenListError): WalletStateHolder {
|
||||
val state = currentStateProvider()
|
||||
return WalletStateHolder.MultiCurrencyContent(
|
||||
return WalletMultiCurrencyState.Content(
|
||||
onBackClick = state.onBackClick,
|
||||
topBarConfig = state.topBarConfig,
|
||||
walletsListConfig = state.walletsListConfig,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package com.tangem.feature.wallet.presentation.wallet.utils
|
|||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.NetworkGroup
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState.TokensListItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState.TokensListItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.LoadingItemsProvider.getLoadingMultiCurrencyTokens
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
|
|
|||
|
|
@ -4,18 +4,20 @@ import com.tangem.common.Provider
|
|||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder.MultiCurrencyContent
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletsListConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletsListConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.utils.TokenListToWalletStateConverter.TokensListModel
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class TokenListToWalletStateConverter(
|
||||
private val currentStateProvider: Provider<WalletStateHolder>,
|
||||
private val cardTypeResolverProvider: Provider<CardTypesResolver>,
|
||||
private val isLockedWalletProvider: Provider<Boolean>,
|
||||
private val isWalletContentHidden: Boolean,
|
||||
private val fiatCurrencyCode: String,
|
||||
private val fiatCurrencySymbol: String,
|
||||
|
|
@ -43,8 +45,8 @@ internal class TokenListToWalletStateConverter(
|
|||
)
|
||||
}
|
||||
|
||||
private fun WalletStateHolder.updateWithTokenList(tokenList: TokenList): MultiCurrencyContent {
|
||||
return MultiCurrencyContent(
|
||||
private fun WalletStateHolder.updateWithTokenList(tokenList: TokenList): WalletMultiCurrencyState.Content {
|
||||
return WalletMultiCurrencyState.Content(
|
||||
onBackClick = onBackClick,
|
||||
topBarConfig = topBarConfig,
|
||||
walletsListConfig = walletsListConfig,
|
||||
|
|
@ -60,7 +62,7 @@ internal class TokenListToWalletStateConverter(
|
|||
val selectedWalletCard = walletsListConfig.wallets[selectedWalletIndex]
|
||||
val converter = FiatBalanceToWalletCardConverter(
|
||||
currentState = selectedWalletCard,
|
||||
isLockedState = this is WalletStateHolder.UnlockWalletContent,
|
||||
isLockedState = isLockedWalletProvider(),
|
||||
cardTypeResolverProvider = cardTypeResolverProvider,
|
||||
isWalletContentHidden = isWalletContentHidden,
|
||||
fiatCurrencyCode = fiatCurrencyCode,
|
||||
|
|
@ -75,7 +77,7 @@ internal class TokenListToWalletStateConverter(
|
|||
}
|
||||
|
||||
private fun WalletStateHolder.getRefreshingStatus(): Boolean {
|
||||
return if (this is MultiCurrencyContent) {
|
||||
return if (this is WalletMultiCurrencyState.Content) {
|
||||
tokensListState.items.any { tokensListItemState ->
|
||||
tokensListItemState is WalletTokensListState.TokensListItemState.Token &&
|
||||
tokensListItemState.state is TokenItemState.Loading
|
||||
|
|
|
|||
|
|
@ -31,4 +31,8 @@ internal interface WalletClickIntents {
|
|||
fun onReloadClick()
|
||||
|
||||
fun onExploreClick()
|
||||
|
||||
fun onUnlockWalletClick()
|
||||
|
||||
fun onUnlockWalletNotificationClick()
|
||||
}
|
||||
|
|
@ -6,9 +6,10 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
|||
import com.tangem.domain.tokens.model.NetworkGroup
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.content.WalletTokensListState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -117,7 +118,7 @@ internal class WalletNotificationsListFactory(
|
|||
}
|
||||
|
||||
return currentStateProvider().let { state ->
|
||||
state is WalletStateHolder.MultiCurrencyContent && state.tokensListState.items.any(isUnreachableState)
|
||||
state is WalletMultiCurrencyState.Content && state.tokensListState.items.any(isUnreachableState)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,10 @@ import com.tangem.domain.wallets.models.UserWallet
|
|||
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.UnlockWalletsUseCase
|
||||
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletBottomSheetConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.factory.WalletStateFactory
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
@ -55,6 +57,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
|
||||
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
|
||||
private val getExploreUrlUseCase: GetExploreUrlUseCase,
|
||||
private val unlockWalletsUseCase: UnlockWalletsUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : ViewModel(), DefaultLifecycleObserver, WalletClickIntents {
|
||||
|
||||
|
|
@ -74,6 +77,7 @@ internal class WalletViewModel @Inject constructor(
|
|||
currentCardTypeResolverProvider = Provider {
|
||||
getCardTypeResolver(index = uiState.walletsListConfig.selectedWalletIndex)
|
||||
},
|
||||
isLockedWalletProvider = Provider { wallets[uiState.walletsListConfig.selectedWalletIndex].isLocked },
|
||||
clickIntents = this,
|
||||
)
|
||||
|
||||
|
|
@ -90,24 +94,31 @@ internal class WalletViewModel @Inject constructor(
|
|||
getWalletsUseCase()
|
||||
.flowWithLifecycle(owner.lifecycle)
|
||||
.distinctUntilChanged()
|
||||
.onEach { wallets ->
|
||||
if (wallets.isEmpty()) return@onEach
|
||||
this.wallets = wallets
|
||||
|
||||
uiState = stateFactory.getSkeletonState(wallets = wallets)
|
||||
|
||||
updateContentItems(index = 0)
|
||||
}
|
||||
.onEach(::updateWallets)
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun updateWallets(sourceList: List<UserWallet>) {
|
||||
if (sourceList.isEmpty() || sourceList.all(UserWallet::isLocked)) return
|
||||
|
||||
wallets = sourceList
|
||||
|
||||
val unlockedWalletIndex = sourceList.indexOfFirst { !it.isLocked }
|
||||
uiState = stateFactory.getSkeletonState(
|
||||
wallets = wallets,
|
||||
index = if (unlockedWalletIndex == -1) 0 else unlockedWalletIndex,
|
||||
)
|
||||
|
||||
updateContentItems(index = unlockedWalletIndex)
|
||||
}
|
||||
|
||||
private fun updateContentItems(index: Int, isRefreshing: Boolean = false) {
|
||||
val cardTypeResolver = getCardTypeResolver(index)
|
||||
if (cardTypeResolver.isMultiwalletAllowed()) {
|
||||
updateByTokensList(index, isRefreshing)
|
||||
} else {
|
||||
updateByTxHistory(index)
|
||||
when {
|
||||
getWallet(index).isLocked -> uiState = stateFactory.getLockedState()
|
||||
cardTypeResolver.isMultiwalletAllowed() -> updateByTokensList(index, isRefreshing)
|
||||
!cardTypeResolver.isMultiwalletAllowed() -> updateByTxHistory(index)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +131,10 @@ internal class WalletViewModel @Inject constructor(
|
|||
isRefreshing = isRefreshing,
|
||||
)
|
||||
|
||||
tokenListEither.onRight { updateNotifications(index = index, tokenList = it) }
|
||||
updateNotifications(
|
||||
index = index,
|
||||
tokenList = tokenListEither.fold(ifLeft = { null }, ifRight = { it }),
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(viewModelScope)
|
||||
|
|
@ -278,4 +292,16 @@ internal class WalletViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnlockWalletClick() {
|
||||
viewModelScope.launch(dispatchers.io) {
|
||||
unlockWalletsUseCase()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnlockWalletNotificationClick() {
|
||||
uiState = stateFactory.getStateWithOpenBottomSheet(
|
||||
content = requireNotNull(uiState.bottomSheetConfig?.content),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue