From 746e83f1e71accbf72bd9b2e444cedafb0c40d04 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 Mar 2024 11:51:24 +0000 Subject: [PATCH 1/4] Updated on 2026-08-14 --- app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt b/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt index 0034c0a08a..70ad852f71 100644 --- a/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt +++ b/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt @@ -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) { _, _ -> } From 3cd82a17822413a5c5deac51ad098adf8f12306f Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 22 Mar 2024 11:31:07 +0000 Subject: [PATCH 2/4] Updated on 2026-08-14 --- .../marketprice/MarketPriceBlock.kt | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/marketprice/MarketPriceBlock.kt b/core/ui/src/main/java/com/tangem/core/ui/components/marketprice/MarketPriceBlock.kt index efbf7b9f2a..873d6dbcb2 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/marketprice/MarketPriceBlock.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/marketprice/MarketPriceBlock.kt @@ -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) } } From e84ef9a182b3d0877c081731dd1eae21d996467c Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 22 Mar 2024 14:25:38 +0400 Subject: [PATCH 3/4] Updated on 2026-08-14 --- .../GeneralUserWalletsListManager.kt | 40 +++++---- .../features/onboarding/OnboardingHelper.kt | 8 +- .../saveWallet/redux/SaveWalletMiddleware.kt | 84 +++++++++++-------- gradle/dependencies.toml | 2 +- 4 files changed, 81 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/GeneralUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/GeneralUserWalletsListManager.kt index e0e160a524..79e30fec1f 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/GeneralUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/GeneralUserWalletsListManager.kt @@ -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 } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index fd59efff07..70c575c06d 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt index 344a0909de..8193fd9e0e 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt @@ -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 = { _, 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, ): CompletionResult { return when { - accessCode != null -> { + accessCode.isNullOrBlank() -> { + CompletionResult.Success(Unit) + } + else -> { tangemSdkManager.saveAccessCode( accessCode = accessCode, cardsIds = cardsInWallet, ) } - else -> { - CompletionResult.Success(Unit) - } } } } \ No newline at end of file diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index b92767f469..64ca08576f 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -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 From 5fd8c076c6f4a120a297923816e0319c70c88351 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 22 Mar 2024 20:06:31 +0800 Subject: [PATCH 4/4] Updated on 2026-08-14 --- .../transformers/ReinitializeWalletTransformer.kt | 13 ++++++++----- .../wallet/viewmodels/WalletViewModel.kt | 6 +++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt index 7caf5d79e0..b60ed80b8a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/ReinitializeWalletTransformer.kt @@ -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(), ) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index 65ca30c4ff..63db20714d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -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, + ), ) }