Skip to content

Commit de18c0f

Browse files
committed
feature: add separate ui-kit module & m3
1 parent c94528b commit de18c0f

File tree

15 files changed

+695
-3
lines changed

15 files changed

+695
-3
lines changed

buildSrc/src/main/kotlin/convention.compose.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ plugins {
77
dependencies {
88
"implementation"(androidx.compose.foundation)
99
"implementation"(androidx.compose.material)
10+
"implementation"(androidx.compose.material3)
1011
"implementation"(androidx.compose.ui)
1112
"implementation"(androidx.compose.runtime)
1213
"implementation"(androidx.lifecycle.viewmodel.compose)

buildSrc/src/main/kotlin/convention.debug.panel.plugin.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@ kotlin {
3434

3535
dependencies {
3636
implementation(project(":panel-core"))
37+
implementation(project(":panel-ui-kit"))
3738
}

panel-core/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ kotlin {
4343
}
4444

4545
dependencies {
46+
implementation(project(":panel-ui-kit"))
47+
4648
implementation(androidx.activity.compose)
4749
implementation(androidx.navigation.compose)
4850
implementation(androidx.core)

panel-core/src/main/kotlin/com/redmadrobot/debug/core/ui/debugpanel/DebugPanelActivity.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ package com.redmadrobot.debug.core.ui.debugpanel
33
import android.os.Bundle
44
import androidx.activity.ComponentActivity
55
import androidx.activity.compose.setContent
6-
import androidx.compose.material.MaterialTheme
6+
import androidx.compose.runtime.remember
77
import com.redmadrobot.debug.core.inapp.compose.DebugPanelScreen
8+
import com.redmadrobot.debug.uikit.theme.DebugPanelTheme
9+
import com.redmadrobot.debug.uikit.theme.ThemeState
810

911
internal class DebugPanelActivity : ComponentActivity() {
1012
override fun onCreate(savedInstanceState: Bundle?) {
1113
super.onCreate(savedInstanceState)
1214
setContent {
13-
MaterialTheme {
15+
val themeState = remember { ThemeState() }
16+
DebugPanelTheme(themeState = themeState) {
1417
DebugPanelScreen(onClose = { finish() })
1518
}
1619
}

panel-ui-kit/build.gradle.kts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
plugins {
2+
id("com.android.library")
3+
id("convention.compose")
4+
id("convention-publish")
5+
id("convention.detekt")
6+
}
7+
8+
description = "Debug panel UI kit: theme, design tokens, shared components"
9+
10+
android {
11+
compileSdk = Project.COMPILE_SDK
12+
lint.targetSdk = Project.TARGET_SDK
13+
14+
defaultConfig {
15+
minSdk = Project.MIN_SDK
16+
17+
consumerProguardFile("consumer-rules.pro")
18+
}
19+
20+
buildTypes {
21+
getByName(Project.BuildTypes.release) {
22+
isMinifyEnabled = false
23+
proguardFiles(
24+
getDefaultProguardFile(Project.Proguard.androidOptimizedRules),
25+
Project.Proguard.projectRules
26+
)
27+
}
28+
}
29+
30+
kotlin {
31+
jvmToolchain(17)
32+
}
33+
34+
namespace = "com.redmadrobot.debug.uikit"
35+
}
36+
37+
kotlin {
38+
explicitApi()
39+
}
40+
41+
dependencies {
42+
implementation(androidx.compose.material3)
43+
implementation(androidx.compose.ui.tooling)
44+
implementation(androidx.compose.ui.tooling.preview)
45+
}

panel-ui-kit/consumer-rules.pro

Whitespace-only changes.

panel-ui-kit/proguard-rules.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Add project specific ProGuard rules here.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest />
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.redmadrobot.debug.uikit.theme
2+
3+
import androidx.compose.animation.animateColorAsState
4+
import androidx.compose.animation.core.spring
5+
import androidx.compose.runtime.Composable
6+
import androidx.compose.runtime.getValue
7+
import androidx.compose.ui.graphics.Color
8+
9+
private val ColorAnimSpec = spring<Color>(stiffness = 600f)
10+
11+
@Composable
12+
internal fun DebugPanelColors.animated(): DebugPanelColors = DebugPanelColors(
13+
background = background.animated(),
14+
button = button.animated(),
15+
content = content.animated(),
16+
stroke = stroke.animated(),
17+
surface = surface.animated(),
18+
source = source.animated(),
19+
)
20+
21+
@Composable
22+
private fun animateColor(target: Color): Color {
23+
val animated by animateColorAsState(
24+
targetValue = target,
25+
animationSpec = ColorAnimSpec,
26+
label = "",
27+
)
28+
return animated
29+
}
30+
31+
@Composable
32+
private fun BackgroundColors.animated(): BackgroundColors = BackgroundColors(
33+
primary = animateColor(primary),
34+
secondary = animateColor(secondary),
35+
tertiary = animateColor(tertiary),
36+
)
37+
38+
@Composable
39+
private fun ButtonColors.animated(): ButtonColors = ButtonColors(
40+
primary = animateColor(primary),
41+
onPrimary = animateColor(onPrimary),
42+
secondary = animateColor(secondary),
43+
onSecondary = animateColor(onSecondary),
44+
error = animateColor(error),
45+
onError = animateColor(onError),
46+
)
47+
48+
@Composable
49+
private fun ContentColors.animated(): ContentColors = ContentColors(
50+
primary = animateColor(primary),
51+
secondary = animateColor(secondary),
52+
tertiary = animateColor(tertiary),
53+
accent = animateColor(accent),
54+
error = animateColor(error),
55+
teal = animateColor(teal),
56+
)
57+
58+
@Composable
59+
private fun StrokeColors.animated(): StrokeColors = StrokeColors(
60+
primary = animateColor(primary),
61+
secondary = animateColor(secondary),
62+
)
63+
64+
@Composable
65+
private fun SurfaceColors.animated(): SurfaceColors = SurfaceColors(
66+
primary = animateColor(primary),
67+
secondary = animateColor(secondary),
68+
tertiary = animateColor(tertiary),
69+
dialog = animateColor(dialog),
70+
selected = animateColor(selected),
71+
)
72+
73+
@Composable
74+
private fun SourceColors.animated(): SourceColors = SourceColors(
75+
defaultText = animateColor(defaultText),
76+
defaultBackground = animateColor(defaultBackground),
77+
debugText = animateColor(debugText),
78+
debugBackground = animateColor(debugBackground),
79+
remoteText = animateColor(remoteText),
80+
remoteBackground = animateColor(remoteBackground),
81+
)
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
@file:Suppress("MagicNumber")
2+
3+
package com.redmadrobot.debug.uikit.theme
4+
5+
import androidx.compose.foundation.background
6+
import androidx.compose.foundation.layout.Arrangement
7+
import androidx.compose.foundation.layout.Box
8+
import androidx.compose.foundation.layout.ExperimentalLayoutApi
9+
import androidx.compose.foundation.layout.FlowRow
10+
import androidx.compose.foundation.layout.fillMaxSize
11+
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.foundation.layout.size
13+
import androidx.compose.foundation.rememberScrollState
14+
import androidx.compose.foundation.verticalScroll
15+
import androidx.compose.material3.Text
16+
import androidx.compose.runtime.Composable
17+
import androidx.compose.ui.Alignment
18+
import androidx.compose.ui.Modifier
19+
import androidx.compose.ui.graphics.Color
20+
import androidx.compose.ui.graphics.luminance
21+
import androidx.compose.ui.tooling.preview.Preview
22+
import androidx.compose.ui.unit.dp
23+
import androidx.compose.ui.unit.sp
24+
25+
internal object BaseColors {
26+
// Purple
27+
val Purple10 = Color(0xFF21005D)
28+
val Purple20 = Color(0xFF381E72)
29+
val Purple30 = Color(0xFF4A4458)
30+
val Purple40 = Color(0xFF6750A4)
31+
val Purple80 = Color(0xFFD0BCFF)
32+
val Purple90 = Color(0xFFE8DEF8)
33+
val Purple95 = Color(0xFFF3EDF7)
34+
val Purple99 = Color(0xFFFEF7FF)
35+
36+
// Neutral
37+
val Neutral10 = Color(0xFF1C1B1F)
38+
val Neutral20 = Color(0xFF313033)
39+
val Neutral30 = Color(0xFF49454F)
40+
val Neutral40 = Color(0xFF605D66)
41+
val Neutral50 = Color(0xFF79747E)
42+
val Neutral60 = Color(0xFF938F99)
43+
val Neutral80 = Color(0xFFCAC4D0)
44+
val Neutral87 = Color(0xFFE6E1E5)
45+
val Neutral90 = Color(0xFFE6E0E9)
46+
val Neutral92 = Color(0xFFECE6F0)
47+
val Neutral94 = Color(0xFFF4EFF4)
48+
val Neutral95 = Color(0xFFE7E0EC)
49+
val Neutral99 = Color(0xFFFFFBFE)
50+
51+
// Neutral variant (dark surfaces)
52+
val NeutralVariant20 = Color(0xFF2B2930)
53+
val NeutralVariant30 = Color(0xFF36343B)
54+
val NeutralVariant40 = Color(0xFF414046)
55+
56+
// Secondary
57+
val Secondary40 = Color(0xFF625B71)
58+
val Secondary80 = Color(0xFFCCC2DC)
59+
val Secondary90 = Color(0xFFE8DEF8)
60+
61+
// Tertiary
62+
val Tertiary20 = Color(0xFF492532)
63+
val Tertiary30 = Color(0xFF633B48)
64+
val Tertiary40 = Color(0xFF7D5260)
65+
val Tertiary80 = Color(0xFFEFB8C8)
66+
val Tertiary90 = Color(0xFFFFD8E4)
67+
68+
// Error
69+
val Error20 = Color(0xFF601410)
70+
val Error30 = Color(0xFF8C1D18)
71+
val Error40 = Color(0xFFB3261E)
72+
val Error80 = Color(0xFFF2B8B5)
73+
val Error90 = Color(0xFFF9DEDC)
74+
75+
// Status / accent
76+
val Teal = Color(0xFF03DAC6)
77+
val Green = Color(0xFF1B6E2D)
78+
val GreenLight = Color(0xFFD6F5E0)
79+
val GreenDark = Color(0xFF1B3D2A)
80+
val GreenDarkText = Color(0xFF7DD99E)
81+
val Orange = Color(0xFFE65100)
82+
val OrangeLight = Color(0xFFFFF3E0)
83+
val OrangeDark = Color(0xFF3D2E10)
84+
val OrangeDarkText = Color(0xFFFFB74D)
85+
86+
val White = Color(0xFFFFFFFF)
87+
val Black = Color(0xFF000000)
88+
}
89+
90+
@Suppress("LongMethod")
91+
@OptIn(ExperimentalLayoutApi::class)
92+
@Composable
93+
@Preview(showBackground = true)
94+
private fun Preview() {
95+
DebugPanelTheme {
96+
FlowRow(
97+
modifier = Modifier
98+
.fillMaxSize()
99+
.verticalScroll(state = rememberScrollState())
100+
.padding(horizontal = 8.dp),
101+
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
102+
verticalArrangement = Arrangement.spacedBy(space = 4.dp),
103+
) {
104+
// Purple
105+
ColorElement(BaseColors.Purple10, "Purple10")
106+
ColorElement(BaseColors.Purple20, "Purple20")
107+
ColorElement(BaseColors.Purple30, "Purple30")
108+
ColorElement(BaseColors.Purple40, "Purple40")
109+
ColorElement(BaseColors.Purple80, "Purple80")
110+
ColorElement(BaseColors.Purple90, "Purple90")
111+
ColorElement(BaseColors.Purple95, "Purple95")
112+
ColorElement(BaseColors.Purple99, "Purple99")
113+
114+
// Neutral
115+
ColorElement(BaseColors.Neutral10, "Neutral10")
116+
ColorElement(BaseColors.Neutral20, "Neutral20")
117+
ColorElement(BaseColors.Neutral30, "Neutral30")
118+
ColorElement(BaseColors.Neutral40, "Neutral40")
119+
ColorElement(BaseColors.Neutral50, "Neutral50")
120+
ColorElement(BaseColors.Neutral60, "Neutral60")
121+
ColorElement(BaseColors.Neutral80, "Neutral80")
122+
ColorElement(BaseColors.Neutral87, "Neutral87")
123+
ColorElement(BaseColors.Neutral90, "Neutral90")
124+
ColorElement(BaseColors.Neutral92, "Neutral92")
125+
ColorElement(BaseColors.Neutral94, "Neutral94")
126+
ColorElement(BaseColors.Neutral95, "Neutral95")
127+
ColorElement(BaseColors.Neutral99, "Neutral99")
128+
129+
// Neutral variant
130+
ColorElement(BaseColors.NeutralVariant20, "NV20")
131+
ColorElement(BaseColors.NeutralVariant30, "NV30")
132+
ColorElement(BaseColors.NeutralVariant40, "NV40")
133+
134+
// Secondary
135+
ColorElement(BaseColors.Secondary40, "Secondary40")
136+
ColorElement(BaseColors.Secondary80, "Secondary80")
137+
ColorElement(BaseColors.Secondary90, "Secondary90")
138+
139+
// Tertiary
140+
ColorElement(BaseColors.Tertiary20, "Tertiary20")
141+
ColorElement(BaseColors.Tertiary30, "Tertiary30")
142+
ColorElement(BaseColors.Tertiary40, "Tertiary40")
143+
ColorElement(BaseColors.Tertiary80, "Tertiary80")
144+
ColorElement(BaseColors.Tertiary90, "Tertiary90")
145+
146+
// Error
147+
ColorElement(BaseColors.Error20, "Error20")
148+
ColorElement(BaseColors.Error30, "Error30")
149+
ColorElement(BaseColors.Error40, "Error40")
150+
ColorElement(BaseColors.Error80, "Error80")
151+
ColorElement(BaseColors.Error90, "Error90")
152+
153+
// Status / accent
154+
ColorElement(BaseColors.Teal, "Teal")
155+
ColorElement(BaseColors.Green, "Green")
156+
ColorElement(BaseColors.GreenLight, "GreenLight")
157+
ColorElement(BaseColors.GreenDark, "GreenDark")
158+
ColorElement(BaseColors.GreenDarkText, "GreenDkTxt")
159+
ColorElement(BaseColors.Orange, "Orange")
160+
ColorElement(BaseColors.OrangeLight, "OrangeLight")
161+
ColorElement(BaseColors.OrangeDark, "OrangeDark")
162+
ColorElement(BaseColors.OrangeDarkText, "OrangeDkTxt")
163+
164+
// Black & White
165+
ColorElement(BaseColors.White, "White")
166+
ColorElement(BaseColors.Black, "Black")
167+
}
168+
}
169+
}
170+
171+
@Composable
172+
private fun ColorElement(color: Color, label: String, modifier: Modifier = Modifier) {
173+
val textColor = if (color.luminance() > 0.5f) Color.Black else Color.White
174+
175+
Box(
176+
modifier = modifier
177+
.size(size = 100.dp)
178+
.background(color = color),
179+
contentAlignment = Alignment.Center,
180+
) {
181+
Text(
182+
text = label,
183+
color = textColor,
184+
fontSize = 10.sp,
185+
)
186+
}
187+
}

0 commit comments

Comments
 (0)