Updated on 2026-08-14

This commit is contained in:
Tangem 2022-12-13 21:41:43 +03:00
parent 888f62179b
commit 22e43fe7d7
12 changed files with 77 additions and 14 deletions

View file

@ -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
}

View file

@ -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 },
)
}
}

View file

@ -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(

View file

@ -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
}

View file

@ -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)

View file

@ -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,
)
}
}

View file

@ -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 ?: "",
)
}

View file

@ -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)
}

View file

@ -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",
)

View file

@ -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,
)
}
}

View file

@ -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,
)

View file

@ -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