Updated on 2026-08-14
This commit is contained in:
parent
41dea25009
commit
4b08a5f605
7 changed files with 148 additions and 162 deletions
|
|
@ -5,15 +5,12 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.SnackbarHost
|
||||
import androidx.compose.material.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.tangem.core.ui.fragments.ComposeBottomSheetFragment
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -29,6 +26,7 @@ internal class WalletSelectorBottomSheetFragment : ComposeBottomSheetFragment<Wa
|
|||
return viewModel.state.collectAsState()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
override fun ScreenContent(
|
||||
modifier: Modifier,
|
||||
|
|
@ -38,7 +36,10 @@ internal class WalletSelectorBottomSheetFragment : ComposeBottomSheetFragment<Wa
|
|||
val errorMessage by rememberUpdatedState(newValue = state.error?.customMessage)
|
||||
val renameWalletDialog by rememberUpdatedState(newValue = state.renameWalletDialog)
|
||||
|
||||
Box(modifier = modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.nestedScroll(connection = rememberNestedScrollInteropConnection()),
|
||||
) {
|
||||
WalletSelectorScreenContent(
|
||||
state = state,
|
||||
onWalletClick = viewModel::walletClicked,
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@ package com.tangem.tap.features.walletSelector.ui
|
|||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem
|
||||
import com.tangem.tap.features.walletSelector.ui.model.RenameWalletDialog
|
||||
import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem
|
||||
import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem
|
||||
|
||||
@Immutable
|
||||
internal data class WalletSelectorScreenState(
|
||||
val wallets: List<UserWalletItem> = listOf(),
|
||||
val multiCurrencyWallets: List<MultiCurrencyUserWalletItem> = emptyList(),
|
||||
val singleCurrencyWallets: List<SingleCurrencyUserWalletItem> = emptyList(),
|
||||
val selectedWalletId: String? = null,
|
||||
val fiatCurrency: FiatCurrency = FiatCurrency.Default,
|
||||
val isLocked: Boolean = true,
|
||||
val isLocked: Boolean = false,
|
||||
val editingWalletsIds: List<String> = listOf(),
|
||||
val renameWalletDialog: RenameWalletDialog? = null,
|
||||
val showAddCardProgress: Boolean = false,
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ internal class WalletSelectorViewModel : ViewModel(), StoreSubscriber<WalletSele
|
|||
fun renameWallet() = with(state.value) {
|
||||
if (editingWalletsIds.isNotEmpty() && renameWalletDialog == null) {
|
||||
val editedWalletId = editingWalletsIds.first()
|
||||
val editedWallet = wallets.find { it.id == editedWalletId }
|
||||
val editedWallet = (multiCurrencyWallets + singleCurrencyWallets)
|
||||
.find { it.id == editedWalletId }
|
||||
|
||||
if (editedWallet != null) {
|
||||
val dialog = RenameWalletDialog(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.tangem.tap.features.walletSelector.ui.components
|
||||
|
||||
import com.tangem.tap.features.walletSelector.ui.WalletSelectorScreenState
|
||||
import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem
|
||||
import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem
|
||||
import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem
|
||||
|
||||
internal object MockData {
|
||||
private val userWallet = UserWalletItem(
|
||||
private val multiCurrencyUserWallet = MultiCurrencyUserWalletItem(
|
||||
id = "wallet_1",
|
||||
balance = UserWalletItem.Balance(
|
||||
amount = "6781.05 $",
|
||||
|
|
@ -12,19 +14,29 @@ internal object MockData {
|
|||
),
|
||||
name = "Wallet",
|
||||
imageUrl = "https://app.tangem.com/cards/card_default.png",
|
||||
type = UserWalletItem.Type.MultiCurrency(tokensCount = 12, cardsInWallet = 3),
|
||||
tokensCount = 12,
|
||||
cardsInWallet = 3,
|
||||
)
|
||||
|
||||
val userWalletList = listOf(
|
||||
userWallet,
|
||||
userWallet.copy(id = "wallet_2"),
|
||||
userWallet.copy(id = "wallet_3", type = UserWalletItem.Type.MultiCurrency(tokensCount = 2, cardsInWallet = 1)),
|
||||
userWallet.copy(id = "wallet_4", type = UserWalletItem.Type.SingleCurrency(tokenName = "Ethereum")),
|
||||
private val singleCurrencyUserWallet = SingleCurrencyUserWalletItem(
|
||||
id = "wallet_4",
|
||||
balance = UserWalletItem.Balance(
|
||||
amount = "6781.05 $",
|
||||
isLoading = false,
|
||||
),
|
||||
name = "Wallet",
|
||||
imageUrl = "https://app.tangem.com/cards/card_default.png",
|
||||
tokenName = "Ethereum",
|
||||
)
|
||||
|
||||
val state = WalletSelectorScreenState(
|
||||
wallets = userWalletList,
|
||||
selectedWalletId = userWalletList[0].id,
|
||||
multiCurrencyWallets = listOf(
|
||||
multiCurrencyUserWallet,
|
||||
multiCurrencyUserWallet.copy(id = "wallet_2"),
|
||||
multiCurrencyUserWallet.copy(id = "wallet_3", tokensCount = 2, cardsInWallet = 1),
|
||||
),
|
||||
singleCurrencyWallets = listOf(singleCurrencyUserWallet),
|
||||
selectedWalletId = multiCurrencyUserWallet.id,
|
||||
isLocked = false,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,11 +1,7 @@
|
|||
package com.tangem.tap.features.walletSelector.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
|
|
@ -19,17 +15,12 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.SecondaryButtonIconRight
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.SpacerH16
|
||||
import com.tangem.core.ui.components.SpacerH24
|
||||
import com.tangem.core.ui.components.SpacerW16
|
||||
import com.tangem.core.ui.components.SpacerW8
|
||||
import com.tangem.core.ui.components.SpacerWMax
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.components.atoms.Hand
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.tap.features.details.ui.cardsettings.resolveReference
|
||||
import com.tangem.tap.features.walletSelector.ui.WalletSelectorScreenState
|
||||
import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@Composable
|
||||
|
|
@ -69,36 +60,44 @@ internal fun WalletSelectorScreenContent(
|
|||
)
|
||||
}
|
||||
SpacerH12()
|
||||
WalletList(
|
||||
wallets = state.wallets,
|
||||
selectedWalletId = state.selectedWalletId,
|
||||
checkedWalletIds = state.editingWalletsIds,
|
||||
isLocked = state.isLocked,
|
||||
onWalletClick = onWalletClick,
|
||||
onWalletLongClick = onWalletLongClick,
|
||||
)
|
||||
SpacerH24()
|
||||
if (state.isLocked) {
|
||||
PrimaryButton(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(
|
||||
state = rememberScrollState(),
|
||||
),
|
||||
) {
|
||||
WalletsList(
|
||||
multiCurrencyWallets = state.multiCurrencyWallets,
|
||||
singleCurrencyWallets = state.singleCurrencyWallets,
|
||||
selectedWalletId = state.selectedWalletId,
|
||||
checkedWalletIds = state.editingWalletsIds,
|
||||
isLocked = state.isLocked,
|
||||
onWalletClick = onWalletClick,
|
||||
onWalletLongClick = onWalletLongClick,
|
||||
)
|
||||
SpacerH24()
|
||||
if (state.isLocked) {
|
||||
PrimaryButton(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(R.string.user_wallet_list_unlock_all_face_id),
|
||||
showProgress = state.showUnlockProgress,
|
||||
onClick = onUnlockClick,
|
||||
)
|
||||
SpacerH12()
|
||||
}
|
||||
SecondaryButtonIconRight(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(R.string.user_wallet_list_unlock_all_face_id),
|
||||
showProgress = state.showUnlockProgress,
|
||||
onClick = onUnlockClick,
|
||||
text = stringResource(R.string.user_wallet_list_add_button),
|
||||
showProgress = state.showAddCardProgress,
|
||||
icon = painterResource(id = R.drawable.ic_tangem),
|
||||
onClick = onAddCardClick,
|
||||
)
|
||||
SpacerH12()
|
||||
SpacerH16()
|
||||
}
|
||||
SecondaryButtonIconRight(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(R.string.user_wallet_list_add_button),
|
||||
showProgress = state.showAddCardProgress,
|
||||
icon = painterResource(id = R.drawable.ic_tangem),
|
||||
onClick = onAddCardClick,
|
||||
)
|
||||
SpacerH16()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,6 +162,49 @@ private fun EditWalletsBar(
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun WalletsList(
|
||||
modifier: Modifier = Modifier,
|
||||
multiCurrencyWallets: List<UserWalletItem>,
|
||||
singleCurrencyWallets: List<UserWalletItem>,
|
||||
selectedWalletId: String?,
|
||||
checkedWalletIds: List<String>,
|
||||
isLocked: Boolean,
|
||||
onWalletClick: (walletId: String) -> Unit,
|
||||
onWalletLongClick: (walletId: String) -> Unit,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
val walletsSection = @Composable { wallets: List<UserWalletItem> ->
|
||||
wallets.forEachIndexed { index, wallet ->
|
||||
if (index == 0) {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = TangemTheme.dimens.spacing16),
|
||||
text = wallet.headerText.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
WalletItem(
|
||||
modifier = Modifier
|
||||
.combinedClickable(
|
||||
onClick = { onWalletClick(wallet.id) },
|
||||
onLongClick = { onWalletLongClick(wallet.id) },
|
||||
)
|
||||
.padding(all = TangemTheme.dimens.spacing16),
|
||||
wallet = wallet,
|
||||
isSelected = wallet.id == selectedWalletId,
|
||||
isChecked = wallet.id in checkedWalletIds,
|
||||
isLocked = isLocked && wallet.id != selectedWalletId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
walletsSection(multiCurrencyWallets)
|
||||
walletsSection(singleCurrencyWallets)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
private fun WalletSelectorScreenContentSample(
|
||||
|
|
@ -221,7 +263,7 @@ private fun WalletSelectorScreenContent_EditWallets_Sample(
|
|||
shape = TangemTheme.shapes.bottomSheet,
|
||||
),
|
||||
state = MockData.state
|
||||
.copy(editingWalletsIds = listOf(MockData.userWalletList[2].id)),
|
||||
.copy(editingWalletsIds = listOf(MockData.state.multiCurrencyWallets[2].id)),
|
||||
onWalletClick = { /* no-op */ },
|
||||
onWalletLongClick = { /* no-op */ },
|
||||
onUnlockClick = { /* no-op */ },
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
@file:OptIn(ExperimentalFoundationApi::class)
|
||||
|
||||
package com.tangem.tap.features.walletSelector.ui.components
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.tap.features.details.ui.cardsettings.resolveReference
|
||||
import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem
|
||||
|
||||
@Composable
|
||||
internal fun WalletList(
|
||||
modifier: Modifier = Modifier,
|
||||
wallets: List<UserWalletItem>,
|
||||
selectedWalletId: String?,
|
||||
checkedWalletIds: List<String>,
|
||||
isLocked: Boolean,
|
||||
onWalletClick: (walletId: String) -> Unit,
|
||||
onWalletLongClick: (walletId: String) -> Unit,
|
||||
) {
|
||||
val multiCurrencyWallets = remember(wallets) {
|
||||
wallets.filter { it.type is UserWalletItem.Type.MultiCurrency }
|
||||
}
|
||||
val singleCurrencyWallets = remember(wallets) {
|
||||
wallets.filter { it.type is UserWalletItem.Type.SingleCurrency }
|
||||
}
|
||||
LazyColumn(modifier = modifier) {
|
||||
val walletSection: (List<UserWalletItem>) -> Unit = { wallets ->
|
||||
itemsIndexed(
|
||||
items = wallets,
|
||||
key = { _, item -> item.id },
|
||||
) { index, wallet ->
|
||||
if (index == 0) {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = TangemTheme.dimens.spacing16),
|
||||
text = wallet.type.headerText.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
WalletItem(
|
||||
modifier = Modifier
|
||||
.combinedClickable(
|
||||
onClick = { onWalletClick(wallet.id) },
|
||||
onLongClick = { onWalletLongClick(wallet.id) },
|
||||
)
|
||||
.padding(all = TangemTheme.dimens.spacing16),
|
||||
wallet = wallet,
|
||||
isSelected = wallet.id == selectedWalletId,
|
||||
isChecked = wallet.id in checkedWalletIds,
|
||||
isLocked = isLocked && wallet.id != selectedWalletId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
walletSection(multiCurrencyWallets)
|
||||
walletSection(singleCurrencyWallets)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,42 +5,38 @@ import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
|||
import com.tangem.wallet.R
|
||||
|
||||
@Immutable
|
||||
internal data class UserWalletItem(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val imageUrl: String,
|
||||
val balance: Balance,
|
||||
val type: Type,
|
||||
) {
|
||||
internal sealed interface UserWalletItem {
|
||||
val id: String
|
||||
val name: String
|
||||
val imageUrl: String
|
||||
val balance: Balance
|
||||
|
||||
val headerText: TextReference
|
||||
get() = when (this) {
|
||||
is MultiCurrencyUserWalletItem -> TextReference.Res(R.string.user_wallet_list_multi_header)
|
||||
is SingleCurrencyUserWalletItem -> TextReference.Res(R.string.user_wallet_list_single_header)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class Balance(
|
||||
val amount: String,
|
||||
val isLoading: Boolean,
|
||||
) {
|
||||
companion object {
|
||||
val Loading = Balance(
|
||||
amount = "0.00",
|
||||
isLoading = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
sealed interface Type {
|
||||
val headerText: TextReference
|
||||
internal data class MultiCurrencyUserWalletItem(
|
||||
override val id: String,
|
||||
override val name: String,
|
||||
override val imageUrl: String,
|
||||
override val balance: UserWalletItem.Balance,
|
||||
val tokensCount: Int,
|
||||
val cardsInWallet: Int,
|
||||
) : UserWalletItem
|
||||
|
||||
@Immutable
|
||||
class MultiCurrency(
|
||||
val tokensCount: Int,
|
||||
val cardsInWallet: Int,
|
||||
) : Type {
|
||||
override val headerText: TextReference
|
||||
get() = TextReference.Res(R.string.user_wallet_list_multi_header)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
class SingleCurrency(val tokenName: String) : Type {
|
||||
override val headerText: TextReference
|
||||
get() = TextReference.Res(R.string.user_wallet_list_single_header)
|
||||
}
|
||||
}
|
||||
}
|
||||
internal data class SingleCurrencyUserWalletItem(
|
||||
override val id: String,
|
||||
override val name: String,
|
||||
override val imageUrl: String,
|
||||
override val balance: UserWalletItem.Balance,
|
||||
val tokenName: String,
|
||||
) : UserWalletItem
|
||||
Loading…
Add table
Add a link
Reference in a new issue