Updated on 2026-08-14
This commit is contained in:
commit
470e62b96c
8 changed files with 105 additions and 82 deletions
|
|
@ -4,7 +4,7 @@ import android.content.Context
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.events.IntroductionProcess
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.tap.common.extensions.dispatchDialogHide
|
||||
import com.tangem.tap.common.feedback.ScanFailsEmail
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
|
|
@ -20,7 +20,7 @@ object ScanFailsDialog {
|
|||
setTitle(context.getString(R.string.common_warning))
|
||||
setMessage(R.string.alert_troubleshooting_scan_card_title)
|
||||
setPositiveButton(R.string.alert_button_request_support) { _, _ ->
|
||||
Analytics.send(IntroductionProcess.ButtonRequestSupport())
|
||||
Analytics.send(Basic.ButtonSupport())
|
||||
store.dispatch(GlobalAction.SendEmail(ScanFailsEmail()))
|
||||
}
|
||||
setNeutralButton(R.string.common_cancel) { _, _ -> }
|
||||
|
|
|
|||
|
|
@ -122,34 +122,38 @@ internal class GeneralUserWalletsListManager(
|
|||
appPreferencesStore.get(key = PreferencesKeys.SAVE_USER_WALLETS_KEY, default = false)
|
||||
.distinctUntilChanged()
|
||||
.onEach { shouldSaveUserWallets ->
|
||||
val manager = if (shouldSaveUserWallets) {
|
||||
biometricUserWalletsListManager.copyFrom(runtimeUserWalletsListManager)
|
||||
val possibleManager = if (shouldSaveUserWallets) {
|
||||
biometricUserWalletsListManager
|
||||
} else {
|
||||
runtimeUserWalletsListManager.copyFrom(biometricUserWalletsListManager)
|
||||
runtimeUserWalletsListManager
|
||||
}
|
||||
|
||||
Timber.d("Switch to ${manager::class.java.simpleName}")
|
||||
if (possibleManager == implementation.value) {
|
||||
error("${possibleManager::class.simpleName}} is already selected")
|
||||
}
|
||||
|
||||
implementation.value = manager
|
||||
Timber.d("Switch to ${possibleManager::class.simpleName}")
|
||||
|
||||
clearOldManager(manager)
|
||||
val previousManager = implementation.value
|
||||
implementation.value = copySelectedUserWallet(
|
||||
sourceManager = previousManager,
|
||||
destinationManager = possibleManager,
|
||||
)
|
||||
|
||||
previousManager.clear()
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(applicationScope)
|
||||
}
|
||||
|
||||
/** Copy data from [old] manager */
|
||||
private suspend fun UserWalletsListManager.copyFrom(old: UserWalletsListManager): UserWalletsListManager {
|
||||
old.selectedUserWalletSync?.let { this.save(it) }
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
private suspend fun clearOldManager(current: UserWalletsListManager) {
|
||||
if (current == biometricUserWalletsListManager) {
|
||||
runtimeUserWalletsListManager.clear()
|
||||
} else {
|
||||
biometricUserWalletsListManager.clear()
|
||||
private suspend fun copySelectedUserWallet(
|
||||
sourceManager: UserWalletsListManager,
|
||||
destinationManager: UserWalletsListManager,
|
||||
): UserWalletsListManager {
|
||||
sourceManager.selectedUserWalletSync?.let { selectedWallet ->
|
||||
destinationManager.save(selectedWallet, canOverride = true)
|
||||
}
|
||||
|
||||
return destinationManager
|
||||
}
|
||||
}
|
||||
|
|
@ -87,7 +87,13 @@ object OnboardingHelper {
|
|||
backupCardsIds = backupCardsIds?.toSet(),
|
||||
),
|
||||
)
|
||||
store.dispatchOnMain(SaveWalletAction.Save)
|
||||
|
||||
val toggles = store.inject(DaggerGraphState::userWalletsListManagerFeatureToggles)
|
||||
if (toggles.isGeneralManagerEnabled) {
|
||||
store.dispatchOnMain(SaveWalletAction.AllowToUseBiometrics)
|
||||
} else {
|
||||
store.dispatchOnMain(SaveWalletAction.Save)
|
||||
}
|
||||
}
|
||||
// When should not save user wallets but device has biometry and save wallet screen has not been shown,
|
||||
// then open save wallet screen
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.core.navigation.NavigationAction
|
|||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.isLockable
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.MainScreen
|
||||
|
|
@ -23,11 +24,16 @@ import com.tangem.tap.common.redux.AppState
|
|||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Middleware
|
||||
import timber.log.Timber
|
||||
|
||||
internal class SaveWalletMiddleware {
|
||||
|
||||
private val saveWalletJobHolder = JobHolder()
|
||||
|
||||
val middleware: Middleware<AppState> = { _, stateProvider ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
|
|
@ -99,9 +105,7 @@ internal class SaveWalletMiddleware {
|
|||
?: return@launch
|
||||
|
||||
val featureToggles = store.inject(DaggerGraphState::userWalletsListManagerFeatureToggles)
|
||||
if (featureToggles.isGeneralManagerEnabled) {
|
||||
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true)
|
||||
} else {
|
||||
if (!featureToggles.isGeneralManagerEnabled) {
|
||||
provideLockableUserWalletsListManagerIfNot()
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +147,7 @@ internal class SaveWalletMiddleware {
|
|||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}.saveIn(saveWalletJobHolder)
|
||||
}
|
||||
|
||||
private fun allowToUseBiometrics(state: SaveWalletState) {
|
||||
|
|
@ -152,10 +156,6 @@ internal class SaveWalletMiddleware {
|
|||
return
|
||||
}
|
||||
|
||||
val scanResponse = state.backupInfo?.scanResponse
|
||||
?: store.state.globalState.scanResponse
|
||||
?: return
|
||||
|
||||
if (state.backupInfo != null) {
|
||||
// TODO: Remove after onboarding refactoring
|
||||
Analytics.send(Onboarding.EnableBiometrics(AnalyticsParam.OnOffState.On))
|
||||
|
|
@ -164,31 +164,49 @@ internal class SaveWalletMiddleware {
|
|||
}
|
||||
|
||||
scope.launch {
|
||||
val userWallet = userWalletsListManager.selectedUserWalletSync
|
||||
?: UserWalletBuilder(scanResponse)
|
||||
.backupCardsIds(state.backupInfo?.backupCardsIds)
|
||||
.build()
|
||||
?: return@launch
|
||||
val backupInfo = state.backupInfo
|
||||
val userWalletFromBackup = backupInfo?.scanResponse
|
||||
?.let(::UserWalletBuilder)
|
||||
?.backupCardsIds(backupInfo.backupCardsIds)
|
||||
?.build()
|
||||
|
||||
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true)
|
||||
if (userWalletFromBackup != null) {
|
||||
userWalletsListManager.save(userWalletFromBackup, canOverride = true)
|
||||
.flatMap { saveAccessCodeIfNeeded(backupInfo.accessCode, userWalletFromBackup.cardsInWallet) }
|
||||
.doOnFailure {
|
||||
Timber.e(it, "Unable to save user wallet")
|
||||
|
||||
saveAccessCodeIfNeeded(accessCode = state.backupInfo?.accessCode, cardsInWallet = userWallet.cardsInWallet)
|
||||
.flatMap {
|
||||
userWalletsListManager.save(userWallet, canOverride = true)
|
||||
}
|
||||
.doOnFailure { error ->
|
||||
store.dispatchWithMain(SaveWalletAction.Save.Error(error))
|
||||
}
|
||||
.doOnSuccess {
|
||||
preferencesStorage.shouldSaveAccessCodes = true
|
||||
store.inject(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = userWallet.hasAccessCode,
|
||||
)
|
||||
store.dispatchWithMain(SaveWalletAction.Save.Error(it))
|
||||
}
|
||||
.doOnSuccess {
|
||||
handleSavingSuccess(userWalletFromBackup)
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
||||
store.dispatchOnMain(SaveWalletAction.Save.Success)
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet))
|
||||
* because it will be automatically saved on UserWalletsListManager switch
|
||||
* */
|
||||
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard {
|
||||
val error = IllegalStateException("No selected user wallet")
|
||||
Timber.e(error, "Unable to save user wallet")
|
||||
store.dispatchWithMain(SaveWalletAction.Save.Error(TangemSdkError.ExceptionError(error)))
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
||||
handleSavingSuccess(selectedUserWallet)
|
||||
}
|
||||
}.saveIn(saveWalletJobHolder)
|
||||
}
|
||||
|
||||
private suspend fun handleSavingSuccess(userWallet: UserWallet) {
|
||||
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true)
|
||||
preferencesStorage.shouldSaveAccessCodes = true
|
||||
store.inject(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = userWallet.hasAccessCode,
|
||||
)
|
||||
|
||||
store.dispatchWithMain(SaveWalletAction.Save.Success)
|
||||
store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Wallet))
|
||||
}
|
||||
|
||||
private suspend fun provideLockableUserWalletsListManagerIfNot() {
|
||||
|
|
@ -223,15 +241,15 @@ internal class SaveWalletMiddleware {
|
|||
cardsInWallet: Set<String>,
|
||||
): CompletionResult<Unit> {
|
||||
return when {
|
||||
accessCode != null -> {
|
||||
accessCode.isNullOrBlank() -> {
|
||||
CompletionResult.Success(Unit)
|
||||
}
|
||||
else -> {
|
||||
tangemSdkManager.saveAccessCode(
|
||||
accessCode = accessCode,
|
||||
cardsIds = cardsInWallet,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
CompletionResult.Success(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,9 @@ import com.tangem.core.ui.utils.BigDecimalFormatter
|
|||
*/
|
||||
@Composable
|
||||
fun MarketPriceBlock(state: MarketPriceBlockState, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
var rootWidth by remember { mutableIntStateOf(value = 0) }
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = TangemTheme.colors.background.primary,
|
||||
|
|
@ -42,27 +44,13 @@ fun MarketPriceBlock(state: MarketPriceBlockState, modifier: Modifier = Modifier
|
|||
)
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = TangemTheme.dimens.size72)
|
||||
.padding(all = TangemTheme.dimens.spacing12),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
.padding(all = TangemTheme.dimens.spacing12)
|
||||
.onSizeChanged { rootWidth = it.width },
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
) {
|
||||
var rootWidth by remember { mutableIntStateOf(value = 0) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier.onSizeChanged { rootWidth = it.width },
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
) {
|
||||
Title(currencyName = state.currencySymbol)
|
||||
Content(state = state, rootWidth = rootWidth)
|
||||
}
|
||||
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size20),
|
||||
painter = painterResource(id = R.drawable.ic_chevron_right_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
Title(currencyName = state.currencySymbol)
|
||||
Content(state = state, rootWidth = rootWidth)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state.transformers
|
||||
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletLoadingStateFactory
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class ReinitializeWalletTransformer(
|
||||
private val userWallet: UserWallet,
|
||||
private val prevWalletId: UserWalletId,
|
||||
private val newUserWallet: UserWallet,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
) : WalletScreenStateTransformer {
|
||||
|
||||
|
|
@ -18,9 +20,10 @@ internal class ReinitializeWalletTransformer(
|
|||
|
||||
override fun transform(prevState: WalletScreenState): WalletScreenState {
|
||||
return prevState.copy(
|
||||
wallets = persistentListOf(
|
||||
walletLoadingStateFactory.create(userWallet),
|
||||
),
|
||||
wallets = prevState.wallets
|
||||
.filterNot { it.walletCardState.id == prevWalletId }
|
||||
.plus(element = walletLoadingStateFactory.create(newUserWallet))
|
||||
.toImmutableList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -223,7 +223,11 @@ internal class WalletViewModel @Inject constructor(
|
|||
)
|
||||
|
||||
stateHolder.update(
|
||||
ReinitializeWalletTransformer(userWallet = action.selectedWallet, clickIntents = clickIntents),
|
||||
ReinitializeWalletTransformer(
|
||||
prevWalletId = action.prevWalletId,
|
||||
newUserWallet = action.selectedWallet,
|
||||
clickIntents = clickIntents,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ web3j = "4.10.1"
|
|||
# region Tangem
|
||||
tangemBlockchainSdk = "release-app_5.8-536"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "release-app_5.8-336"
|
||||
tangemCardSdk = "release-app_5.8-338"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
# endregion Tangem
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue