diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4e00ab9a9..e5f2003a9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,6 +14,7 @@ <uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <application android:name=".BitwardenApplication" diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt index 25def43de..a7fbaf83d 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt @@ -221,19 +221,6 @@ interface SettingsDiskSource { blockedAutofillUris: List<String>?, ) - /** - * Gets whether or not the given [userId] has enabled approving passwordless logins. - */ - fun getApprovePasswordlessLoginsEnabled(userId: String): Boolean? - - /** - * Stores whether or not [isApprovePasswordlessLoginsEnabled] for the given [userId]. - */ - fun storeApprovePasswordlessLoginsEnabled( - userId: String, - isApprovePasswordlessLoginsEnabled: Boolean?, - ) - /** * Gets whether or not the given [userId] has enabled screen capture. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt index dd8653bc0..379a0de70 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt @@ -26,7 +26,6 @@ private const val DEFAULT_URI_MATCH_TYPE_KEY = "defaultUriMatch" private const val DISABLE_AUTO_TOTP_COPY_KEY = "disableAutoTotpCopy" private const val DISABLE_AUTOFILL_SAVE_PROMPT_KEY = "autofillDisableSavePrompt" private const val DISABLE_ICON_LOADING_KEY = "disableFavicon" -private const val APPROVE_PASSWORDLESS_LOGINS_KEY = "approvePasswordlessLogins" private const val SCREEN_CAPTURE_ALLOW_KEY = "screenCaptureAllowed" private const val SYSTEM_BIOMETRIC_INTEGRITY_SOURCE_KEY = "biometricIntegritySource" private const val ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY = "accountBiometricIntegrityValid" @@ -139,10 +138,6 @@ class SettingsDiskSourceImpl( storePullToRefreshEnabled(userId = userId, isPullToRefreshEnabled = null) storeInlineAutofillEnabled(userId = userId, isInlineAutofillEnabled = null) storeBlockedAutofillUris(userId = userId, blockedAutofillUris = null) - storeApprovePasswordlessLoginsEnabled( - userId = userId, - isApprovePasswordlessLoginsEnabled = null, - ) storeLastSyncTime(userId = userId, lastSyncTime = null) storeClearClipboardFrequencySeconds(userId = userId, frequency = null) removeWithPrefix(prefix = ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY.appendIdentifier(userId)) @@ -356,20 +351,6 @@ class SettingsDiskSourceImpl( bufferedMutableSharedFlow(replay = 1) } - override fun getApprovePasswordlessLoginsEnabled(userId: String): Boolean? { - return getBoolean(key = APPROVE_PASSWORDLESS_LOGINS_KEY.appendIdentifier(userId)) - } - - override fun storeApprovePasswordlessLoginsEnabled( - userId: String, - isApprovePasswordlessLoginsEnabled: Boolean?, - ) { - putBoolean( - key = APPROVE_PASSWORDLESS_LOGINS_KEY.appendIdentifier(userId), - value = isApprovePasswordlessLoginsEnabled, - ) - } - override fun getScreenCaptureAllowed(userId: String): Boolean? { return getBoolean(key = SCREEN_CAPTURE_ALLOW_KEY.appendIdentifier(userId)) } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt index 15ee443c1..063b483bb 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt @@ -2,7 +2,6 @@ package com.x8bit.bitwarden.data.platform.manager import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource import com.x8bit.bitwarden.data.platform.datasource.disk.PushDiskSource -import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource import com.x8bit.bitwarden.data.platform.datasource.network.model.PushTokenRequest import com.x8bit.bitwarden.data.platform.datasource.network.service.PushService import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager @@ -36,10 +35,8 @@ import javax.inject.Inject /** * Primary implementation of [PushManager]. */ -@Suppress("LongParameterList") class PushManagerImpl @Inject constructor( private val authDiskSource: AuthDiskSource, - private val settingsDiskSource: SettingsDiskSource, private val pushDiskSource: PushDiskSource, private val pushService: PushService, private val clock: Clock, @@ -125,16 +122,14 @@ class PushManagerImpl @Inject constructor( NotificationType.AUTH_REQUEST, NotificationType.AUTH_REQUEST_RESPONSE, -> { - if (settingsDiskSource.getApprovePasswordlessLoginsEnabled(userId) == true) { - val payload: NotificationPayload.PasswordlessRequestNotification = - json.decodeFromString(string = notification.payload) - mutablePasswordlessRequestSharedFlow.tryEmit( - PasswordlessRequestData( - loginRequestId = payload.id, - userId = payload.userId, - ), - ) - } + val payload: NotificationPayload.PasswordlessRequestNotification = + json.decodeFromString(string = notification.payload) + mutablePasswordlessRequestSharedFlow.tryEmit( + PasswordlessRequestData( + loginRequestId = payload.id, + userId = payload.userId, + ), + ) } NotificationType.LOG_OUT -> { diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/di/PlatformManagerModule.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/di/PlatformManagerModule.kt index f6d75425c..c97284996 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/di/PlatformManagerModule.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/di/PlatformManagerModule.kt @@ -143,7 +143,6 @@ object PlatformManagerModule { @Singleton fun providePushManager( authDiskSource: AuthDiskSource, - settingsDiskSource: SettingsDiskSource, pushDiskSource: PushDiskSource, pushService: PushService, dispatcherManager: DispatcherManager, @@ -151,7 +150,6 @@ object PlatformManagerModule { json: Json, ): PushManager = PushManagerImpl( authDiskSource = authDiskSource, - settingsDiskSource = settingsDiskSource, pushDiskSource = pushDiskSource, pushService = pushService, dispatcherManager = dispatcherManager, diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt index 7522de7f4..5c15fe7ea 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt @@ -118,11 +118,6 @@ interface SettingsRepository { */ var blockedAutofillUris: List<String> - /** - * Whether or not approving passwordless logins is enabled for the current user. - */ - var isApprovePasswordlessLoginsEnabled: Boolean - /** * Emits updates whenever there is a change in the app's status for supporting autofill. * diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt index fa5225f58..1fa6c1cf5 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt @@ -245,19 +245,6 @@ class SettingsRepositoryImpl( ) } - override var isApprovePasswordlessLoginsEnabled: Boolean - get() = activeUserId - ?.let { - settingsDiskSource.getApprovePasswordlessLoginsEnabled(it) - } - ?: false - set(value) { - val userId = activeUserId ?: return - settingsDiskSource.storeApprovePasswordlessLoginsEnabled( - userId = userId, - isApprovePasswordlessLoginsEnabled = value, - ) - } override val isAutofillEnabledStateFlow: StateFlow<Boolean> = autofillEnabledManager.isAutofillEnabledStateFlow diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreen.kt index e727e7db3..96de7d8d1 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreen.kt @@ -1,7 +1,5 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity -import android.Manifest -import android.os.Build import android.widget.Toast import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -58,10 +56,8 @@ import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenWideSwitch import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter import com.x8bit.bitwarden.ui.platform.composition.LocalBiometricsManager import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager -import com.x8bit.bitwarden.ui.platform.composition.LocalPermissionsManager import com.x8bit.bitwarden.ui.platform.manager.biometrics.BiometricsManager import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager -import com.x8bit.bitwarden.ui.platform.manager.permissions.PermissionsManager import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialColors import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialTypography import com.x8bit.bitwarden.ui.platform.util.displayLabel @@ -84,7 +80,6 @@ fun AccountSecurityScreen( viewModel: AccountSecurityViewModel = hiltViewModel(), biometricsManager: BiometricsManager = LocalBiometricsManager.current, intentManager: IntentManager = LocalIntentManager.current, - permissionsManager: PermissionsManager = LocalPermissionsManager.current, ) { val state by viewModel.stateFlow.collectAsState() val context = LocalContext.current @@ -149,7 +144,7 @@ fun AccountSecurityScreen( }, ) { innerPadding -> Column( - Modifier + modifier = Modifier .padding(innerPadding) .fillMaxSize() .verticalScroll(rememberScrollState()), @@ -160,31 +155,15 @@ fun AccountSecurityScreen( .fillMaxWidth() .padding(horizontal = 16.dp), ) - ApprovePasswordlessLoginsRow( - isApproveLoginRequestsEnabled = state.isApproveLoginRequestsEnabled, - onApprovePasswordlessLoginsAction = remember(viewModel) { - { viewModel.trySendAction(it) } - }, - permissionsManager = permissionsManager, - onPushNotificationConfirm = remember(viewModel) { - { viewModel.trySendAction(AccountSecurityAction.PushNotificationConfirm) } + BitwardenTextRow( + text = stringResource(id = R.string.pending_log_in_requests), + onClick = remember(viewModel) { + { viewModel.trySendAction(AccountSecurityAction.PendingLoginRequestsClick) } }, modifier = Modifier - .testTag("ApproveLoginRequestsSwitch") - .fillMaxWidth() - .padding(horizontal = 16.dp), + .testTag("PendingLogInRequestsLabel") + .fillMaxWidth(), ) - if (state.isApproveLoginRequestsEnabled) { - BitwardenTextRow( - text = stringResource(id = R.string.pending_log_in_requests), - onClick = remember(viewModel) { - { viewModel.trySendAction(AccountSecurityAction.PendingLoginRequestsClick) } - }, - modifier = Modifier - .testTag("PendingLogInRequestsLabel") - .fillMaxWidth(), - ) - } Spacer(Modifier.height(16.dp)) BitwardenListHeaderText( @@ -824,92 +803,3 @@ private fun FingerPrintPhraseDialog( containerColor = MaterialTheme.colorScheme.surfaceContainerHigh, ) } - -@Suppress("LongMethod") -@Composable -private fun ApprovePasswordlessLoginsRow( - isApproveLoginRequestsEnabled: Boolean, - @Suppress("MaxLineLength") - onApprovePasswordlessLoginsAction: (AccountSecurityAction.ApprovePasswordlessLoginsToggle) -> Unit, - onPushNotificationConfirm: () -> Unit, - permissionsManager: PermissionsManager, - modifier: Modifier = Modifier, -) { - var shouldShowConfirmationDialog by remember { mutableStateOf(false) } - var shouldShowPermissionDialog by remember { mutableStateOf(false) } - BitwardenWideSwitch( - label = stringResource( - id = R.string.use_this_device_to_approve_login_requests_made_from_other_devices, - ), - isChecked = isApproveLoginRequestsEnabled, - onCheckedChange = { isChecked -> - if (isChecked) { - onApprovePasswordlessLoginsAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.PendingEnabled, - ) - shouldShowConfirmationDialog = true - } else { - onApprovePasswordlessLoginsAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Disabled, - ) - } - }, - modifier = modifier, - ) - - if (shouldShowConfirmationDialog) { - BitwardenTwoButtonDialog( - title = stringResource(id = R.string.approve_login_requests), - message = stringResource( - id = R.string.use_this_device_to_approve_login_requests_made_from_other_devices, - ), - confirmButtonText = stringResource(id = R.string.yes), - dismissButtonText = stringResource(id = R.string.no), - onConfirmClick = { - onApprovePasswordlessLoginsAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Enabled, - ) - shouldShowConfirmationDialog = false - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - @Suppress("MaxLineLength") - if (!permissionsManager.checkPermission(Manifest.permission.POST_NOTIFICATIONS)) { - shouldShowPermissionDialog = true - } - } - }, - onDismissClick = { - onApprovePasswordlessLoginsAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Disabled, - ) - shouldShowConfirmationDialog = false - }, - onDismissRequest = { - onApprovePasswordlessLoginsAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Disabled, - ) - shouldShowConfirmationDialog = false - }, - ) - } - - if (shouldShowPermissionDialog) { - BitwardenTwoButtonDialog( - title = null, - message = stringResource( - id = R.string.receive_push_notifications_for_new_login_requests, - ), - confirmButtonText = stringResource(id = R.string.settings), - dismissButtonText = stringResource(id = R.string.no_thanks), - onConfirmClick = { - shouldShowPermissionDialog = false - onPushNotificationConfirm() - }, - onDismissClick = { - shouldShowPermissionDialog = false - }, - onDismissRequest = { - shouldShowPermissionDialog = false - }, - ) - } -} diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModel.kt index d21ac3851..bd81da627 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModel.kt @@ -41,14 +41,13 @@ class AccountSecurityViewModel @Inject constructor( private val vaultRepository: VaultRepository, private val settingsRepository: SettingsRepository, private val environmentRepository: EnvironmentRepository, - private val policyManager: PolicyManager, + policyManager: PolicyManager, savedStateHandle: SavedStateHandle, ) : BaseViewModel<AccountSecurityState, AccountSecurityEvent, AccountSecurityAction>( initialState = savedStateHandle[KEY_STATE] ?: AccountSecurityState( dialog = null, fingerprintPhrase = "".asText(), // This will be filled in dynamically - isApproveLoginRequestsEnabled = settingsRepository.isApprovePasswordlessLoginsEnabled, isUnlockWithBiometricsEnabled = settingsRepository.isUnlockWithBiometricsEnabled, isUnlockWithPasswordEnabled = authRepository .userStateFlow @@ -118,11 +117,6 @@ class AccountSecurityViewModel @Inject constructor( } is AccountSecurityAction.UnlockWithPinToggle -> handleUnlockWithPinToggle(action) - - is AccountSecurityAction.ApprovePasswordlessLoginsToggle -> { - handleApprovePasswordlessLoginsToggle(action) - } - is AccountSecurityAction.PushNotificationConfirm -> handlePushNotificationConfirm() is AccountSecurityAction.Internal -> handleInternalAction(action) } @@ -158,26 +152,6 @@ class AccountSecurityViewModel @Inject constructor( vaultRepository.lockVaultForCurrentUser() } - private fun handleApprovePasswordlessLoginsToggle( - action: AccountSecurityAction.ApprovePasswordlessLoginsToggle, - ) { - when (action) { - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Disabled -> { - settingsRepository.isApprovePasswordlessLoginsEnabled = false - mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = false) } - } - - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Enabled -> { - settingsRepository.isApprovePasswordlessLoginsEnabled = true - mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = true) } - } - - AccountSecurityAction.ApprovePasswordlessLoginsToggle.PendingEnabled -> { - mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = true) } - } - } - } - private fun handlePushNotificationConfirm() { sendEvent(AccountSecurityEvent.NavigateToApplicationDataSettings) } @@ -368,7 +342,6 @@ class AccountSecurityViewModel @Inject constructor( data class AccountSecurityState( val dialog: AccountSecurityDialog?, val fingerprintPhrase: Text, - val isApproveLoginRequestsEnabled: Boolean, val isUnlockWithBiometricsEnabled: Boolean, val isUnlockWithPasswordEnabled: Boolean, val isUnlockWithPinEnabled: Boolean, @@ -551,26 +524,6 @@ sealed class AccountSecurityAction { */ data object PushNotificationConfirm : AccountSecurityAction() - /** - * User toggled the approve passwordless logins switch. - */ - sealed class ApprovePasswordlessLoginsToggle : AccountSecurityAction() { - /** - * The toggle was enabled and confirmed. - */ - data object Enabled : ApprovePasswordlessLoginsToggle() - - /** - * The toggle was enabled but not yet confirmed. - */ - data object PendingEnabled : ApprovePasswordlessLoginsToggle() - - /** - * The toggle was disabled. - */ - data object Disabled : ApprovePasswordlessLoginsToggle() - } - /** * User toggled the unlock with pin switch. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt index 463f0cdc7..6ef191335 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreen.kt @@ -1,5 +1,7 @@ package com.x8bit.bitwarden.ui.vault.feature.vault +import android.Manifest +import android.os.Build import android.widget.Toast import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.scaleIn @@ -54,9 +56,11 @@ import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter import com.x8bit.bitwarden.ui.platform.composition.LocalExitManager import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager +import com.x8bit.bitwarden.ui.platform.composition.LocalPermissionsManager import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType import com.x8bit.bitwarden.ui.platform.manager.exit.ExitManager import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager +import com.x8bit.bitwarden.ui.platform.manager.permissions.PermissionsManager import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction import com.x8bit.bitwarden.ui.vault.feature.vault.handlers.VaultHandlers import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType @@ -80,6 +84,7 @@ fun VaultScreen( onDimBottomNavBarRequest: (shouldDim: Boolean) -> Unit, exitManager: ExitManager = LocalExitManager.current, intentManager: IntentManager = LocalIntentManager.current, + permissionsManager: PermissionsManager = LocalPermissionsManager.current, ) { val state by viewModel.stateFlow.collectAsState() val context = LocalContext.current @@ -120,6 +125,7 @@ fun VaultScreen( } } val vaultHandlers = remember(viewModel) { VaultHandlers.create(viewModel) } + VaultScreenPushNotifications(permissionsManager = permissionsManager) VaultScreenScaffold( state = state, pullToRefreshState = pullToRefreshState, @@ -128,6 +134,25 @@ fun VaultScreen( ) } +/** + * Handles the notifications permission request. + */ +@Composable +private fun VaultScreenPushNotifications( + permissionsManager: PermissionsManager, +) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return + val launcher = permissionsManager.getLauncher { + // We do not actually care what the response is, we just need + // to give the user a chance to give us the permission. + } + LaunchedEffect(key1 = Unit) { + if (!permissionsManager.checkPermission(Manifest.permission.POST_NOTIFICATIONS)) { + launcher.launch(Manifest.permission.POST_NOTIFICATIONS) + } + } +} + /** * Scaffold for the [VaultScreen] */ diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceTest.kt index 83352cfdf..ab5bb37b7 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceTest.kt @@ -127,10 +127,6 @@ class SettingsDiskSourceTest { userId = userId, blockedAutofillUris = listOf("www.example.com"), ) - settingsDiskSource.storeApprovePasswordlessLoginsEnabled( - userId = userId, - isApprovePasswordlessLoginsEnabled = true, - ) settingsDiskSource.storeLastSyncTime( userId = userId, lastSyncTime = Instant.parse("2023-10-27T12:00:00Z"), @@ -161,7 +157,6 @@ class SettingsDiskSourceTest { assertNull(settingsDiskSource.getPullToRefreshEnabled(userId = userId)) assertNull(settingsDiskSource.getInlineAutofillEnabled(userId = userId)) assertNull(settingsDiskSource.getBlockedAutofillUris(userId = userId)) - assertNull(settingsDiskSource.getApprovePasswordlessLoginsEnabled(userId = userId)) assertNull(settingsDiskSource.getLastSyncTime(userId = userId)) assertNull(settingsDiskSource.getClearClipboardFrequencySeconds(userId = userId)) assertNull( @@ -821,67 +816,6 @@ class SettingsDiskSourceTest { ) } - @Suppress("MaxLineLength") - @Test - fun `getApprovePasswordlessLoginsEnabled when values are present should pull from SharedPreferences`() { - val approvePasswordlessLoginsBaseKey = "bwPreferencesStorage:approvePasswordlessLogins" - val mockUserId = "mockUserId" - val isEnabled = true - fakeSharedPreferences - .edit { - putBoolean( - "${approvePasswordlessLoginsBaseKey}_$mockUserId", - isEnabled, - ) - } - val actual = settingsDiskSource.getApprovePasswordlessLoginsEnabled(userId = mockUserId) - assertEquals( - isEnabled, - actual, - ) - } - - @Test - fun `getApprovePasswordlessLoginsEnabled when values are absent should return null`() { - val mockUserId = "mockUserId" - assertNull(settingsDiskSource.getApprovePasswordlessLoginsEnabled(userId = mockUserId)) - } - - @Suppress("MaxLineLength") - @Test - fun `storeApprovePasswordlessLoginsEnabled for non-null values should update SharedPreferences`() { - val approvePasswordlessLoginsBaseKey = "bwPreferencesStorage:approvePasswordlessLogins" - val mockUserId = "mockUserId" - val isEnabled = true - settingsDiskSource.storeApprovePasswordlessLoginsEnabled( - userId = mockUserId, - isApprovePasswordlessLoginsEnabled = isEnabled, - ) - val actual = fakeSharedPreferences.getBoolean( - "${approvePasswordlessLoginsBaseKey}_$mockUserId", - false, - ) - assertEquals( - isEnabled, - actual, - ) - } - - @Test - fun `storeApprovePasswordlessLoginsEnabled for null values should clear SharedPreferences`() { - val approvePasswordlessLoginsBaseKey = "bwPreferencesStorage:approvePasswordlessLogins" - val mockUserId = "mockUserId" - val approvePasswordlessLoginsKey = "${approvePasswordlessLoginsBaseKey}_$mockUserId" - fakeSharedPreferences.edit { - putBoolean(approvePasswordlessLoginsKey, true) - } - settingsDiskSource.storeApprovePasswordlessLoginsEnabled( - userId = mockUserId, - isApprovePasswordlessLoginsEnabled = null, - ) - assertFalse(fakeSharedPreferences.contains(approvePasswordlessLoginsKey)) - } - @Test fun `getScreenCaptureAllowed should pull from SharedPreferences`() { val screenCaptureAllowBaseKey = "bwPreferencesStorage:screenCaptureAllowed" diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/util/FakeSettingsDiskSource.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/util/FakeSettingsDiskSource.kt index 040516710..479fe72e7 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/util/FakeSettingsDiskSource.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/util/FakeSettingsDiskSource.kt @@ -53,7 +53,6 @@ class FakeSettingsDiskSource : SettingsDiskSource { private var storedIsIconLoadingDisabled: Boolean? = null private var storedIsCrashLoggingEnabled: Boolean? = null private var storedInitialAutofillDialogShown: Boolean? = null - private val storedApprovePasswordLoginsEnabled = mutableMapOf<String, Boolean?>() private val storedScreenCaptureAllowed = mutableMapOf<String, Boolean?>() private var storedSystemBiometricIntegritySource: String? = null private val storedAccountBiometricIntegrityValidity = mutableMapOf<String, Boolean?>() @@ -247,16 +246,6 @@ class FakeSettingsDiskSource : SettingsDiskSource { storedBlockedAutofillUris[userId] = blockedAutofillUris } - override fun getApprovePasswordlessLoginsEnabled(userId: String): Boolean? = - storedApprovePasswordLoginsEnabled[userId] - - override fun storeApprovePasswordlessLoginsEnabled( - userId: String, - isApprovePasswordlessLoginsEnabled: Boolean?, - ) { - storedApprovePasswordLoginsEnabled[userId] = isApprovePasswordlessLoginsEnabled - } - override fun getScreenCaptureAllowed(userId: String): Boolean? = storedScreenCaptureAllowed[userId] diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt index ae65d6679..0cb56e546 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt @@ -10,8 +10,6 @@ import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager import com.x8bit.bitwarden.data.platform.base.FakeSharedPreferences import com.x8bit.bitwarden.data.platform.datasource.disk.PushDiskSource import com.x8bit.bitwarden.data.platform.datasource.disk.PushDiskSourceImpl -import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource -import com.x8bit.bitwarden.data.platform.datasource.disk.util.FakeSettingsDiskSource import com.x8bit.bitwarden.data.platform.datasource.network.di.PlatformNetworkModule import com.x8bit.bitwarden.data.platform.datasource.network.model.PushTokenRequest import com.x8bit.bitwarden.data.platform.datasource.network.service.PushService @@ -51,8 +49,6 @@ class PushManagerTest { private val authDiskSource: AuthDiskSource = FakeAuthDiskSource() - private val settingsDiskSource: SettingsDiskSource = FakeSettingsDiskSource() - private val pushDiskSource: PushDiskSource = PushDiskSourceImpl(FakeSharedPreferences()) private val pushService: PushService = mockk() @@ -63,7 +59,6 @@ class PushManagerTest { fun setUp() { pushManager = PushManagerImpl( authDiskSource = authDiskSource, - settingsDiskSource = settingsDiskSource, pushDiskSource = pushDiskSource, pushService = pushService, dispatcherManager = dispatcherManager, @@ -91,73 +86,33 @@ class PushManagerTest { pushManager.onMessageReceived(INVALID_NOTIFICATION_JSON) } - @Suppress("MaxLineLength") @Test - fun `onMessageReceived auth request emits to nothing when getApprovePasswordlessLoginsEnabled is not true`() = - runTest { - settingsDiskSource.storeApprovePasswordlessLoginsEnabled( - userId = userId, - isApprovePasswordlessLoginsEnabled = false, + fun `onMessageReceived auth request emits to passwordlessRequestFlow`() = runTest { + pushManager.passwordlessRequestFlow.test { + pushManager.onMessageReceived(AUTH_REQUEST_NOTIFICATION_JSON) + assertEquals( + PasswordlessRequestData( + loginRequestId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + userId = "078966a2-93c2-4618-ae2a-0a2394c88d37", + ), + awaitItem(), ) - pushManager.passwordlessRequestFlow.test { - pushManager.onMessageReceived(AUTH_REQUEST_NOTIFICATION_JSON) - expectNoEvents() - } } + } - @Suppress("MaxLineLength") @Test - fun `onMessageReceived auth request emits to passwordlessRequestFlow when getApprovePasswordlessLoginsEnabled is true`() = - runTest { - settingsDiskSource.storeApprovePasswordlessLoginsEnabled( - userId = userId, - isApprovePasswordlessLoginsEnabled = true, + fun `onMessageReceived auth request response emits to passwordlessRequestFlow`() = runTest { + pushManager.passwordlessRequestFlow.test { + pushManager.onMessageReceived(AUTH_REQUEST_RESPONSE_NOTIFICATION_JSON) + assertEquals( + PasswordlessRequestData( + loginRequestId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + userId = "078966a2-93c2-4618-ae2a-0a2394c88d37", + ), + awaitItem(), ) - pushManager.passwordlessRequestFlow.test { - pushManager.onMessageReceived(AUTH_REQUEST_NOTIFICATION_JSON) - assertEquals( - PasswordlessRequestData( - loginRequestId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", - userId = "078966a2-93c2-4618-ae2a-0a2394c88d37", - ), - awaitItem(), - ) - } - } - - @Suppress("MaxLineLength") - @Test - fun `onMessageReceived auth request response emits nothing when getApprovePasswordlessLoginsEnabled is not true`() = - runTest { - settingsDiskSource.storeApprovePasswordlessLoginsEnabled( - userId = userId, - isApprovePasswordlessLoginsEnabled = false, - ) - pushManager.passwordlessRequestFlow.test { - pushManager.onMessageReceived(AUTH_REQUEST_RESPONSE_NOTIFICATION_JSON) - expectNoEvents() - } - } - - @Suppress("MaxLineLength") - @Test - fun `onMessageReceived auth request response emits to passwordlessRequestFlow when getApprovePasswordlessLoginsEnabled is true`() = - runTest { - settingsDiskSource.storeApprovePasswordlessLoginsEnabled( - userId = userId, - isApprovePasswordlessLoginsEnabled = true, - ) - pushManager.passwordlessRequestFlow.test { - pushManager.onMessageReceived(AUTH_REQUEST_RESPONSE_NOTIFICATION_JSON) - assertEquals( - PasswordlessRequestData( - loginRequestId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", - userId = "078966a2-93c2-4618-ae2a-0a2394c88d37", - ), - awaitItem(), - ) - } } + } @Test fun `onMessageReceived logout should emit to logoutFlow`() = runTest { diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt index 20dc4bf8e..65af832d6 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt @@ -905,31 +905,6 @@ class SettingsRepositoryTest { } } - @Test - fun `isApprovePasswordlessLoginsEnabled should properly update SettingsDiskSource`() { - fakeAuthDiskSource.userState = null - assertFalse(settingsRepository.isApprovePasswordlessLoginsEnabled) - - fakeAuthDiskSource.userState = MOCK_USER_STATE - - // Updates to the disk source change the repository value - fakeSettingsDiskSource.storeApprovePasswordlessLoginsEnabled( - userId = USER_ID, - isApprovePasswordlessLoginsEnabled = true, - ) - assertEquals( - true, - settingsRepository.isApprovePasswordlessLoginsEnabled, - ) - - // Updates to the repository value change the disk source - settingsRepository.isApprovePasswordlessLoginsEnabled = false - assertEquals( - false, - fakeSettingsDiskSource.getApprovePasswordlessLoginsEnabled(userId = USER_ID), - ) - } - @Test fun `isScreenCaptureAllowed property should update SettingsDiskSource and emit changes`() = runTest { diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreenTest.kt index 06e3a5f94..35048e253 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityScreenTest.kt @@ -25,7 +25,6 @@ import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest import com.x8bit.bitwarden.ui.platform.base.util.asText import com.x8bit.bitwarden.ui.platform.manager.biometrics.BiometricsManager import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager -import com.x8bit.bitwarden.ui.platform.manager.permissions.FakePermissionManager import com.x8bit.bitwarden.ui.util.assertNoDialogExists import io.mockk.every import io.mockk.just @@ -51,7 +50,6 @@ class AccountSecurityScreenTest : BaseComposeTest() { every { startActivity(any()) } just runs every { startApplicationDetailsSettingsActivity() } just runs } - private val permissionsManager = FakePermissionManager() private val captureBiometricsSuccess = slot<() -> Unit>() private val captureBiometricsCancel = slot<() -> Unit>() private val captureBiometricsLockOut = slot<() -> Unit>() @@ -84,7 +82,6 @@ class AccountSecurityScreenTest : BaseComposeTest() { viewModel = viewModel, biometricsManager = biometricsManager, intentManager = intentManager, - permissionsManager = permissionsManager, ) } } @@ -95,211 +92,6 @@ class AccountSecurityScreenTest : BaseComposeTest() { verify { viewModel.trySendAction(AccountSecurityAction.LogoutClick) } } - @Suppress("MaxLineLength") - @Test - fun `on approve login requests toggle on should send PendingEnabled action and display dialog`() { - composeTestRule.assertNoDialogExists() - - composeTestRule - .onNodeWithText("Use this device to approve login requests made from other devices") - .performScrollTo() - .performClick() - - composeTestRule - .onAllNodesWithText("Approve login requests") - .filterToOne(hasAnyAncestor(isDialog())) - .assertIsDisplayed() - composeTestRule - .onAllNodesWithText( - "Use this device to approve login requests made from other devices", - ) - .filterToOne(hasAnyAncestor(isDialog())) - .assertIsDisplayed() - composeTestRule - .onAllNodesWithText("No") - .filterToOne(hasAnyAncestor(isDialog())) - .assertIsDisplayed() - composeTestRule - .onAllNodesWithText("Yes") - .filterToOne(hasAnyAncestor(isDialog())) - .assertIsDisplayed() - - verify { - viewModel.trySendAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.PendingEnabled, - ) - } - } - - @Test - fun `on approve login requests toggle off should send Disabled action and hide requests row`() { - composeTestRule - .onNodeWithText("Pending login requests") - .assertDoesNotExist() - - mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = true) } - - composeTestRule - .onNodeWithText("Use this device to approve login requests made from other devices") - .performScrollTo() - .performClick() - composeTestRule - .onNodeWithText("Pending login requests") - .performScrollTo() - .assertIsDisplayed() - - verify { - viewModel.trySendAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Disabled, - ) - } - } - - @Suppress("MaxLineLength") - @Test - fun `on approve login requests confirm Yes should send Enabled action and hide dialog when permission already granted`() { - permissionsManager.checkPermissionResult = true - mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = false) } - - composeTestRule - .onNodeWithText("Use this device to approve login requests made from other devices") - .performScrollTo() - .performClick() - - composeTestRule - .onAllNodesWithText("Yes") - .filterToOne(hasAnyAncestor(isDialog())) - .performClick() - - composeTestRule.assertNoDialogExists() - - verify { - viewModel.trySendAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Enabled, - ) - } - } - - @Suppress("MaxLineLength") - @Test - fun `on approve login requests confirm Yes should send Enabled action and show permission dialog when permission not granted`() { - permissionsManager.checkPermissionResult = false - mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = false) } - - composeTestRule - .onNodeWithText("Use this device to approve login requests made from other devices") - .performScrollTo() - .performClick() - - composeTestRule - .onAllNodesWithText("Yes") - .filterToOne(hasAnyAncestor(isDialog())) - .performClick() - - composeTestRule - .onAllNodesWithText("Receive push notifications for new login requests") - .filterToOne(hasAnyAncestor(isDialog())) - .assertIsDisplayed() - composeTestRule - .onAllNodesWithText("No thanks") - .filterToOne(hasAnyAncestor(isDialog())) - .assertIsDisplayed() - composeTestRule - .onAllNodesWithText("Settings") - .filterToOne(hasAnyAncestor(isDialog())) - .assertIsDisplayed() - - verify { - viewModel.trySendAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Enabled, - ) - } - } - - @Test - fun `on approve login requests confirm No should send Disabled action and hide dialog`() { - mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = false) } - - composeTestRule - .onNodeWithText("Use this device to approve login requests made from other devices") - .performScrollTo() - .performClick() - - composeTestRule - .onAllNodesWithText("No") - .filterToOne(hasAnyAncestor(isDialog())) - .performClick() - - composeTestRule.assertNoDialogExists() - - verify { - viewModel.trySendAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Disabled, - ) - } - } - - @Test - fun `on approve login requests should be toggled on or off according to state`() { - composeTestRule - .onNodeWithText("Use this device to approve login requests made from other devices") - .assertIsOff() - mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = true) } - composeTestRule - .onNodeWithText("Use this device to approve login requests made from other devices") - .assertIsOn() - } - - @Test - fun `on push permission dialog No thanks should hide dialog`() { - permissionsManager.checkPermissionResult = false - mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = false) } - - composeTestRule - .onNodeWithText("Use this device to approve login requests made from other devices") - .performScrollTo() - .performClick() - - composeTestRule - .onAllNodesWithText("Yes") - .filterToOne(hasAnyAncestor(isDialog())) - .performClick() - - composeTestRule - .onAllNodesWithText("No thanks") - .filterToOne(hasAnyAncestor(isDialog())) - .performClick() - - composeTestRule.assertNoDialogExists() - } - - @Test - fun `on push permission dialog Settings should hide dialog and send confirm action`() { - permissionsManager.checkPermissionResult = false - mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = false) } - - composeTestRule - .onNodeWithText("Use this device to approve login requests made from other devices") - .performScrollTo() - .performClick() - - composeTestRule - .onAllNodesWithText("Yes") - .filterToOne(hasAnyAncestor(isDialog())) - .performClick() - - composeTestRule - .onAllNodesWithText("Settings") - .filterToOne(hasAnyAncestor(isDialog())) - .performClick() - - composeTestRule.assertNoDialogExists() - - verify { - viewModel.trySendAction(AccountSecurityAction.PushNotificationConfirm) - } - } - @Test fun `on NavigateToApplicationDataSettings should launch the correct intent`() { mutableEventFlow.tryEmit(AccountSecurityEvent.NavigateToApplicationDataSettings) @@ -309,7 +101,6 @@ class AccountSecurityScreenTest : BaseComposeTest() { @Test fun `on pending login requests click should send PendingLoginRequestsClick`() { - mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = true) } composeTestRule .onNodeWithText("Pending login requests") .performScrollTo() @@ -1566,19 +1357,16 @@ class AccountSecurityScreenTest : BaseComposeTest() { composeTestRule.onNodeWithText(rowText).assertDoesNotExist() } - - companion object { - private val DEFAULT_STATE = AccountSecurityState( - dialog = null, - fingerprintPhrase = "fingerprint-placeholder".asText(), - isApproveLoginRequestsEnabled = false, - isUnlockWithBiometricsEnabled = false, - isUnlockWithPasswordEnabled = true, - isUnlockWithPinEnabled = false, - vaultTimeout = VaultTimeout.ThirtyMinutes, - vaultTimeoutAction = VaultTimeoutAction.LOCK, - vaultTimeoutPolicyMinutes = null, - vaultTimeoutPolicyAction = null, - ) - } } + +private val DEFAULT_STATE = AccountSecurityState( + dialog = null, + fingerprintPhrase = "fingerprint-placeholder".asText(), + isUnlockWithBiometricsEnabled = false, + isUnlockWithPasswordEnabled = true, + isUnlockWithPinEnabled = false, + vaultTimeout = VaultTimeout.ThirtyMinutes, + vaultTimeoutAction = VaultTimeoutAction.LOCK, + vaultTimeoutPolicyMinutes = null, + vaultTimeoutPolicyAction = null, +) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt index bfa888a6a..239b4f33a 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt @@ -35,8 +35,6 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.encodeToJsonElement import kotlinx.serialization.json.jsonObject import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertFalse -import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test class AccountSecurityViewModelTest : BaseViewModelTest() { @@ -49,7 +47,6 @@ class AccountSecurityViewModelTest : BaseViewModelTest() { private val vaultRepository: VaultRepository = mockk(relaxed = true) private val settingsRepository: SettingsRepository = mockk { every { isUnlockWithBiometricsEnabled } returns false - every { isApprovePasswordlessLoginsEnabled } returns false every { isUnlockWithPinEnabled } returns false every { vaultTimeout } returns VaultTimeout.ThirtyMinutes every { vaultTimeoutAction } returns VaultTimeoutAction.LOCK @@ -530,54 +527,6 @@ class AccountSecurityViewModelTest : BaseViewModelTest() { assertEquals(DEFAULT_STATE.copy(dialog = null), viewModel.stateFlow.value) } - @Suppress("MaxLineLength") - @Test - fun `on ApprovePasswordlessLoginsToggle enabled should update settings and set isApprovePasswordlessLoginsEnabled to true`() = - runTest { - every { settingsRepository.isApprovePasswordlessLoginsEnabled = true } just runs - val viewModel = createViewModel() - viewModel.eventFlow.test { - viewModel.trySendAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Enabled, - ) - expectNoEvents() - verify(exactly = 1) { settingsRepository.isApprovePasswordlessLoginsEnabled = true } - } - assertTrue(viewModel.stateFlow.value.isApproveLoginRequestsEnabled) - } - - @Suppress("MaxLineLength") - @Test - fun `on ApprovePasswordlessLoginsToggle pending enabled should set isApprovePasswordlessLoginsEnabled to true`() = - runTest { - val viewModel = createViewModel() - viewModel.eventFlow.test { - viewModel.trySendAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.PendingEnabled, - ) - expectNoEvents() - } - assertTrue(viewModel.stateFlow.value.isApproveLoginRequestsEnabled) - } - - @Suppress("MaxLineLength") - @Test - fun `on ApprovePasswordlessLoginsToggle disabled should update settings and set isApprovePasswordlessLoginsEnabled to false`() = - runTest { - every { settingsRepository.isApprovePasswordlessLoginsEnabled = false } just runs - val viewModel = createViewModel() - viewModel.eventFlow.test { - viewModel.trySendAction( - AccountSecurityAction.ApprovePasswordlessLoginsToggle.Disabled, - ) - expectNoEvents() - verify(exactly = 1) { - settingsRepository.isApprovePasswordlessLoginsEnabled = false - } - } - assertFalse(viewModel.stateFlow.value.isApproveLoginRequestsEnabled) - } - @Test fun `on PushNotificationConfirm should send NavigateToApplicationDataSettings event`() = runTest { @@ -616,7 +565,6 @@ private const val FINGERPRINT: String = "fingerprint" private val DEFAULT_STATE: AccountSecurityState = AccountSecurityState( dialog = null, fingerprintPhrase = FINGERPRINT.asText(), - isApproveLoginRequestsEnabled = false, isUnlockWithBiometricsEnabled = false, isUnlockWithPasswordEnabled = true, isUnlockWithPinEnabled = false, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt index a5ef4bf46..4119ddb70 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt @@ -25,6 +25,7 @@ import com.x8bit.bitwarden.ui.platform.base.util.asText import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary import com.x8bit.bitwarden.ui.platform.manager.exit.ExitManager import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager +import com.x8bit.bitwarden.ui.platform.manager.permissions.FakePermissionManager import com.x8bit.bitwarden.ui.util.assertLockOrLogoutDialogIsDisplayed import com.x8bit.bitwarden.ui.util.assertLogoutConfirmationDialogIsDisplayed import com.x8bit.bitwarden.ui.util.assertNoDialogExists @@ -68,6 +69,7 @@ class VaultScreenTest : BaseComposeTest() { private var onNavigateToSearchScreen = false private val exitManager = mockk<ExitManager>(relaxed = true) private val intentManager = mockk<IntentManager>(relaxed = true) + private val permissionsManager = FakePermissionManager() private val mutableEventFlow = bufferedMutableSharedFlow<VaultEvent>() private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE) @@ -90,6 +92,7 @@ class VaultScreenTest : BaseComposeTest() { onNavigateToSearchVault = { onNavigateToSearchScreen = true }, exitManager = exitManager, intentManager = intentManager, + permissionsManager = permissionsManager, ) } }