feat: add high-contrast theme with accessible message bubbles (#5135)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
James Rich 2026-04-14 20:14:20 -05:00 committed by GitHub
parent f48fc61729
commit fa63a4ac50
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 328 additions and 65 deletions

View file

@ -169,7 +169,8 @@ private fun ApplicationScope.ThemeAndLocaleProvider(uiViewModel: UIViewModel) {
val uiPrefs = koinInject<UiPrefs>()
val themePref by uiPrefs.theme.collectAsState(initial = -1)
val localePref by uiPrefs.locale.collectAsState(initial = "")
val contrastLevelValue by uiPrefs.contrastLevel.collectAsState(initial = 0)
val contrastLevel = org.meshtastic.core.ui.theme.ContrastLevel.fromValue(contrastLevelValue)
Locale.setDefault(localePref.takeIf { it.isNotEmpty() }?.let(Locale::forLanguageTag) ?: systemLocale)
val isDarkTheme =
@ -179,7 +180,7 @@ private fun ApplicationScope.ThemeAndLocaleProvider(uiViewModel: UIViewModel) {
else -> isSystemInDarkTheme()
}
MeshtasticDesktopApp(uiViewModel, isDarkTheme)
MeshtasticDesktopApp(uiViewModel, isDarkTheme, contrastLevel)
}
// ----- Application chrome (tray, window, navigation) -----
@ -187,7 +188,11 @@ private fun ApplicationScope.ThemeAndLocaleProvider(uiViewModel: UIViewModel) {
/** Composes the system tray, window, and Coil image loader. */
@Composable
@OptIn(ExperimentalCoilApi::class)
private fun ApplicationScope.MeshtasticDesktopApp(uiViewModel: UIViewModel, isDarkTheme: Boolean) {
private fun ApplicationScope.MeshtasticDesktopApp(
uiViewModel: UIViewModel,
isDarkTheme: Boolean,
contrastLevel: org.meshtastic.core.ui.theme.ContrastLevel,
) {
var isAppVisible by remember { mutableStateOf(true) }
var isWindowReady by remember { mutableStateOf(false) }
val trayState = rememberTrayState()
@ -219,7 +224,7 @@ private fun ApplicationScope.MeshtasticDesktopApp(uiViewModel: UIViewModel, isDa
)
if (isWindowReady && isAppVisible) {
MeshtasticWindow(uiViewModel, isDarkTheme, appIcon, windowState) { isAppVisible = false }
MeshtasticWindow(uiViewModel, isDarkTheme, contrastLevel, appIcon, windowState) { isAppVisible = false }
}
}
@ -267,6 +272,7 @@ private fun WindowBoundsManager(
private fun ApplicationScope.MeshtasticWindow(
uiViewModel: UIViewModel,
isDarkTheme: Boolean,
contrastLevel: org.meshtastic.core.ui.theme.ContrastLevel,
appIcon: Painter,
windowState: WindowState,
onCloseRequest: () -> Unit,
@ -281,7 +287,9 @@ private fun ApplicationScope.MeshtasticWindow(
onPreviewKeyEvent = { event -> handleKeyboardShortcut(event, multiBackstack, ::exitApplication) },
) {
CoilImageLoaderSetup()
AppTheme(darkTheme = isDarkTheme) { DesktopMainScreen(uiViewModel, multiBackstack) }
AppTheme(darkTheme = isDarkTheme, contrastLevel = contrastLevel) {
DesktopMainScreen(uiViewModel, multiBackstack)
}
}
}