Skip to content

Refactor Quick Settings UI - #530

Open
Kimblebee wants to merge 65 commits into
mainfrom
kim/refactor/quickSettings/button-rows
Open

Refactor Quick Settings UI#530
Kimblebee wants to merge 65 commits into
mainfrom
kim/refactor/quickSettings/button-rows

Conversation

@Kimblebee

Copy link
Copy Markdown
Collaborator

No description provided.

Kimblebee added 30 commits April 8, 2026 19:12
- remove flip camera, stream config, and concurrent camera from quick settings
- all quick settings menu items adopt the button row ux
- WIP unique selection of settings depending on current capture mode
auxiliary function for settings subtitles
… state

- Re-added the 'More Settings' button to the Quick Settings bottom sheet.

- Introduced a 'showMoreSettingsButton' boolean parameter to control its visibility, defaulting to true.

- Removed unused 'focusedQuickSetting' state from 'QuickSettingsUiState' and 'TrackedCaptureUiState'.

- Cleaned up 'FlashModeUiStateAdapter.kt' by removing a debug 'println' and adding a 'todo(kc)' for 'visibleFlashModes'.
    Remove unused drawables and their corresponding enum classes in
    QuickSettingsEnums that are no longer referenced after the quick
    settings refactoring.
    - Decoupled dynamic range (video HDR) from image format (image HDR) settings across UI, controller, and CameraX configuration layers.
    - Removed dynamic range constraints from the createImageUseCase configuration in CameraSession.kt, enabling independent Ultra HDR
  image capture.
    - Updated QuickSettings bottom sheet click handlers to mutate only the HDR setting relevant to the active capture mode.
    - Enforced specialized Low Light Boost vs Ultra HDR conflicts in CameraXCameraSystem.kt, prioritizing Low Light Boost.
    - Created HdrUiStateAdapterTest.kt covering all HDR availability states and flash conflicts.
    - Refactored CameraXCameraSystemTest.kt to run parameterized HDR decoupling tests on both front and rear lenses.
@Kimblebee
Kimblebee marked this pull request as ready for review June 19, 2026 15:28
…ra test

    - Simplify HdrUiState.from signature by removing redundant externalCaptureMode parameter.
    - Use cameraAppSettings.captureMode directly, as it already incorporates external overrides on startup.
    - Update CaptureUiStateAdapter to match the new signature.
    - Refactor HdrUiStateAdapterTest to use the new signature.
    - Add unit test to verify that concurrent camera (dual mode) disables HDR video.
    Refactors `SettingRow` in `QuickSettingsComponents.kt` to accept a
    `buttons: @composable RowScope.() -> Unit` slot instead of a `vararg`
    array of Composables.

    This makes the Composable stable and skippable, preventing unnecessary
    recompositions, and eliminates `.toTypedArray()` allocations at call sites.
    Updates all callers (CaptureModeRow, HdrRow, AspectRatioRow, FlashRow,
    and previews) to use the new trailing lambda syntax.
Base automatically changed from kim/hdr/decouple-capture-modes to main July 7, 2026 23:06

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to take externalCaptureMode as a dependency constructor parameter here?

Upstream state resolution already applies externalCaptureMode on the CameraSystem defaults, and HdrUiStateAdapter accurately reacts to it by emitting omitting/restricting the UI state. Because the UI adapter is already preventing interaction under these conditions, repeating defensive guards here in the controller is redundant.

We should be able to remove externalCaptureMode entirely from this file (and its fake) and just blindly forward changes to the CameraSystem – letting the UiStateAdapters handle correct UI visibility/blocking.

Comment thread ui/components/capture/src/main/res/values/strings.xml Outdated
),
onNavigateToSettings = {},
quickSettingsController = NoOpQuickSettingsController()
private fun VideoQuickSettings(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since ImageAndVideoQuickSettings, VideoQuickSettings, and ImageQuickSettings share the exact same structural boilerplate (a title, a <Row> list, and a conditional QuickNavSettings button at the bottom), could we consolidate them into a shared base <QuickSettingsLayout> composable?

For example:

@Composable
private fun QuickSettingsLayout(
    @StringRes titleRes: Int,
    showMoreSettingsButton: Boolean,
    onNavigateToSettings: () -> Unit,
    content: @Composable ColumnScope.() -> Unit
) {
    Column {
        Text(
            modifier = Modifier.padding(start = 16.dp, end = 16.dp, bottom = 8.dp),
            text = stringResource(id = titleRes),
            style = MaterialTheme.typography.titleLarge
        )
        content()
    }
    if (showMoreSettingsButton) {
        QuickNavSettings(onNavigateToSettings = onNavigateToSettings)
    }
}

// 3. Special handling for LOW_LIGHT_BOOST based on other settings.
if (mode == FlashMode.LOW_LIGHT_BOOST) {
if (cameraAppSettings.concurrentCameraMode == ConcurrentCameraMode.DUAL) {
continue // Hide LLB if Dual Camera is active

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: same point on formatting as elsewhere – can we move all of these trailing comments (lines 101, 109, 121, etc) to their own dedicated lines above the relevant declarations?

MaterialTheme(colorScheme = darkColorScheme()) {
Surface(
modifier = Modifier.fillMaxWidth(),
color = Color.Black // Consistent with Camera UI

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: please move the trailing comment to its own dedicated line above the code rather than inline.

class QuickSettingsControllerImpl(
private val trackedCaptureUiState: MutableStateFlow<TrackedCaptureUiState>,
private val cameraSystem: CameraSystem,
private val externalCaptureMode: ExternalCaptureMode,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the order of externalCaptureMode and cameraSystem just got swapped.

To clarify my previous comment: we shouldn't need externalCaptureMode passed into the Quick Settings controller anymore. Because the UI State Adapters react to the external capture mode (by hiding/disabling conflicting UI elements based on the initial app settings), the UI is already structurally prevented from sending conflicting interactions down to this controller.

Repeating defensive guards for externalCaptureMode here inside the controller is redundant. We should totally remove externalCaptureMode from this file and FakeQuickSettingsController!

}
}

override fun setFocusedSetting(focusedQuickSetting: FocusedQuickSetting) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just re-flagging that we still need updates to QuickSettingsControllerImplTest.kt!

The control flows inside QuickSettingsControllerImpl (such as setFocusedSetting) were heavily modified in this PR. We need ensuring unit tests added to verify that state mutates properly against our Fake dependencies.

* @param externalCaptureMode The external capture mode, if any.
* @return A [QuickSettingsUiState.Available] instance containing the consolidated states.
*/
fun QuickSettingsUiState.Companion.from(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Friendly ping on this. I still don't see a QuickSettingsUiStateAdapterTest.kt file in the diff.

Because we've refactored how QuickSettingsUiState is mapped from the injected sub-states (aspectRatio, captureMode, flashMode, etc.), it's vital we add test coverage verifying that this adapter effectively outputs the correct QuickSettingsUiState.Available or Unavailable states.

- Remove redundant `externalCaptureMode` from `QuickSettingsControllerImpl` constructor and streamline selection guards.
- Align `CameraXCameraSystem` HDR format constraints check with `HdrUiStateAdapter` by checking if the active effect targets image capture instead of checking for any active effect.
- Address PR styling comments by converting trailing comments to dedicated lines.
- Fix UI accessibility nit (remove duplicate announcements) and add missing KDoc to `HdrIndicator`.
- Create unit tests for `QuickSettingsControllerImpl` and `QuickSettingsUiStateAdapter`, and add test coverage for effect interactions in `HdrUiStateAdapterTest`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants