From 8e96433f447d6856780bddb33be2901f233b6f39 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 20 Mar 2024 19:24:52 +0400 Subject: [PATCH 01/15] Updated on 2026-08-14 --- .../details/redux/DetailsMiddleware.kt | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index f429e3423f..685a09edee 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -39,6 +39,7 @@ import com.tangem.utils.coroutines.saveIn import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.rekotlin.Action @@ -217,7 +218,7 @@ class DetailsMiddleware { } } is DetailsAction.AppSettings.CheckBiometricsStatus -> { - observeBiometricsStatusChanges(state, action.lifecycleScope) + observeBiometricsStatusChanges(action.lifecycleScope) } is DetailsAction.AppSettings.EnrollBiometrics -> { enrollBiometrics() @@ -239,20 +240,27 @@ class DetailsMiddleware { } } - private fun observeBiometricsStatusChanges(state: DetailsState, lifecycleScope: LifecycleCoroutineScope) { - lifecycleScope.launch(Dispatchers.IO) { + private fun observeBiometricsStatusChanges(lifecycleScope: LifecycleCoroutineScope) { + val needEnrollBiometricsFlow = flow { do { val needEnrollBiometrics = runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull() - if (needEnrollBiometrics != null && - needEnrollBiometrics != state.appSettingsState.needEnrollBiometrics - ) { - store.dispatchWithMain(DetailsAction.AppSettings.BiometricsStatusChanged(needEnrollBiometrics)) + if (needEnrollBiometrics != null) { + emit(needEnrollBiometrics) } - delay(timeMillis = 500) + delay(timeMillis = 200) } while (true) - }.saveIn(checkBiometricsStatusJobHolder) + } + + needEnrollBiometricsFlow + .distinctUntilChanged() + .onEach { needEnrollBiometrics -> + store.dispatchWithMain(DetailsAction.AppSettings.BiometricsStatusChanged(needEnrollBiometrics)) + } + .flowOn(Dispatchers.IO) + .launchIn(lifecycleScope) + .saveIn(checkBiometricsStatusJobHolder) } private fun enrollBiometrics() { From aa77c81f2da30ac16c1c48dcfa8dbf2946c9f58e Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 20 Mar 2024 16:21:41 +0000 Subject: [PATCH 02/15] Updated on 2026-08-14 --- .../viewmodels/intents/WalletWarningsClickIntents.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt index f16f13dda2..1ff5dc6191 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt @@ -80,11 +80,10 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( override fun onAddBackupCardClick() { analyticsEventHandler.send(MainScreen.NoticeBackupYourWalletTapped) - prepareOnboardingProcess() - router.openOnboardingScreen() + prepareAndStartOnboardingProcess() } - private fun prepareOnboardingProcess() { + private fun prepareAndStartOnboardingProcess() { viewModelScope.launch(dispatchers.main) { getSelectedUserWallet()?.let { reduxStateHolder.dispatch( @@ -94,6 +93,8 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( ), ) } + // navigation action shouldn't be out of coroutine to avoid race + router.openOnboardingScreen() } } From 69234e50efd7f2ee9d29ba5e164dab23124cd17e Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 Mar 2024 09:37:32 +0000 Subject: [PATCH 03/15] Updated on 2026-08-14 --- .../tap/network/auth/DefaultAppVersionProvider.kt | 11 +++++++++++ .../java/com/tangem/tap/network/auth/di/AuthModule.kt | 8 ++++++++ .../java/com/tangem/datasource/di/NetworkModule.kt | 3 +++ .../java/com/tangem/datasource/utils/RequestHeader.kt | 6 ++++++ .../java/com/tangem/lib/auth/AppVersionProvider.kt | 6 ++++++ 5 files changed, 34 insertions(+) create mode 100644 app/src/main/java/com/tangem/tap/network/auth/DefaultAppVersionProvider.kt create mode 100644 libs/auth/src/main/java/com/tangem/lib/auth/AppVersionProvider.kt diff --git a/app/src/main/java/com/tangem/tap/network/auth/DefaultAppVersionProvider.kt b/app/src/main/java/com/tangem/tap/network/auth/DefaultAppVersionProvider.kt new file mode 100644 index 0000000000..7987d7ce6e --- /dev/null +++ b/app/src/main/java/com/tangem/tap/network/auth/DefaultAppVersionProvider.kt @@ -0,0 +1,11 @@ +package com.tangem.tap.network.auth + +import com.tangem.lib.auth.AppVersionProvider +import com.tangem.wallet.BuildConfig + +internal class DefaultAppVersionProvider : AppVersionProvider { + + override fun getAppVersion(): String { + return BuildConfig.VERSION_NAME + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt index fa9aa920a1..0185472a6e 100644 --- a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt +++ b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt @@ -2,8 +2,10 @@ package com.tangem.tap.network.auth.di import com.tangem.datasource.config.ConfigManager import com.tangem.datasource.local.userwallet.UserWalletsStore +import com.tangem.lib.auth.AppVersionProvider import com.tangem.lib.auth.AuthProvider import com.tangem.lib.auth.ExpressAuthProvider +import com.tangem.tap.network.auth.DefaultAppVersionProvider import com.tangem.tap.network.auth.DefaultAuthProvider import com.tangem.tap.network.auth.DefaultExpressAuthProvider import com.tangem.tap.proxy.AppStateHolder @@ -34,4 +36,10 @@ class AuthModule { configManager = configManager, ) } + + @Provides + @Singleton + fun provideAppVersionProvider(): AppVersionProvider { + return DefaultAppVersionProvider() + } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt index eb61db86b2..e52008bbc5 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt @@ -9,6 +9,7 @@ import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.utils.RequestHeader.* import com.tangem.datasource.utils.addHeaders import com.tangem.datasource.utils.addLoggers +import com.tangem.lib.auth.AppVersionProvider import com.tangem.lib.auth.ExpressAuthProvider import dagger.Module import dagger.Provides @@ -30,6 +31,7 @@ class NetworkModule { @NetworkMoshi moshi: Moshi, @ApplicationContext context: Context, expressAuthProvider: ExpressAuthProvider, + appVersionProvider: AppVersionProvider, ): TangemExpressApi { val url = if (BuildConfig.ENVIRONMENT == "dev") { DEV_EXPRESS_BASE_URL @@ -43,6 +45,7 @@ class NetworkModule { .client( OkHttpClient.Builder() .addHeaders(Express(expressAuthProvider)) + .addHeaders(AppVersionPlatformHeaders(appVersionProvider)) .addLoggers(context) .build(), ) diff --git a/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt b/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt index d84b00ac2e..bd725ea0b6 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt @@ -1,5 +1,6 @@ package com.tangem.datasource.utils +import com.tangem.lib.auth.AppVersionProvider import com.tangem.lib.auth.AuthBearerProvider import com.tangem.lib.auth.AuthProvider import com.tangem.lib.auth.ExpressAuthProvider @@ -30,4 +31,9 @@ sealed class RequestHeader(vararg pairs: Pair String>) { class AuthBearerHeader(authBearerProvider: AuthBearerProvider) : RequestHeader( "Authorization" to { "Bearer " + authBearerProvider.getApiKey() }, ) + + class AppVersionPlatformHeaders(appVersionProvider: AppVersionProvider) : RequestHeader( + "version" to { appVersionProvider.getAppVersion() }, + "platform" to { "android" }, + ) } \ No newline at end of file diff --git a/libs/auth/src/main/java/com/tangem/lib/auth/AppVersionProvider.kt b/libs/auth/src/main/java/com/tangem/lib/auth/AppVersionProvider.kt new file mode 100644 index 0000000000..3b8e606e9c --- /dev/null +++ b/libs/auth/src/main/java/com/tangem/lib/auth/AppVersionProvider.kt @@ -0,0 +1,6 @@ +package com.tangem.lib.auth + +interface AppVersionProvider { + + fun getAppVersion(): String +} \ No newline at end of file From 746e83f1e71accbf72bd9b2e444cedafb0c40d04 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 Mar 2024 11:51:24 +0000 Subject: [PATCH 04/15] 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 05/15] 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 06/15] 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 07/15] 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, + ), ) } From 8a3cf50a04edeca772979902f81a71778bb991a8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 22 Mar 2024 13:48:54 +0000 Subject: [PATCH 08/15] Updated on 2026-08-14 --- .../implementation/GeneralUserWalletsListManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 79e30fec1f..1e01c26cd2 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 @@ -129,7 +129,7 @@ internal class GeneralUserWalletsListManager( } if (possibleManager == implementation.value) { - error("${possibleManager::class.simpleName}} is already selected") + Timber.e("Switch to same manager ${possibleManager::class.simpleName}") } Timber.d("Switch to ${possibleManager::class.simpleName}") From f2aad5009e5e510fa2500c699bd3444e74f06f9b Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 22 Mar 2024 15:12:31 +0000 Subject: [PATCH 09/15] Updated on 2026-08-14 --- .../features/details/redux/DetailsMiddleware.kt | 14 ++++++++++---- .../products/twins/redux/TwinCardsMiddleware.kt | 5 ++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index 685a09edee..e7c01ea29e 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -20,7 +20,7 @@ import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.userwallets.UserWalletBuilder import com.tangem.domain.userwallets.UserWalletIdBuilder import com.tangem.domain.wallets.legacy.UserWalletsListManager -import com.tangem.domain.wallets.legacy.isLockedSync +import com.tangem.domain.wallets.legacy.asLockable import com.tangem.tap.* import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Settings @@ -120,8 +120,12 @@ class DetailsMiddleware { doBeforeErase() tangemSdkManager.resetToFactorySettings(card.cardId, true) - .flatMap { userWalletsListManager.delete(listOfNotNull(userWalletId)) } - .flatMap { tangemSdkManager.deleteSavedUserCodes(setOf(card.cardId)) } + .flatMap { + userWalletsListManager.delete(listOfNotNull(userWalletId)) + } + .flatMap { + tangemSdkManager.deleteSavedUserCodes(setOf(card.cardId)) + } .doOnSuccess { Analytics.send(Settings.CardSettings.FactoryResetFinished()) @@ -130,7 +134,9 @@ class DetailsMiddleware { store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet)) store.onUserWalletSelected(selectedUserWallet) } else { - if (userWalletsListManager.isLockedSync) { + val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync } + .fold(onSuccess = { true }, onFailure = { false }) + if (isLocked) { store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Welcome)) } else { store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home)) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index 90f14188f3..e7919af2f3 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -11,6 +11,7 @@ import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.userwallets.UserWalletIdBuilder +import com.tangem.domain.wallets.legacy.asLockable import com.tangem.domain.wallets.legacy.isLockedSync import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Onboarding @@ -356,7 +357,9 @@ private fun handle(action: Action, dispatch: DispatchFunction) { private fun getPopBackScreen(): AppScreen { return if (userWalletsListManager.hasUserWallets) { - if (userWalletsListManager.isLockedSync) { + val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync } + .fold(onSuccess = { true }, onFailure = { false }) + if (isLocked) { AppScreen.Welcome } else { AppScreen.Wallet From 659786b74caa1c7f7ad0d3409f392997aec89109 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 22 Mar 2024 16:57:06 +0000 Subject: [PATCH 10/15] Updated on 2026-08-14 --- .../com/tangem/tap/features/details/redux/DetailsMiddleware.kt | 3 ++- .../onboarding/products/twins/redux/TwinCardsMiddleware.kt | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index e7c01ea29e..90aa10f2cd 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -82,6 +82,7 @@ class DetailsMiddleware { } class EraseWalletMiddleware { + @Suppress("CyclomaticComplexMethod") fun handle(action: DetailsAction.ResetToFactory) { when (action) { is DetailsAction.ResetToFactory.Start -> { @@ -136,7 +137,7 @@ class DetailsMiddleware { } else { val isLocked = runCatching { userWalletsListManager.asLockable()?.isLockedSync } .fold(onSuccess = { true }, onFailure = { false }) - if (isLocked) { + if (isLocked && userWalletsListManager.hasUserWallets) { store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Welcome)) } else { store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home)) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index e7919af2f3..c2fc60baaa 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -12,7 +12,6 @@ import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.userwallets.UserWalletIdBuilder import com.tangem.domain.wallets.legacy.asLockable -import com.tangem.domain.wallets.legacy.isLockedSync import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.entities.ProgressState From 1c856e49e077fbf4582f032efefa8849ca1a14e6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 25 Mar 2024 15:34:17 +0800 Subject: [PATCH 11/15] Updated on 2026-08-14 --- .../features/onboarding/OnboardingHelper.kt | 8 +- .../saveWallet/redux/SaveWalletAction.kt | 2 + .../saveWallet/redux/SaveWalletMiddleware.kt | 92 ++++++++++--------- .../saveWallet/redux/SaveWalletReducer.kt | 4 +- .../ReinitializeWalletTransformer.kt | 6 ++ .../viewmodels/WalletsUpdateActionResolver.kt | 5 +- 6 files changed, 68 insertions(+), 49 deletions(-) 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 70c575c06d..6d69e20e28 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 @@ -78,9 +78,7 @@ object OnboardingHelper { when { // When should save user wallets, then save card without navigate to save wallet screen store.inject(DaggerGraphState::walletsRepository).shouldSaveUserWalletsSync() -> { - proceedWithScanResponse(scanResponse, backupCardsIds) - - store.dispatchOnMain( + store.dispatchWithMain( SaveWalletAction.ProvideBackupInfo( scanResponse = scanResponse, accessCode = accessCode, @@ -90,9 +88,9 @@ object OnboardingHelper { val toggles = store.inject(DaggerGraphState::userWalletsListManagerFeatureToggles) if (toggles.isGeneralManagerEnabled) { - store.dispatchOnMain(SaveWalletAction.AllowToUseBiometrics) + store.dispatchWithMain(SaveWalletAction.SaveWalletAfterBackup) } else { - store.dispatchOnMain(SaveWalletAction.Save) + store.dispatchWithMain(SaveWalletAction.Save) } } // When should not save user wallets but device has biometry and save wallet screen has not been shown, diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletAction.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletAction.kt index e5625ad1d2..b76bdfcac5 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletAction.kt @@ -27,4 +27,6 @@ internal sealed interface SaveWalletAction : Action { } data object SaveWalletWasShown : SaveWalletAction + + data object SaveWalletAfterBackup : SaveWalletAction } \ No newline at end of file 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 8193fd9e0e..62fa03d837 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 @@ -1,11 +1,8 @@ package com.tangem.tap.features.saveWallet.redux -import com.tangem.common.CompletionResult +import com.tangem.common.* import com.tangem.common.core.TangemSdkError -import com.tangem.common.doOnFailure -import com.tangem.common.doOnSuccess import com.tangem.common.extensions.guard -import com.tangem.common.flatMap import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction @@ -20,6 +17,7 @@ import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchWithMain import com.tangem.tap.common.extensions.inject +import com.tangem.tap.common.extensions.onUserWalletSelected import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation @@ -28,6 +26,7 @@ import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn import kotlinx.coroutines.launch import org.rekotlin.Middleware +import org.rekotlin.Store import timber.log.Timber internal class SaveWalletMiddleware { @@ -53,6 +52,7 @@ internal class SaveWalletMiddleware { is SaveWalletAction.EnrollBiometrics.Enroll -> enrollBiometrics() is SaveWalletAction.SaveWalletWasShown -> saveWalletWasShown() is SaveWalletAction.Dismiss -> dismiss(state) + is SaveWalletAction.SaveWalletAfterBackup -> saveWalletAfterBackup(state) is SaveWalletAction.Save.Success, is SaveWalletAction.ProvideBackupInfo, is SaveWalletAction.CloseError, @@ -63,6 +63,30 @@ internal class SaveWalletMiddleware { } } + private fun saveWalletAfterBackup(state: SaveWalletState) { + scope.launch { + val backupInfo = state.backupInfo ?: error("Backup info is null") + + val userWallet = UserWalletBuilder(backupInfo.scanResponse) + .backupCardsIds(state.backupInfo.backupCardsIds) + .build() + .guard { + Timber.e("User wallet not created") + return@launch + } + + userWalletsListManager.save(userWallet, canOverride = true) + .flatMap { + saveAccessCodeIfNeeded(accessCode = backupInfo.accessCode, cardsInWallet = userWallet.cardsInWallet) + } + .doOnFailure { error -> + Timber.e(error, "Unable to save user wallet") + } + .doOnSuccess { mainScope.launch { store.onUserWalletSelected(userWallet) } } + .doOnResult { store.navigateToWallet() } + } + } + private fun enrollBiometrics() { store.dispatchOnMain(NavigationAction.OpenBiometricsSettings) } @@ -138,14 +162,7 @@ internal class SaveWalletMiddleware { } store.dispatchOnMain(SaveWalletAction.Save.Success) - - store.dispatchOnMain( - if (store.state.navigationState.backStack.contains(AppScreen.Wallet)) { - NavigationAction.PopBackTo(AppScreen.Wallet) - } else { - NavigationAction.NavigateTo(AppScreen.Wallet) - }, - ) + store.navigateToWallet() } }.saveIn(saveWalletJobHolder) } @@ -164,41 +181,22 @@ internal class SaveWalletMiddleware { } scope.launch { - val backupInfo = state.backupInfo - val userWalletFromBackup = backupInfo?.scanResponse - ?.let(::UserWalletBuilder) - ?.backupCardsIds(backupInfo.backupCardsIds) - ?.build() + /* - if (userWalletFromBackup != null) { - userWalletsListManager.save(userWalletFromBackup, canOverride = true) - .flatMap { saveAccessCodeIfNeeded(backupInfo.accessCode, userWalletFromBackup.cardsInWallet) } - .doOnFailure { - Timber.e(it, "Unable to save user wallet") - - store.dispatchWithMain(SaveWalletAction.Save.Error(it)) - } - .doOnSuccess { - handleSavingSuccess(userWalletFromBackup) - } - } else { - /* - - * 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) + * 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 } + + handleSuccessAllowing(selectedUserWallet) }.saveIn(saveWalletJobHolder) } - private suspend fun handleSavingSuccess(userWallet: UserWallet) { + private suspend fun handleSuccessAllowing(userWallet: UserWallet) { store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true) preferencesStorage.shouldSaveAccessCodes = true store.inject(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy( @@ -252,4 +250,14 @@ internal class SaveWalletMiddleware { } } } + + private suspend fun Store.navigateToWallet() { + dispatchWithMain( + if (store.state.navigationState.backStack.contains(AppScreen.Wallet)) { + NavigationAction.PopBackTo(AppScreen.Wallet) + } else { + NavigationAction.NavigateTo(AppScreen.Wallet) + }, + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletReducer.kt index b1c7269494..88b5697eca 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletReducer.kt @@ -47,7 +47,9 @@ internal object SaveWalletReducer { needEnrollBiometrics = false, isSaveInProgress = false, ) - is SaveWalletAction.SaveWalletWasShown -> state + is SaveWalletAction.SaveWalletWasShown, + is SaveWalletAction.SaveWalletAfterBackup, + -> state } } } \ No newline at end of file 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 b60ed80b8a..8b18dcf457 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 @@ -8,6 +8,12 @@ import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletCl import kotlinx.collections.immutable.toImmutableList /** + * Reinitialize wallet transformer + * + * @property prevWalletId reinitialized wallet id + * @property newUserWallet new user wallet + * @property clickIntents click intents + * [REDACTED_AUTHOR] */ internal class ReinitializeWalletTransformer( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolver.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolver.kt index 012aee200d..94b310fd4a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolver.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolver.kt @@ -214,7 +214,10 @@ internal class WalletsUpdateActionResolver @Inject constructor( } /** - * Reinitialize selected wallet. Example, scanning a new card if wallets saving is turned off + * Reinitialize selected wallet. + * Uses when: + * 1. user scanned a new card but wallets saving is turned off; + * 2. user reset Twins. * * @property prevWalletId previous selected wallet id * @property selectedWallet selected wallet From fe638d05b098e92221c87a5f48816a919a95fbad Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 26 Mar 2024 08:47:35 +0000 Subject: [PATCH 12/15] Updated on 2026-08-14 --- .../main/java/com/tangem/feature/swap/ui/StateBuilder.kt | 8 +------- .../com/tangem/feature/swap/viewmodels/SwapViewModel.kt | 1 - 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index 4566c64fae..33beaf6e3f 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -1027,7 +1027,6 @@ internal class StateBuilder( fun showSelectProviderBottomSheet( uiState: SwapStateHolder, selectedProviderId: String, - bestRatedProviderId: String, pricesLowerBest: Map, providersStates: Map, unavailableProviders: List, @@ -1035,7 +1034,7 @@ internal class StateBuilder( ): SwapStateHolder { val availableProvidersStates = providersStates.entries .mapNotNull { - it.convertToProviderBottomSheetState(pricesLowerBest, bestRatedProviderId, actions.onProviderSelect) + it.convertToProviderBottomSheetState(pricesLowerBest, actions.onProviderSelect) } .sortedWith(ProviderPercentDiffComparator) val unavailableProviderStates = unavailableProviders.map { @@ -1183,7 +1182,6 @@ internal class StateBuilder( private fun Map.Entry.convertToProviderBottomSheetState( pricesLowerBest: Map, - bestRatedProviderId: String, onProviderSelect: (String) -> Unit, ): ProviderState? { val provider = this.key @@ -1191,7 +1189,6 @@ internal class StateBuilder( is SwapState.EmptyAmountState -> null is SwapState.QuotesLoadedState -> { provider.convertToContentSelectableProviderState( - isBestRate = bestRatedProviderId == provider.providerId, state = state, onProviderClick = onProviderSelect, pricesLowerBest = pricesLowerBest, @@ -1301,7 +1298,6 @@ internal class StateBuilder( } private fun SwapProvider.convertToContentSelectableProviderState( - isBestRate: Boolean, state: SwapState.QuotesLoadedState, selectionType: ProviderState.SelectionType, pricesLowerBest: Map, @@ -1311,8 +1307,6 @@ internal class StateBuilder( val rateString = toTokenInfo.tokenAmount.getFormattedCryptoAmount(toTokenInfo.cryptoCurrencyStatus.currency) val additionalBadge = if (state.permissionState is PermissionDataState.PermissionReadyForRequest) { ProviderState.AdditionalBadge.PermissionRequired - } else if (isBestRate) { - ProviderState.AdditionalBadge.BestTrade } else { ProviderState.AdditionalBadge.Empty } diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index 51969a1ec1..d30242c9f2 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -928,7 +928,6 @@ internal class SwapViewModel @Inject constructor( selectedProviderId = providerId, pricesLowerBest = pricesLowerBest, unavailableProviders = unavailableProviders, - bestRatedProviderId = findBestQuoteProvider(states)?.providerId ?: providerId, providersStates = dataState.lastLoadedSwapStates, ) { uiState = stateBuilder.dismissBottomSheet(uiState) } }, From 4c9d4cc544eae0a3008c0dd7f729b4d15f707465 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 25 Mar 2024 17:54:45 +0000 Subject: [PATCH 13/15] Updated on 2026-08-14 --- .../com/tangem/tap/common/redux/AppReducer.kt | 2 -- .../com/tangem/tap/common/redux/AppState.kt | 4 ---- .../tap/features/home/redux/HomeMiddleware.kt | 23 +++++++++++++++++-- .../tap/features/signin/redux/SignInAction.kt | 12 ---------- .../features/signin/redux/SignInMiddleware.kt | 15 ------------ .../features/signin/redux/SignInReducer.kt | 17 -------------- .../tap/features/signin/redux/SignInState.kt | 8 ------- .../welcome/redux/WelcomeMiddleware.kt | 3 --- 8 files changed, 21 insertions(+), 63 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/features/signin/redux/SignInAction.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/signin/redux/SignInMiddleware.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/signin/redux/SignInReducer.kt delete mode 100644 app/src/main/java/com/tangem/tap/features/signin/redux/SignInState.kt diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt index a1232dd031..91992dd437 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppReducer.kt @@ -13,7 +13,6 @@ import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWallet import com.tangem.tap.features.saveWallet.redux.SaveWalletReducer import com.tangem.tap.features.send.redux.reducers.SendScreenReducer import com.tangem.tap.features.shop.redux.ShopReducer -import com.tangem.tap.features.signin.redux.SignInReducer import com.tangem.tap.features.tokens.legacy.redux.TokensReducer import com.tangem.tap.features.welcome.redux.WelcomeReducer import com.tangem.tap.proxy.AppStateHolder @@ -40,7 +39,6 @@ fun appReducer(action: Action, state: AppState?, appStateHolder: AppStateHolder) shopState = ShopReducer.reduce(action, state.shopState), welcomeState = WelcomeReducer.reduce(action, state), saveWalletState = SaveWalletReducer.reduce(action, state), - signInState = SignInReducer.reduce(action, state), daggerGraphState = DaggerGraphReducer.reduce(action, state), ) } diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt index 892271058e..72726532fe 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt @@ -31,8 +31,6 @@ import com.tangem.tap.features.send.redux.middlewares.SendMiddleware import com.tangem.tap.features.send.redux.states.SendState import com.tangem.tap.features.shop.redux.ShopMiddleware import com.tangem.tap.features.shop.redux.ShopState -import com.tangem.tap.features.signin.redux.SignInMiddleware -import com.tangem.tap.features.signin.redux.SignInState import com.tangem.tap.features.tokens.legacy.redux.TokensState import com.tangem.tap.features.wallet.redux.middlewares.TradeCryptoMiddleware import com.tangem.tap.features.welcome.redux.WelcomeMiddleware @@ -59,7 +57,6 @@ data class AppState( val shopState: ShopState = ShopState(), val welcomeState: WelcomeState = WelcomeState(), val saveWalletState: SaveWalletState = SaveWalletState(), - val signInState: SignInState = SignInState(), val daggerGraphState: DaggerGraphState = DaggerGraphState(), ) : StateType { @@ -97,7 +94,6 @@ data class AppState( SaveWalletMiddleware().middleware, LockUserWalletsTimerMiddleware().middleware, AccessCodeRequestPolicyMiddleware().middleware, - SignInMiddleware.middleware, DaggerGraphMiddleware.daggerGraphMiddleware, LegacyMiddleware.legacyMiddleware, TradeCryptoMiddleware.middleware, diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index 2bec7b7af6..be5b026c2d 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -9,8 +9,10 @@ import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.Basic import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.userwallets.UserWalletBuilder +import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.analytics.events.Shop import com.tangem.tap.common.entities.IndeterminateProgressButton @@ -19,7 +21,6 @@ import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.features.home.redux.HomeMiddleware.NEW_BUY_WALLET_URL import com.tangem.tap.features.send.redux.states.ButtonState -import com.tangem.tap.features.signin.redux.SignInAction import com.tangem.tap.preferencesStorage import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope @@ -113,14 +114,32 @@ private fun proceedWithScanResponse(scanResponse: ScanResponse) = scope.launch { Timber.e(error, "Unable to save user wallet") } .doOnSuccess { + sendSignedInCardAnalyticsEvent(scanResponse) scope.launch { store.onUserWalletSelected(userWallet = userWallet) } } .doOnResult { - store.dispatchOnMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Card)) navigateTo(AppScreen.Wallet) } } +private fun sendSignedInCardAnalyticsEvent(scanResponse: ScanResponse) { + val currency = ParamCardCurrencyConverter().convert( + value = scanResponse.cardTypesResolver, + ) + + if (currency != null) { + Analytics.send( + event = Basic.SignedIn( + currency = currency, + batch = scanResponse.card.batchId, + signInType = Basic.SignedIn.SignInType.Card, + walletsCount = userWalletsListManager.walletsCount.toString(), + hasBackup = scanResponse.card.backupStatus?.isActive, + ), + ) + } +} + private suspend fun navigateTo(appScreen: AppScreen) { store.dispatchOnMain(NavigationAction.NavigateTo(appScreen)) delay(timeMillis = 200) diff --git a/app/src/main/java/com/tangem/tap/features/signin/redux/SignInAction.kt b/app/src/main/java/com/tangem/tap/features/signin/redux/SignInAction.kt deleted file mode 100644 index 7978ed3f13..0000000000 --- a/app/src/main/java/com/tangem/tap/features/signin/redux/SignInAction.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.tangem.tap.features.signin.redux - -import com.tangem.core.analytics.models.Basic -import org.rekotlin.Action - -/** -[REDACTED_AUTHOR] - */ -sealed interface SignInAction : Action { - - data class SetSignInType(val type: Basic.SignedIn.SignInType) : SignInAction -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/signin/redux/SignInMiddleware.kt b/app/src/main/java/com/tangem/tap/features/signin/redux/SignInMiddleware.kt deleted file mode 100644 index 1f44dff0f7..0000000000 --- a/app/src/main/java/com/tangem/tap/features/signin/redux/SignInMiddleware.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.tangem.tap.features.signin.redux - -import com.tangem.tap.common.redux.AppState -import org.rekotlin.Middleware - -/** -[REDACTED_AUTHOR] - */ -object SignInMiddleware { - val middleware: Middleware = { _, _ -> - { next -> - { action -> next(action) } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/signin/redux/SignInReducer.kt b/app/src/main/java/com/tangem/tap/features/signin/redux/SignInReducer.kt deleted file mode 100644 index 3d5910774d..0000000000 --- a/app/src/main/java/com/tangem/tap/features/signin/redux/SignInReducer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.tangem.tap.features.signin.redux - -import com.tangem.tap.common.redux.AppState -import org.rekotlin.Action - -/** -[REDACTED_AUTHOR] - */ -object SignInReducer { - fun reduce(action: Action, state: AppState): SignInState { - if (action !is SignInAction) return state.signInState - - return when (action) { - is SignInAction.SetSignInType -> state.signInState.copy(type = action.type) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/signin/redux/SignInState.kt b/app/src/main/java/com/tangem/tap/features/signin/redux/SignInState.kt deleted file mode 100644 index 27858a8ad7..0000000000 --- a/app/src/main/java/com/tangem/tap/features/signin/redux/SignInState.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.tap.features.signin.redux - -import com.tangem.core.analytics.models.Basic - -/** -[REDACTED_AUTHOR] - */ -data class SignInState(val type: Basic.SignedIn.SignInType? = null) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt index ca7d00d461..e2ff46f387 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/redux/WelcomeMiddleware.kt @@ -25,7 +25,6 @@ import com.tangem.tap.common.extensions.onUserWalletSelected import com.tangem.tap.common.redux.AppState import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandler import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler -import com.tangem.tap.features.signin.redux.SignInAction import com.tangem.tap.proxy.redux.DaggerGraphState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -98,7 +97,6 @@ internal class WelcomeMiddleware { signInType = Basic.SignedIn.SignInType.Biometric, ) - store.dispatchWithMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Biometric)) store.dispatchWithMain(NavigationAction.NavigateTo(AppScreen.Wallet)) store.dispatchWithMain(WelcomeAction.ProceedWithBiometrics.Success) store.onUserWalletSelected(userWallet = selectedUserWallet) @@ -128,7 +126,6 @@ internal class WelcomeMiddleware { .doOnSuccess { sendSignedInAnalyticsEvent(scanResponse = scanResponse, signInType = Basic.SignedIn.SignInType.Card) - store.dispatchWithMain(SignInAction.SetSignInType(Basic.SignedIn.SignInType.Card)) store.dispatchWithMain(NavigationAction.NavigateTo(AppScreen.Wallet)) store.dispatchWithMain(WelcomeAction.ProceedWithCard.Success) store.onUserWalletSelected(userWallet = userWallet) From 4dba6e3c3dd192c8a777b8696fa99c441887009d Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 26 Mar 2024 12:54:37 +0000 Subject: [PATCH 14/15] Updated on 2026-08-14 --- .../java/com/tangem/feature/swap/ui/StateBuilder.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index 33beaf6e3f..1761af22d7 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -410,11 +410,11 @@ internal class StateBuilder( fromToken: CryptoCurrency, warnings: MutableList, ) { - val feeEnoughState = quoteModel.preparedSwapConfigState.feeState - if (feeEnoughState is SwapFeeState.NotEnough && - quoteModel.preparedSwapConfigState.isBalanceEnough && - quoteModel.permissionState !is PermissionDataState.PermissionLoading - ) { + val feeEnoughState = quoteModel.preparedSwapConfigState.feeState as? SwapFeeState.NotEnough ?: return + val needShowCoverWarning = quoteModel.preparedSwapConfigState.isBalanceEnough && + quoteModel.permissionState !is PermissionDataState.PermissionLoading && + feeEnoughState.feeCurrency != fromToken + if (needShowCoverWarning) { warnings.add( SwapWarning.UnableToCoverFeeWarning( createUnableToCoverFeeNotificationConfig( From 417fb70159954846289c2be4077a5abb309e353a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 27 Mar 2024 14:40:57 +0400 Subject: [PATCH 15/15] Updated on 2026-08-14 --- .../domain/walletconnect2/domain/WalletConnectInteractor.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt index 3c71527ab2..884d3ac5d7 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt @@ -41,9 +41,9 @@ class WalletConnectInteractor( coroutineScope { launch { subscribeToEvents() } launch { subscribeToSessions() } - } - walletConnectRepository.updateSessions() + walletConnectRepository.updateSessions() + } } fun setUserChains(accounts: List) {