3 Commits

Author SHA1 Message Date
b4d3ead8f0 Merge pull request 'fix(components): match full-screen picker bar icons to the runtime theme' (#3) from fix/picker-bar-icon-appearance into main 2026-07-24 15:24:12 +00:00
9bbef911c0 fix(components): match full-screen picker bar icons to the runtime theme
A Compose Dialog owns its own Window whose status/navigation-bar icon
appearance is seeded from the XML theme, not from the host activity's
runtime edge-to-edge state. With decorFitsSystemWindows = false the
FullScreenPicker draws under the bars, exposing icons that don't match
the active theme — dark icons on a dark picker (near-invisible), and the
mirror-image nav-bar bug in light theme.

Expose the resolved light/dark decision from FloretExpressiveTheme as
LocalFloretDarkTheme and drive the dialog window's
isAppearanceLight{Status,Navigation}Bars from it, so the appearance
tracks the in-app light/dark choice even when it diverges from the
system night resource qualifier.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 17:11:16 +02:00
75b90d1b3b Merge pull request 'feat(components): expose SelectedCheck as a family primitive' (#2) from feat/selected-check-primitive into main 2026-07-20 13:27:22 +00:00
3 changed files with 40 additions and 9 deletions

View File

@@ -39,6 +39,8 @@ dependencies {
// core-locale backs the language-picker recipe (AppLanguage).
implementation(project(":core-locale"))
implementation(libs.androidx.core.ktx)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.foundation)

View File

@@ -13,6 +13,8 @@ import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.window.DialogWindowProvider
import androidx.core.view.WindowCompat
import de.jeanlucmakiola.floret.identity.LocalFloretDarkTheme
/**
* Full-screen scaffold for selection pickers: a full-bleed [Dialog] that reuses
@@ -41,14 +43,28 @@ fun FullScreenPicker(
decorFitsSystemWindows = false,
),
) {
// The dialog window pans by default when the keyboard opens, which —
// A Compose Dialog owns a separate android.view.Window whose bar-icon
// appearance is seeded from the XML theme, not from the activity window's
// runtime edge-to-edge state — so with decorFitsSystemWindows = false it
// draws edge-to-edge under bars whose icons don't match the active theme
// (dark icons on a dark picker). Drive the appearance from the runtime
// [LocalFloretDarkTheme] so it tracks the in-app light/dark choice even
// when that diverges from the system night qualifier.
//
// Same window also pans by default when the keyboard opens, which —
// combined with the content's own imePadding — leaves a fixed black gap
// above the keyboard. Switch it to ADJUST_NOTHING so the window stays
// full-screen and imePadding alone lifts the focused field.
val view = LocalView.current
val darkTheme = LocalFloretDarkTheme.current
SideEffect {
(view.parent as? DialogWindowProvider)?.window
?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
(view.parent as? DialogWindowProvider)?.window?.let { window ->
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
WindowCompat.getInsetsController(window, view).apply {
isAppearanceLightStatusBars = !darkTheme
isAppearanceLightNavigationBars = !darkTheme
}
}
}
CollapsingScaffold(
title = title,

View File

@@ -10,8 +10,19 @@ import androidx.compose.material3.Typography
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.platform.LocalContext
/**
* The resolved light/dark decision the current [FloretExpressiveTheme] is running
* with, carried down the tree so components can align window chrome (e.g. status-
* and navigation-bar icon appearance) with the *runtime* theme rather than the
* system night resource qualifier — the two diverge whenever an app overrides
* light/dark from settings. Defaults to `false` (light) outside a Floret theme.
*/
val LocalFloretDarkTheme = staticCompositionLocalOf { false }
/**
* The family's Material 3 Expressive theme factory. Honours system light/dark
* and Material You dynamic colour (API 31+), falling back to the app-supplied
@@ -43,6 +54,7 @@ fun FloretExpressiveTheme(
else -> lightScheme
}
CompositionLocalProvider(LocalFloretDarkTheme provides darkTheme) {
MaterialExpressiveTheme(
colorScheme = colorScheme,
typography = typography,
@@ -50,3 +62,4 @@ fun FloretExpressiveTheme(
content = content,
)
}
}