1+ package com.kavi.droid.color.picker.ui.pickers
2+
3+ import androidx.compose.foundation.background
4+ import androidx.compose.foundation.border
5+ import androidx.compose.foundation.layout.Arrangement
6+ import androidx.compose.foundation.layout.Box
7+ import androidx.compose.foundation.layout.Column
8+ import androidx.compose.foundation.layout.Row
9+ import androidx.compose.foundation.layout.Spacer
10+ import androidx.compose.foundation.layout.fillMaxWidth
11+ import androidx.compose.foundation.layout.height
12+ import androidx.compose.foundation.layout.padding
13+ import androidx.compose.foundation.layout.size
14+ import androidx.compose.foundation.layout.width
15+ import androidx.compose.foundation.shape.RoundedCornerShape
16+ import androidx.compose.material3.Icon
17+ import androidx.compose.material3.MaterialTheme
18+ import androidx.compose.material3.Slider
19+ import androidx.compose.material3.Text
20+ import androidx.compose.runtime.Composable
21+ import androidx.compose.runtime.LaunchedEffect
22+ import androidx.compose.runtime.derivedStateOf
23+ import androidx.compose.runtime.getValue
24+ import androidx.compose.runtime.mutableFloatStateOf
25+ import androidx.compose.runtime.mutableStateOf
26+ import androidx.compose.runtime.remember
27+ import androidx.compose.runtime.setValue
28+ import androidx.compose.ui.Alignment
29+ import androidx.compose.ui.Modifier
30+ import androidx.compose.ui.draw.shadow
31+ import androidx.compose.ui.graphics.Color
32+ import androidx.compose.ui.res.painterResource
33+ import androidx.compose.ui.res.stringResource
34+ import androidx.compose.ui.text.style.TextAlign
35+ import androidx.compose.ui.unit.dp
36+ import androidx.compose.ui.unit.sp
37+ import com.kavi.droid.color.palette.extension.hsl
38+ import com.kavi.droid.color.palette.util.ColorUtil
39+ import com.kavi.droid.color.picker.R
40+ import com.kavi.droid.color.picker.ui.common.SliderHue
41+
42+ /* *
43+ * A composable function that creates a color picker UI to select color by selecting two colors and blend.
44+ * This component contains two color spectrum(s) to select first and second color to blend and one slider, that consumer
45+ * can change how blended color bias to first or second color.
46+ * By selecting first and second color then by adjusting color bias value, consumer can select or generate their desired color.
47+ *
48+ * @param modifier: Modifier: The modifier to apply to this layout.
49+ * @param onColorSelected: (selectedColor: Color) -> Unit: Callback to invoke when a color is selected.
50+ *
51+ * @return @Composable: A color picker UI for selecting blended color.
52+ */
53+ @Composable
54+ fun BlendColorPicker (
55+ modifier : Modifier = Modifier ,
56+ onColorSelected : (selectedColor: Color ) -> Unit
57+ ) {
58+ // State variables for first color hue and second color hue
59+ val firstHue = remember { mutableFloatStateOf(Color .White .hsl.hue) }
60+ val secondHue = remember { mutableFloatStateOf(Color .White .hsl.hue) }
61+
62+ val firstBlendColor = remember { mutableStateOf(Color .White ) }
63+ val firstBlendColorHex = remember { mutableStateOf(ColorUtil .getHex(Color .White )) }
64+ val secondBlendColor = remember { mutableStateOf(Color .White ) }
65+ val secondBlendColorHex = remember { mutableStateOf(ColorUtil .getHex(Color .White )) }
66+
67+ var colorBias by remember { mutableFloatStateOf(.5f ) }
68+
69+ // Derived state for the color based on blending selected first and second color
70+ val color by remember {
71+ derivedStateOf {
72+ ColorUtil .blendColors(firstBlendColor.value, secondBlendColor.value, bias = colorBias)
73+ }
74+ }
75+
76+ // Launch an effect to invoke the provided callback with the selected color
77+ LaunchedEffect (color) {
78+ onColorSelected.invoke(color)
79+ }
80+
81+ Column (modifier = modifier, verticalArrangement = Arrangement .spacedBy(8 .dp)) {
82+ Column (
83+ modifier = Modifier
84+ .border(1 .dp, Color .White , shape = RoundedCornerShape (8 .dp))
85+ .shadow(
86+ elevation = 10 .dp,
87+ shape = RoundedCornerShape (8 .dp)
88+ )
89+ .background(Color .White )
90+ .padding(start = 12 .dp, end = 12 .dp, top = 12 .dp, bottom = 12 .dp)
91+ ) {
92+
93+ Text (
94+ text = stringResource(R .string.phrase_select_color_blend),
95+ textAlign = TextAlign .Start ,
96+ modifier = Modifier
97+ .fillMaxWidth().padding(start = 12 .dp, end = 12 .dp, top = 12 .dp),
98+ color = Color .Gray ,
99+ style = MaterialTheme .typography.bodySmall,
100+ fontSize = 12 .sp
101+ )
102+
103+ Row (
104+ modifier = Modifier
105+ .padding(top = 8 .dp)
106+ .fillMaxWidth(),
107+ verticalAlignment = Alignment .CenterVertically ,
108+ horizontalArrangement = Arrangement .Center
109+ ) {
110+ Column (
111+ modifier = Modifier .weight(.5f ),
112+ horizontalAlignment = Alignment .CenterHorizontally ,
113+ verticalArrangement = Arrangement .Center
114+ ) {
115+ SliderHue (Modifier .padding(top = 4 .dp, bottom = 4 .dp), onColorSelect = { selectedColor ->
116+ firstHue.floatValue = selectedColor.hsl.hue
117+ firstBlendColor.value = selectedColor
118+ firstBlendColorHex.value = ColorUtil .getHex(selectedColor)
119+ })
120+
121+ Text (text = firstBlendColorHex.value)
122+ }
123+
124+ Spacer (modifier = Modifier .width(8 .dp))
125+
126+ Column (
127+ modifier = Modifier .weight(.5f ),
128+ horizontalAlignment = Alignment .CenterHorizontally ,
129+ verticalArrangement = Arrangement .Center
130+ ) {
131+ SliderHue (Modifier .padding(top = 4 .dp, bottom = 4 .dp), onColorSelect = { selectedColor ->
132+ secondHue.floatValue = selectedColor.hsl.hue
133+ secondBlendColor.value = selectedColor
134+ secondBlendColorHex.value = ColorUtil .getHex(selectedColor)
135+ })
136+
137+ Text (text = secondBlendColorHex.value)
138+ }
139+ }
140+
141+ Row (
142+ modifier = Modifier
143+ .padding(top = 8 .dp)
144+ .fillMaxWidth(),
145+ verticalAlignment = Alignment .CenterVertically ,
146+ horizontalArrangement = Arrangement .Center
147+ ) {
148+ Column (
149+ modifier = Modifier
150+ .weight(.2f ),
151+ horizontalAlignment = Alignment .Start ,
152+ verticalArrangement = Arrangement .Center
153+ ) {
154+ Box (
155+ modifier = Modifier
156+ .padding(4 .dp)
157+ .height(50 .dp)
158+ .width(50 .dp)
159+ .background(
160+ firstBlendColor.value,
161+ shape = MaterialTheme .shapes.large
162+ )
163+ .border(
164+ 2 .dp,
165+ MaterialTheme .colorScheme.primary,
166+ RoundedCornerShape (12 .dp)
167+ )
168+ )
169+ }
170+
171+ Spacer (modifier = Modifier .width(4 .dp))
172+
173+ Row (
174+ modifier = Modifier .weight(.7f ),
175+ verticalAlignment = Alignment .CenterVertically
176+ ) {
177+ Icon (
178+ painter = painterResource(R .drawable.icon_left_arrow),
179+ contentDescription = " Left arrow" ,
180+ Modifier
181+ .weight(.25f )
182+ .size(40 .dp)
183+ )
184+
185+ Slider (
186+ modifier = Modifier
187+ .height(50 .dp)
188+ .weight(.7f ),
189+ value = colorBias,
190+ valueRange = 0f .. 1f ,
191+ onValueChange = {
192+ colorBias = it
193+ },
194+ )
195+ Icon (
196+ painter = painterResource(R .drawable.icon_right_arrow),
197+ contentDescription = " Right arrow" ,
198+ Modifier
199+ .weight(.25f )
200+ .size(40 .dp)
201+ )
202+ }
203+
204+ Spacer (modifier = Modifier .width(4 .dp))
205+
206+ Column (
207+ modifier = Modifier
208+ .weight(.2f ),
209+ horizontalAlignment = Alignment .End ,
210+ verticalArrangement = Arrangement .Center
211+ ) {
212+ Box (
213+ modifier = Modifier
214+ .padding(4 .dp)
215+ .height(50 .dp)
216+ .width(50 .dp)
217+ .background(
218+ secondBlendColor.value,
219+ shape = MaterialTheme .shapes.large
220+ )
221+ .border(
222+ 2 .dp,
223+ MaterialTheme .colorScheme.primary,
224+ RoundedCornerShape (12 .dp)
225+ )
226+ )
227+ }
228+ }
229+ }
230+ }
231+ }
0 commit comments