mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-05-18 19:56:34 -04:00
feat: align theme with Design Standards v1.3, remove contrast setting (#5355)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -128,8 +128,6 @@ class MainActivity : AppCompatActivity() {
|
||||
setSingletonImageLoaderFactory { get<ImageLoader>() }
|
||||
|
||||
val theme by model.theme.collectAsStateWithLifecycle()
|
||||
val contrastLevelValue by model.contrastLevel.collectAsStateWithLifecycle()
|
||||
val contrastLevel = org.meshtastic.core.ui.theme.ContrastLevel.fromValue(contrastLevelValue)
|
||||
val dynamic = theme == MODE_DYNAMIC
|
||||
val dark =
|
||||
when (theme) {
|
||||
@@ -147,7 +145,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
AppCompositionLocals {
|
||||
AppTheme(dynamicColor = dynamic, darkTheme = dark, contrastLevel = contrastLevel) {
|
||||
AppTheme(dynamicColor = dynamic, darkTheme = dark) {
|
||||
val appIntroCompleted by model.appIntroCompleted.collectAsStateWithLifecycle()
|
||||
|
||||
// Signal to the system that the initial UI is "fully drawn"
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.domain.usecase.settings
|
||||
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.repository.UiPrefs
|
||||
|
||||
@Single
|
||||
open class SetContrastLevelUseCase constructor(private val uiPrefs: UiPrefs) {
|
||||
operator fun invoke(value: Int) {
|
||||
uiPrefs.setContrastLevel(value)
|
||||
}
|
||||
}
|
||||
@@ -62,13 +62,6 @@ class UiPrefsImpl(
|
||||
scope.launch { dataStore.edit { it[KEY_THEME] = value } }
|
||||
}
|
||||
|
||||
override val contrastLevel: StateFlow<Int> =
|
||||
dataStore.data.map { it[KEY_CONTRAST_LEVEL] ?: 0 }.stateIn(scope, SharingStarted.Lazily, 0)
|
||||
|
||||
override fun setContrastLevel(value: Int) {
|
||||
scope.launch { dataStore.edit { it[KEY_CONTRAST_LEVEL] = value } }
|
||||
}
|
||||
|
||||
override val locale: StateFlow<String> =
|
||||
dataStore.data.map { it[KEY_LOCALE] ?: "" }.stateIn(scope, SharingStarted.Eagerly, "")
|
||||
|
||||
@@ -194,7 +187,6 @@ class UiPrefsImpl(
|
||||
|
||||
val KEY_APP_INTRO_COMPLETED = booleanPreferencesKey("app_intro_completed")
|
||||
val KEY_THEME = intPreferencesKey("theme")
|
||||
val KEY_CONTRAST_LEVEL = intPreferencesKey("contrast-level")
|
||||
val KEY_LOCALE = stringPreferencesKey("locale")
|
||||
val KEY_NODE_SORT = intPreferencesKey("node-sort-option")
|
||||
val KEY_INCLUDE_UNKNOWN = booleanPreferencesKey("include-unknown")
|
||||
|
||||
@@ -80,10 +80,6 @@ interface UiPrefs {
|
||||
|
||||
fun setTheme(value: Int)
|
||||
|
||||
val contrastLevel: StateFlow<Int>
|
||||
|
||||
fun setContrastLevel(value: Int)
|
||||
|
||||
val locale: StateFlow<String>
|
||||
|
||||
fun setLocale(languageTag: String)
|
||||
|
||||
@@ -84,12 +84,6 @@ class FakeUiPrefs : UiPrefs {
|
||||
theme.value = value
|
||||
}
|
||||
|
||||
override val contrastLevel = MutableStateFlow(0)
|
||||
|
||||
override fun setContrastLevel(value: Int) {
|
||||
contrastLevel.value = value
|
||||
}
|
||||
|
||||
override val locale = MutableStateFlow("en")
|
||||
|
||||
override fun setLocale(languageTag: String) {
|
||||
|
||||
@@ -18,218 +18,81 @@ package org.meshtastic.core.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val primaryLight = Color(0xFF306A42)
|
||||
// ─── Meshtastic Design Standards v1.3 ───
|
||||
// Primary: Green 700 #2D8F52 | Secondary: Neutral 600 #555668
|
||||
// Tertiary: Blue 700 #2855A8 | Neutral: #2C2D3C | Neutral Variant: #303245
|
||||
// See: standards/meshtastic_design_standards_v1_3.md §8
|
||||
|
||||
// ─── Light Scheme (§8.2) ───
|
||||
val primaryLight = Color(0xFF2D8F52) // Green 700
|
||||
val onPrimaryLight = Color(0xFFFFFFFF)
|
||||
val primaryContainerLight = Color(0xFFB3F1BF)
|
||||
val onPrimaryContainerLight = Color(0xFF00210D)
|
||||
val secondaryLight = Color(0xFF506353)
|
||||
val primaryContainerLight = Color(0xFFB5F5CE) // Green 300
|
||||
val onPrimaryContainerLight = Color(0xFF002E13) // Green 950
|
||||
val secondaryLight = Color(0xFF555668) // Neutral 600
|
||||
val onSecondaryLight = Color(0xFFFFFFFF)
|
||||
val secondaryContainerLight = Color(0xFFD2E8D3)
|
||||
val onSecondaryContainerLight = Color(0xFF0D1F12)
|
||||
val tertiaryLight = Color(0xFF3A656E)
|
||||
val secondaryContainerLight = Color(0xFFD5D6E0) // Neutral 200
|
||||
val onSecondaryContainerLight = Color(0xFF2C2D3C) // Neutral 800
|
||||
val tertiaryLight = Color(0xFF2855A8) // Blue 700
|
||||
val onTertiaryLight = Color(0xFFFFFFFF)
|
||||
val tertiaryContainerLight = Color(0xFFBEEAF6)
|
||||
val onTertiaryContainerLight = Color(0xFF001F25)
|
||||
val errorLight = Color(0xFFBA1A1A)
|
||||
val tertiaryContainerLight = Color(0xFFE8EAF6) // Blue 50
|
||||
val onTertiaryContainerLight = Color(0xFF001849) // Blue 950
|
||||
val errorLight = Color(0xFFBA1A1A) // Error 600 (WCAG-safe on white)
|
||||
val onErrorLight = Color(0xFFFFFFFF)
|
||||
val errorContainerLight = Color(0xFFFFDAD6)
|
||||
val onErrorContainerLight = Color(0xFF410002)
|
||||
val backgroundLight = Color(0xFFF6FBF3)
|
||||
val onBackgroundLight = Color(0xFF181D18)
|
||||
val surfaceLight = Color(0xFFF6FBF3)
|
||||
val onSurfaceLight = Color(0xFF181D18)
|
||||
val surfaceVariantLight = Color(0xFFDDE5DA)
|
||||
val onSurfaceVariantLight = Color(0xFF414941)
|
||||
val outlineLight = Color(0xFF717971)
|
||||
val outlineVariantLight = Color(0xFFC1C9BF)
|
||||
val errorContainerLight = Color(0xFFFDEAEA) // Error 100
|
||||
val onErrorContainerLight = Color(0xFF410002) // Error 900
|
||||
val backgroundLight = Color(0xFFF5F6FA) // Neutral 50
|
||||
val onBackgroundLight = Color(0xFF2C2D3C) // Neutral 800
|
||||
val surfaceLight = Color(0xFFF5F6FA) // Neutral 50
|
||||
val onSurfaceLight = Color(0xFF2C2D3C) // Neutral 800
|
||||
val surfaceVariantLight = Color(0xFFDADBE7) // NV 200
|
||||
val onSurfaceVariantLight = Color(0xFF5C5E78) // NV 600
|
||||
val outlineLight = Color(0xFF767892) // NV 500
|
||||
val outlineVariantLight = Color(0xFFBDBFCF) // NV 300
|
||||
val scrimLight = Color(0xFF000000)
|
||||
val inverseSurfaceLight = Color(0xFF2D322D)
|
||||
val inverseOnSurfaceLight = Color(0xFFEEF2EA)
|
||||
val inversePrimaryLight = Color(0xFF97D5A5)
|
||||
val surfaceDimLight = Color(0xFFD7DBD4)
|
||||
val surfaceBrightLight = Color(0xFFF6FBF3)
|
||||
val inverseSurfaceLight = Color(0xFF3D3E50) // Neutral 700
|
||||
val inverseOnSurfaceLight = Color(0xFFECEDF3) // Neutral 100
|
||||
val inversePrimaryLight = Color(0xFF67EA94) // Green 500
|
||||
val surfaceDimLight = Color(0xFFD5D6E0) // Neutral 200
|
||||
val surfaceBrightLight = Color(0xFFF5F6FA) // Neutral 50
|
||||
val surfaceContainerLowestLight = Color(0xFFFFFFFF)
|
||||
val surfaceContainerLowLight = Color(0xFFF0F5ED)
|
||||
val surfaceContainerLight = Color(0xFFEBEFE7)
|
||||
val surfaceContainerHighLight = Color(0xFFE5EAE2)
|
||||
val surfaceContainerHighestLight = Color(0xFFDFE4DC)
|
||||
val surfaceContainerLowLight = Color(0xFFF5F6FA) // Neutral 50
|
||||
val surfaceContainerLight = Color(0xFFECEDF3) // Neutral 100
|
||||
val surfaceContainerHighLight = Color(0xFFE0E1EB) // Interpolated 100↔200
|
||||
val surfaceContainerHighestLight = Color(0xFFD5D6E0) // Neutral 200
|
||||
|
||||
val primaryLightMediumContrast = Color(0xFF0F4D29)
|
||||
val onPrimaryLightMediumContrast = Color(0xFFFFFFFF)
|
||||
val primaryContainerLightMediumContrast = Color(0xFF478157)
|
||||
val onPrimaryContainerLightMediumContrast = Color(0xFFFFFFFF)
|
||||
val secondaryLightMediumContrast = Color(0xFF344738)
|
||||
val onSecondaryLightMediumContrast = Color(0xFFFFFFFF)
|
||||
val secondaryContainerLightMediumContrast = Color(0xFF657A68)
|
||||
val onSecondaryContainerLightMediumContrast = Color(0xFFFFFFFF)
|
||||
val tertiaryLightMediumContrast = Color(0xFF1C4952)
|
||||
val onTertiaryLightMediumContrast = Color(0xFFFFFFFF)
|
||||
val tertiaryContainerLightMediumContrast = Color(0xFF517B85)
|
||||
val onTertiaryContainerLightMediumContrast = Color(0xFFFFFFFF)
|
||||
val errorLightMediumContrast = Color(0xFF8C0009)
|
||||
val onErrorLightMediumContrast = Color(0xFFFFFFFF)
|
||||
val errorContainerLightMediumContrast = Color(0xFFDA342E)
|
||||
val onErrorContainerLightMediumContrast = Color(0xFFFFFFFF)
|
||||
val backgroundLightMediumContrast = Color(0xFFF6FBF3)
|
||||
val onBackgroundLightMediumContrast = Color(0xFF181D18)
|
||||
val surfaceLightMediumContrast = Color(0xFFF6FBF3)
|
||||
val onSurfaceLightMediumContrast = Color(0xFF181D18)
|
||||
val surfaceVariantLightMediumContrast = Color(0xFFDDE5DA)
|
||||
val onSurfaceVariantLightMediumContrast = Color(0xFF3D453D)
|
||||
val outlineLightMediumContrast = Color(0xFF596159)
|
||||
val outlineVariantLightMediumContrast = Color(0xFF757D74)
|
||||
val scrimLightMediumContrast = Color(0xFF000000)
|
||||
val inverseSurfaceLightMediumContrast = Color(0xFF2D322D)
|
||||
val inverseOnSurfaceLightMediumContrast = Color(0xFFEEF2EA)
|
||||
val inversePrimaryLightMediumContrast = Color(0xFF97D5A5)
|
||||
val surfaceDimLightMediumContrast = Color(0xFFD7DBD4)
|
||||
val surfaceBrightLightMediumContrast = Color(0xFFF6FBF3)
|
||||
val surfaceContainerLowestLightMediumContrast = Color(0xFFFFFFFF)
|
||||
val surfaceContainerLowLightMediumContrast = Color(0xFFF0F5ED)
|
||||
val surfaceContainerLightMediumContrast = Color(0xFFEBEFE7)
|
||||
val surfaceContainerHighLightMediumContrast = Color(0xFFE5EAE2)
|
||||
val surfaceContainerHighestLightMediumContrast = Color(0xFFDFE4DC)
|
||||
|
||||
val primaryLightHighContrast = Color(0xFF002911)
|
||||
val onPrimaryLightHighContrast = Color(0xFFFFFFFF)
|
||||
val primaryContainerLightHighContrast = Color(0xFF0F4D29)
|
||||
val onPrimaryContainerLightHighContrast = Color(0xFFFFFFFF)
|
||||
val secondaryLightHighContrast = Color(0xFF142619)
|
||||
val onSecondaryLightHighContrast = Color(0xFFFFFFFF)
|
||||
val secondaryContainerLightHighContrast = Color(0xFF344738)
|
||||
val onSecondaryContainerLightHighContrast = Color(0xFFFFFFFF)
|
||||
val tertiaryLightHighContrast = Color(0xFF00262E)
|
||||
val onTertiaryLightHighContrast = Color(0xFFFFFFFF)
|
||||
val tertiaryContainerLightHighContrast = Color(0xFF1C4952)
|
||||
val onTertiaryContainerLightHighContrast = Color(0xFFFFFFFF)
|
||||
val errorLightHighContrast = Color(0xFF4E0002)
|
||||
val onErrorLightHighContrast = Color(0xFFFFFFFF)
|
||||
val errorContainerLightHighContrast = Color(0xFF8C0009)
|
||||
val onErrorContainerLightHighContrast = Color(0xFFFFFFFF)
|
||||
val backgroundLightHighContrast = Color(0xFFF6FBF3)
|
||||
val onBackgroundLightHighContrast = Color(0xFF181D18)
|
||||
val surfaceLightHighContrast = Color(0xFFF6FBF3)
|
||||
val onSurfaceLightHighContrast = Color(0xFF000000)
|
||||
val surfaceVariantLightHighContrast = Color(0xFFDDE5DA)
|
||||
val onSurfaceVariantLightHighContrast = Color(0xFF1E261F)
|
||||
val outlineLightHighContrast = Color(0xFF3D453D)
|
||||
val outlineVariantLightHighContrast = Color(0xFF3D453D)
|
||||
val scrimLightHighContrast = Color(0xFF000000)
|
||||
val inverseSurfaceLightHighContrast = Color(0xFF2D322D)
|
||||
val inverseOnSurfaceLightHighContrast = Color(0xFFFFFFFF)
|
||||
val inversePrimaryLightHighContrast = Color(0xFFBCFBC8)
|
||||
val surfaceDimLightHighContrast = Color(0xFFD7DBD4)
|
||||
val surfaceBrightLightHighContrast = Color(0xFFF6FBF3)
|
||||
val surfaceContainerLowestLightHighContrast = Color(0xFFFFFFFF)
|
||||
val surfaceContainerLowLightHighContrast = Color(0xFFF0F5ED)
|
||||
val surfaceContainerLightHighContrast = Color(0xFFEBEFE7)
|
||||
val surfaceContainerHighLightHighContrast = Color(0xFFE5EAE2)
|
||||
val surfaceContainerHighestLightHighContrast = Color(0xFFDFE4DC)
|
||||
|
||||
val primaryDark = Color(0xFF97D5A5)
|
||||
val onPrimaryDark = Color(0xFF00391A)
|
||||
val primaryContainerDark = Color(0xFF15512C)
|
||||
val onPrimaryContainerDark = Color(0xFFB3F1BF)
|
||||
val secondaryDark = Color(0xFFB6CCB8)
|
||||
val onSecondaryDark = Color(0xFF223526)
|
||||
val secondaryContainerDark = Color(0xFF384B3C)
|
||||
val onSecondaryContainerDark = Color(0xFFD2E8D3)
|
||||
val tertiaryDark = Color(0xFFA2CED9)
|
||||
val onTertiaryDark = Color(0xFF01363F)
|
||||
val tertiaryContainerDark = Color(0xFF204D56)
|
||||
val onTertiaryContainerDark = Color(0xFFBEEAF6)
|
||||
val errorDark = Color(0xFFFFB4AB)
|
||||
val onErrorDark = Color(0xFF690005)
|
||||
val errorContainerDark = Color(0xFF93000A)
|
||||
val onErrorContainerDark = Color(0xFFFFDAD6)
|
||||
val backgroundDark = Color(0xFF101510)
|
||||
val onBackgroundDark = Color(0xFFDFE4DC)
|
||||
val surfaceDark = Color(0xFF101510)
|
||||
val onSurfaceDark = Color(0xFFDFE4DC)
|
||||
val surfaceVariantDark = Color(0xFF414941)
|
||||
val onSurfaceVariantDark = Color(0xFFC1C9BF)
|
||||
val outlineDark = Color(0xFF8B938A)
|
||||
val outlineVariantDark = Color(0xFF414941)
|
||||
// ─── Dark Scheme (§8.3) ───
|
||||
val primaryDark = Color(0xFF67EA94) // Green 500
|
||||
val onPrimaryDark = Color(0xFF0F1017) // Neutral 950
|
||||
val primaryContainerDark = Color(0xFF2D8F52) // Green 700
|
||||
val onPrimaryContainerDark = Color(0xFFB5F5CE) // Green 300
|
||||
val secondaryDark = Color(0xFFB8BAC8) // Neutral 300
|
||||
val onSecondaryDark = Color(0xFF1A1B26) // Neutral 900
|
||||
val secondaryContainerDark = Color(0xFF3D3E50) // Neutral 700
|
||||
val onSecondaryContainerDark = Color(0xFFD5D6E0) // Neutral 200
|
||||
val tertiaryDark = Color(0xFFB0BFF0) // Blue 300
|
||||
val onTertiaryDark = Color(0xFF001849) // Blue 950
|
||||
val tertiaryContainerDark = Color(0xFF2855A8) // Blue 700
|
||||
val onTertiaryContainerDark = Color(0xFFE8EAF6) // Blue 50
|
||||
val errorDark = Color(0xFFFFB4AB) // Error 300
|
||||
val onErrorDark = Color(0xFF690005) // Error 800
|
||||
val errorContainerDark = Color(0xFF93000A) // Error 700
|
||||
val onErrorContainerDark = Color(0xFFFDEAEA) // Error 100
|
||||
val backgroundDark = Color(0xFF1A1B26) // Neutral 900
|
||||
val onBackgroundDark = Color(0xFFECEDF3) // Neutral 100
|
||||
val surfaceDark = Color(0xFF1A1B26) // Neutral 900
|
||||
val onSurfaceDark = Color(0xFFECEDF3) // Neutral 100
|
||||
val surfaceVariantDark = Color(0xFF444660) // NV 700
|
||||
val onSurfaceVariantDark = Color(0xFFBDBFCF) // NV 300
|
||||
val outlineDark = Color(0xFF767892) // NV 500
|
||||
val outlineVariantDark = Color(0xFF444660) // NV 700
|
||||
val scrimDark = Color(0xFF000000)
|
||||
val inverseSurfaceDark = Color(0xFFDFE4DC)
|
||||
val inverseOnSurfaceDark = Color(0xFF2D322D)
|
||||
val inversePrimaryDark = Color(0xFF306A42)
|
||||
val surfaceDimDark = Color(0xFF101510)
|
||||
val surfaceBrightDark = Color(0xFF353A35)
|
||||
val surfaceContainerLowestDark = Color(0xFF0A0F0B)
|
||||
val surfaceContainerLowDark = Color(0xFF181D18)
|
||||
val surfaceContainerDark = Color(0xFF1C211C)
|
||||
val surfaceContainerHighDark = Color(0xFF262B26)
|
||||
val surfaceContainerHighestDark = Color(0xFF313631)
|
||||
|
||||
val primaryDarkMediumContrast = Color(0xFF9BD9A9)
|
||||
val onPrimaryDarkMediumContrast = Color(0xFF001B09)
|
||||
val primaryContainerDarkMediumContrast = Color(0xFF639D72)
|
||||
val onPrimaryContainerDarkMediumContrast = Color(0xFF000000)
|
||||
val secondaryDarkMediumContrast = Color(0xFFBBD0BC)
|
||||
val onSecondaryDarkMediumContrast = Color(0xFF081A0D)
|
||||
val secondaryContainerDarkMediumContrast = Color(0xFF819683)
|
||||
val onSecondaryContainerDarkMediumContrast = Color(0xFF000000)
|
||||
val tertiaryDarkMediumContrast = Color(0xFFA6D2DD)
|
||||
val onTertiaryDarkMediumContrast = Color(0xFF00191F)
|
||||
val tertiaryContainerDarkMediumContrast = Color(0xFF6D97A2)
|
||||
val onTertiaryContainerDarkMediumContrast = Color(0xFF000000)
|
||||
val errorDarkMediumContrast = Color(0xFFFFBAB1)
|
||||
val onErrorDarkMediumContrast = Color(0xFF370001)
|
||||
val errorContainerDarkMediumContrast = Color(0xFFFF5449)
|
||||
val onErrorContainerDarkMediumContrast = Color(0xFF000000)
|
||||
val backgroundDarkMediumContrast = Color(0xFF101510)
|
||||
val onBackgroundDarkMediumContrast = Color(0xFFDFE4DC)
|
||||
val surfaceDarkMediumContrast = Color(0xFF101510)
|
||||
val onSurfaceDarkMediumContrast = Color(0xFFF8FCF4)
|
||||
val surfaceVariantDarkMediumContrast = Color(0xFF414941)
|
||||
val onSurfaceVariantDarkMediumContrast = Color(0xFFC5CDC3)
|
||||
val outlineDarkMediumContrast = Color(0xFF9DA59C)
|
||||
val outlineVariantDarkMediumContrast = Color(0xFF7D857D)
|
||||
val scrimDarkMediumContrast = Color(0xFF000000)
|
||||
val inverseSurfaceDarkMediumContrast = Color(0xFFDFE4DC)
|
||||
val inverseOnSurfaceDarkMediumContrast = Color(0xFF262B26)
|
||||
val inversePrimaryDarkMediumContrast = Color(0xFF16522E)
|
||||
val surfaceDimDarkMediumContrast = Color(0xFF101510)
|
||||
val surfaceBrightDarkMediumContrast = Color(0xFF353A35)
|
||||
val surfaceContainerLowestDarkMediumContrast = Color(0xFF0A0F0B)
|
||||
val surfaceContainerLowDarkMediumContrast = Color(0xFF181D18)
|
||||
val surfaceContainerDarkMediumContrast = Color(0xFF1C211C)
|
||||
val surfaceContainerHighDarkMediumContrast = Color(0xFF262B26)
|
||||
val surfaceContainerHighestDarkMediumContrast = Color(0xFF313631)
|
||||
|
||||
val primaryDarkHighContrast = Color(0xFFEFFFEE)
|
||||
val onPrimaryDarkHighContrast = Color(0xFF000000)
|
||||
val primaryContainerDarkHighContrast = Color(0xFF9BD9A9)
|
||||
val onPrimaryContainerDarkHighContrast = Color(0xFF000000)
|
||||
val secondaryDarkHighContrast = Color(0xFFEFFFEE)
|
||||
val onSecondaryDarkHighContrast = Color(0xFF000000)
|
||||
val secondaryContainerDarkHighContrast = Color(0xFFBBD0BC)
|
||||
val onSecondaryContainerDarkHighContrast = Color(0xFF000000)
|
||||
val tertiaryDarkHighContrast = Color(0xFFF3FCFF)
|
||||
val onTertiaryDarkHighContrast = Color(0xFF000000)
|
||||
val tertiaryContainerDarkHighContrast = Color(0xFFA6D2DD)
|
||||
val onTertiaryContainerDarkHighContrast = Color(0xFF000000)
|
||||
val errorDarkHighContrast = Color(0xFFFFF9F9)
|
||||
val onErrorDarkHighContrast = Color(0xFF000000)
|
||||
val errorContainerDarkHighContrast = Color(0xFFFFBAB1)
|
||||
val onErrorContainerDarkHighContrast = Color(0xFF000000)
|
||||
val backgroundDarkHighContrast = Color(0xFF101510)
|
||||
val onBackgroundDarkHighContrast = Color(0xFFDFE4DC)
|
||||
val surfaceDarkHighContrast = Color(0xFF101510)
|
||||
val onSurfaceDarkHighContrast = Color(0xFFFFFFFF)
|
||||
val surfaceVariantDarkHighContrast = Color(0xFF414941)
|
||||
val onSurfaceVariantDarkHighContrast = Color(0xFFF5FDF2)
|
||||
val outlineDarkHighContrast = Color(0xFFC5CDC3)
|
||||
val outlineVariantDarkHighContrast = Color(0xFFC5CDC3)
|
||||
val scrimDarkHighContrast = Color(0xFF000000)
|
||||
val inverseSurfaceDarkHighContrast = Color(0xFFDFE4DC)
|
||||
val inverseOnSurfaceDarkHighContrast = Color(0xFF000000)
|
||||
val inversePrimaryDarkHighContrast = Color(0xFF003216)
|
||||
val surfaceDimDarkHighContrast = Color(0xFF101510)
|
||||
val surfaceBrightDarkHighContrast = Color(0xFF353A35)
|
||||
val surfaceContainerLowestDarkHighContrast = Color(0xFF0A0F0B)
|
||||
val surfaceContainerLowDarkHighContrast = Color(0xFF181D18)
|
||||
val surfaceContainerDarkHighContrast = Color(0xFF1C211C)
|
||||
val surfaceContainerHighDarkHighContrast = Color(0xFF262B26)
|
||||
val surfaceContainerHighestDarkHighContrast = Color(0xFF313631)
|
||||
val inverseSurfaceDark = Color(0xFFECEDF3) // Neutral 100
|
||||
val inverseOnSurfaceDark = Color(0xFF2C2D3C) // Neutral 800
|
||||
val inversePrimaryDark = Color(0xFF2D8F52) // Green 700
|
||||
val surfaceDimDark = Color(0xFF0F1017) // Neutral 950
|
||||
val surfaceBrightDark = Color(0xFF3D3E50) // Neutral 700
|
||||
val surfaceContainerLowestDark = Color(0xFF0F1017) // Neutral 950
|
||||
val surfaceContainerLowDark = Color(0xFF1A1B26) // Neutral 900
|
||||
val surfaceContainerDark = Color(0xFF242533) // Interpolated 900↔800
|
||||
val surfaceContainerHighDark = Color(0xFF2C2D3C) // Neutral 800
|
||||
val surfaceContainerHighestDark = Color(0xFF3D3E50) // Neutral 700
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.ui.theme
|
||||
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
|
||||
/**
|
||||
* Application-wide contrast level for accessibility.
|
||||
*
|
||||
* [STANDARD] keeps the default Material 3 color scheme. [MEDIUM] uses Material 3 medium-contrast color tokens and
|
||||
* increases message bubble opacity. [HIGH] uses Material 3 high-contrast color tokens, forces `onSurface` text in
|
||||
* message bubbles, and replaces translucent node-color fills with opaque theme surfaces plus accent borders.
|
||||
*/
|
||||
enum class ContrastLevel(val value: Int) {
|
||||
STANDARD(0),
|
||||
MEDIUM(1),
|
||||
HIGH(2),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun fromValue(value: Int): ContrastLevel = entries.firstOrNull { it.value == value } ?: MEDIUM
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Composition local providing the current [ContrastLevel].
|
||||
*
|
||||
* Read by components that need to adapt their rendering for accessibility (e.g. message bubbles, signal indicators).
|
||||
*/
|
||||
@Suppress("CompositionLocalAllowlist")
|
||||
val LocalContrastLevel = staticCompositionLocalOf { ContrastLevel.MEDIUM }
|
||||
@@ -21,10 +21,98 @@ import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val MeshtasticGreen = Color(0xFF67EA94)
|
||||
val MeshtasticAlt = Color(0xFF2C2D3C)
|
||||
val HyperlinkBlue = Color(0xFF43C3B0)
|
||||
val AnnotationColor = Color(0xFF039BE5)
|
||||
// ─── Brand Colors (Design Standards v1.3) ───
|
||||
val MeshtasticGreen = Color(0xFF67EA94) // Green 500 — Brand Accent
|
||||
val MeshtasticAlt = Color(0xFF2C2D3C) // Neutral 800 — Brand Primary
|
||||
|
||||
// ─── Neutral Scale ───
|
||||
object NeutralPalette {
|
||||
val N950 = Color(0xFF0F1017)
|
||||
val N900 = Color(0xFF1A1B26)
|
||||
val N800 = Color(0xFF2C2D3C)
|
||||
val N700 = Color(0xFF3D3E50)
|
||||
val N600 = Color(0xFF555668)
|
||||
val N500 = Color(0xFF6E7082)
|
||||
val N400 = Color(0xFF9496A6)
|
||||
val N300 = Color(0xFFB8BAC8)
|
||||
val N200 = Color(0xFFD5D6E0)
|
||||
val N100 = Color(0xFFECEDF3)
|
||||
val N50 = Color(0xFFF5F6FA)
|
||||
}
|
||||
|
||||
// ─── Neutral Variant Scale (§7.3) ───
|
||||
object NeutralVariantPalette {
|
||||
val NV900 = Color(0xFF1D1E2B)
|
||||
val NV800 = Color(0xFF303245)
|
||||
val NV700 = Color(0xFF444660)
|
||||
val NV600 = Color(0xFF5C5E78)
|
||||
val NV500 = Color(0xFF767892)
|
||||
val NV400 = Color(0xFF9698B0)
|
||||
val NV300 = Color(0xFFBDBFCF)
|
||||
val NV200 = Color(0xFFDADBE7)
|
||||
val NV100 = Color(0xFFEDEEF6)
|
||||
val NV50 = Color(0xFFF6F7FC)
|
||||
}
|
||||
|
||||
// ─── Green Scale (§7.4) ───
|
||||
object GreenPalette {
|
||||
val G950 = Color(0xFF002E13)
|
||||
val G900 = Color(0xFF003D1A)
|
||||
val G800 = Color(0xFF005C2E)
|
||||
val G700 = Color(0xFF2D8F52)
|
||||
val G600 = Color(0xFF3FB86D)
|
||||
val G500 = Color(0xFF67EA94)
|
||||
val G400 = Color(0xFF8FF0B2)
|
||||
val G300 = Color(0xFFB5F5CE)
|
||||
val G200 = Color(0xFFCCFADD)
|
||||
val G100 = Color(0xFFE5FCEE)
|
||||
val G50 = Color(0xFFF0FEF5)
|
||||
}
|
||||
|
||||
// ─── Accent Blue Scale (§7.5) ───
|
||||
object BluePalette {
|
||||
val B950 = Color(0xFF001849)
|
||||
val B900 = Color(0xFF002366)
|
||||
val B800 = Color(0xFF1A3F8C)
|
||||
val B700 = Color(0xFF2855A8)
|
||||
val B600 = Color(0xFF5C6BC0)
|
||||
val B500 = Color(0xFF7B8AD0)
|
||||
val B400 = Color(0xFF9BA8E0)
|
||||
val B300 = Color(0xFFB0BFF0)
|
||||
val B200 = Color(0xFFD0D8F5)
|
||||
val B100 = Color(0xFFE0E3F8)
|
||||
val B50 = Color(0xFFE8EAF6)
|
||||
}
|
||||
|
||||
// ─── Error Scale (§7.6) ───
|
||||
object ErrorPalette {
|
||||
val E900 = Color(0xFF410002)
|
||||
val E800 = Color(0xFF690005)
|
||||
val E700 = Color(0xFF93000A)
|
||||
val E600 = Color(0xFFBA1A1A)
|
||||
val E500 = Color(0xFFE05252)
|
||||
val E400 = Color(0xFFFF897D)
|
||||
val E300 = Color(0xFFFFB4AB)
|
||||
val E200 = Color(0xFFFFDAD6)
|
||||
val E100 = Color(0xFFFDEAEA)
|
||||
}
|
||||
|
||||
// ─── Semantic Colors (§7.7) ───
|
||||
object SemanticColors {
|
||||
val Accent = Color(0xFF2855A8) // Blue 700
|
||||
val AccentLight = Color(0xFFE0E3F8) // Blue 100
|
||||
val Info = Color(0xFF5C6BC0) // Blue 600
|
||||
val InfoLight = Color(0xFFE8EAF6) // Blue 50
|
||||
val Warning = Color(0xFFE8A33E)
|
||||
val WarningLight = Color(0xFFFFF3E0)
|
||||
val Error = Color(0xFFE05252) // Error 500 — non-text indicators only
|
||||
val ErrorLight = Color(0xFFFDEAEA) // Error 100
|
||||
val Success = Color(0xFF3FB86D) // Green 600
|
||||
val SuccessLight = Color(0xFFE5FCEE) // Green 100
|
||||
}
|
||||
|
||||
val HyperlinkBlue = Color(0xFF5C6BC0) // Blue 600 (Info)
|
||||
val AnnotationColor = Color(0xFF2855A8) // Blue 700 (Accent)
|
||||
|
||||
object TracerouteColors {
|
||||
// High-contrast pair that stays legible on light/dark tiles and for most color-blind users.
|
||||
@@ -69,20 +157,20 @@ object GraphColors {
|
||||
object StatusColors {
|
||||
val ColorScheme.StatusGreen: Color
|
||||
@Composable
|
||||
get() = // If it might change based on theme
|
||||
get() =
|
||||
if (isSystemInDarkTheme()) {
|
||||
Color(0xFF28A03B) // Example dark green
|
||||
Color(0xFF3FB86D) // Green 600
|
||||
} else {
|
||||
Color(0xFF30C047)
|
||||
Color(0xFF3FB86D) // Green 600 (Success)
|
||||
}
|
||||
|
||||
val ColorScheme.StatusYellow: Color
|
||||
@Composable
|
||||
get() =
|
||||
if (isSystemInDarkTheme()) {
|
||||
Color(0xFFFFC107)
|
||||
Color(0xFFE8A33E) // Warning
|
||||
} else {
|
||||
Color(0xFFFFD54F)
|
||||
Color(0xFFE8A33E) // Warning
|
||||
}
|
||||
|
||||
val ColorScheme.StatusOrange: Color
|
||||
@@ -96,20 +184,20 @@ object StatusColors {
|
||||
|
||||
val ColorScheme.StatusRed: Color
|
||||
@Composable
|
||||
get() = // If it might change based on theme
|
||||
get() =
|
||||
if (isSystemInDarkTheme()) {
|
||||
Color(0xFFB00020)
|
||||
Color(0xFFE05252) // Error
|
||||
} else {
|
||||
Color(0xFFF44336)
|
||||
Color(0xFFE05252) // Error
|
||||
}
|
||||
|
||||
val ColorScheme.StatusBlue: Color
|
||||
@Composable
|
||||
get() = // If it might change based on theme
|
||||
get() =
|
||||
if (isSystemInDarkTheme()) {
|
||||
Color(0xFF2196F3)
|
||||
Color(0xFF5C6BC0) // Info
|
||||
} else {
|
||||
Color(0xFF42A5F5)
|
||||
Color(0xFF5C6BC0) // Info
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.compose.material3.MotionScheme.Companion.expressive
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
@@ -107,162 +106,6 @@ private val darkScheme =
|
||||
surfaceContainerHighest = surfaceContainerHighestDark,
|
||||
)
|
||||
|
||||
private val mediumContrastLightColorScheme =
|
||||
lightColorScheme(
|
||||
primary = primaryLightMediumContrast,
|
||||
onPrimary = onPrimaryLightMediumContrast,
|
||||
primaryContainer = primaryContainerLightMediumContrast,
|
||||
onPrimaryContainer = onPrimaryContainerLightMediumContrast,
|
||||
secondary = secondaryLightMediumContrast,
|
||||
onSecondary = onSecondaryLightMediumContrast,
|
||||
secondaryContainer = secondaryContainerLightMediumContrast,
|
||||
onSecondaryContainer = onSecondaryContainerLightMediumContrast,
|
||||
tertiary = tertiaryLightMediumContrast,
|
||||
onTertiary = onTertiaryLightMediumContrast,
|
||||
tertiaryContainer = tertiaryContainerLightMediumContrast,
|
||||
onTertiaryContainer = onTertiaryContainerLightMediumContrast,
|
||||
error = errorLightMediumContrast,
|
||||
onError = onErrorLightMediumContrast,
|
||||
errorContainer = errorContainerLightMediumContrast,
|
||||
onErrorContainer = onErrorContainerLightMediumContrast,
|
||||
background = backgroundLightMediumContrast,
|
||||
onBackground = onBackgroundLightMediumContrast,
|
||||
surface = surfaceLightMediumContrast,
|
||||
onSurface = onSurfaceLightMediumContrast,
|
||||
surfaceVariant = surfaceVariantLightMediumContrast,
|
||||
onSurfaceVariant = onSurfaceVariantLightMediumContrast,
|
||||
outline = outlineLightMediumContrast,
|
||||
outlineVariant = outlineVariantLightMediumContrast,
|
||||
scrim = scrimLightMediumContrast,
|
||||
inverseSurface = inverseSurfaceLightMediumContrast,
|
||||
inverseOnSurface = inverseOnSurfaceLightMediumContrast,
|
||||
inversePrimary = inversePrimaryLightMediumContrast,
|
||||
surfaceDim = surfaceDimLightMediumContrast,
|
||||
surfaceBright = surfaceBrightLightMediumContrast,
|
||||
surfaceContainerLowest = surfaceContainerLowestLightMediumContrast,
|
||||
surfaceContainerLow = surfaceContainerLowLightMediumContrast,
|
||||
surfaceContainer = surfaceContainerLightMediumContrast,
|
||||
surfaceContainerHigh = surfaceContainerHighLightMediumContrast,
|
||||
surfaceContainerHighest = surfaceContainerHighestLightMediumContrast,
|
||||
)
|
||||
|
||||
private val highContrastLightColorScheme =
|
||||
lightColorScheme(
|
||||
primary = primaryLightHighContrast,
|
||||
onPrimary = onPrimaryLightHighContrast,
|
||||
primaryContainer = primaryContainerLightHighContrast,
|
||||
onPrimaryContainer = onPrimaryContainerLightHighContrast,
|
||||
secondary = secondaryLightHighContrast,
|
||||
onSecondary = onSecondaryLightHighContrast,
|
||||
secondaryContainer = secondaryContainerLightHighContrast,
|
||||
onSecondaryContainer = onSecondaryContainerLightHighContrast,
|
||||
tertiary = tertiaryLightHighContrast,
|
||||
onTertiary = onTertiaryLightHighContrast,
|
||||
tertiaryContainer = tertiaryContainerLightHighContrast,
|
||||
onTertiaryContainer = onTertiaryContainerLightHighContrast,
|
||||
error = errorLightHighContrast,
|
||||
onError = onErrorLightHighContrast,
|
||||
errorContainer = errorContainerLightHighContrast,
|
||||
onErrorContainer = onErrorContainerLightHighContrast,
|
||||
background = backgroundLightHighContrast,
|
||||
onBackground = onBackgroundLightHighContrast,
|
||||
surface = surfaceLightHighContrast,
|
||||
onSurface = onSurfaceLightHighContrast,
|
||||
surfaceVariant = surfaceVariantLightHighContrast,
|
||||
onSurfaceVariant = onSurfaceVariantLightHighContrast,
|
||||
outline = outlineLightHighContrast,
|
||||
outlineVariant = outlineVariantLightHighContrast,
|
||||
scrim = scrimLightHighContrast,
|
||||
inverseSurface = inverseSurfaceLightHighContrast,
|
||||
inverseOnSurface = inverseOnSurfaceLightHighContrast,
|
||||
inversePrimary = inversePrimaryLightHighContrast,
|
||||
surfaceDim = surfaceDimLightHighContrast,
|
||||
surfaceBright = surfaceBrightLightHighContrast,
|
||||
surfaceContainerLowest = surfaceContainerLowestLightHighContrast,
|
||||
surfaceContainerLow = surfaceContainerLowLightHighContrast,
|
||||
surfaceContainer = surfaceContainerLightHighContrast,
|
||||
surfaceContainerHigh = surfaceContainerHighLightHighContrast,
|
||||
surfaceContainerHighest = surfaceContainerHighestLightHighContrast,
|
||||
)
|
||||
|
||||
private val mediumContrastDarkColorScheme =
|
||||
darkColorScheme(
|
||||
primary = primaryDarkMediumContrast,
|
||||
onPrimary = onPrimaryDarkMediumContrast,
|
||||
primaryContainer = primaryContainerDarkMediumContrast,
|
||||
onPrimaryContainer = onPrimaryContainerDarkMediumContrast,
|
||||
secondary = secondaryDarkMediumContrast,
|
||||
onSecondary = onSecondaryDarkMediumContrast,
|
||||
secondaryContainer = secondaryContainerDarkMediumContrast,
|
||||
onSecondaryContainer = onSecondaryContainerDarkMediumContrast,
|
||||
tertiary = tertiaryDarkMediumContrast,
|
||||
onTertiary = onTertiaryDarkMediumContrast,
|
||||
tertiaryContainer = tertiaryContainerDarkMediumContrast,
|
||||
onTertiaryContainer = onTertiaryContainerDarkMediumContrast,
|
||||
error = errorDarkMediumContrast,
|
||||
onError = onErrorDarkMediumContrast,
|
||||
errorContainer = errorContainerDarkMediumContrast,
|
||||
onErrorContainer = onErrorContainerDarkMediumContrast,
|
||||
background = backgroundDarkMediumContrast,
|
||||
onBackground = onBackgroundDarkMediumContrast,
|
||||
surface = surfaceDarkMediumContrast,
|
||||
onSurface = onSurfaceDarkMediumContrast,
|
||||
surfaceVariant = surfaceVariantDarkMediumContrast,
|
||||
onSurfaceVariant = onSurfaceVariantDarkMediumContrast,
|
||||
outline = outlineDarkMediumContrast,
|
||||
outlineVariant = outlineVariantDarkMediumContrast,
|
||||
scrim = scrimDarkMediumContrast,
|
||||
inverseSurface = inverseSurfaceDarkMediumContrast,
|
||||
inverseOnSurface = inverseOnSurfaceDarkMediumContrast,
|
||||
inversePrimary = inversePrimaryDarkMediumContrast,
|
||||
surfaceDim = surfaceDimDarkMediumContrast,
|
||||
surfaceBright = surfaceBrightDarkMediumContrast,
|
||||
surfaceContainerLowest = surfaceContainerLowestDarkMediumContrast,
|
||||
surfaceContainerLow = surfaceContainerLowDarkMediumContrast,
|
||||
surfaceContainer = surfaceContainerDarkMediumContrast,
|
||||
surfaceContainerHigh = surfaceContainerHighDarkMediumContrast,
|
||||
surfaceContainerHighest = surfaceContainerHighestDarkMediumContrast,
|
||||
)
|
||||
|
||||
private val highContrastDarkColorScheme =
|
||||
darkColorScheme(
|
||||
primary = primaryDarkHighContrast,
|
||||
onPrimary = onPrimaryDarkHighContrast,
|
||||
primaryContainer = primaryContainerDarkHighContrast,
|
||||
onPrimaryContainer = onPrimaryContainerDarkHighContrast,
|
||||
secondary = secondaryDarkHighContrast,
|
||||
onSecondary = onSecondaryDarkHighContrast,
|
||||
secondaryContainer = secondaryContainerDarkHighContrast,
|
||||
onSecondaryContainer = onSecondaryContainerDarkHighContrast,
|
||||
tertiary = tertiaryDarkHighContrast,
|
||||
onTertiary = onTertiaryDarkHighContrast,
|
||||
tertiaryContainer = tertiaryContainerDarkHighContrast,
|
||||
onTertiaryContainer = onTertiaryContainerDarkHighContrast,
|
||||
error = errorDarkHighContrast,
|
||||
onError = onErrorDarkHighContrast,
|
||||
errorContainer = errorContainerDarkHighContrast,
|
||||
onErrorContainer = onErrorContainerDarkHighContrast,
|
||||
background = backgroundDarkHighContrast,
|
||||
onBackground = onBackgroundDarkHighContrast,
|
||||
surface = surfaceDarkHighContrast,
|
||||
onSurface = onSurfaceDarkHighContrast,
|
||||
surfaceVariant = surfaceVariantDarkHighContrast,
|
||||
onSurfaceVariant = onSurfaceVariantDarkHighContrast,
|
||||
outline = outlineDarkHighContrast,
|
||||
outlineVariant = outlineVariantDarkHighContrast,
|
||||
scrim = scrimDarkHighContrast,
|
||||
inverseSurface = inverseSurfaceDarkHighContrast,
|
||||
inverseOnSurface = inverseOnSurfaceDarkHighContrast,
|
||||
inversePrimary = inversePrimaryDarkHighContrast,
|
||||
surfaceDim = surfaceDimDarkHighContrast,
|
||||
surfaceBright = surfaceBrightDarkHighContrast,
|
||||
surfaceContainerLowest = surfaceContainerLowestDarkHighContrast,
|
||||
surfaceContainerLow = surfaceContainerLowDarkHighContrast,
|
||||
surfaceContainer = surfaceContainerDarkHighContrast,
|
||||
surfaceContainerHigh = surfaceContainerHighDarkHighContrast,
|
||||
surfaceContainerHighest = surfaceContainerHighestDarkHighContrast,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
data class ColorFamily(val color: Color, val onColor: Color, val colorContainer: Color, val onColorContainer: Color)
|
||||
|
||||
@@ -273,33 +116,23 @@ val unspecified_scheme = ColorFamily(Color.Unspecified, Color.Unspecified, Color
|
||||
fun AppTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
dynamicColor: Boolean = true,
|
||||
contrastLevel: ContrastLevel = ContrastLevel.STANDARD,
|
||||
content:
|
||||
@Composable()
|
||||
() -> Unit,
|
||||
) {
|
||||
val dynamicScheme =
|
||||
if (dynamicColor && contrastLevel == ContrastLevel.STANDARD) {
|
||||
val colorScheme =
|
||||
if (dynamicColor) {
|
||||
dynamicColorScheme(darkTheme)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val colorScheme =
|
||||
dynamicScheme
|
||||
?: when (contrastLevel) {
|
||||
ContrastLevel.MEDIUM -> if (darkTheme) mediumContrastDarkColorScheme else mediumContrastLightColorScheme
|
||||
ContrastLevel.HIGH -> if (darkTheme) highContrastDarkColorScheme else highContrastLightColorScheme
|
||||
else -> if (darkTheme) darkScheme else lightScheme
|
||||
}
|
||||
} ?: if (darkTheme) darkScheme else lightScheme
|
||||
|
||||
CompositionLocalProvider(LocalContrastLevel provides contrastLevel) {
|
||||
MaterialExpressiveTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = AppTypography,
|
||||
motionScheme = expressive(),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
MaterialExpressiveTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = AppTypography,
|
||||
motionScheme = expressive(),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
||||
const val MODE_DYNAMIC = 6969420
|
||||
|
||||
@@ -120,7 +120,6 @@ class UIViewModel(
|
||||
}
|
||||
|
||||
val theme: StateFlow<Int> = uiPrefs.theme
|
||||
val contrastLevel: StateFlow<Int> = uiPrefs.contrastLevel
|
||||
|
||||
val firmwareEdition = meshLogRepository.getMyNodeInfo().map { nodeInfo -> nodeInfo?.firmware_edition }
|
||||
|
||||
|
||||
@@ -170,6 +170,7 @@ private fun MeshServiceLifecycle() {
|
||||
// ----- Theme, locale, and application shell -----
|
||||
|
||||
/** Resolves the user's theme/locale preferences and renders the full application UI. */
|
||||
@Suppress("ViewModelForwarding")
|
||||
@Composable
|
||||
@OptIn(ExperimentalCoilApi::class)
|
||||
private fun ApplicationScope.ThemeAndLocaleProvider(uiViewModel: UIViewModel) {
|
||||
@@ -177,8 +178,6 @@ 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 =
|
||||
@@ -188,19 +187,16 @@ private fun ApplicationScope.ThemeAndLocaleProvider(uiViewModel: UIViewModel) {
|
||||
else -> isSystemInDarkTheme()
|
||||
}
|
||||
|
||||
MeshtasticDesktopApp(uiViewModel, isDarkTheme, contrastLevel)
|
||||
MeshtasticDesktopApp(uiViewModel, isDarkTheme)
|
||||
}
|
||||
|
||||
// ----- Application chrome (tray, window, navigation) -----
|
||||
|
||||
/** Composes the system tray, window, and Coil image loader. */
|
||||
@Suppress("ViewModelForwarding")
|
||||
@Composable
|
||||
@OptIn(ExperimentalCoilApi::class)
|
||||
private fun ApplicationScope.MeshtasticDesktopApp(
|
||||
uiViewModel: UIViewModel,
|
||||
isDarkTheme: Boolean,
|
||||
contrastLevel: org.meshtastic.core.ui.theme.ContrastLevel,
|
||||
) {
|
||||
private fun ApplicationScope.MeshtasticDesktopApp(uiViewModel: UIViewModel, isDarkTheme: Boolean) {
|
||||
var isAppVisible by remember { mutableStateOf(true) }
|
||||
var isWindowReady by remember { mutableStateOf(false) }
|
||||
val trayState = rememberTrayState()
|
||||
@@ -232,7 +228,7 @@ private fun ApplicationScope.MeshtasticDesktopApp(
|
||||
)
|
||||
|
||||
if (isWindowReady && isAppVisible) {
|
||||
MeshtasticWindow(uiViewModel, isDarkTheme, contrastLevel, appIcon, windowState) { isAppVisible = false }
|
||||
MeshtasticWindow(uiViewModel, isDarkTheme, appIcon, windowState) { isAppVisible = false }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,12 +271,12 @@ private fun WindowBoundsManager(
|
||||
// ----- Main window with keyboard shortcuts and Coil -----
|
||||
|
||||
/** Renders the main application window with keyboard shortcuts, Coil image loading, and the Compose UI tree. */
|
||||
@Suppress("ViewModelForwarding")
|
||||
@Composable
|
||||
@OptIn(ExperimentalCoilApi::class)
|
||||
private fun ApplicationScope.MeshtasticWindow(
|
||||
uiViewModel: UIViewModel,
|
||||
isDarkTheme: Boolean,
|
||||
contrastLevel: org.meshtastic.core.ui.theme.ContrastLevel,
|
||||
appIcon: Painter,
|
||||
windowState: WindowState,
|
||||
onCloseRequest: () -> Unit,
|
||||
@@ -306,9 +302,7 @@ private fun ApplicationScope.MeshtasticWindow(
|
||||
|
||||
CoilImageLoaderSetup()
|
||||
CompositionLocalProvider(LocalEventBranding provides eventEdition) {
|
||||
AppTheme(darkTheme = isDarkTheme, contrastLevel = contrastLevel) {
|
||||
DesktopMainScreen(uiViewModel, multiBackstack)
|
||||
}
|
||||
AppTheme(darkTheme = isDarkTheme) { DesktopMainScreen(uiViewModel, multiBackstack) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package org.meshtastic.feature.messaging.component
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
@@ -73,8 +74,6 @@ import org.meshtastic.core.ui.emoji.EmojiPickerDialog
|
||||
import org.meshtastic.core.ui.icon.FormatQuote
|
||||
import org.meshtastic.core.ui.icon.HopCount
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.theme.ContrastLevel
|
||||
import org.meshtastic.core.ui.theme.LocalContrastLevel
|
||||
import org.meshtastic.core.ui.theme.MessageItemColors
|
||||
import org.meshtastic.core.ui.util.createClipEntry
|
||||
|
||||
@@ -178,7 +177,6 @@ fun MessageItem(
|
||||
}
|
||||
|
||||
val containsBel = message.text.contains('\u0007')
|
||||
val contrastLevel = LocalContrastLevel.current
|
||||
|
||||
val nodeColor = Color(if (message.fromLocal) ourNode.colors.second else node.colors.second)
|
||||
val alpha =
|
||||
@@ -190,33 +188,9 @@ fun MessageItem(
|
||||
NORMAL_ALPHA
|
||||
}
|
||||
|
||||
val containerColor =
|
||||
when (contrastLevel) {
|
||||
ContrastLevel.HIGH ->
|
||||
when {
|
||||
message.filtered -> MaterialTheme.colorScheme.surfaceContainerLow
|
||||
inSelectionMode && selected -> MaterialTheme.colorScheme.surfaceContainerHighest
|
||||
inSelectionMode && !selected -> MaterialTheme.colorScheme.surfaceContainerLow
|
||||
else -> MaterialTheme.colorScheme.surfaceContainerHigh
|
||||
}
|
||||
|
||||
ContrastLevel.MEDIUM -> nodeColor.copy(alpha = (alpha + 0.2f).coerceAtMost(1f))
|
||||
|
||||
ContrastLevel.STANDARD -> nodeColor.copy(alpha = alpha)
|
||||
}
|
||||
val contentColor =
|
||||
when (contrastLevel) {
|
||||
ContrastLevel.HIGH,
|
||||
ContrastLevel.MEDIUM,
|
||||
-> MaterialTheme.colorScheme.onSurface
|
||||
|
||||
ContrastLevel.STANDARD -> Color(if (message.fromLocal) ourNode.colors.first else node.colors.first)
|
||||
}
|
||||
val metadataStyle =
|
||||
when (contrastLevel) {
|
||||
ContrastLevel.HIGH -> MaterialTheme.typography.bodySmall
|
||||
else -> MaterialTheme.typography.labelSmall
|
||||
}
|
||||
val containerColor = nodeColor.copy(alpha = alpha)
|
||||
val contentColor = MaterialTheme.colorScheme.onSurface
|
||||
val metadataStyle = MaterialTheme.typography.labelSmall
|
||||
val messageShape =
|
||||
getMessageBubbleShape(
|
||||
cornerRadius = 8.dp,
|
||||
@@ -230,14 +204,7 @@ fun MessageItem(
|
||||
if (containsBel) {
|
||||
Modifier.border(2.dp, color = MessageItemColors.Red, shape = messageShape)
|
||||
} else {
|
||||
when (contrastLevel) {
|
||||
ContrastLevel.HIGH -> Modifier.border(2.dp, color = nodeColor, shape = messageShape)
|
||||
|
||||
ContrastLevel.MEDIUM ->
|
||||
Modifier.border(1.dp, color = nodeColor.copy(alpha = 0.6f), shape = messageShape)
|
||||
|
||||
ContrastLevel.STANDARD -> Modifier
|
||||
}
|
||||
Modifier
|
||||
},
|
||||
)
|
||||
val senderName = if (message.fromLocal) ourNode.user.long_name else node.user.long_name
|
||||
@@ -282,6 +249,7 @@ fun MessageItem(
|
||||
color = containerColor,
|
||||
contentColor = contentColor,
|
||||
shape = messageShape,
|
||||
border = BorderStroke(0.5.dp, nodeColor),
|
||||
) {
|
||||
Column(modifier = Modifier.width(IntrinsicSize.Max)) {
|
||||
OriginalMessageSnippet(
|
||||
@@ -292,7 +260,7 @@ fun MessageItem(
|
||||
)
|
||||
|
||||
Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 2.dp)) {
|
||||
AutoLinkText(text = message.text, style = MaterialTheme.typography.bodyMedium, color = contentColor)
|
||||
AutoLinkText(text = message.text, style = MaterialTheme.typography.bodyLarge, color = contentColor)
|
||||
|
||||
Row(modifier = Modifier, verticalAlignment = Alignment.CenterVertically) {
|
||||
if (!message.fromLocal) {
|
||||
@@ -337,12 +305,7 @@ fun MessageItem(
|
||||
Text(
|
||||
text = stringResource(Res.string.filter_message_label),
|
||||
style = metadataStyle,
|
||||
color =
|
||||
if (contrastLevel == ContrastLevel.HIGH) {
|
||||
MaterialTheme.colorScheme.onSurface
|
||||
} else {
|
||||
MaterialTheme.colorScheme.onSurfaceVariant
|
||||
},
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(start = 8.dp, end = 4.dp),
|
||||
)
|
||||
}
|
||||
@@ -393,20 +356,8 @@ private fun OriginalMessageSnippet(
|
||||
val originalMessage = message.originalMessage
|
||||
if (originalMessage != null && originalMessage.packetId != 0) {
|
||||
val originalMessageNode = if (originalMessage.fromLocal) ourNode else originalMessage.node
|
||||
val contrastLevel = LocalContrastLevel.current
|
||||
val replyContainerColor =
|
||||
when (contrastLevel) {
|
||||
ContrastLevel.HIGH -> MaterialTheme.colorScheme.surfaceContainer
|
||||
else -> Color(originalMessageNode.colors.second).copy(alpha = 0.8f)
|
||||
}
|
||||
val replyContentColor =
|
||||
when (contrastLevel) {
|
||||
ContrastLevel.HIGH,
|
||||
ContrastLevel.MEDIUM,
|
||||
-> MaterialTheme.colorScheme.onSurface
|
||||
|
||||
ContrastLevel.STANDARD -> Color(originalMessageNode.colors.first)
|
||||
}
|
||||
val replyContainerColor = Color(originalMessageNode.colors.second).copy(alpha = 0.8f)
|
||||
val replyContentColor = MaterialTheme.colorScheme.onSurface
|
||||
// Rectangle shape — the outer message bubble's Surface clips to its
|
||||
// rounded corners, so the reply header inherits the correct top radii
|
||||
// automatically and stays square on the bottom where body text follows.
|
||||
|
||||
@@ -59,7 +59,6 @@ import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.icon.Wifi
|
||||
import org.meshtastic.feature.settings.component.AppInfoSection
|
||||
import org.meshtastic.feature.settings.component.AppearanceSection
|
||||
import org.meshtastic.feature.settings.component.ContrastPickerDialog
|
||||
import org.meshtastic.feature.settings.component.ExpressiveSection
|
||||
import org.meshtastic.feature.settings.component.PersistenceSection
|
||||
import org.meshtastic.feature.settings.component.PrivacySection
|
||||
@@ -163,14 +162,6 @@ fun SettingsScreen(
|
||||
)
|
||||
}
|
||||
|
||||
var showContrastPickerDialog by remember { mutableStateOf(false) }
|
||||
if (showContrastPickerDialog) {
|
||||
ContrastPickerDialog(
|
||||
onClickContrast = { settingsViewModel.setContrastLevel(it) },
|
||||
onDismiss = { showContrastPickerDialog = false },
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
// Show back arrow when remotely administering (caller supplies onBack and we're not on the local node).
|
||||
@@ -245,7 +236,6 @@ fun SettingsScreen(
|
||||
AppearanceSection(
|
||||
onShowLanguagePicker = { showLanguagePickerDialog = true },
|
||||
onShowThemePicker = { showThemePickerDialog = true },
|
||||
onShowContrastPicker = { showContrastPickerDialog = true },
|
||||
)
|
||||
|
||||
ExpressiveSection(title = stringResource(Res.string.wifi_devices)) {
|
||||
|
||||
@@ -28,7 +28,6 @@ import androidx.core.net.toUri
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.app_settings
|
||||
import org.meshtastic.core.resources.contrast
|
||||
import org.meshtastic.core.resources.preferences_language
|
||||
import org.meshtastic.core.resources.theme
|
||||
import org.meshtastic.core.ui.component.ListItem
|
||||
@@ -38,13 +37,9 @@ import org.meshtastic.core.ui.icon.Language
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.theme.AppTheme
|
||||
|
||||
/** Section for app appearance settings like language, theme, and contrast. */
|
||||
/** Section for app appearance settings like language and theme. */
|
||||
@Composable
|
||||
fun AppearanceSection(
|
||||
onShowLanguagePicker: () -> Unit,
|
||||
onShowThemePicker: () -> Unit,
|
||||
onShowContrastPicker: () -> Unit,
|
||||
) {
|
||||
fun AppearanceSection(onShowLanguagePicker: () -> Unit, onShowThemePicker: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val settingsLauncher =
|
||||
rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {}
|
||||
@@ -79,19 +74,11 @@ fun AppearanceSection(
|
||||
) {
|
||||
onShowThemePicker()
|
||||
}
|
||||
|
||||
ListItem(
|
||||
text = stringResource(Res.string.contrast),
|
||||
leadingIcon = MeshtasticIcons.FormatPaint,
|
||||
trailingIcon = null,
|
||||
) {
|
||||
onShowContrastPicker()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun AppearanceSectionPreview() {
|
||||
AppTheme { AppearanceSection(onShowLanguagePicker = {}, onShowThemePicker = {}, onShowContrastPicker = {}) }
|
||||
AppTheme { AppearanceSection(onShowLanguagePicker = {}, onShowThemePicker = {}) }
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ import org.meshtastic.core.domain.usecase.settings.ExportDataUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.IsOtaCapableUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.MeshLocationUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.SetAppIntroCompletedUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.SetContrastLevelUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.SetDatabaseCacheLimitUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.SetLocaleUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.SetMeshLogSettingsUseCase
|
||||
@@ -66,7 +65,6 @@ class SettingsViewModel(
|
||||
private val meshLogPrefs: MeshLogPrefs,
|
||||
private val notificationPrefs: NotificationPrefs,
|
||||
private val setThemeUseCase: SetThemeUseCase,
|
||||
private val setContrastLevelUseCase: SetContrastLevelUseCase,
|
||||
private val setLocaleUseCase: SetLocaleUseCase,
|
||||
private val setAppIntroCompletedUseCase: SetAppIntroCompletedUseCase,
|
||||
private val setProvideLocationUseCase: SetProvideLocationUseCase,
|
||||
@@ -164,10 +162,6 @@ class SettingsViewModel(
|
||||
setThemeUseCase(theme)
|
||||
}
|
||||
|
||||
fun setContrastLevel(level: Int) {
|
||||
setContrastLevelUseCase(level)
|
||||
}
|
||||
|
||||
/** Set the application locale. Empty string means system default. */
|
||||
fun setLocale(languageTag: String) {
|
||||
setLocaleUseCase(languageTag)
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@file:Suppress("MatchingDeclarationName")
|
||||
|
||||
package org.meshtastic.feature.settings.component
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.runtime.Composable
|
||||
import org.jetbrains.compose.resources.StringResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.choose_contrast
|
||||
import org.meshtastic.core.resources.contrast_high
|
||||
import org.meshtastic.core.resources.contrast_medium
|
||||
import org.meshtastic.core.resources.contrast_standard
|
||||
import org.meshtastic.core.ui.component.ListItem
|
||||
import org.meshtastic.core.ui.component.MeshtasticDialog
|
||||
import org.meshtastic.core.ui.theme.ContrastLevel
|
||||
|
||||
/** Contrast level options matching [ContrastLevel] ordinal values. */
|
||||
enum class ContrastOption(val label: StringResource, val level: ContrastLevel) {
|
||||
STANDARD(label = Res.string.contrast_standard, level = ContrastLevel.STANDARD),
|
||||
MEDIUM(label = Res.string.contrast_medium, level = ContrastLevel.MEDIUM),
|
||||
HIGH(label = Res.string.contrast_high, level = ContrastLevel.HIGH),
|
||||
}
|
||||
|
||||
/** Shared dialog for picking a contrast level. Used by both Android and Desktop settings screens. */
|
||||
@Composable
|
||||
fun ContrastPickerDialog(onClickContrast: (Int) -> Unit, onDismiss: () -> Unit) {
|
||||
MeshtasticDialog(
|
||||
title = stringResource(Res.string.choose_contrast),
|
||||
onDismiss = onDismiss,
|
||||
text = {
|
||||
Column {
|
||||
ContrastOption.entries.forEach { option ->
|
||||
ListItem(text = stringResource(option.label), trailingIcon = null) {
|
||||
onClickContrast(option.level.value)
|
||||
onDismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -40,7 +40,6 @@ import org.meshtastic.core.domain.usecase.settings.ExportDataUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.IsOtaCapableUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.MeshLocationUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.SetAppIntroCompletedUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.SetContrastLevelUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.SetDatabaseCacheLimitUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.SetLocaleUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.SetMeshLogSettingsUseCase
|
||||
@@ -97,7 +96,6 @@ class SettingsViewModelTest {
|
||||
|
||||
val uiPrefs = appPreferences.ui
|
||||
val setThemeUseCase = SetThemeUseCase(uiPrefs)
|
||||
val setContrastLevelUseCase = SetContrastLevelUseCase(uiPrefs)
|
||||
val setLocaleUseCase = SetLocaleUseCase(uiPrefs)
|
||||
val setAppIntroCompletedUseCase = SetAppIntroCompletedUseCase(uiPrefs)
|
||||
val setProvideLocationUseCase = SetProvideLocationUseCase(uiPrefs)
|
||||
@@ -118,7 +116,6 @@ class SettingsViewModelTest {
|
||||
meshLogPrefs = appPreferences.meshLog,
|
||||
notificationPrefs = notificationPrefs,
|
||||
setThemeUseCase = setThemeUseCase,
|
||||
setContrastLevelUseCase = setContrastLevelUseCase,
|
||||
setLocaleUseCase = setLocaleUseCase,
|
||||
setAppIntroCompletedUseCase = setAppIntroCompletedUseCase,
|
||||
setProvideLocationUseCase = setProvideLocationUseCase,
|
||||
|
||||
@@ -46,7 +46,6 @@ import org.meshtastic.core.resources.acknowledgements
|
||||
import org.meshtastic.core.resources.app_settings
|
||||
import org.meshtastic.core.resources.app_version
|
||||
import org.meshtastic.core.resources.bottom_nav_settings
|
||||
import org.meshtastic.core.resources.contrast
|
||||
import org.meshtastic.core.resources.device_db_cache_limit
|
||||
import org.meshtastic.core.resources.device_db_cache_limit_summary
|
||||
import org.meshtastic.core.resources.info
|
||||
@@ -68,7 +67,6 @@ import org.meshtastic.core.ui.icon.Memory
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.icon.Wifi
|
||||
import org.meshtastic.core.ui.util.rememberShowToastResource
|
||||
import org.meshtastic.feature.settings.component.ContrastPickerDialog
|
||||
import org.meshtastic.feature.settings.component.ExpressiveSection
|
||||
import org.meshtastic.feature.settings.component.HomoglyphSetting
|
||||
import org.meshtastic.feature.settings.component.NotificationSection
|
||||
@@ -103,7 +101,6 @@ fun DesktopSettingsScreen(
|
||||
|
||||
var showThemePickerDialog by remember { mutableStateOf(false) }
|
||||
var showLanguagePickerDialog by remember { mutableStateOf(false) }
|
||||
var showContrastPickerDialog by remember { mutableStateOf(false) }
|
||||
if (showThemePickerDialog) {
|
||||
ThemePickerDialog(
|
||||
onClickTheme = { settingsViewModel.setTheme(it) },
|
||||
@@ -111,13 +108,6 @@ fun DesktopSettingsScreen(
|
||||
)
|
||||
}
|
||||
|
||||
if (showContrastPickerDialog) {
|
||||
ContrastPickerDialog(
|
||||
onClickContrast = { settingsViewModel.setContrastLevel(it) },
|
||||
onDismiss = { showContrastPickerDialog = false },
|
||||
)
|
||||
}
|
||||
|
||||
if (showLanguagePickerDialog) {
|
||||
LanguagePickerDialog(
|
||||
onSelectLanguage = { tag -> settingsViewModel.setLocale(tag) },
|
||||
@@ -182,14 +172,6 @@ fun DesktopSettingsScreen(
|
||||
showThemePickerDialog = true
|
||||
}
|
||||
|
||||
ListItem(
|
||||
text = stringResource(Res.string.contrast),
|
||||
leadingIcon = MeshtasticIcons.FormatPaint,
|
||||
trailingIcon = null,
|
||||
) {
|
||||
showContrastPickerDialog = true
|
||||
}
|
||||
|
||||
ListItem(
|
||||
text = stringResource(Res.string.preferences_language),
|
||||
leadingIcon = MeshtasticIcons.Language,
|
||||
|
||||
Reference in New Issue
Block a user