feat: Improve UI and theme handling

This commit introduces several UI and theming enhancements:

- Adds labels to the "Dark theme" and "Dynamic theme" switches for better clarity.
- Implements dynamic status bar icon colors to match the current theme (light/dark), improving system integration.
- Enhances the color grid items by:
    - Automatically calculating and applying a contrasting content color (text and border) for better readability against the background color.
    - Displaying the hex code of the color.
- Bumps the Compose BOM version to `2025.12.00`.
This commit is contained in:
2025-12-16 11:47:20 +03:00
parent 9d5e53314c
commit 817d3919e2
3 changed files with 64 additions and 21 deletions
@@ -42,11 +42,13 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.graphics.ColorUtils
import dev.meloda.app.materialcolors.ui.theme.AppTheme import dev.meloda.app.materialcolors.ui.theme.AppTheme
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@@ -66,7 +68,7 @@ fun RootContent() {
AppTheme( AppTheme(
darkTheme = dark, darkTheme = dark,
dynamicColor = dynamic dynamicColor = dynamic,
) { ) {
Scaffold(modifier = Modifier.fillMaxSize()) { padding -> Scaffold(modifier = Modifier.fillMaxSize()) { padding ->
Column( Column(
@@ -78,15 +80,22 @@ fun RootContent() {
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly horizontalArrangement = Arrangement.SpaceEvenly
) { ) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "Dark theme")
Switch( Switch(
checked = dark, checked = dark,
onCheckedChange = { dark = it }, onCheckedChange = { dark = it },
) )
}
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "Dynamic theme")
Switch( Switch(
checked = dynamic, checked = dynamic,
onCheckedChange = { dynamic = it }, onCheckedChange = { dynamic = it },
) )
} }
}
ColorsGrid() ColorsGrid()
} }
@@ -187,9 +196,9 @@ fun ColorsGrid(
@Composable @Composable
private fun ColorGridItem( private fun ColorGridItem(
modifier: Modifier = Modifier,
title: String, title: String,
color: ULong color: ULong,
modifier: Modifier = Modifier,
) { ) {
val context = LocalContext.current val context = LocalContext.current
val animatedColor by animateColorAsState( val animatedColor by animateColorAsState(
@@ -197,7 +206,34 @@ private fun ColorGridItem(
label = "animate color" label = "animate color"
) )
val shape = RoundedCornerShape(25) val shape = remember {
RoundedCornerShape(25)
}
val color = remember(color) {
Color(color)
}
val isLight = remember(color) {
ColorUtils.calculateLuminance(color.toArgb()) >= 0.5f
}
val hex = remember(color) {
"#%02X%02X%02X".format(
(color.red * 255).toInt(),
(color.green * 255).toInt(),
(color.blue * 255).toInt()
)
}
val borderColor by animateColorAsState(
targetValue = if (isLight) Color.DarkGray else Color.LightGray,
label = "borderColor"
)
val contentColor by animateColorAsState(
targetValue = MaterialTheme.colorScheme.contentColorFor(Color(color.value))
.takeIf { it != Color.Unspecified } ?: if (isLight) Color.Black else Color.White,
label = "contentColor"
)
Box( Box(
modifier = modifier modifier = modifier
@@ -205,16 +241,10 @@ private fun ColorGridItem(
.background(color = animatedColor) .background(color = animatedColor)
.border( .border(
width = 1.dp, width = 1.dp,
color = Color(0xffCCCCCC), color = borderColor,
shape = shape shape = shape
) )
.clickable { .clickable {
val color = Color(color)
val hex = "#%02X%02X%02X".format(
(color.red * 255).toInt(),
(color.green * 255).toInt(),
(color.blue * 255).toInt()
)
Log.d("Material Colors", "picked color: $hex") Log.d("Material Colors", "picked color: $hex")
(context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager) (context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager)
@@ -233,7 +263,7 @@ private fun ColorGridItem(
Text( Text(
text = title, text = title,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.contentColorFor(Color(color)), color = contentColor,
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
fontSize = 12.sp, fontSize = 12.sp,
letterSpacing = 0.sp, letterSpacing = 0.sp,
@@ -1,5 +1,6 @@
package dev.meloda.app.materialcolors.ui.theme package dev.meloda.app.materialcolors.ui.theme
import android.app.Activity
import android.os.Build import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@@ -8,7 +9,10 @@ import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
@Composable @Composable
fun AppTheme( fun AppTheme(
@@ -26,6 +30,15 @@ fun AppTheme(
else -> lightColorScheme() else -> lightColorScheme()
} }
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
val insetsController = WindowCompat.getInsetsController(window, view)
insetsController.isAppearanceLightStatusBars = !darkTheme
}
}
MaterialTheme( MaterialTheme(
colorScheme = colorScheme, colorScheme = colorScheme,
typography = Typography, typography = Typography,
+1 -1
View File
@@ -4,7 +4,7 @@ kotlin = "2.2.0"
coreKtx = "1.16.0" coreKtx = "1.16.0"
lifecycleRuntimeKtx = "2.9.1" lifecycleRuntimeKtx = "2.9.1"
activityCompose = "1.10.1" activityCompose = "1.10.1"
composeBom = "2025.06.01" composeBom = "2025.12.00"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }