Updated on 2026-08-14
This commit is contained in:
parent
5bffc604db
commit
dd9d7f2e45
15 changed files with 351 additions and 37 deletions
|
|
@ -0,0 +1,74 @@
|
||||||
|
package com.tangem.core.ui.components
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.animateColorAsState
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=281-248&mode=design&t=bXqehWPHyATKcZEW-4)
|
||||||
|
* */
|
||||||
|
@Composable
|
||||||
|
fun SimpleSettingsRow(
|
||||||
|
title: String,
|
||||||
|
@DrawableRes icon: Int,
|
||||||
|
onItemsClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
subtitle: String? = null,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = modifier
|
||||||
|
.height(TangemTheme.dimens.size56)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable(
|
||||||
|
onClick = {
|
||||||
|
if (enabled) {
|
||||||
|
onItemsClick()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
horizontalArrangement = Arrangement.Start,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
val textColor: Color by animateColorAsState(
|
||||||
|
targetValue = if (enabled) {
|
||||||
|
TangemTheme.colors.text.primary1
|
||||||
|
} else {
|
||||||
|
TangemTheme.colors.text.secondary
|
||||||
|
},
|
||||||
|
)
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = icon),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing20),
|
||||||
|
tint = textColor,
|
||||||
|
)
|
||||||
|
Column(modifier = Modifier.padding(end = TangemTheme.dimens.spacing20)) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = TangemTheme.typography.subtitle1,
|
||||||
|
color = textColor,
|
||||||
|
)
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = !subtitle.isNullOrEmpty(),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = subtitle ?: "",
|
||||||
|
style = TangemTheme.typography.body2,
|
||||||
|
color = TangemTheme.colors.text.secondary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.*
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
import com.tangem.feature.wallet.presentation.wallet.state.components.*
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState.TokensListItemState
|
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState.TokensListItemState
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.collections.immutable.toPersistentList
|
import kotlinx.collections.immutable.toPersistentList
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
@ -99,7 +100,8 @@ internal object WalletPreviewData {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
isTestnet = false,
|
isTestnet = false,
|
||||||
onClick = {},
|
onItemClick = {},
|
||||||
|
onItemLongClick = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,7 +128,8 @@ internal object WalletPreviewData {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
isTestnet = false,
|
isTestnet = false,
|
||||||
onClick = {},
|
onItemClick = {},
|
||||||
|
onItemLongClick = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -258,15 +261,25 @@ internal object WalletPreviewData {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val manageButtons by lazy {
|
val actionsBottomSheet = ActionsBottomSheetConfig(
|
||||||
persistentListOf(
|
isShow = true,
|
||||||
WalletManageButton.Buy(onClick = {}),
|
onDismissRequest = {},
|
||||||
WalletManageButton.Send(onClick = {}),
|
actions = listOf(
|
||||||
WalletManageButton.Receive(onClick = {}),
|
TokenActionButtonConfig(
|
||||||
WalletManageButton.Exchange(onClick = {}),
|
text = "Send",
|
||||||
WalletManageButton.CopyAddress(onClick = {}),
|
iconResId = R.drawable.ic_share_24,
|
||||||
)
|
onClick = {},
|
||||||
}
|
),
|
||||||
|
).toImmutableList(),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val manageButtons = persistentListOf(
|
||||||
|
WalletManageButton.Buy(onClick = {}),
|
||||||
|
WalletManageButton.Send(onClick = {}),
|
||||||
|
WalletManageButton.Receive(onClick = {}),
|
||||||
|
WalletManageButton.Exchange(onClick = {}),
|
||||||
|
WalletManageButton.CopyAddress(onClick = {}),
|
||||||
|
)
|
||||||
|
|
||||||
val multicurrencyWalletScreenState by lazy {
|
val multicurrencyWalletScreenState by lazy {
|
||||||
WalletMultiCurrencyState.Content(
|
WalletMultiCurrencyState.Content(
|
||||||
|
|
@ -336,6 +349,7 @@ internal object WalletPreviewData {
|
||||||
WalletNotification.ScanCard(onClick = {}),
|
WalletNotification.ScanCard(onClick = {}),
|
||||||
),
|
),
|
||||||
bottomSheetConfig = bottomSheet,
|
bottomSheetConfig = bottomSheet,
|
||||||
|
tokenActionsBottomSheet = actionsBottomSheet,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@ import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
|
@ -21,7 +23,9 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.ColorMatrix
|
import androidx.compose.ui.graphics.ColorMatrix
|
||||||
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
|
@ -65,11 +69,18 @@ internal fun TokenItem(state: TokenItemState, modifier: Modifier = Modifier) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun ContentTokenItem(content: TokenItemState.Content, modifier: Modifier = Modifier) {
|
private fun ContentTokenItem(content: TokenItemState.Content, modifier: Modifier = Modifier) {
|
||||||
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
InternalTokenItem(
|
InternalTokenItem(
|
||||||
modifier = modifier,
|
modifier = modifier.combinedClickable(
|
||||||
onClick = content.onClick,
|
onClick = content.onItemClick,
|
||||||
|
onLongClick = {
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
content.onItemLongClick()
|
||||||
|
},
|
||||||
|
),
|
||||||
name = content.name,
|
name = content.name,
|
||||||
tokenIconUrl = content.tokenIconUrl,
|
tokenIconUrl = content.tokenIconUrl,
|
||||||
tokenIconResId = content.tokenIconResId,
|
tokenIconResId = content.tokenIconResId,
|
||||||
|
|
@ -300,15 +311,15 @@ private fun InternalTokenItem(
|
||||||
options: @Composable ConstraintLayoutScope.(ref: ConstrainedLayoutReference) -> Unit,
|
options: @Composable ConstraintLayoutScope.(ref: ConstrainedLayoutReference) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
isTestnet: Boolean = false,
|
isTestnet: Boolean = false,
|
||||||
onClick: (() -> Unit)? = null,
|
|
||||||
) {
|
) {
|
||||||
BaseSurface(
|
Box(
|
||||||
modifier = modifier,
|
modifier = modifier
|
||||||
onClick = onClick,
|
.defaultMinSize(minHeight = TOKEN_ITEM_HEIGHT)
|
||||||
|
.background(color = TangemTheme.colors.background.primary),
|
||||||
) {
|
) {
|
||||||
ConstraintLayout(
|
ConstraintLayout(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxSize()
|
||||||
.padding(
|
.padding(
|
||||||
horizontal = TangemTheme.dimens.spacing14,
|
horizontal = TangemTheme.dimens.spacing14,
|
||||||
vertical = TangemTheme.dimens.spacing4,
|
vertical = TangemTheme.dimens.spacing4,
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ internal sealed interface TokenItemState {
|
||||||
* @property hasPending pending tx in blockchain
|
* @property hasPending pending tx in blockchain
|
||||||
* @property tokenOptions state for token options
|
* @property tokenOptions state for token options
|
||||||
* @property isTestnet indicates whether the token is from test network or not
|
* @property isTestnet indicates whether the token is from test network or not
|
||||||
* @property onClick callback which will be called when an item is clicked
|
* @property onItemClick callback which will be called when an item is clicked
|
||||||
|
* @property onItemLongClick callback which will be called when an item is long clicked
|
||||||
*/
|
*/
|
||||||
data class Content(
|
data class Content(
|
||||||
override val id: String,
|
override val id: String,
|
||||||
|
|
@ -40,7 +41,8 @@ internal sealed interface TokenItemState {
|
||||||
val hasPending: Boolean,
|
val hasPending: Boolean,
|
||||||
val tokenOptions: TokenOptionsState,
|
val tokenOptions: TokenOptionsState,
|
||||||
val isTestnet: Boolean,
|
val isTestnet: Boolean,
|
||||||
val onClick: () -> Unit,
|
val onItemClick: () -> Unit,
|
||||||
|
val onItemLongClick: () -> Unit,
|
||||||
) : TokenItemState
|
) : TokenItemState
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.tangem.feature.wallet.presentation.wallet.state
|
||||||
|
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config for the token actions bottom sheet
|
||||||
|
*
|
||||||
|
* @property isShow flag that determine if bottom sheet is shown
|
||||||
|
* @property onDismissRequest lambda be invoked when bottom sheet is dismissed
|
||||||
|
* @property actions actions
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
internal data class ActionsBottomSheetConfig(
|
||||||
|
val isShow: Boolean,
|
||||||
|
val onDismissRequest: () -> Unit,
|
||||||
|
val actions: ImmutableList<TokenActionButtonConfig>,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.tangem.feature.wallet.presentation.wallet.state
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action button config
|
||||||
|
*
|
||||||
|
* @property text text
|
||||||
|
* @property iconResId icon resource id
|
||||||
|
* @property onClick lambda be invoked when action component is clicked
|
||||||
|
* @property enabled enabled
|
||||||
|
*/
|
||||||
|
data class TokenActionButtonConfig(
|
||||||
|
val text: String,
|
||||||
|
@DrawableRes val iconResId: Int,
|
||||||
|
val onClick: () -> Unit,
|
||||||
|
val enabled: Boolean = true,
|
||||||
|
)
|
||||||
|
|
@ -22,6 +22,7 @@ internal sealed class WalletMultiCurrencyState : WalletState.ContentState() {
|
||||||
override val notifications: ImmutableList<WalletNotification>,
|
override val notifications: ImmutableList<WalletNotification>,
|
||||||
override val bottomSheetConfig: WalletBottomSheetConfig?,
|
override val bottomSheetConfig: WalletBottomSheetConfig?,
|
||||||
override val tokensListState: WalletTokensListState,
|
override val tokensListState: WalletTokensListState,
|
||||||
|
val tokenActionsBottomSheet: ActionsBottomSheetConfig?,
|
||||||
) : WalletMultiCurrencyState()
|
) : WalletMultiCurrencyState()
|
||||||
|
|
||||||
data class Locked(
|
data class Locked(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.tangem.feature.wallet.presentation.wallet.state.factory
|
||||||
|
|
||||||
|
import com.tangem.common.Provider
|
||||||
|
import com.tangem.feature.wallet.impl.R
|
||||||
|
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||||
|
import com.tangem.feature.wallet.presentation.wallet.state.TokenActionButtonConfig
|
||||||
|
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converter from loaded [TokenItemState.Content] to ImmutableList<[TokenActionButtonConfig]>
|
||||||
|
*
|
||||||
|
* @property currentStateProvider current ui state provider
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Suppress("UnusedPrivateMember")
|
||||||
|
internal class TokenActionsProvider(
|
||||||
|
private val currentStateProvider: Provider<WalletState>,
|
||||||
|
) {
|
||||||
|
|
||||||
|
@Suppress("UnusedPrivateMember")
|
||||||
|
fun provideActions(tokenId: String): ImmutableList<TokenActionButtonConfig> {
|
||||||
|
// TODO: [REDACTED_JIRA]
|
||||||
|
return mockTokenActionButtonConfig().toImmutableList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mockTokenActionButtonConfig(): List<TokenActionButtonConfig> {
|
||||||
|
return listOf(
|
||||||
|
TokenActionButtonConfig(
|
||||||
|
text = "Send",
|
||||||
|
iconResId = R.drawable.ic_plus_24,
|
||||||
|
onClick = {},
|
||||||
|
),
|
||||||
|
TokenActionButtonConfig(
|
||||||
|
text = "Buy",
|
||||||
|
iconResId = R.drawable.ic_plus_24,
|
||||||
|
onClick = {},
|
||||||
|
),
|
||||||
|
TokenActionButtonConfig(
|
||||||
|
text = "Sell",
|
||||||
|
iconResId = R.drawable.ic_plus_24,
|
||||||
|
onClick = {},
|
||||||
|
),
|
||||||
|
TokenActionButtonConfig(
|
||||||
|
text = "Swap",
|
||||||
|
iconResId = R.drawable.ic_plus_24,
|
||||||
|
onClick = {},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -51,6 +51,7 @@ internal class WalletSkeletonStateConverter(
|
||||||
tokensListState = WalletTokensListState.Loading(),
|
tokensListState = WalletTokensListState.Loading(),
|
||||||
notifications = persistentListOf(),
|
notifications = persistentListOf(),
|
||||||
bottomSheetConfig = null,
|
bottomSheetConfig = null,
|
||||||
|
tokenActionsBottomSheet = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import com.tangem.domain.txhistory.models.TxHistoryListError
|
||||||
import com.tangem.domain.txhistory.models.TxHistoryStateError
|
import com.tangem.domain.txhistory.models.TxHistoryStateError
|
||||||
import com.tangem.domain.wallets.models.UserWallet
|
import com.tangem.domain.wallets.models.UserWallet
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
|
||||||
|
import com.tangem.feature.wallet.presentation.wallet.state.ActionsBottomSheetConfig
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState
|
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.WalletSingleCurrencyState
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
import com.tangem.feature.wallet.presentation.wallet.state.WalletState
|
||||||
|
|
@ -45,6 +46,7 @@ internal class WalletStateFactory(
|
||||||
private val clickIntents: WalletClickIntents,
|
private val clickIntents: WalletClickIntents,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val tokenActionsProvider by lazy { TokenActionsProvider(currentStateProvider = currentStateProvider) }
|
||||||
private val skeletonConverter by lazy { WalletSkeletonStateConverter(currentStateProvider, clickIntents) }
|
private val skeletonConverter by lazy { WalletSkeletonStateConverter(currentStateProvider, clickIntents) }
|
||||||
|
|
||||||
private val loadedTokensListConverter by lazy {
|
private val loadedTokensListConverter by lazy {
|
||||||
|
|
@ -119,29 +121,29 @@ internal class WalletStateFactory(
|
||||||
|
|
||||||
fun getStateAfterContentRefreshing(): WalletState = refreshStateConverter.convert(Unit)
|
fun getStateAfterContentRefreshing(): WalletState = refreshStateConverter.convert(Unit)
|
||||||
|
|
||||||
fun getStateWithOpenBottomSheet(content: WalletBottomSheetConfig.BottomSheetContentConfig): WalletState {
|
fun getStateWithOpenWalletBottomSheet(content: WalletBottomSheetConfig.BottomSheetContentConfig): WalletState {
|
||||||
return when (val state = currentStateProvider() as WalletState.ContentState) {
|
return when (val state = currentStateProvider() as WalletState.ContentState) {
|
||||||
is WalletMultiCurrencyState.Content -> state.copy(
|
is WalletMultiCurrencyState.Content -> state.copy(
|
||||||
bottomSheetConfig = WalletBottomSheetConfig(
|
bottomSheetConfig = WalletBottomSheetConfig(
|
||||||
isShow = true,
|
isShow = true,
|
||||||
onDismissRequest = clickIntents::onBottomSheetDismiss,
|
onDismissRequest = clickIntents::onDismissBottomSheet,
|
||||||
content = content,
|
content = content,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
is WalletMultiCurrencyState.Locked -> state.copy(
|
is WalletMultiCurrencyState.Locked -> state.copy(
|
||||||
isBottomSheetShow = true,
|
isBottomSheetShow = true,
|
||||||
onBottomSheetDismiss = clickIntents::onBottomSheetDismiss,
|
onBottomSheetDismiss = clickIntents::onDismissBottomSheet,
|
||||||
)
|
)
|
||||||
is WalletSingleCurrencyState.Content -> state.copy(
|
is WalletSingleCurrencyState.Content -> state.copy(
|
||||||
bottomSheetConfig = WalletBottomSheetConfig(
|
bottomSheetConfig = WalletBottomSheetConfig(
|
||||||
isShow = true,
|
isShow = true,
|
||||||
onDismissRequest = clickIntents::onBottomSheetDismiss,
|
onDismissRequest = clickIntents::onDismissBottomSheet,
|
||||||
content = content,
|
content = content,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
is WalletSingleCurrencyState.Locked -> state.copy(
|
is WalletSingleCurrencyState.Locked -> state.copy(
|
||||||
isBottomSheetShow = true,
|
isBottomSheetShow = true,
|
||||||
onBottomSheetDismiss = clickIntents::onBottomSheetDismiss,
|
onBottomSheetDismiss = clickIntents::onDismissBottomSheet,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -159,6 +161,19 @@ internal class WalletStateFactory(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getStateWithTokenActionBottomSheet(tokenId: String): WalletState {
|
||||||
|
return when (val state = currentStateProvider() as WalletState.ContentState) {
|
||||||
|
is WalletMultiCurrencyState.Content -> state.copy(
|
||||||
|
tokenActionsBottomSheet = ActionsBottomSheetConfig(
|
||||||
|
isShow = true,
|
||||||
|
actions = tokenActionsProvider.provideActions(tokenId = tokenId),
|
||||||
|
onDismissRequest = clickIntents::onDismissActionsBottomSheet,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else -> state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getLoadingTxHistoryState(itemsCountEither: Either<TxHistoryStateError, Int>): WalletState {
|
fun getLoadingTxHistoryState(itemsCountEither: Either<TxHistoryStateError, Int>): WalletState {
|
||||||
return loadingTransactionsStateConverter.convert(value = itemsCountEither)
|
return loadingTransactionsStateConverter.convert(value = itemsCountEither)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencySt
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState
|
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.WalletState
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletTokensListState
|
||||||
|
import com.tangem.feature.wallet.presentation.wallet.ui.components.TokenActionsBottomSheet
|
||||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletsList
|
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.common.*
|
||||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.organizeButton
|
import com.tangem.feature.wallet.presentation.wallet.ui.components.multicurrency.organizeButton
|
||||||
|
|
@ -122,12 +123,23 @@ private fun WalletContent(state: WalletState.ContentState) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val bottomSheetConfig = state.bottomSheetConfig
|
WalletBottomSheets(state = state)
|
||||||
|
|
||||||
|
WalletSideEffects(lazyListState = walletsListState, walletsListConfig = state.walletsListConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun WalletBottomSheets(state: WalletState) {
|
||||||
|
val bottomSheetConfig = (state as? WalletState.ContentState)?.bottomSheetConfig
|
||||||
if (bottomSheetConfig != null && bottomSheetConfig.isShow) {
|
if (bottomSheetConfig != null && bottomSheetConfig.isShow) {
|
||||||
WalletBottomSheet(config = bottomSheetConfig)
|
WalletBottomSheet(config = bottomSheetConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletSideEffects(lazyListState = walletsListState, walletsListConfig = state.walletsListConfig)
|
(state as? WalletMultiCurrencyState.Content)?.let { multiCurrencyState ->
|
||||||
|
if (multiCurrencyState.tokenActionsBottomSheet != null && multiCurrencyState.tokenActionsBottomSheet.isShow) {
|
||||||
|
TokenActionsBottomSheet(config = multiCurrencyState.tokenActionsBottomSheet)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// region Preview
|
// region Preview
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
package com.tangem.feature.wallet.presentation.wallet.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.material3.BottomSheetDefaults
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
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.SimpleSettingsRow
|
||||||
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||||
|
import com.tangem.feature.wallet.presentation.wallet.state.ActionsBottomSheetConfig
|
||||||
|
import com.tangem.feature.wallet.presentation.wallet.state.TokenActionButtonConfig
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
internal fun TokenActionsBottomSheet(config: ActionsBottomSheetConfig) {
|
||||||
|
ModalBottomSheet(
|
||||||
|
onDismissRequest = config.onDismissRequest,
|
||||||
|
sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
|
||||||
|
containerColor = TangemTheme.colors.background.primary,
|
||||||
|
dragHandle = { BottomSheetDefaults.DragHandle() },
|
||||||
|
) {
|
||||||
|
ActionsBottomSheetContent(config.actions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ActionsBottomSheetContent(actions: ImmutableList<TokenActionButtonConfig>) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.background(TangemTheme.colors.background.primary),
|
||||||
|
) {
|
||||||
|
actions.forEach { action ->
|
||||||
|
SimpleSettingsRow(
|
||||||
|
title = action.text,
|
||||||
|
icon = action.iconResId,
|
||||||
|
enabled = action.enabled,
|
||||||
|
onItemsClick = action.onClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun ActionsBottomSheetContent_Light(
|
||||||
|
@PreviewParameter(ActionsBottomSheetContentConfigProvider::class)
|
||||||
|
config: ActionsBottomSheetConfig,
|
||||||
|
) {
|
||||||
|
TangemTheme(isDark = false) {
|
||||||
|
// Use preview of content because ModalBottomSheet isn't supported in Preview mode
|
||||||
|
ActionsBottomSheetContent(actions = config.actions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun ActionsBottomSheetContent_Dark(
|
||||||
|
@PreviewParameter(ActionsBottomSheetContentConfigProvider::class)
|
||||||
|
config: ActionsBottomSheetConfig,
|
||||||
|
) {
|
||||||
|
TangemTheme(isDark = false) {
|
||||||
|
// Use preview of content because ModalBottomSheet isn't supported in Preview mode
|
||||||
|
ActionsBottomSheetContent(actions = config.actions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ActionsBottomSheetContentConfigProvider : CollectionPreviewParameterProvider<ActionsBottomSheetConfig>(
|
||||||
|
collection = listOf(WalletPreviewData.actionsBottomSheet),
|
||||||
|
)
|
||||||
|
|
@ -51,7 +51,8 @@ internal class CryptoCurrencyStatusToTokenItemConverter(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
isTestnet = currency.network.isTestnet,
|
isTestnet = currency.network.isTestnet,
|
||||||
onClick = { clickIntents.onTokenClick(currency) },
|
onItemClick = { clickIntents.onTokenItemClick(currency) },
|
||||||
|
onItemLongClick = { clickIntents.onTokenItemLongClick(currency) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,13 @@ internal interface WalletClickIntents : TxHistoryClickIntents {
|
||||||
|
|
||||||
fun onUnlockWalletNotificationClick()
|
fun onUnlockWalletNotificationClick()
|
||||||
|
|
||||||
fun onBottomSheetDismiss()
|
fun onDismissBottomSheet()
|
||||||
|
|
||||||
fun onTokenClick(currency: CryptoCurrency)
|
fun onTokenItemClick(currency: CryptoCurrency)
|
||||||
|
|
||||||
|
fun onTokenItemLongClick(currency: CryptoCurrency)
|
||||||
|
|
||||||
|
fun onDismissActionsBottomSheet()
|
||||||
|
|
||||||
fun onRenameClick(userWalletId: UserWalletId, name: String)
|
fun onRenameClick(userWalletId: UserWalletId, name: String)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -296,7 +296,7 @@ internal class WalletViewModel @Inject constructor(
|
||||||
override fun onBackupCardClick() = router.openOnboardingScreen()
|
override fun onBackupCardClick() = router.openOnboardingScreen()
|
||||||
|
|
||||||
override fun onCriticalWarningAlreadySignedHashesClick() {
|
override fun onCriticalWarningAlreadySignedHashesClick() {
|
||||||
uiState = stateFactory.getStateWithOpenBottomSheet(
|
uiState = stateFactory.getStateWithOpenWalletBottomSheet(
|
||||||
content = WalletBottomSheetConfig.BottomSheetContentConfig.CriticalWarningAlreadySignedHashes(
|
content = WalletBottomSheetConfig.BottomSheetContentConfig.CriticalWarningAlreadySignedHashes(
|
||||||
onOkClick = {},
|
onOkClick = {},
|
||||||
onCancelClick = {},
|
onCancelClick = {},
|
||||||
|
|
@ -309,7 +309,7 @@ internal class WalletViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLikeTangemAppClick() {
|
override fun onLikeTangemAppClick() {
|
||||||
uiState = stateFactory.getStateWithOpenBottomSheet(
|
uiState = stateFactory.getStateWithOpenWalletBottomSheet(
|
||||||
content = WalletBottomSheetConfig.BottomSheetContentConfig.LikeTangemApp(
|
content = WalletBottomSheetConfig.BottomSheetContentConfig.LikeTangemApp(
|
||||||
onRateTheAppClick = ::onRateTheAppClick,
|
onRateTheAppClick = ::onRateTheAppClick,
|
||||||
onShareClick = ::onShareClick,
|
onShareClick = ::onShareClick,
|
||||||
|
|
@ -445,7 +445,7 @@ internal class WalletViewModel @Inject constructor(
|
||||||
"Impossible to unlock wallet if state isn't WalletLockedState"
|
"Impossible to unlock wallet if state isn't WalletLockedState"
|
||||||
}
|
}
|
||||||
|
|
||||||
uiState = stateFactory.getStateWithOpenBottomSheet(
|
uiState = stateFactory.getStateWithOpenWalletBottomSheet(
|
||||||
content = when (state) {
|
content = when (state) {
|
||||||
is WalletMultiCurrencyState.Locked -> state.bottomSheetConfig.content
|
is WalletMultiCurrencyState.Locked -> state.bottomSheetConfig.content
|
||||||
is WalletSingleCurrencyState.Locked -> state.bottomSheetConfig.content
|
is WalletSingleCurrencyState.Locked -> state.bottomSheetConfig.content
|
||||||
|
|
@ -453,12 +453,14 @@ internal class WalletViewModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBottomSheetDismiss() {
|
override fun onTokenItemClick(currency: CryptoCurrency) {
|
||||||
uiState = stateFactory.getStateWithClosedBottomSheet()
|
router.openTokenDetails(currency = currency)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTokenClick(currency: CryptoCurrency) {
|
override fun onTokenItemLongClick(currency: CryptoCurrency) {
|
||||||
router.openTokenDetails(currency = currency)
|
uiState = stateFactory.getStateWithTokenActionBottomSheet(
|
||||||
|
tokenId = currency.id.value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRenameClick(userWalletId: UserWalletId, name: String) {
|
override fun onRenameClick(userWalletId: UserWalletId, name: String) {
|
||||||
|
|
@ -484,4 +486,18 @@ internal class WalletViewModel @Inject constructor(
|
||||||
initialValue = AppCurrency.Default,
|
initialValue = AppCurrency.Default,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDismissBottomSheet() {
|
||||||
|
uiState = stateFactory.getStateWithClosedBottomSheet()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismissActionsBottomSheet() {
|
||||||
|
(uiState as? WalletMultiCurrencyState.Content)?.let { state ->
|
||||||
|
uiState = state.copy(
|
||||||
|
tokenActionsBottomSheet = state.tokenActionsBottomSheet?.copy(
|
||||||
|
isShow = false,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue