@@ -8,9 +8,7 @@ import androidx.compose.foundation.lazy.grid.GridCells
88import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
99import androidx.compose.foundation.lazy.grid.itemsIndexed
1010import androidx.compose.foundation.shape.RoundedCornerShape
11- import androidx.compose.material.Icon
12- import androidx.compose.material.IconButton
13- import androidx.compose.material.Text
11+ import androidx.compose.material.*
1412import androidx.compose.material.icons.Icons
1513import androidx.compose.material.icons.filled.Check
1614import androidx.compose.runtime.*
@@ -27,7 +25,6 @@ import androidx.compose.ui.text.style.TextAlign
2725import androidx.compose.ui.unit.dp
2826import androidx.compose.ui.unit.sp
2927import com.smarttoolfactory.extendedcolors.ColorSwatch
30- import com.smarttoolfactory.extendedcolors.MaterialColor
3128import com.smarttoolfactory.extendedcolors.parser.rememberColorParser
3229import com.smarttoolfactory.extendedcolors.util.colorToHSL
3330import com.smarttoolfactory.extendedcolors.util.colorToHex
@@ -38,6 +35,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
3835import kotlinx.coroutines.flow.flowOn
3936import kotlinx.coroutines.flow.mapLatest
4037
38+
4139@Composable
4240fun M3ColorPicker (onColorChange : (Color ) -> Unit ) {
4341
@@ -53,24 +51,44 @@ fun M3ColorPicker(onColorChange: (Color) -> Unit) {
5351
5452 val colorNameParser = rememberColorParser()
5553
56- var colorSwatchIndex by remember { mutableStateOf(0 ) }
57- var color by remember { mutableStateOf(MaterialColor .Red500 ) }
58- var md3Tones by remember { mutableStateOf(getColorTonesList(color)) }
54+ // Show primary or accent colors
55+ var primaryAccentSelection by remember {
56+ mutableStateOf(0 )
57+ }
5958
59+ // Index of selected list as main and index of color in that list
6060 val colorSelectionIndex =
6161 remember { ColorSelectionIndex (mainSelection = 0 , subSelection = 0 ) }
6262
63+ // This is the selected color swatch in top grid which is swatch/list of colors
64+ var colorSwatchIndex by remember { mutableStateOf(0 ) }
65+
6366 val colorSwatch: LinkedHashMap <Int , Color > =
64- remember(colorSwatchIndex) { ColorSwatch .primaryColorSwatches[colorSwatchIndex] }
67+ remember(
68+ colorSwatchIndex,
69+ primaryAccentSelection
70+ ) {
71+ if (primaryAccentSelection == 0 )
72+ ColorSwatch .primaryColorSwatches[colorSwatchIndex] else
73+ ColorSwatch .accentColorSwatches[colorSwatchIndex]
74+ }
6575
66- val keys: MutableList <Int > = colorSwatch.keys.toMutableList()
67- val colors: MutableList <Color > = colorSwatch.values.toMutableList()
76+ // Get keys and colors for second grid to display Material Design 2 keys
77+ // and shades like 100, 200, 900
78+ val m2ColorIndices: List <Int > = colorSwatch.keys.toList()
79+ val m2ColorList: List <Color > = colorSwatch.values.toList()
6880
81+ // Current color picked by user or initial color as Red500
82+ var currentColor by remember { mutableStateOf(ColorSwatch .primaryHeaderColors.first()) }
83+ // Always get Material Design3 tonal palette from color picked recently from
84+ // first or second grid
85+ var m3Tones by remember { mutableStateOf(getColorTonesList(currentColor)) }
86+ // Name of the color that is currently picked
6987 var colorName by remember { mutableStateOf(" " ) }
7088
7189 LaunchedEffect (key1 = colorNameParser) {
7290
73- snapshotFlow { color }
91+ snapshotFlow { currentColor }
7492 .distinctUntilChanged()
7593 .mapLatest { color: Color ->
7694 colorNameParser.parseColorName(color)
@@ -81,116 +99,120 @@ fun M3ColorPicker(onColorChange: (Color) -> Unit) {
8199 }
82100 }
83101
84- LazyVerticalGrid (
85- columns = GridCells .Fixed (6 ),
102+ Spacer (modifier = Modifier .height(20 .dp))
103+ PrimaryAccentSelectionTab (
104+ modifier = Modifier .width(300 .dp),
105+ selectedIndex = primaryAccentSelection
106+ ) {
107+ primaryAccentSelection = it
108+ colorSelectionIndex.mainSelection = 0
109+ colorSelectionIndex.subSelection = 0
110+ colorSwatchIndex = 0
111+ currentColor = ColorSwatch .primaryHeaderColors.first()
112+ }
113+
114+ Spacer (modifier = Modifier .height(10 .dp))
115+
116+ // Color Swatch Selection
117+ ColorSelectionGrid (
118+ columns = GridCells .Fixed (8 ),
86119 contentPadding = PaddingValues (8 .dp),
87120 verticalArrangement = Arrangement .spacedBy(4 .dp),
88121 horizontalArrangement = Arrangement .spacedBy(4 .dp),
89- ) {
90- itemsIndexed(ColorSwatch .primaryHeaderColors) { index: Int , item: Color ->
91-
92- ColorDisplayWithIcon (
93- modifier = Modifier
94- .clip(RoundedCornerShape (8 .dp))
95- .aspectRatio(1f )
96- .clickable {
97- color = item
98- onColorChange(item)
99- colorSwatchIndex = index
100- colorSelectionIndex.mainSelection = 0
101- colorSelectionIndex.subSelection = index
102- md3Tones = getColorTonesList(item)
103- },
104- selected = (colorSelectionIndex.mainSelection == 0 &&
105- colorSelectionIndex.subSelection == index) || (
106- colorSelectionIndex.mainSelection == 1 &&
107- colorSelectionIndex.subSelection == 5 &&
108- index == colorSwatchIndex
109- ),
110- backgroundColor = item
111- )
112- }
122+ colorSelectionList = if (primaryAccentSelection == 0 )
123+ ColorSwatch .primaryHeaderColors else ColorSwatch .accentHeaderColors,
124+ selected = { index ->
125+ (colorSelectionIndex.mainSelection == 0 &&
126+ colorSelectionIndex.subSelection == index) || (
127+ primaryAccentSelection == 0 && colorSelectionIndex.mainSelection == 1 &&
128+ colorSelectionIndex.subSelection == 5 &&
129+ index == colorSwatchIndex
130+ )
131+ },
132+ tint = { Color .Unspecified },
133+ ) { index: Int , item: Color ->
134+ currentColor = item
135+ onColorChange(item)
136+ colorSelectionIndex.mainSelection = 0
137+ colorSelectionIndex.subSelection = index
138+ colorSwatchIndex = index
139+ m3Tones = getColorTonesList(item)
113140 }
114141
115142 Text (
116143 text = " Material Design2 Shade" ,
117144 modifier = Modifier
118145 .fillMaxWidth()
119- .padding(2 .dp),
146+ .padding(5 .dp),
120147 textAlign = TextAlign .Center ,
121148 fontSize = 16 .sp,
122149 fontWeight = FontWeight .Bold ,
123150 color = Color .White
124151 )
125152
126- LazyVerticalGrid (
127- columns = GridCells .Fixed (8 ),
153+ // Primary/Accent Color Selection
154+ ColorSelectionGrid (
155+ modifier = Modifier .fillMaxWidth(if (primaryAccentSelection == 0 ) 1f else .5f ),
156+ columns = GridCells .Fixed (if (primaryAccentSelection == 0 ) 8 else 4 ),
128157 contentPadding = PaddingValues (8 .dp),
129158 verticalArrangement = Arrangement .spacedBy(4 .dp),
130159 horizontalArrangement = Arrangement .spacedBy(4 .dp),
131- ) {
132- itemsIndexed(colors) { index: Int , item: Color ->
133- ColorDisplayWithTitle (
134- modifier = Modifier
135- .clip(RoundedCornerShape (8 .dp))
136- .aspectRatio(1f )
137- .clickable {
138- color = item
139- colorSelectionIndex.mainSelection = 1
140- colorSelectionIndex.subSelection = index
141- onColorChange(item)
142- md3Tones = getColorTonesList(item)
143- },
144- selected = (colorSelectionIndex.mainSelection == 0 && index == 5 )
145- || (colorSelectionIndex.mainSelection == 1
146- && colorSelectionIndex.subSelection == index),
147- backgroundColor = item,
148- contentColor = if (index < 5 ) Color .Black else Color .White ,
149- title = keys[index].toString(),
150- )
151- }
160+ colorSelectionList = m2ColorList,
161+ colorKeys = m2ColorIndices,
162+ selected = { index ->
163+ (primaryAccentSelection == 0 && colorSelectionIndex.mainSelection == 0 && index == 5 )
164+ || (colorSelectionIndex.mainSelection == 1
165+ && colorSelectionIndex.subSelection == index)
166+ },
167+ tint = { index ->
168+ if (index < 5 ) Color .Black else Color .White
169+ },
170+
171+ ) { index: Int , item: Color ->
172+ currentColor = item
173+ colorSelectionIndex.mainSelection = 1
174+ colorSelectionIndex.subSelection = index
175+ onColorChange(item)
176+ m3Tones = getColorTonesList(item)
152177 }
153178
154179 Text (
155180 text = " Material Design3 Tonal Palette" ,
156181 modifier = Modifier
157182 .fillMaxWidth()
158- .padding(2 .dp),
183+ .padding(5 .dp),
159184 textAlign = TextAlign .Center ,
160185 fontSize = 16 .sp,
161186 fontWeight = FontWeight .Bold ,
162187 color = Color .White
163188 )
164189
165- LazyVerticalGrid (
190+
191+ // M3 Tone Selection
192+ ColorSelectionGrid (
166193 columns = GridCells .Fixed (8 ),
167194 contentPadding = PaddingValues (8 .dp),
168195 verticalArrangement = Arrangement .spacedBy(4 .dp),
169196 horizontalArrangement = Arrangement .spacedBy(4 .dp),
170- ) {
171- itemsIndexed(md3Tones) { index: Int , item: Color ->
172- ColorDisplayWithTitle (
173- modifier = Modifier
174- .aspectRatio(1f )
175- .clip(RoundedCornerShape (8 .dp))
176- .aspectRatio(1f )
177- .clickable {
178- colorSelectionIndex.mainSelection = 2
179- colorSelectionIndex.subSelection = index
180- color = item
181- onColorChange(item)
182- },
183- backgroundColor = item,
184- selected = (colorSelectionIndex.mainSelection == 2
185- && colorSelectionIndex.subSelection == index),
186- contentColor = if (index < 6 ) Color .White else Color .Black ,
187- title = material3ToneRange[index].toString()
188- )
189- }
197+ colorSelectionList = m3Tones,
198+ colorKeys = material3ToneRange,
199+ selected = { index ->
200+ (colorSelectionIndex.mainSelection == 2
201+ && colorSelectionIndex.subSelection == index)
202+ },
203+ tint = { index ->
204+ if (index < 6 ) Color .White else Color .Black
205+ },
206+ ) { index: Int , item: Color ->
207+ colorSelectionIndex.mainSelection = 2
208+ colorSelectionIndex.subSelection = index
209+ currentColor = item
210+ onColorChange(item)
190211 }
191212
213+
192214 Spacer (modifier = Modifier .height(30 .dp))
193- val lightness = colorToHSL(color )[2 ]
215+ val lightness = colorToHSL(currentColor )[2 ]
194216 val textColor = if (lightness < .6f ) Color .White else Color .Black
195217
196218
@@ -209,12 +231,12 @@ fun M3ColorPicker(onColorChange: (Color) -> Unit) {
209231 Row (
210232 modifier = Modifier
211233 .padding(8 .dp)
212- .background(color = color , RoundedCornerShape (50 ))
234+ .background(color = currentColor , RoundedCornerShape (50 ))
213235 .padding(horizontal = 20 .dp, vertical = 10 .dp),
214236 verticalAlignment = Alignment .CenterVertically
215237 ) {
216238
217- val hexText = colorToHex(color = color )
239+ val hexText = colorToHex(color = currentColor )
218240 Text (
219241 text = hexText,
220242 fontSize = 24 .sp,
@@ -232,16 +254,93 @@ fun M3ColorPicker(onColorChange: (Color) -> Unit) {
232254 )
233255 }
234256 }
257+ }
258+ }
259+
260+ @Composable
261+ fun ColorSelectionGrid (
262+ modifier : Modifier = Modifier ,
263+ columns : GridCells = GridCells .Fixed (8),
264+ contentPadding : PaddingValues = PaddingValues (8.dp),
265+ verticalArrangement : Arrangement .Vertical = Arrangement .spacedBy(4.dp),
266+ horizontalArrangement : Arrangement .Horizontal = Arrangement .spacedBy(4.dp),
267+ colorSelectionList : List <Color >,
268+ colorKeys : List <Int >? = null,
269+ selected : (Int ) -> Boolean ,
270+ tint : (Int ) -> Color ,
271+ onClick : (Int , Color ) -> Unit ,
272+ ) {
273+ LazyVerticalGrid (
274+ modifier = modifier,
275+ columns = columns,
276+ contentPadding = contentPadding,
277+ verticalArrangement = verticalArrangement,
278+ horizontalArrangement = horizontalArrangement,
279+ ) {
280+ itemsIndexed(colorSelectionList) { index: Int , item: Color ->
281+
282+ ColorDisplayWithTitle (
283+ modifier = Modifier
284+ .aspectRatio(1f )
285+ .clip(RoundedCornerShape (8 .dp))
286+ .aspectRatio(1f )
287+ .clickable {
288+ onClick(index, item)
289+ },
290+ backgroundColor = item,
291+ selected = selected(index),
292+ tint = tint(index),
293+ title = colorKeys?.get(index)?.toString() ? : " "
294+ )
295+ }
296+ }
297+ }
235298
299+ @Composable
300+ fun PrimaryAccentSelectionTab (
301+ modifier : Modifier = Modifier ,
302+ selectedIndex : Int ,
303+ onTabChange : (Int ) -> Unit
304+ ) {
305+
306+ val list = listOf (" Primary" , " Accent" )
307+
308+ TabRow (selectedTabIndex = selectedIndex,
309+ backgroundColor = Color .DarkGray ,
310+ modifier = modifier.clip(RoundedCornerShape (10 .dp)),
311+ indicator = {}
312+ ) {
313+ list.forEachIndexed { index, text ->
314+ val selected = selectedIndex == index
315+ Tab (
316+ modifier = if (selected) Modifier
317+ .clip(RoundedCornerShape (10 .dp))
318+ .background(Color (0xff6FAAEE ))
319+ else Modifier
320+ .clip(RoundedCornerShape (10 .dp))
321+ .background(Color .DarkGray ),
322+ selected = selected,
323+ onClick = {
324+ onTabChange(index)
325+ },
326+ text = {
327+ Text (
328+ text = text, color = if (selected) Color .White
329+ else Color .White .copy(.5f )
330+ )
331+ }
332+ )
333+ }
236334 }
237335}
238336
337+
239338@Composable
240339fun ColorDisplayWithTitle (
241340 modifier : Modifier ,
242341 title : String = "",
243342 selected : Boolean ,
244- contentColor : Color = Color .Unspecified ,
343+ tint : Color = Color .Unspecified ,
245344 backgroundColor : Color
246345) {
247346 Box (
@@ -252,12 +351,14 @@ fun ColorDisplayWithTitle(
252351 .background(backgroundColor)
253352 )
254353
255- Text (text = title, color = contentColor, fontSize = 16 .sp)
354+ if (title.isNotEmpty()) {
355+ Text (text = title, color = tint, fontSize = 16 .sp)
356+ }
256357
257358 if (selected) {
258359 Icon (
259360 modifier = modifier
260- .background(contentColor .copy(alpha = .5f ))
361+ .background(tint .copy(alpha = .5f ))
261362 .padding(4 .dp),
262363 imageVector = Icons .Default .Check ,
263364 contentDescription = " check" ,
0 commit comments