diff --git a/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt index f944a89717..637030995e 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt @@ -29,7 +29,14 @@ internal object LegacyMiddleware { val walletsRepository = store.inject(DaggerGraphState::walletsRepository) selectedUserWallet() - .distinctUntilChanged() + .distinctUntilChanged { old, new -> + if (old is UserWallet.Cold && new is UserWallet.Cold) { + old.walletId == new.walletId && + old.scanResponse == new.scanResponse + } else { + old.walletId == new.walletId + } + } .onEach { selectedUserWallet -> val initializedAppSettingsStateContent = initializeAppSettingsState( shouldSaveUserWallets = walletsRepository.shouldSaveUserWalletsSync(), @@ -78,6 +85,7 @@ internal object LegacyMiddleware { isHidingEnabled = store.inject(DaggerGraphState::balanceHidingRepository) .getBalanceHidingSettings().isHidingEnabledInSettings, needEnrollBiometrics = runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull() == true, + hasSecuredWallets = store.inject(DaggerGraphState::userWalletsListRepository).hasSecuredWallets(), ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt index f8af3f022b..16456eb969 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt @@ -483,4 +483,12 @@ internal object WalletsDomainModule { dispatchers = dispatcherProvider, ) } + + @Provides + @Singleton + fun provideHasSecuredWalletsUseCase( + userWalletsListRepository: UserWalletsListRepository, + ): HasSecuredWalletsUseCase { + return HasSecuredWalletsUseCase(userWalletsListRepository = userWalletsListRepository) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt index 36b368b111..3c58898109 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt @@ -345,6 +345,12 @@ internal class DefaultUserWalletsListRepository( userWalletEncryptionKeysRepository.clear() } + override suspend fun hasSecuredWallets(): Boolean { + val userWallets = userWalletsSync() + val unsecuredWalletIds = userWalletEncryptionKeysRepository.getAllUnsecured().map { it.walletId }.toSet() + return userWallets.any { it.walletId !in unsecuredWalletIds } + } + private suspend fun requestPasswordRecursive( hotWalletId: HotWalletId, block: suspend (CharArray) -> UserWalletEncryptionKey?, 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 25964c3070..bc49d31e9d 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 @@ -66,14 +66,8 @@ class DetailsMiddleware { when (action.setting) { AppSetting.SaveWallets -> toggleSaveWallets(state, enable = action.enable) AppSetting.SaveAccessCode -> toggleSaveAccessCodes(state, enable = action.enable) - AppSetting.RequireAccessCode -> toggleRequireAccessCode( - state = state, - enable = action.enable, - ) - AppSetting.BiometricAuthentication -> toggleBiometricsAuthentication( - state = state, - enable = action.enable, - ) + AppSetting.RequireAccessCode -> toggleRequireAccessCode(enable = action.enable) + AppSetting.BiometricAuthentication -> toggleBiometricsAuthentication(enable = action.enable) } } is DetailsAction.AppSettings.CheckBiometricsStatus -> { @@ -100,7 +94,7 @@ class DetailsMiddleware { } } - private fun toggleBiometricsAuthentication(state: DetailsState, enable: Boolean) { + private fun toggleBiometricsAuthentication(enable: Boolean) { scope.launch { val walletsRepository = store.inject(DaggerGraphState::walletsRepository) @@ -110,16 +104,12 @@ class DetailsMiddleware { return@launch } - toggleRequireAccessCode( - state = state, - enable = true, - ) - if (enable) { setBiometricLockForAllWallets() } else { // Remove all biometric-related data removeAllBiometricData() + walletsRepository.setRequireAccessCode(value = true) } walletsRepository.setUseBiometricAuthentication(value = enable) @@ -127,7 +117,7 @@ class DetailsMiddleware { } } - private fun toggleRequireAccessCode(state: DetailsState, enable: Boolean) { + private fun toggleRequireAccessCode(enable: Boolean) { scope.launch { val walletsRepository = store.inject(DaggerGraphState::walletsRepository) @@ -138,11 +128,8 @@ class DetailsMiddleware { } if (enable) { - // Remove all biometric sign data + // Remove all saved access codes removeAllBiometricSingData() - toggleSaveAccessCodes(state, enable = false) - } else { - toggleSaveAccessCodes(state, enable = true) } walletsRepository.setRequireAccessCode(value = enable) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index 5b219a6c22..54a13d6915 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -111,6 +111,9 @@ private fun handlePrivacyAction(action: DetailsAction.AppSettings, state: Detail isHidingEnabled = action.state.isHidingEnabled, selectedAppCurrency = action.state.selectedAppCurrency, selectedThemeMode = action.state.selectedThemeMode, + useBiometricAuthentication = action.state.useBiometricAuthentication, + requireAccessCode = action.state.requireAccessCode, + hasSecuredWallets = action.state.hasSecuredWallets, ), ) is DetailsAction.AppSettings.EnrollBiometrics, diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt index f7e7eaa6dc..518cd67afb 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -22,6 +22,7 @@ data class AppSettingsState( val requireAccessCode: Boolean = false, val useBiometricAuthentication: Boolean = false, val needEnrollBiometrics: Boolean = false, + val hasSecuredWallets: Boolean = false, val isHidingEnabled: Boolean = false, val isInProgress: Boolean = false, val selectedAppCurrency: AppCurrency = AppCurrency.Default, diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/model/AppSettingsModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/model/AppSettingsModel.kt index d9d1ad29f8..2df9cb3974 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/model/AppSettingsModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/appsettings/model/AppSettingsModel.kt @@ -10,6 +10,7 @@ import com.tangem.domain.appcurrency.repository.AppCurrencyRepository import com.tangem.domain.apptheme.model.AppThemeMode import com.tangem.domain.apptheme.repository.AppThemeModeRepository import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository +import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.settings.CanUseBiometryUseCase import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.wallets.repository.WalletsRepository @@ -48,6 +49,7 @@ internal class AppSettingsModel @Inject constructor( private val appCurrencyRepository: AppCurrencyRepository, private val walletsRepository: WalletsRepository, private val canUseBiometryUseCase: CanUseBiometryUseCase, + private val userWalletsListRepository: UserWalletsListRepository, private val balanceHidingRepository: BalanceHidingRepository, private val analyticsEventHandler: AnalyticsEventHandler, private val appThemeModeRepository: AppThemeModeRepository, @@ -114,7 +116,8 @@ internal class AppSettingsModel @Inject constructor( ) if (hotWalletFeatureToggles.isHotWalletEnabled) { - val canUseBiometrics = !state.needEnrollBiometrics && !state.isInProgress + val canUseBiometrics = + !state.needEnrollBiometrics && !state.isInProgress && state.hasSecuredWallets add( itemsFactory.createUseBiometricsSwitch( @@ -126,7 +129,7 @@ internal class AppSettingsModel @Inject constructor( add( itemsFactory.createRequireAccessCodeSwitch( - isChecked = state.requireAccessCode, + isChecked = state.requireAccessCode || !state.useBiometricAuthentication, isEnabled = canUseBiometrics && state.useBiometricAuthentication, onCheckedChange = ::onRequireAccessCodeToggled, ), @@ -206,14 +209,12 @@ internal class AppSettingsModel @Inject constructor( // analyticsEventHandler.send(Settings.AppSettings.BiometricAuthenticationChanged(param)) if (isChecked) { onSettingsToggled(AppSetting.BiometricAuthentication, enable = true) - onSettingsToggled(AppSetting.RequireAccessCode, enable = true) } else { updateContentState { copy( dialog = dialogsFactory.createDisableBiometricAuthenticationAlert( onDisable = { onSettingsToggled(AppSetting.BiometricAuthentication, enable = false) - onSettingsToggled(AppSetting.RequireAccessCode, enable = true) dismissDialog() }, onDismiss = ::dismissDialog, @@ -323,6 +324,7 @@ internal class AppSettingsModel @Inject constructor( isHidingEnabled = balanceHidingRepository.getBalanceHidingSettings().isHidingEnabledInSettings, selectedAppCurrency = appCurrencyRepository.getSelectedAppCurrency().firstOrNull() ?: AppCurrency.Default, selectedThemeMode = appThemeModeRepository.getAppThemeMode().firstOrNull() ?: AppThemeMode.DEFAULT, + hasSecuredWallets = userWalletsListRepository.hasSecuredWallets(), ) store.dispatchWithMain(DetailsAction.AppSettings.Prepare(state)) diff --git a/domain/common/src/main/java/com/tangem/domain/common/wallets/UserWalletsListRepository.kt b/domain/common/src/main/java/com/tangem/domain/common/wallets/UserWalletsListRepository.kt index 7a07b10402..52df2eb43d 100644 --- a/domain/common/src/main/java/com/tangem/domain/common/wallets/UserWalletsListRepository.kt +++ b/domain/common/src/main/java/com/tangem/domain/common/wallets/UserWalletsListRepository.kt @@ -123,6 +123,11 @@ interface UserWalletsListRepository { */ suspend fun clearPersistentData() + /** + * Checks if there are any secured wallets (wallets that are not locked with [LockMethod.NoLock]). + */ + suspend fun hasSecuredWallets(): Boolean + sealed class LockMethod { data object Biometric : LockMethod() class AccessCode(val accessCode: CharArray) : LockMethod() diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/HasSecuredWalletsUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/HasSecuredWalletsUseCase.kt new file mode 100644 index 0000000000..30fd74b65e --- /dev/null +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/HasSecuredWalletsUseCase.kt @@ -0,0 +1,10 @@ +package com.tangem.domain.wallets.usecase + +import com.tangem.domain.common.wallets.UserWalletsListRepository + +class HasSecuredWalletsUseCase(private val userWalletsListRepository: UserWalletsListRepository) { + + suspend operator fun invoke(): Boolean { + return userWalletsListRepository.hasSecuredWallets() + } +} \ No newline at end of file diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/accesscode/AccessCodeModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/accesscode/AccessCodeModel.kt index 066416eb67..58636050b1 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/accesscode/AccessCodeModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/accesscode/AccessCodeModel.kt @@ -81,7 +81,7 @@ internal class AccessCodeModel @Inject constructor( accessCodeColor = when { params.accessCodeToConfirm == null -> PinTextColor.Primary value.length != uiState.value.accessCodeLength -> PinTextColor.Primary - value == params.accessCodeToConfirm -> PinTextColor.Success + value == params.accessCodeToConfirm -> PinTextColor.Primary else -> PinTextColor.WrongCode }, )