Updated on 2026-08-14
This commit is contained in:
parent
888f62179b
commit
22e43fe7d7
12 changed files with 77 additions and 14 deletions
|
|
@ -13,6 +13,7 @@ import com.tangem.domain.common.util.UserWalletId
|
|||
* TODO: Replace with [com.tangem.domain.common.CardDTO]
|
||||
* @property cardId ID of user's wallet primary card
|
||||
* @property hasAccessCode Indicates if the user's wallet primary card has access code
|
||||
* @property isLocked Indicates if this primary card has no currency wallets
|
||||
* @property isSaved Indicates if this user wallet is saved
|
||||
* */
|
||||
data class UserWallet(
|
||||
|
|
@ -28,5 +29,8 @@ data class UserWallet(
|
|||
val hasAccessCode: Boolean
|
||||
get() = scanResponse.card.isAccessCodeSet
|
||||
|
||||
val isLocked: Boolean
|
||||
get() = scanResponse.card.wallets.isEmpty()
|
||||
|
||||
internal var isSaved: Boolean = true
|
||||
}
|
||||
|
|
@ -62,10 +62,22 @@ internal class BiometricUserWalletsListManager(
|
|||
|
||||
override suspend fun unlockWithCard(userWallet: UserWallet): CompletionResult<Unit> {
|
||||
state.update { prevState ->
|
||||
userWallet.isSaved = false
|
||||
// If the previous state contains a saved user wallet with the same ID, it is also saved
|
||||
userWallet.isSaved = prevState.wallets.any {
|
||||
it.walletId == userWallet.walletId && it.isSaved
|
||||
}
|
||||
|
||||
val newEncryptionKeys = prevState.encryptionKeys
|
||||
.plus(UserWalletEncryptionKey(userWallet))
|
||||
.distinctBy { it.walletId }
|
||||
val newUserWallets = prevState.wallets
|
||||
.plus(userWallet)
|
||||
.distinctBy { it.walletId }
|
||||
|
||||
prevState.copy(
|
||||
encryptionKeys = listOf(UserWalletEncryptionKey(userWallet)),
|
||||
wallets = listOf(userWallet),
|
||||
encryptionKeys = newEncryptionKeys,
|
||||
wallets = newUserWallets,
|
||||
selectedWalletId = userWallet.walletId,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -73,8 +85,7 @@ internal class BiometricUserWalletsListManager(
|
|||
.map {
|
||||
state.update { prevState ->
|
||||
prevState.copy(
|
||||
selectedWalletId = userWallet.walletId,
|
||||
isLocked = prevState.wallets.size != 1,
|
||||
isLocked = prevState.wallets.any { it.isLocked },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ data class UserWalletModel(
|
|||
val artworkUrl: String,
|
||||
val type: Type,
|
||||
val fiatBalance: TotalFiatBalance,
|
||||
val isLocked: Boolean,
|
||||
) {
|
||||
sealed interface Type {
|
||||
data class SingleCurrency(
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ internal sealed interface WalletSelectorAction : Action {
|
|||
val walletId: String,
|
||||
) : WalletSelectorAction
|
||||
|
||||
data class UnlockWalletWithCard(
|
||||
val walletId: String,
|
||||
) : WalletSelectorAction
|
||||
|
||||
data class RenameWallet(
|
||||
val walletId: String,
|
||||
val newName: String,
|
||||
|
|
@ -56,5 +60,6 @@ internal sealed interface WalletSelectorAction : Action {
|
|||
) : WalletSelectorAction
|
||||
|
||||
data class HandleError(val error: TangemError) : WalletSelectorAction
|
||||
|
||||
object CloseError : WalletSelectorAction
|
||||
}
|
||||
|
|
@ -61,6 +61,9 @@ internal class WalletSelectorMiddleware {
|
|||
is WalletSelectorAction.SelectWallet -> {
|
||||
selectWallet(action.walletId)
|
||||
}
|
||||
is WalletSelectorAction.UnlockWalletWithCard -> {
|
||||
unlockWalletWithCard(action.walletId)
|
||||
}
|
||||
is WalletSelectorAction.RemoveWallets -> {
|
||||
removeWallets(action.walletIdsToRemove, state)
|
||||
}
|
||||
|
|
@ -155,6 +158,40 @@ internal class WalletSelectorMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private fun unlockWalletWithCard(id: String) {
|
||||
scope.launch {
|
||||
userWalletsListManager.get(UserWalletId(id))
|
||||
.flatMap { userWallet ->
|
||||
updateUserWalletWithScannedCard(userWallet)
|
||||
}
|
||||
.flatMap { updatedUserWallet ->
|
||||
unlockUserWallet(updatedUserWallet)
|
||||
}
|
||||
.doOnFailure { error ->
|
||||
store.dispatchOnMain(WalletSelectorAction.HandleError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateUserWalletWithScannedCard(userWallet: UserWallet): CompletionResult<UserWallet> {
|
||||
return tangemSdkManager.scanCard(userWallet.cardId)
|
||||
.map { scannedCard ->
|
||||
userWallet.copy(
|
||||
scanResponse = userWallet.scanResponse.copy(
|
||||
card = scannedCard,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun unlockUserWallet(userWallet: UserWallet): CompletionResult<Unit> {
|
||||
return userWalletsListManager.unlockWithCard(userWallet)
|
||||
.doOnSuccess {
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet))
|
||||
store.onUserWalletSelected(userWallet)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeWallets(walletIdsToRemove: List<String>, state: WalletSelectorState) {
|
||||
Analytics.send(MyWallets.Button.DeleteWalletTapped)
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ internal object WalletSelectorReducer {
|
|||
)
|
||||
is WalletSelectorAction.WalletStoresChanged,
|
||||
is WalletSelectorAction.SelectWallet,
|
||||
is WalletSelectorAction.UnlockWalletWithCard,
|
||||
is WalletSelectorAction.RemoveWallets,
|
||||
is WalletSelectorAction.RenameWallet,
|
||||
-> state
|
||||
|
|
@ -70,6 +71,7 @@ internal object WalletSelectorReducer {
|
|||
it.copy(
|
||||
name = userWallet.name,
|
||||
artworkUrl = userWallet.artworkUrl,
|
||||
isLocked = userWallet.isLocked,
|
||||
type = userWallet.getType(prevType = it.type),
|
||||
)
|
||||
}
|
||||
|
|
@ -80,6 +82,7 @@ internal object WalletSelectorReducer {
|
|||
artworkUrl = artworkUrl,
|
||||
type = getType(),
|
||||
fiatBalance = TotalFiatBalance.Loading,
|
||||
isLocked = isLocked,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ private fun List<UserWalletModel>.toUiModels(
|
|||
name = name,
|
||||
imageUrl = artworkUrl,
|
||||
balance = balance,
|
||||
isLocked = isLocked,
|
||||
cardsInWallet = type.cardsInWallet,
|
||||
tokensCount = type.tokensCount,
|
||||
)
|
||||
|
|
@ -68,6 +69,7 @@ private fun List<UserWalletModel>.toUiModels(
|
|||
name = name,
|
||||
imageUrl = artworkUrl,
|
||||
balance = balance,
|
||||
isLocked = isLocked,
|
||||
tokenName = type.blockchainName ?: "—",
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,9 @@ internal class WalletSelectorViewModel : ViewModel(), StoreSubscriber<WalletSele
|
|||
|
||||
fun walletClicked(walletId: String) = with(state.value) {
|
||||
when {
|
||||
isLocked -> Unit
|
||||
isLocked -> {
|
||||
store.dispatch(WalletSelectorAction.UnlockWalletWithCard(walletId))
|
||||
}
|
||||
editingWalletsIds.isNotEmpty() && !editingWalletsIds.contains(walletId) -> {
|
||||
editWallet(walletId)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ internal object MockData {
|
|||
),
|
||||
name = "Wallet",
|
||||
imageUrl = "https://app.tangem.com/cards/card_default.png",
|
||||
isLocked = false,
|
||||
tokensCount = 12,
|
||||
cardsInWallet = 3,
|
||||
)
|
||||
|
|
@ -26,6 +27,7 @@ internal object MockData {
|
|||
),
|
||||
name = "Wallet",
|
||||
imageUrl = "https://app.tangem.com/cards/card_default.png",
|
||||
isLocked = false,
|
||||
tokenName = "Ethereum",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ internal fun WalletSelectorScreenContent(
|
|||
singleCurrencyWallets = state.singleCurrencyWallets,
|
||||
selectedWalletId = state.selectedWalletId,
|
||||
checkedWalletIds = state.editingWalletsIds,
|
||||
isLocked = state.isLocked,
|
||||
onWalletClick = onWalletClick,
|
||||
onWalletLongClick = onWalletLongClick,
|
||||
)
|
||||
|
|
@ -141,7 +140,6 @@ private fun WalletsList(
|
|||
singleCurrencyWallets: List<UserWalletItem>,
|
||||
selectedWalletId: String?,
|
||||
checkedWalletIds: List<String>,
|
||||
isLocked: Boolean,
|
||||
onWalletClick: (walletId: String) -> Unit,
|
||||
onWalletLongClick: (walletId: String) -> Unit,
|
||||
) {
|
||||
|
|
@ -166,7 +164,6 @@ private fun WalletsList(
|
|||
wallet = wallet,
|
||||
isSelected = wallet.id == selectedWalletId,
|
||||
isChecked = wallet.id in checkedWalletIds,
|
||||
isLocked = isLocked && wallet.id != selectedWalletId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ internal fun WalletItem(
|
|||
wallet: UserWalletItem,
|
||||
isSelected: Boolean,
|
||||
isChecked: Boolean,
|
||||
isLocked: Boolean,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
|
|
@ -59,7 +58,7 @@ internal fun WalletItem(
|
|||
SpacerW6()
|
||||
TokensInfo(
|
||||
modifier = Modifier.weight(weight = .4f),
|
||||
isLocked = isLocked,
|
||||
isLocked = wallet.isLocked,
|
||||
balance = wallet.balance,
|
||||
tokensCount = (wallet as? MultiCurrencyUserWalletItem)?.tokensCount,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
package com.tangem.tap.features.walletSelector.ui.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@Immutable
|
||||
internal sealed interface UserWalletItem {
|
||||
val id: String
|
||||
val name: String
|
||||
val imageUrl: String
|
||||
val balance: Balance
|
||||
val isLocked: Boolean
|
||||
|
||||
val headerText: TextReference
|
||||
get() = when (this) {
|
||||
|
|
@ -17,7 +16,6 @@ internal sealed interface UserWalletItem {
|
|||
is SingleCurrencyUserWalletItem -> TextReference.Res(R.string.user_wallet_list_single_header)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class Balance(
|
||||
val amount: String,
|
||||
val isLoading: Boolean,
|
||||
|
|
@ -29,6 +27,7 @@ internal data class MultiCurrencyUserWalletItem(
|
|||
override val name: String,
|
||||
override val imageUrl: String,
|
||||
override val balance: UserWalletItem.Balance,
|
||||
override val isLocked: Boolean,
|
||||
val tokensCount: Int,
|
||||
val cardsInWallet: Int,
|
||||
) : UserWalletItem
|
||||
|
|
@ -38,5 +37,6 @@ internal data class SingleCurrencyUserWalletItem(
|
|||
override val name: String,
|
||||
override val imageUrl: String,
|
||||
override val balance: UserWalletItem.Balance,
|
||||
override val isLocked: Boolean,
|
||||
val tokenName: String,
|
||||
) : UserWalletItem
|
||||
Loading…
Add table
Add a link
Reference in a new issue