[PM-27092] Changing screen capture flow from event based to state based on Authenticator (#6062)

This commit is contained in:
aj-rosado 2025-10-24 10:26:53 +01:00 committed by GitHub
parent 38bdda0a41
commit be27c76bd3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 50 additions and 15 deletions

View File

@ -62,6 +62,7 @@ class MainActivity : AppCompatActivity() {
setupEdgeToEdge(appThemeFlow = mainViewModel.stateFlow.map { it.theme }) setupEdgeToEdge(appThemeFlow = mainViewModel.stateFlow.map { it.theme })
setContent { setContent {
val state by mainViewModel.stateFlow.collectAsStateWithLifecycle() val state by mainViewModel.stateFlow.collectAsStateWithLifecycle()
updateScreenCapture(isScreenCaptureAllowed = state.isScreenCaptureAllowed)
val navController = rememberNavController() val navController = rememberNavController()
observeViewModelEvents(navController) observeViewModelEvents(navController)
LocalManagerProvider { LocalManagerProvider {
@ -96,10 +97,6 @@ class MainActivity : AppCompatActivity() {
.eventFlow .eventFlow
.onEach { event -> .onEach { event ->
when (event) { when (event) {
is MainEvent.ScreenCaptureSettingChange -> {
handleScreenCaptureSettingChange(event)
}
MainEvent.NavigateToDebugMenu -> navController.navigateToDebugMenuScreen() MainEvent.NavigateToDebugMenu -> navController.navigateToDebugMenuScreen()
is MainEvent.UpdateAppTheme -> { is MainEvent.UpdateAppTheme -> {
AppCompatDelegate.setDefaultNightMode(event.osTheme) AppCompatDelegate.setDefaultNightMode(event.osTheme)
@ -123,8 +120,8 @@ class MainActivity : AppCompatActivity() {
mainViewModel.trySendAction(MainAction.OpenDebugMenu) mainViewModel.trySendAction(MainAction.OpenDebugMenu)
} }
private fun handleScreenCaptureSettingChange(event: MainEvent.ScreenCaptureSettingChange) { private fun updateScreenCapture(isScreenCaptureAllowed: Boolean) {
if (event.isAllowed) { if (isScreenCaptureAllowed) {
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
} else { } else {
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE) window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)

View File

@ -26,6 +26,7 @@ class MainViewModel @Inject constructor(
) : BaseViewModel<MainState, MainEvent, MainAction>( ) : BaseViewModel<MainState, MainEvent, MainAction>(
MainState( MainState(
theme = settingsRepository.appTheme, theme = settingsRepository.appTheme,
isScreenCaptureAllowed = settingsRepository.isScreenCaptureAllowed,
isDynamicColorsEnabled = settingsRepository.isDynamicColorsEnabled, isDynamicColorsEnabled = settingsRepository.isDynamicColorsEnabled,
), ),
) { ) {
@ -43,9 +44,10 @@ class MainViewModel @Inject constructor(
.launchIn(viewModelScope) .launchIn(viewModelScope)
settingsRepository settingsRepository
.isScreenCaptureAllowedStateFlow .isScreenCaptureAllowedStateFlow
.map { MainEvent.ScreenCaptureSettingChange(it) } .map { MainAction.Internal.ScreenCaptureUpdate(it) }
.onEach(::sendEvent) .onEach(::sendAction)
.launchIn(viewModelScope) .launchIn(viewModelScope)
viewModelScope.launch { viewModelScope.launch {
configRepository.getServerConfig(forceRefresh = false) configRepository.getServerConfig(forceRefresh = false)
} }
@ -64,6 +66,10 @@ class MainViewModel @Inject constructor(
when (action) { when (action) {
is MainAction.Internal.DynamicColorUpdate -> handleDynamicColorUpdate(action) is MainAction.Internal.DynamicColorUpdate -> handleDynamicColorUpdate(action)
is MainAction.Internal.ThemeUpdate -> handleThemeUpdated(action) is MainAction.Internal.ThemeUpdate -> handleThemeUpdated(action)
is MainAction.Internal.ScreenCaptureUpdate -> handleScreenCaptureUpdate(
screenCaptureUpdateAction = action,
)
} }
} }
@ -94,6 +100,16 @@ class MainViewModel @Inject constructor(
) )
} }
private fun handleScreenCaptureUpdate(
screenCaptureUpdateAction: MainAction.Internal.ScreenCaptureUpdate,
) {
mutableStateFlow.update {
it.copy(
isScreenCaptureAllowed = screenCaptureUpdateAction.isScreenCaptureEnabled,
)
}
}
private fun handleIntent( private fun handleIntent(
intent: Intent, intent: Intent,
isFirstIntent: Boolean, isFirstIntent: Boolean,
@ -109,6 +125,7 @@ class MainViewModel @Inject constructor(
data class MainState( data class MainState(
val theme: AppTheme, val theme: AppTheme,
val isDynamicColorsEnabled: Boolean, val isDynamicColorsEnabled: Boolean,
val isScreenCaptureAllowed: Boolean,
) : Parcelable ) : Parcelable
/** /**
@ -147,6 +164,13 @@ sealed class MainAction {
data class ThemeUpdate( data class ThemeUpdate(
val theme: AppTheme, val theme: AppTheme,
) : Internal() ) : Internal()
/**
* Indicates that the screen capture state has changed.
*/
data class ScreenCaptureUpdate(
val isScreenCaptureEnabled: Boolean,
) : Internal()
} }
} }
@ -160,11 +184,6 @@ sealed class MainEvent {
*/ */
data object NavigateToDebugMenu : MainEvent() data object NavigateToDebugMenu : MainEvent()
/**
* Event indicating a change in the screen capture setting.
*/
data class ScreenCaptureSettingChange(val isAllowed: Boolean) : MainEvent()
/** /**
* Indicates that the app theme has been updated. * Indicates that the app theme has been updated.
*/ */

View File

@ -22,6 +22,7 @@ class MainViewModelTest : BaseViewModelTest() {
every { appTheme } returns AppTheme.DEFAULT every { appTheme } returns AppTheme.DEFAULT
every { appThemeStateFlow } returns mutableAppThemeFlow every { appThemeStateFlow } returns mutableAppThemeFlow
every { isScreenCaptureAllowedStateFlow } returns mutableScreenCaptureAllowedFlow every { isScreenCaptureAllowedStateFlow } returns mutableScreenCaptureAllowedFlow
every { isScreenCaptureAllowed } returns false
every { isDynamicColorsEnabled } returns false every { isDynamicColorsEnabled } returns false
every { isDynamicColorsEnabledFlow } returns mutableIsDynamicColorsEnabledFlow every { isDynamicColorsEnabledFlow } returns mutableIsDynamicColorsEnabledFlow
} }
@ -31,7 +32,7 @@ class MainViewModelTest : BaseViewModelTest() {
fun `on AppThemeChanged should update state`() = runTest { fun `on AppThemeChanged should update state`() = runTest {
val viewModel = createViewModel() val viewModel = createViewModel()
viewModel.stateEventFlow(backgroundScope) { stateFlow, eventFlow -> viewModel.stateEventFlow(backgroundScope) { stateFlow, eventFlow ->
eventFlow.skipItems(count = 2) eventFlow.skipItems(count = 1)
assertEquals( assertEquals(
DEFAULT_STATE, DEFAULT_STATE,
stateFlow.awaitItem(), stateFlow.awaitItem(),
@ -79,12 +80,29 @@ class MainViewModelTest : BaseViewModelTest() {
val viewModel = createViewModel() val viewModel = createViewModel()
viewModel.eventFlow.test { viewModel.eventFlow.test {
// Ignore the events that are fired off by flows in the ViewModel init // Ignore the events that are fired off by flows in the ViewModel init
skipItems(2) skipItems(1)
viewModel.trySendAction(MainAction.OpenDebugMenu) viewModel.trySendAction(MainAction.OpenDebugMenu)
assertEquals(MainEvent.NavigateToDebugMenu, awaitItem()) assertEquals(MainEvent.NavigateToDebugMenu, awaitItem())
} }
} }
@Test
fun `changes in the allowed screen capture value should update the state`() {
val viewModel = createViewModel()
assertEquals(
DEFAULT_STATE.copy(isScreenCaptureAllowed = false),
viewModel.stateFlow.value,
)
mutableScreenCaptureAllowedFlow.value = true
assertEquals(
DEFAULT_STATE.copy(isScreenCaptureAllowed = true),
viewModel.stateFlow.value,
)
}
private fun createViewModel(): MainViewModel = private fun createViewModel(): MainViewModel =
MainViewModel( MainViewModel(
settingsRepository = settingsRepository, settingsRepository = settingsRepository,
@ -95,4 +113,5 @@ class MainViewModelTest : BaseViewModelTest() {
private val DEFAULT_STATE = MainState( private val DEFAULT_STATE = MainState(
theme = AppTheme.DEFAULT, theme = AppTheme.DEFAULT,
isDynamicColorsEnabled = false, isDynamicColorsEnabled = false,
isScreenCaptureAllowed = false,
) )