Dirk Hoffmann
05/27/2021, 2:56 PMWindow {
DesktopTheme {
MyCustomDeskMaterialTheme {
MinRootContent()
...
@Composable
fun MyCustomDeskMaterialTheme(content: @Composable () -> Unit) {
MaterialTheme(
colors = if (isDarkTheme()) DarkColorPalette() else LightColorPalette(),
typography = if (isDarkTheme()) DarkTypography() else LightTypography()
) {
...
fun DarkTypography() : Typography {
val orig = Typography()
return orig.copy(
subtitle1 = orig.subtitle1.copy(color = DarkColorPalette().onBackground),
subtitle2 = orig.subtitle2.copy(color = DarkColorPalette().onBackground),
body1 = orig.body1.copy(color = DarkColorPalette().onSurface),
body2 = orig.body2.copy(color = DarkColorPalette().onSurface))
}
fun LightTypography() : Typography {
val orig = Typography()
return orig.copy(
subtitle1 = orig.subtitle1.copy(color = LightColorPalette().onBackground),
subtitle2 = orig.subtitle2.copy(color = LightColorPalette().onBackground),
body1 = orig.body1.copy(color = LightColorPalette().onSurface),
body2 = orig.body2.copy(color = LightColorPalette().onSurface))
}
fun DarkColorPalette() = darkColors(
primary = Solarized.Base1,
...
when accessing it with e.g. MaterialTheme.typography.subtitle2
font has always the color of the mode app started withZach Klippenstein (he/him) [MOD]
05/27/2021, 3:34 PMText
source code:
val textColor = color.takeOrElse {
style.color.takeOrElse {
LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
}
}
val mergedStyle = style.merge(
TextStyle(
color = textColor,
…
)
)
You can see the actual logic used to choose the color. If you have a composable that’s passing an explicit color in, that will always be used. Otherwise the `LocalTextStyle`’s color will be used – are you sure that ambient is being set correctly?Dirk Hoffmann
05/27/2021, 4:13 PMZach Klippenstein (he/him) [MOD]
05/27/2021, 4:15 PMLocalTextStyle
– you can do a “Find Usages” in android studio to find out.Chris Sinco [G]
05/27/2021, 4:59 PMLocalContentColor
tries to use onSurface
or onBackground
from MaterialTheme depending on where the Text
composable sits in a hierarchy. If you change those two keys in the color palettes passed to your app theme, it should switch automatically without needing conditionals at the call site of your Text composables.Dirk Hoffmann
05/27/2021, 6:39 PMLocalTextStyle
when my mutableStateOf<Boolean> for `dark/light`mode change, but I'd like to be able to set some/all of the Typography TextStyles (body1, body2, h1, h2, ...) to values the `Outlined|...|TextField(... styledText: TextStyle)`throughout my UI are using ... (MaterialTheme.typography.(body1|body2|subtitle1|subtitile2|h1|h2|h3|error|onError|...
)Louis Pullen-Freilich [G]
05/27/2021, 7:12 PMLocalTextStyle
is provided by different components, and they just read from MaterialTheme.typography
. So if you change MaterialTheme.typography
, then any components that provide a value for LocalTextStyle
will also update with the new stylesMaterialTheme
for example provides a default of body1
, so if you change between light and dark, MaterialTheme
will provide the new body1
defined for your dark set of typographyDirk Hoffmann
05/27/2021, 7:15 PMLouis Pullen-Freilich [G]
05/27/2021, 7:20 PMTextStyle
is not what you want here - colors should be provided by the components outside the Text
itselfSurface()
, by default it will automatically use onSurface
as the colorText
to be the color from the style, since it will use LocalContentColor
by defaultLocalContentColor
- what exactly is not working for you here?Dirk Hoffmann
05/28/2021, 8:53 AM...
TextField(textStyle = MaterialTheme.typography.section1)
now with my switchable dark/light mode State (am trying to do it as much solarized as possible, so the colors of default typography TextStyles do not fit anymore, as they are sometimes using different primary/surface/background colors in light vs dark mode),
I wanna achieve that every time a TextField has e.g. section1
text style, it has a) a custom color and b) this color should be a special one that is depending on current light or dark mode.
What I CAN do is e.g. TextField(textStyle = if(ADState.ADTheme.isDarkTheme()) DarkTypography().subtitle1 else LightTypography().subtitle1)
But I'd very much prefer to just say TextField(textStyle = MaterialTheme.typography.section1)
and having the color of the textStyle defined in my Theme Typography() BUT it should be a dark or light one, depending on if I am currently in light or dark mode.
This is all working fine, if I start the App in either light or dark mode.
BUT if I change from light to dark or vice versa at runtime!
MaterialTheme.typography.section1 still gives me the textStyle color of the Dark|LightTypography it has been on startup of the App (if I just reference MaterialTheme.typography.section1
.
So in my Code at the beginning of this thread, switching dark light, does NOT honour my DarkTypography()
LightTypography()
settings when I dynamically change between dark and light modes at runtimeLouis Pullen-Freilich [G]
05/28/2021, 1:41 PMDirk Hoffmann
05/28/2021, 2:16 PM@ExperimentalAnimationApi
@Composable
fun QuickSearchAutoComplete(items: List<Person>) {
val (text, setText) = remember { mutableStateOf(TextFieldValue("")) }
TextField("OutOfBox", onValueChange = {}, textStyle = MaterialTheme.typography.subtitle1)
AutoCompleteDropdown(
items,
itemContent = { person: Person ->
PersonDropdownAutoCompleteItem(person)
},
) { // this: AutoCompleteStateScope<Person>
// /** things that interact with the `AutoCompleteState` */
// interface AutoCompleteStateScope<T : AutoCompleteEntity> : AutoCompleteStateDesignScope, IsVisibleState {
// fun filter(query: String)
// fun onItemSelected(block: (T) -> Unit = {}) }
onItemSelected { person ->
setText(TextFieldValue(person.name, selection = TextRange(person.name.length)))
filter(person.name)
visible = false
}
TextField(
value = text,
onValueChange = { setText(it) ; filter(it.text) },
modifier = Modifier
.onGloballyPositioned { textFieldRect.value = it.rectInWindow() }
.onPreviewKeyEvent {
when (it.key) {
Key.Enter -> {
hide()
true // true = stop propagation KeyEvent upwards
}
Key.Escape -> {
hide()
true
}
else -> {
if (text.text.isBlank()) {
hide()
} else {
show()
}
false // false = propagate upwards (to textField)
}
}
}
.onFocusChanged { visible = it.isFocused },
textStyle = MaterialTheme.typography.subtitle1,
label = { Text("quick search:") },
placeholder = { Text("e.g. sign contract") },
trailingIcon = {
IconButton(
onClick = { println("TODO trailing quicksearch Icon clicked") ; setText(TextFieldValue("")) }
) {
Icon(Icons.TwoTone.Clear, contentDescription = "Top Search")
}
},
singleLine = true
)
}
}
I have the IDENTICAL Component call QuickSearchAutoComplete(FakeData.PERSONS)
a) in the AppTopBar of Scaffold
b) in a column
in AppTopBar of Scaffold the given textStyle is honored on dynamic dark/light change ..
in a column in "normal" content it is not (see screenshots)val dummy = ADState.ADTheme.darkTheme.value
to my component THEN it is dependant on dark/light boolean state
and THEN it will honour the new typography,
otherwise the
remember { mutableStateOf(TextFieldValue("")) }
I pass into the TextField will "remember" also the typgraphy textStyle it "once had"QuickSearchAutoComplete
(providing an AutoCompleteStateScope) it does not honour it without that explicit depencency