Updated on 2026-08-14
This commit is contained in:
commit
3544354a97
9 changed files with 34 additions and 52 deletions
|
|
@ -14,6 +14,7 @@ import com.tangem.tap.common.extensions.dispatchOnMain
|
|||
import com.tangem.tap.common.extensions.setContext
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.model.UserWallet
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
import com.tangem.tap.domain.walletStores.WalletStoresError
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
import com.tangem.tap.features.disclaimer.createDisclaimer
|
||||
|
|
@ -36,7 +37,10 @@ class TapWalletManager {
|
|||
|
||||
suspend fun onWalletSelected(userWallet: UserWallet, refresh: Boolean, sendAnalyticsEvent: Boolean) {
|
||||
// do nothing if its the same wallet
|
||||
if (store.state.globalState.scanResponse == userWallet.scanResponse) return
|
||||
store.state.globalState.scanResponse?.let {
|
||||
val userWalletId = UserWalletIdBuilder.scanResponse(it).build()
|
||||
if (userWalletId == userWallet.walletId) return
|
||||
}
|
||||
|
||||
Analytics.setContext(userWallet.scanResponse)
|
||||
if (sendAnalyticsEvent) {
|
||||
|
|
|
|||
|
|
@ -54,16 +54,6 @@ internal class BiometricUserWalletsListManager(
|
|||
get() = keysRepository.hasSavedEncryptionKeys()
|
||||
|
||||
override suspend fun unlock(): CompletionResult<UserWallet> {
|
||||
// Occurs when user has locked user wallets after unlocking with biometry
|
||||
// e.g. after biometric storage master key invalidation
|
||||
if (state.value.hasLockedUserWalletsAfterUnlock) {
|
||||
return CompletionResult.Failure(
|
||||
error = UserWalletsListError.UnableToUnlockUserWallets(
|
||||
cause = IllegalStateException("Permanently locked"),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return unlockWithBiometryInternal()
|
||||
.mapFailure { error ->
|
||||
if (error is UserWalletsListError) {
|
||||
|
|
@ -216,10 +206,7 @@ internal class BiometricUserWalletsListManager(
|
|||
.map {
|
||||
state.update { prevState ->
|
||||
val hasLockedUserWallets = prevState.userWallets.any { it.isLocked }
|
||||
prevState.copy(
|
||||
isLocked = hasLockedUserWallets,
|
||||
hasLockedUserWalletsAfterUnlock = hasLockedUserWallets,
|
||||
)
|
||||
prevState.copy(isLocked = hasLockedUserWallets)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -262,15 +249,6 @@ internal class BiometricUserWalletsListManager(
|
|||
}
|
||||
}
|
||||
}
|
||||
.doOnFailure { error ->
|
||||
if (error is UserWalletsListError.EncryptionKeyInvalidated) {
|
||||
state.update { prevState ->
|
||||
prevState.copy(
|
||||
hasLockedUserWalletsAfterUnlock = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getSavedUserWallets(): CompletionResult<List<UserWallet>> {
|
||||
|
|
@ -334,6 +312,5 @@ internal class BiometricUserWalletsListManager(
|
|||
val userWallets: List<UserWallet> = emptyList(),
|
||||
val selectedUserWalletId: UserWalletId? = null,
|
||||
val isLocked: Boolean = true,
|
||||
val hasLockedUserWalletsAfterUnlock: Boolean = false,
|
||||
)
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import com.tangem.core.analytics.Analytics
|
|||
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
|
|
@ -31,14 +32,6 @@ import com.tangem.tap.features.demo.DemoHelper
|
|||
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.foregroundActivityObserver
|
||||
import com.tangem.tap.preferencesStorage
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.tap.userTokensRepository
|
||||
import com.tangem.tap.userWalletsListManager
|
||||
import com.tangem.tap.walletStoresManager
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
@ -84,6 +77,8 @@ class DetailsMiddleware {
|
|||
allowsRequestAccessCodeFromRepository = true,
|
||||
)
|
||||
.doOnSuccess { scanResponse ->
|
||||
// if we use biometric, scanResponse in GlobalState is null, and crashes NPE on twin cards
|
||||
store.dispatch(GlobalAction.SaveScanResponse(scanResponse))
|
||||
val currentUserWalletId = state.scanResponse
|
||||
?.let { UserWalletIdBuilder.scanResponse(it).build() }
|
||||
val scannedUserWalletId = UserWalletIdBuilder.scanResponse(scanResponse)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.wallet.redux
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
|
|
@ -16,6 +17,7 @@ import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
|
|||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.StateType
|
||||
import java.math.BigDecimal
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
|
||||
data class WalletState(
|
||||
|
|
@ -103,6 +105,9 @@ data class WalletState(
|
|||
it.derivationPath?.rawPath == currency.derivationPath
|
||||
}
|
||||
}
|
||||
|
||||
fun getBlockchainAmount(currency: Currency): BigDecimal =
|
||||
getWalletManager(currency)?.wallet?.amounts?.get(AmountType.Coin)?.value ?: BigDecimal.ZERO
|
||||
}
|
||||
|
||||
enum class ProgressState : WidgetState { Loading, Refreshing, Done, Error }
|
||||
|
|
@ -114,7 +119,6 @@ enum class ErrorType {
|
|||
|
||||
sealed class WalletMainButton(enabled: Boolean) : Button(enabled) {
|
||||
class SendButton(enabled: Boolean) : WalletMainButton(enabled)
|
||||
class CreateWalletButton(enabled: Boolean) : WalletMainButton(enabled)
|
||||
}
|
||||
|
||||
data class Artwork(
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
|
@ -128,7 +129,8 @@ class WalletDetailsFragment :
|
|||
(WalletState::selectedWalletData or WalletState::isExchangeServiceFeatureOn) { state ->
|
||||
val selectedWallet = state.selectedWalletData
|
||||
if (selectedWallet != null) {
|
||||
setupButtonsRow(selectedWallet, state.isExchangeServiceFeatureOn)
|
||||
val blockchainAmount: BigDecimal = state.getBlockchainAmount(selectedWallet.currency)
|
||||
setupButtonsRow(selectedWallet, state.isExchangeServiceFeatureOn, blockchainAmount)
|
||||
}
|
||||
}
|
||||
(WalletState::state or WalletState::error) { state ->
|
||||
|
|
@ -281,7 +283,11 @@ class WalletDetailsFragment :
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupButtonsRow(selectedWallet: WalletDataModel, isExchangeServiceFeatureOn: Boolean) {
|
||||
private fun setupButtonsRow(
|
||||
selectedWallet: WalletDataModel,
|
||||
isExchangeServiceFeatureOn: Boolean,
|
||||
blockchainAmount: BigDecimal,
|
||||
) {
|
||||
val exchangeManager = store.state.globalState.exchangeManager
|
||||
binding.rowButtons.apply {
|
||||
onBuyClick = { store.dispatch(WalletAction.TradeCryptoAction.Buy()) }
|
||||
|
|
@ -310,7 +316,7 @@ class WalletDetailsFragment :
|
|||
binding.rowButtons.updateButtonsVisibility(
|
||||
actions = actions,
|
||||
exchangeServiceFeatureOn = isExchangeServiceFeatureOn,
|
||||
sendAllowed = selectedWallet.mainButton.enabled,
|
||||
sendAllowed = selectedWallet.mainButton(blockchainAmount).enabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -239,7 +239,10 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), SafeStoreSubscriber<W
|
|||
(activity as? MainActivity)?.showSnackbar(
|
||||
text = R.string.wallet_notification_no_internet,
|
||||
buttonTitle = R.string.common_retry,
|
||||
) { store.dispatch(WalletAction.LoadData) }
|
||||
)
|
||||
// because was added logic of autoupdate mainscreen data, remove retry
|
||||
// TODO("remove comment after release 4.6")
|
||||
// { store.dispatch(WalletAction.LoadData) }
|
||||
} else {
|
||||
isNetworkConnectionError.value = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,9 @@ import com.tangem.tap.features.wallet.redux.utils.UNKNOWN_AMOUNT_SIGN
|
|||
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal val WalletDataModel.mainButton: WalletMainButton
|
||||
get() = WalletMainButton.SendButton(
|
||||
enabled = !status.amount.isZero() && status.pendingTransactions.isEmpty(),
|
||||
)
|
||||
internal fun WalletDataModel.mainButton(blockchainAmount: BigDecimal): WalletMainButton = WalletMainButton.SendButton(
|
||||
enabled = !isEmptyAmount && status.pendingTransactions.isEmpty() && !blockchainAmount.isZero(),
|
||||
)
|
||||
|
||||
internal fun WalletDataModel.getFormattedAmount(): String {
|
||||
return status.amount.toFormattedCurrencyString(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import com.tangem.tap.features.wallet.models.Currency
|
|||
import com.tangem.tap.features.wallet.models.PendingTransaction
|
||||
import com.tangem.tap.features.wallet.models.PendingTransactionType
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletMainButton
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.ui.BalanceWidget
|
||||
import com.tangem.tap.features.wallet.ui.MultipleAddressUiHelper
|
||||
|
|
@ -175,15 +174,10 @@ class SingleWalletView : WalletView() {
|
|||
binding?.rowButtons?.updateButtonsVisibility(
|
||||
actions = actions,
|
||||
exchangeServiceFeatureOn = isExchangeServiceFeatureEnabled,
|
||||
sendAllowed = walletData.mainButton.enabled,
|
||||
sendAllowed = walletData.mainButton(walletData.status.amount).enabled,
|
||||
)
|
||||
|
||||
rowButtons.onSendClick = {
|
||||
when (walletData.mainButton) {
|
||||
is WalletMainButton.SendButton -> store.dispatch(WalletAction.Send())
|
||||
is WalletMainButton.CreateWalletButton -> store.dispatch(WalletAction.CreateWallet)
|
||||
}
|
||||
}
|
||||
rowButtons.onSendClick = { store.dispatch(WalletAction.Send()) }
|
||||
}
|
||||
|
||||
private fun setupAddressCard(state: WalletState, binding: FragmentWalletBinding) = with(binding.lAddress) {
|
||||
|
|
|
|||
|
|
@ -72,9 +72,9 @@ arrow = "1.2.0-RC"
|
|||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
tangemBlockchainSdk = "develop-209"
|
||||
tangemBlockchainSdk = "release-app_4.5-215"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-229"
|
||||
tangemCardSdk = "develop-235"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds
|
||||
# endregion Tangem
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue