diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/MainActivity.kt b/app/src/main/kotlin/com/x8bit/bitwarden/MainActivity.kt index 627b849b51..a616cbaa7c 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/MainActivity.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/MainActivity.kt @@ -84,6 +84,7 @@ class MainActivity : AppCompatActivity() { val navController = rememberBitwardenNavController(name = "MainActivity") SetupEventsEffect(navController = navController) val state by mainViewModel.stateFlow.collectAsStateWithLifecycle() + updateScreenCapture(isScreenCaptureAllowed = state.isScreenCaptureAllowed) LocalManagerProvider(featureFlagsState = state.featureFlagsState) { ObserveScreenDataEffect( onDataUpdate = remember(mainViewModel) { @@ -185,10 +186,6 @@ class MainActivity : AppCompatActivity() { } is MainEvent.UpdateAppTheme -> AppCompatDelegate.setDefaultNightMode(event.osTheme) - - is MainEvent.ScreenCaptureSettingChange -> { - handleScreenCaptureSettingChange(isScreenCaptureAllowed = event.isAllowed) - } } } } @@ -217,7 +214,7 @@ class MainActivity : AppCompatActivity() { recreate() } - private fun handleScreenCaptureSettingChange(isScreenCaptureAllowed: Boolean) { + private fun updateScreenCapture(isScreenCaptureAllowed: Boolean) { if (isScreenCaptureAllowed) { window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) } else { diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/MainViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/MainViewModel.kt index 33a794c843..74ed3223a4 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/MainViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/MainViewModel.kt @@ -84,6 +84,7 @@ class MainViewModel @Inject constructor( ) : BaseViewModel( initialState = MainState( theme = settingsRepository.appTheme, + isScreenCaptureAllowed = settingsRepository.isScreenCaptureAllowed, isErrorReportingDialogEnabled = featureFlagManager.getFeatureFlag( key = FlagKey.MobileErrorReporting, ), @@ -264,7 +265,7 @@ class MainViewModel @Inject constructor( } private fun handleScreenCaptureUpdate(action: MainAction.Internal.ScreenCaptureUpdate) { - sendEvent(MainEvent.ScreenCaptureSettingChange(isAllowed = action.isScreenCaptureEnabled)) + mutableStateFlow.update { it.copy(isScreenCaptureAllowed = action.isScreenCaptureEnabled) } } private fun handleAppThemeUpdated(action: MainAction.Internal.ThemeUpdate) { @@ -492,6 +493,7 @@ class MainViewModel @Inject constructor( @Parcelize data class MainState( val theme: AppTheme, + val isScreenCaptureAllowed: Boolean, val isDynamicColorsEnabled: Boolean, private val isErrorReportingDialogEnabled: Boolean, ) : Parcelable { @@ -637,9 +639,4 @@ sealed class MainEvent { data class UpdateAppTheme( val osTheme: Int, ) : MainEvent() - - /** - * Event indicating a change in the screen capture setting. - */ - data class ScreenCaptureSettingChange(val isAllowed: Boolean) : MainEvent() } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt index eec8de5555..a63afde2c8 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt @@ -93,7 +93,7 @@ class SettingsDiskSourceImpl( private val mutableHasSeenGeneratorCoachMarkFlow = bufferedMutableSharedFlow() - private val mutableScreenCaptureAllowedFlow = bufferedMutableSharedFlow(replay = 1) + private val mutableScreenCaptureAllowedFlow = bufferedMutableSharedFlow() private val mutableVaultRegisteredForExportFlow = mutableMapOf>() diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/MainViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/MainViewModelTest.kt index b3a792c93c..3da2bcb990 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/MainViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/MainViewModelTest.kt @@ -243,9 +243,7 @@ class MainViewModelTest : BaseViewModelTest() { val viewModel = createViewModel() viewModel.eventFlow.test { - // We skip the first 3 events because they are the - // default appTheme, appLanguage and ScreenCaptureUpdate - awaitItem() + // We skip the first 2 events because they are the default appTheme and appLanguage awaitItem() awaitItem() @@ -296,9 +294,7 @@ class MainViewModelTest : BaseViewModelTest() { val viewModel = createViewModel() viewModel.eventFlow.test { - // We skip the first 3 events because they are the - // default appTheme, appLanguage and ScreenCaptureUpdate - awaitItem() + // We skip the first 2 events because they are the default appTheme and appLanguage awaitItem() awaitItem() @@ -319,9 +315,7 @@ class MainViewModelTest : BaseViewModelTest() { val viewModel = createViewModel() val cipherView = mockk() viewModel.eventFlow.test { - // We skip the first 3 events because they are the - // default appTheme, appLanguage and ScreenCaptureUpdate - awaitItem() + // We skip the first 2 events because they are the default appTheme and appLanguage awaitItem() awaitItem() @@ -338,9 +332,7 @@ class MainViewModelTest : BaseViewModelTest() { val viewModel = createViewModel() val cipherView = mockk() viewModel.eventFlow.test { - // We skip the first 3 events because they are the - // default appTheme, appLanguage and ScreenCaptureUpdate - awaitItem() + // We skip the first 2 events because they are the default appTheme and appLanguage awaitItem() awaitItem() @@ -373,9 +365,7 @@ class MainViewModelTest : BaseViewModelTest() { val viewModel = createViewModel() viewModel.stateEventFlow(backgroundScope) { stateFlow, eventFlow -> - // We skip the first 3 events because they are the - // default appTheme, appLanguage and ScreenCaptureUpdate - eventFlow.awaitItem() + // We skip the first 2 events because they are the default appTheme and appLanguage eventFlow.awaitItem() eventFlow.awaitItem() @@ -398,9 +388,7 @@ class MainViewModelTest : BaseViewModelTest() { val viewModel = createViewModel() viewModel.eventFlow.test { - // We skip the first 3 events because they are the - // default appTheme, appLanguage and ScreenCaptureUpdate - awaitItem() + // We skip the first 2 events because they are the default appTheme and appLanguage awaitItem() awaitItem() @@ -608,9 +596,7 @@ class MainViewModelTest : BaseViewModelTest() { } returns EmailTokenResult.Error(message = null, error = Throwable("Fail!")) viewModel.eventFlow.test { - // We skip the first 3 events because they are the - // default appTheme, appLanguage and ScreenCaptureUpdate - awaitItem() + // We skip the first 2 events because they are the default appTheme and appLanguage awaitItem() awaitItem() @@ -644,9 +630,7 @@ class MainViewModelTest : BaseViewModelTest() { } returns EmailTokenResult.Error(message = expectedMessage, error = null) viewModel.eventFlow.test { - // We skip the first 3 events because they are the - // default appTheme, appLanguage and ScreenCaptureUpdate - awaitItem() + // We skip the first 2 events because they are the default appTheme and appLanguage awaitItem() awaitItem() @@ -1021,13 +1005,25 @@ class MainViewModelTest : BaseViewModelTest() { ) } + @Test + fun `changes in the allowed screen capture value should update the state`() { + val viewModel = createViewModel() + + assertEquals(DEFAULT_STATE, viewModel.stateFlow.value) + + mutableScreenCaptureAllowedFlow.value = false + + assertEquals( + DEFAULT_STATE.copy(isScreenCaptureAllowed = false), + viewModel.stateFlow.value, + ) + } + @Test fun `send NavigateToDebugMenu action when OpenDebugMenu action is sent`() = runTest { val viewModel = createViewModel() viewModel.eventFlow.test { - // We skip the first 3 events because they are the - // default appTheme, appLanguage and ScreenCaptureUpdate - awaitItem() + // We skip the first 2 events because they are the default appTheme and appLanguage awaitItem() awaitItem() @@ -1121,22 +1117,6 @@ class MainViewModelTest : BaseViewModelTest() { verify { settingsRepository.appLanguage = AppLanguage.SPANISH } } - @Test - fun `on ScreenCaptureUpdate should trigger the ScreenCaptureSettingChange event`() = runTest { - val viewModel = createViewModel() - - viewModel.eventFlow.test { - // We skip the first 3 events because they are the - // default appTheme, appLanguage and ScreenCaptureUpdate - awaitItem() - awaitItem() - awaitItem() - - viewModel.trySendAction(MainAction.Internal.ScreenCaptureUpdate(true)) - assertEquals(MainEvent.ScreenCaptureSettingChange(true), awaitItem()) - } - } - private fun createViewModel( initialSpecialCircumstance: SpecialCircumstance? = null, ) = MainViewModel( @@ -1162,6 +1142,7 @@ class MainViewModelTest : BaseViewModelTest() { private val DEFAULT_STATE: MainState = MainState( theme = AppTheme.DEFAULT, + isScreenCaptureAllowed = true, isErrorReportingDialogEnabled = false, isDynamicColorsEnabled = false, )