fix: add ugly hacks because reflection breaks it

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2023-11-01 04:28:02 +01:00
parent 6be963154d
commit 88faa795ba
5 changed files with 357 additions and 51 deletions

View File

@ -82,3 +82,29 @@
public static *** w(...); public static *** w(...);
public static *** e(...); public static *** e(...);
} }
-dontwarn kotlin.**
-dontwarn org.w3c.dom.events.*
-dontwarn org.jetbrains.kotlin.di.InjectorForRuntimeDescriptorLoader
-keep class kotlin.** { *; }
-keep class org.jetbrains.kotlin.** { *; }
-keepclassmembers,allowoptimization enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
**[] $VALUES;
public *;
}
-keepattributes InnerClasses
-keep class androidx.compose.ui.graphics.ColorKt { *; }
-keep class androidx.compose.material3.ColorScheme { *; }
-keep class androidx.compose.material3.ColorSchemeKt { *; }
-keep class androidx.compose.material3.ColorSchemeKt$* { *; }
-keepclassmembers class androidx.compose.material3.ColorSchemeKt {
public static final <fields>;
public <fields>;
}

View File

@ -1,5 +1,6 @@
package chat.revolt.api.schemas package chat.revolt.api.schemas
import chat.revolt.ui.theme.OverridableColourScheme
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
@ -18,5 +19,5 @@ data class AndroidSpecificSettings(
* Colour overrides. * Colour overrides.
* Map of `primary, onPrimary, primaryContainer, onPrimaryContainer, inversePrimary, secondary, onSecondary, secondaryContainer, onSecondaryContainer, tertiary, onTertiary, tertiaryContainer, onTertiaryContainer, background, onBackground, surface, onSurface, surfaceVariant, onSurfaceVariant, surfaceTint, inverseSurface, inverseOnSurface, error, onError, errorContainer, onErrorContainer, outline, outlineVariant, scrim` to int colours. * Map of `primary, onPrimary, primaryContainer, onPrimaryContainer, inversePrimary, secondary, onSecondary, secondaryContainer, onSecondaryContainer, tertiary, onTertiary, tertiaryContainer, onTertiaryContainer, background, onBackground, surface, onSurface, surfaceVariant, onSurfaceVariant, surfaceTint, inverseSurface, inverseOnSurface, error, onError, errorContainer, onErrorContainer, outline, outlineVariant, scrim` to int colours.
*/ */
var colourOverrides: Map<String, Int>? = null, var colourOverrides: OverridableColourScheme? = null,
) )

View File

@ -31,7 +31,6 @@ import androidx.compose.material.icons.filled.KeyboardArrowLeft
import androidx.compose.material.icons.filled.KeyboardArrowRight import androidx.compose.material.icons.filled.KeyboardArrowRight
import androidx.compose.material.ripple.LocalRippleTheme import androidx.compose.material.ripple.LocalRippleTheme
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -65,12 +64,15 @@ import androidx.lifecycle.viewModelScope
import androidx.navigation.NavController import androidx.navigation.NavController
import chat.revolt.R import chat.revolt.R
import chat.revolt.api.RevoltCbor import chat.revolt.api.RevoltCbor
import chat.revolt.api.RevoltJson
import chat.revolt.api.settings.GlobalState import chat.revolt.api.settings.GlobalState
import chat.revolt.api.settings.SyncedSettings import chat.revolt.api.settings.SyncedSettings
import chat.revolt.components.generic.PageHeader import chat.revolt.components.generic.PageHeader
import chat.revolt.components.screens.settings.appearance.ColourChip import chat.revolt.components.screens.settings.appearance.ColourChip
import chat.revolt.ui.theme.ClearRippleTheme import chat.revolt.ui.theme.ClearRippleTheme
import chat.revolt.ui.theme.OverridableColourScheme
import chat.revolt.ui.theme.Theme import chat.revolt.ui.theme.Theme
import chat.revolt.ui.theme.getFieldByName
import chat.revolt.ui.theme.systemSupportsDynamicColors import chat.revolt.ui.theme.systemSupportsDynamicColors
import com.github.skydoves.colorpicker.compose.AlphaSlider import com.github.skydoves.colorpicker.compose.AlphaSlider
import com.github.skydoves.colorpicker.compose.BrightnessSlider import com.github.skydoves.colorpicker.compose.BrightnessSlider
@ -85,8 +87,6 @@ import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
import kotlin.reflect.KVisibility
import kotlin.reflect.full.memberProperties
@HiltViewModel @HiltViewModel
@Suppress("StaticFieldLeak") @Suppress("StaticFieldLeak")
@ -110,7 +110,17 @@ class AppearanceSettingsScreenViewModel @Inject constructor(
val overrides = SyncedSettings.android.copy().colourOverrides val overrides = SyncedSettings.android.copy().colourOverrides
if (overrides != null) { if (overrides != null) {
val mutOverrides = overrides.toMutableMap() // Yes, this looks stupid. Please see the comments in OverridableColourScheme.kt regarding this.
val json = RevoltJson.encodeToString(
OverridableColourScheme.serializer(),
overrides
)
val asMap = RevoltJson.decodeFromString(
MapSerializer(String.serializer(), Int.serializer()),
json
)
val mutOverrides = asMap.toMutableMap()
if (value == null) { if (value == null) {
mutOverrides.remove(fieldName) mutOverrides.remove(fieldName)
} else { } else {
@ -119,35 +129,31 @@ class AppearanceSettingsScreenViewModel @Inject constructor(
SyncedSettings.updateAndroid( SyncedSettings.updateAndroid(
SyncedSettings.android.copy( SyncedSettings.android.copy(
colourOverrides = mutOverrides colourOverrides = OverridableColourScheme()
.applyFromKeyValueMap(mutOverrides)
) )
) )
} else if (value != null) { } else if (value != null) {
SyncedSettings.updateAndroid( SyncedSettings.updateAndroid(
SyncedSettings.android.copy( SyncedSettings.android.copy(
colourOverrides = mapOf( colourOverrides = OverridableColourScheme()
fieldName to value .applyFromKeyValueMap(
) mapOf(fieldName to value)
)
) )
) )
} }
} }
} }
private fun validOverrideKey(key: String): Boolean {
return ColorScheme::class.memberProperties.any { it.name == key }
}
private fun applyBulkOverrides(overrides: Map<String, Int>) { private fun applyBulkOverrides(overrides: Map<String, Int>) {
val existingOverrides = SyncedSettings.android.colourOverrides ?: mapOf() val existingOverrides = SyncedSettings.android.colourOverrides ?: OverridableColourScheme()
val newOverrides = existingOverrides.toMutableMap()
newOverrides.putAll(overrides.filterKeys { validOverrideKey(it) })
viewModelScope.launch { viewModelScope.launch {
SyncedSettings.updateAndroid( SyncedSettings.updateAndroid(
SyncedSettings.android.copy( SyncedSettings.android.copy(
colourOverrides = newOverrides colourOverrides = existingOverrides
.applyFromKeyValueMap(overrides.filterKeys { it in OverridableColourScheme.fieldNames })
) )
) )
} }
@ -186,8 +192,8 @@ class AppearanceSettingsScreenViewModel @Inject constructor(
context.contentResolver.openOutputStream(uri)?.use { outputStream -> context.contentResolver.openOutputStream(uri)?.use { outputStream ->
outputStream.write( outputStream.write(
RevoltCbor.encodeToByteArray( RevoltCbor.encodeToByteArray(
MapSerializer(String.serializer(), Int.serializer()), OverridableColourScheme.serializer(),
SyncedSettings.android.colourOverrides ?: mapOf() SyncedSettings.android.colourOverrides ?: OverridableColourScheme()
) )
) )
} }
@ -452,28 +458,23 @@ fun AppearanceSettingsScreen(
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
ColorScheme::class.memberProperties.forEach { member -> OverridableColourScheme.fieldNames.forEach { fieldName ->
if (member.visibility != KVisibility.PUBLIC) return@forEach val value =
SyncedSettings.android.colourOverrides?.getFieldByName(fieldName)
val name = member.name ?: MaterialTheme.colorScheme.getFieldByName(fieldName)
val value = member.getter.call(MaterialTheme.colorScheme) as Color
ColourChip( ColourChip(
color = value, color = Color(value ?: 0),
text = try { text = OverridableColourScheme.fieldNameToResource[fieldName]
R.string::class.java.getField("settings_appearance_colour_overrides_${name.toSnakeCase()}") ?.let { context.getString(it) }
.getInt(null) ?: fieldName,
.let { context.getString(it) }
} catch (e: Exception) {
name
},
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(start = 20.dp, end = 20.dp) .padding(start = 20.dp, end = 20.dp)
.testTag("set_colour_override_$name") .testTag("set_colour_override_$fieldName")
) { ) {
viewModel.selectedOverrideName = name viewModel.selectedOverrideName = fieldName
viewModel.selectedOverrideInitialValue = value.toArgb() viewModel.selectedOverrideInitialValue = value
viewModel.overridePickerSheetVisible = true viewModel.overridePickerSheetVisible = true
} }
} }

View File

@ -0,0 +1,286 @@
package chat.revolt.ui.theme
import androidx.compose.material3.ColorScheme
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import chat.revolt.R
import kotlinx.serialization.Serializable
// Word of warning, this file is ugly, because I've had to fight a bit with the Compose compiler,
// namely native Kotlin (not Java) reflection seems to consistently break it.
// So I've had to resort to... methods like this. I'm sorry.
// If you've been linked to this file, I promise the rest of the codebase is not like this.
// Original comments during research and development preserved.
@Serializable
data class OverridableColourScheme(
val primary: Int? = null,
val onPrimary: Int? = null,
val primaryContainer: Int? = null,
val onPrimaryContainer: Int? = null,
val inversePrimary: Int? = null,
val secondary: Int? = null,
val onSecondary: Int? = null,
val secondaryContainer: Int? = null,
val onSecondaryContainer: Int? = null,
val tertiary: Int? = null,
val onTertiary: Int? = null,
val tertiaryContainer: Int? = null,
val onTertiaryContainer: Int? = null,
val background: Int? = null,
val onBackground: Int? = null,
val surface: Int? = null,
val onSurface: Int? = null,
val surfaceVariant: Int? = null,
val onSurfaceVariant: Int? = null,
val surfaceTint: Int? = null,
val inverseSurface: Int? = null,
val inverseOnSurface: Int? = null,
val error: Int? = null,
val onError: Int? = null,
val errorContainer: Int? = null,
val onErrorContainer: Int? = null,
val outline: Int? = null,
val outlineVariant: Int? = null,
val scrim: Int? = null
) {
fun applyTo(colorScheme: ColorScheme): ColorScheme {
var newScheme = colorScheme.copy()
// This is SLOW. It is also STUPID. But using reflection breaks the Compose compiler.
// Another piece of trash from Google. This company should go bankrupt already, what a
// joke.
if (primary != null) newScheme = newScheme.copy(primary = Color(primary))
if (onPrimary != null) newScheme = newScheme.copy(onPrimary = Color(onPrimary))
if (primaryContainer != null) newScheme =
newScheme.copy(primaryContainer = Color(primaryContainer))
if (onPrimaryContainer != null) newScheme =
newScheme.copy(onPrimaryContainer = Color(onPrimaryContainer))
if (inversePrimary != null) newScheme =
newScheme.copy(inversePrimary = Color(inversePrimary))
if (secondary != null) newScheme = newScheme.copy(secondary = Color(secondary))
if (onSecondary != null) newScheme = newScheme.copy(onSecondary = Color(onSecondary))
if (secondaryContainer != null) newScheme =
newScheme.copy(secondaryContainer = Color(secondaryContainer))
if (onSecondaryContainer != null) newScheme =
newScheme.copy(onSecondaryContainer = Color(onSecondaryContainer))
if (tertiary != null) newScheme = newScheme.copy(tertiary = Color(tertiary))
if (onTertiary != null) newScheme = newScheme.copy(onTertiary = Color(onTertiary))
if (tertiaryContainer != null) newScheme =
newScheme.copy(tertiaryContainer = Color(tertiaryContainer))
if (onTertiaryContainer != null) newScheme =
newScheme.copy(onTertiaryContainer = Color(onTertiaryContainer))
if (background != null) newScheme = newScheme.copy(background = Color(background))
if (onBackground != null) newScheme = newScheme.copy(onBackground = Color(onBackground))
if (surface != null) newScheme = newScheme.copy(surface = Color(surface))
if (onSurface != null) newScheme = newScheme.copy(onSurface = Color(onSurface))
if (surfaceVariant != null) newScheme =
newScheme.copy(surfaceVariant = Color(surfaceVariant))
if (onSurfaceVariant != null) newScheme =
newScheme.copy(onSurfaceVariant = Color(onSurfaceVariant))
if (surfaceTint != null) newScheme = newScheme.copy(surfaceTint = Color(surfaceTint))
if (inverseSurface != null) newScheme =
newScheme.copy(inverseSurface = Color(inverseSurface))
if (inverseOnSurface != null) newScheme =
newScheme.copy(inverseOnSurface = Color(inverseOnSurface))
if (error != null) newScheme = newScheme.copy(error = Color(error))
if (onError != null) newScheme = newScheme.copy(onError = Color(onError))
if (errorContainer != null) newScheme =
newScheme.copy(errorContainer = Color(errorContainer))
if (onErrorContainer != null) newScheme =
newScheme.copy(onErrorContainer = Color(onErrorContainer))
if (outline != null) newScheme = newScheme.copy(outline = Color(outline))
if (outlineVariant != null) newScheme =
newScheme.copy(outlineVariant = Color(outlineVariant))
if (scrim != null) newScheme = newScheme.copy(scrim = Color(scrim))
return newScheme
}
fun applyFromKeyValueMap(map: Map<String, Int>): OverridableColourScheme {
var newScheme = this
map.filterKeys { it in fieldNames }.forEach { (key, value) ->
when (key) {
"primary" -> newScheme = newScheme.copy(primary = value)
"onPrimary" -> newScheme = newScheme.copy(onPrimary = value)
"primaryContainer" -> newScheme = newScheme.copy(primaryContainer = value)
"onPrimaryContainer" -> newScheme =
newScheme.copy(onPrimaryContainer = value)
"inversePrimary" -> newScheme = newScheme.copy(inversePrimary = (value))
"secondary" -> newScheme = newScheme.copy(secondary = (value))
"onSecondary" -> newScheme = newScheme.copy(onSecondary = (value))
"secondaryContainer" -> newScheme =
newScheme.copy(secondaryContainer = (value))
"onSecondaryContainer" -> newScheme =
newScheme.copy(onSecondaryContainer = (value))
"tertiary" -> newScheme = newScheme.copy(tertiary = (value))
"onTertiary" -> newScheme = newScheme.copy(onTertiary = (value))
"tertiaryContainer" -> newScheme = newScheme.copy(tertiaryContainer = (value))
"onTertiaryContainer" -> newScheme =
newScheme.copy(onTertiaryContainer = (value))
"background" -> newScheme = newScheme.copy(background = (value))
"onBackground" -> newScheme = newScheme.copy(onBackground = (value))
"surface" -> newScheme = newScheme.copy(surface = (value))
"onSurface" -> newScheme = newScheme.copy(onSurface = (value))
"surfaceVariant" -> newScheme = newScheme.copy(surfaceVariant = (value))
"onSurfaceVariant" -> newScheme = newScheme.copy(onSurfaceVariant = (value))
"surfaceTint" -> newScheme = newScheme.copy(surfaceTint = (value))
"inverseSurface" -> newScheme = newScheme.copy(inverseSurface = (value))
"inverseOnSurface" -> newScheme = newScheme.copy(inverseOnSurface = (value))
"error" -> newScheme = newScheme.copy(error = (value))
"onError" -> newScheme = newScheme.copy(onError = (value))
"errorContainer" -> newScheme = newScheme.copy(errorContainer = (value))
"onErrorContainer" -> newScheme = newScheme.copy(onErrorContainer = (value))
"outline" -> newScheme = newScheme.copy(outline = (value))
"outlineVariant" -> newScheme = newScheme.copy(outlineVariant = (value))
"scrim" -> newScheme = newScheme.copy(scrim = (value))
}
}
return newScheme
}
fun getFieldByName(name: String): Int? {
return when (name) {
"primary" -> primary
"onPrimary" -> onPrimary
"primaryContainer" -> primaryContainer
"onPrimaryContainer" -> onPrimaryContainer
"inversePrimary" -> inversePrimary
"secondary" -> secondary
"onSecondary" -> onSecondary
"secondaryContainer" -> secondaryContainer
"onSecondaryContainer" -> onSecondaryContainer
"tertiary" -> tertiary
"onTertiary" -> onTertiary
"tertiaryContainer" -> tertiaryContainer
"onTertiaryContainer" -> onTertiaryContainer
"background" -> background
"onBackground" -> onBackground
"surface" -> surface
"onSurface" -> onSurface
"surfaceVariant" -> surfaceVariant
"onSurfaceVariant" -> onSurfaceVariant
"surfaceTint" -> surfaceTint
"inverseSurface" -> inverseSurface
"inverseOnSurface" -> inverseOnSurface
"error" -> error
"onError" -> onError
"errorContainer" -> errorContainer
"onErrorContainer" -> onErrorContainer
"outline" -> outline
"outlineVariant" -> outlineVariant
"scrim" -> scrim
else -> null
}
}
companion object {
// I am genuinely going to go to Google's office and hand them this code and tell them
// to fix their garbage Gradle plugin
val fieldNames = listOf(
"primary",
"onPrimary",
"primaryContainer",
"onPrimaryContainer",
"inversePrimary",
"secondary",
"onSecondary",
"secondaryContainer",
"onSecondaryContainer",
"tertiary",
"onTertiary",
"tertiaryContainer",
"onTertiaryContainer",
"background",
"onBackground",
"surface",
"onSurface",
"surfaceVariant",
"onSurfaceVariant",
"surfaceTint",
"inverseSurface",
"inverseOnSurface",
"error",
"onError",
"errorContainer",
"onErrorContainer",
"outline",
"outlineVariant",
"scrim"
)
// See above comment HOLY SHIT i am genuinely going insane
val fieldNameToResource = mapOf(
"primary" to R.string.settings_appearance_colour_overrides_primary,
"onPrimary" to R.string.settings_appearance_colour_overrides_on_primary,
"primaryContainer" to R.string.settings_appearance_colour_overrides_primary_container,
"onPrimaryContainer" to R.string.settings_appearance_colour_overrides_on_primary_container,
"inversePrimary" to R.string.settings_appearance_colour_overrides_inverse_primary,
"secondary" to R.string.settings_appearance_colour_overrides_secondary,
"onSecondary" to R.string.settings_appearance_colour_overrides_on_secondary,
"secondaryContainer" to R.string.settings_appearance_colour_overrides_secondary_container,
"onSecondaryContainer" to R.string.settings_appearance_colour_overrides_on_secondary_container,
"tertiary" to R.string.settings_appearance_colour_overrides_tertiary,
"onTertiary" to R.string.settings_appearance_colour_overrides_on_tertiary,
"tertiaryContainer" to R.string.settings_appearance_colour_overrides_tertiary_container,
"onTertiaryContainer" to R.string.settings_appearance_colour_overrides_on_tertiary_container,
"background" to R.string.settings_appearance_colour_overrides_background,
"onBackground" to R.string.settings_appearance_colour_overrides_on_background,
"surface" to R.string.settings_appearance_colour_overrides_surface,
"onSurface" to R.string.settings_appearance_colour_overrides_on_surface,
"surfaceVariant" to R.string.settings_appearance_colour_overrides_surface_variant,
"onSurfaceVariant" to R.string.settings_appearance_colour_overrides_on_surface_variant,
"surfaceTint" to R.string.settings_appearance_colour_overrides_surface_tint,
"inverseSurface" to R.string.settings_appearance_colour_overrides_inverse_surface,
"inverseOnSurface" to R.string.settings_appearance_colour_overrides_inverse_on_surface,
"error" to R.string.settings_appearance_colour_overrides_error,
"onError" to R.string.settings_appearance_colour_overrides_on_error,
"errorContainer" to R.string.settings_appearance_colour_overrides_error_container,
"onErrorContainer" to R.string.settings_appearance_colour_overrides_on_error_container,
"outline" to R.string.settings_appearance_colour_overrides_outline,
"outlineVariant" to R.string.settings_appearance_colour_overrides_outline_variant,
"scrim" to R.string.settings_appearance_colour_overrides_scrim
)
}
}
fun ColorScheme.getFieldByName(name: String): Int? {
return when (name) {
"primary" -> primary.toArgb()
"onPrimary" -> onPrimary.toArgb()
"primaryContainer" -> primaryContainer.toArgb()
"onPrimaryContainer" -> onPrimaryContainer.toArgb()
"inversePrimary" -> inversePrimary.toArgb()
"secondary" -> secondary.toArgb()
"onSecondary" -> onSecondary.toArgb()
"secondaryContainer" -> secondaryContainer.toArgb()
"onSecondaryContainer" -> onSecondaryContainer.toArgb()
"tertiary" -> tertiary.toArgb()
"onTertiary" -> onTertiary.toArgb()
"tertiaryContainer" -> tertiaryContainer.toArgb()
"onTertiaryContainer" -> onTertiaryContainer.toArgb()
"background" -> background.toArgb()
"onBackground" -> onBackground.toArgb()
"surface" -> surface.toArgb()
"onSurface" -> onSurface.toArgb()
"surfaceVariant" -> surfaceVariant.toArgb()
"onSurfaceVariant" -> onSurfaceVariant.toArgb()
"surfaceTint" -> surfaceTint.toArgb()
"inverseSurface" -> inverseSurface.toArgb()
"inverseOnSurface" -> inverseOnSurface.toArgb()
"error" -> error.toArgb()
"onError" -> onError.toArgb()
"errorContainer" -> errorContainer.toArgb()
"onErrorContainer" -> onErrorContainer.toArgb()
"outline" -> outline.toArgb()
"outlineVariant" -> outlineVariant.toArgb()
"scrim" -> scrim.toArgb()
else -> null
}
}

View File

@ -19,8 +19,6 @@ import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import kotlin.reflect.KMutableProperty
import kotlin.reflect.full.memberProperties
val RevoltColorScheme = darkColorScheme( val RevoltColorScheme = darkColorScheme(
primary = Color(0xffda4e5b), primary = Color(0xffda4e5b),
@ -68,7 +66,10 @@ enum class Theme {
} }
@Composable @Composable
fun getColorScheme(requestedTheme: Theme, colourOverrides: Map<String, Int>? = null): ColorScheme { fun getColorScheme(
requestedTheme: Theme,
colourOverrides: OverridableColourScheme? = null
): ColorScheme {
val context = LocalContext.current val context = LocalContext.current
val systemInDarkTheme = isSystemInDarkTheme() val systemInDarkTheme = isSystemInDarkTheme()
@ -112,24 +113,15 @@ fun getColorScheme(requestedTheme: Theme, colourOverrides: Map<String, Int>? = n
} }
} }
colorScheme::class.memberProperties.forEach { if (colourOverrides == null) return colorScheme
if (it is KMutableProperty<*>) { return colourOverrides.applyTo(colorScheme)
val name = it.name
val value = colourOverrides?.get(name)
if (value != null) {
it.setter.call(colorScheme, Color(value))
}
}
}
return colorScheme
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
fun RevoltTheme( fun RevoltTheme(
requestedTheme: Theme, requestedTheme: Theme,
colourOverrides: Map<String, Int>?, colourOverrides: OverridableColourScheme? = null,
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
val colorScheme = getColorScheme(requestedTheme, colourOverrides) val colorScheme = getColorScheme(requestedTheme, colourOverrides)