commit 9d5e53314c45914c2b1dcf96244c45f6872f50c4 Author: Danil Nikolaev Date: Tue Jun 24 19:26:36 2025 +0300 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..1c99a9f --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,59 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) +} + +android { + namespace = "dev.meloda.app.materialcolors" + compileSdk = 35 + + defaultConfig { + applicationId = "dev.meloda.app.materialcolors" + minSdk = 24 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + } + + buildTypes { + release { + isMinifyEnabled = false + signingConfig = signingConfigs.getByName("debug") + + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + + } + kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_11 + } + } + buildFeatures { + compose = true + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e30bd07 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/java/dev/meloda/app/materialcolors/ColorItem.kt b/app/src/main/java/dev/meloda/app/materialcolors/ColorItem.kt new file mode 100644 index 0000000..8e49b6d --- /dev/null +++ b/app/src/main/java/dev/meloda/app/materialcolors/ColorItem.kt @@ -0,0 +1,6 @@ +package dev.meloda.app.materialcolors + +data class ColorItem( + val color: ULong, + val title: String +) diff --git a/app/src/main/java/dev/meloda/app/materialcolors/MainActivity.kt b/app/src/main/java/dev/meloda/app/materialcolors/MainActivity.kt new file mode 100644 index 0000000..6252685 --- /dev/null +++ b/app/src/main/java/dev/meloda/app/materialcolors/MainActivity.kt @@ -0,0 +1,255 @@ +package dev.meloda.app.materialcolors + + +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import android.os.Bundle +import android.util.Log +import android.widget.Toast +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.animation.animateColorAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.GridItemSpan +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ColorScheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.material3.contentColorFor +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import dev.meloda.app.materialcolors.ui.theme.AppTheme + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + RootContent() + } + } +} + +@Composable +fun RootContent() { + var dark by remember { mutableStateOf(false) } + var dynamic by remember { mutableStateOf(false) } + + AppTheme( + darkTheme = dark, + dynamicColor = dynamic + ) { + Scaffold(modifier = Modifier.fillMaxSize()) { padding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Switch( + checked = dark, + onCheckedChange = { dark = it }, + ) + Switch( + checked = dynamic, + onCheckedChange = { dynamic = it }, + ) + } + + ColorsGrid() + } + } + } +} + +@Composable +fun ColorsGrid( + modifier: Modifier = Modifier, + colorScheme: ColorScheme? = null +) { + val c = colorScheme ?: MaterialTheme.colorScheme + + val titles = listOf( + "Primary", "OnPrimary", "Primary\nContainer", "OnPrimary\nContainer", + "Inverse\nPrimary", + "Secondary", "OnSecondary", "Secondary\nContainer", "OnSecondary\nContainer", + "Tertiary", "OnTertiary", "Tertiary\nContainer", "OnTertiary\nContainer", + "Error", "OnError", "Error\nContainer", "OnError\nContainer", + "Background", "OnBackground", + "Outline", "OutlineVariant", + "Surface", "OnSurface", + "SurfaceBright", "SurfaceDim", + "Surface\nVariant", "OnSurface\nVariant", + "Surface\nContainer", + + "Surface\nContainer\nLowest", + "Surface\nContainer\nLow", + "Surface\nContainer\nHigh", + "Surface\nContainer\nHighest", + + "Inverse\nSurface", "Inverse\nOn\nSurface", + ) + + val colors = listOf( + c.primary, c.onPrimary, c.primaryContainer, c.onPrimaryContainer, + c.inversePrimary, + c.secondary, c.onSecondary, c.secondaryContainer, c.onSecondaryContainer, + c.tertiary, c.onTertiary, c.tertiaryContainer, c.onTertiaryContainer, + c.error, c.onError, c.errorContainer, c.onErrorContainer, + c.background, c.onBackground, + c.outline, c.outlineVariant, + c.surface, c.onSurface, + c.surfaceBright, c.surfaceDim, + c.surfaceVariant, c.onSurfaceVariant, + c.surfaceContainer, + + c.surfaceContainerLowest, + c.surfaceContainerLow, + c.surfaceContainerHigh, + c.surfaceContainerHighest, + + c.inverseSurface, c.inverseOnSurface + ).map(Color::value) + + val items = List(colors.size) { index -> + ColorItem( + color = colors[index], + title = titles[index] + ) + } + + LazyVerticalGrid( + modifier = modifier + .padding(horizontal = 16.dp) + .fillMaxSize(), + columns = GridCells.Fixed(4), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + items( + items = items, + span = { item -> + GridItemSpan( + when { + item.title == "Inverse\nPrimary" -> 4 + item.title.contains("Background") -> 2 + item.title.contains("Outline") -> 2 + item.title in listOf("Surface", "OnSurface") -> 2 + item.title in listOf("SurfaceBright", "SurfaceDim") -> 2 + item.title.contains("Surface\nVariant") -> 2 + item.title == "Surface\nContainer" -> 4 + item.title in listOf("Inverse\nSurface", "Inverse\nOn\nSurface") -> 2 + + else -> 1 + } + ) + } + ) { item -> + ColorGridItem( + title = item.title, + color = item.color + ) + } + } +} + +@Composable +private fun ColorGridItem( + modifier: Modifier = Modifier, + title: String, + color: ULong +) { + val context = LocalContext.current + val animatedColor by animateColorAsState( + targetValue = Color(color), + label = "animate color" + ) + + val shape = RoundedCornerShape(25) + + Box( + modifier = modifier + .clip(shape) + .background(color = animatedColor) + .border( + width = 1.dp, + color = Color(0xffCCCCCC), + shape = shape + ) + .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") + + (context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager) + .setPrimaryClip( + ClipData.newPlainText("color", hex) + ) + Toast.makeText( + context, + "Color \"${title.replace("\n", "")}\" copied\nvalue: $hex", + Toast.LENGTH_LONG + ).show() + } + .height(42.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = title, + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.contentColorFor(Color(color)), + style = MaterialTheme.typography.labelSmall, + fontSize = 12.sp, + letterSpacing = 0.sp, + lineHeight = 12.sp + ) + } +} + +@Preview() +@Composable +private fun ColorsPreview() { + AppTheme( + darkTheme = false, + dynamicColor = false + ) { + ColorsGrid() + } +} + diff --git a/app/src/main/java/dev/meloda/app/materialcolors/ui/theme/Theme.kt b/app/src/main/java/dev/meloda/app/materialcolors/ui/theme/Theme.kt new file mode 100644 index 0000000..4a76284 --- /dev/null +++ b/app/src/main/java/dev/meloda/app/materialcolors/ui/theme/Theme.kt @@ -0,0 +1,34 @@ +package dev.meloda.app.materialcolors.ui.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +@Composable +fun AppTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> darkColorScheme() + else -> lightColorScheme() + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} diff --git a/app/src/main/java/dev/meloda/app/materialcolors/ui/theme/Type.kt b/app/src/main/java/dev/meloda/app/materialcolors/ui/theme/Type.kt new file mode 100644 index 0000000..68f3362 --- /dev/null +++ b/app/src/main/java/dev/meloda/app/materialcolors/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package dev.meloda.app.materialcolors.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..7706ab9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..b3e26b4 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..b3e26b4 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..ca1931b --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..fd555ab --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + MaterialColors + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..b96bdfb --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +