Rewrite color picker

This commit is contained in:
MM20 2023-04-17 15:44:20 +02:00
parent 64e7528cb0
commit 7bb16753e0
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
5 changed files with 234 additions and 43 deletions

View File

@ -81,8 +81,6 @@ dependencies {
implementation(libs.androidx.navigation.compose)
implementation(libs.composecolorpicker)
implementation(libs.jsoup)
// Legacy dependencies

View File

@ -0,0 +1,230 @@
package de.mm20.launcher2.ui.component.colorpicker
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
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.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
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.AbsoluteAlignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.dp
import de.mm20.launcher2.ui.ktx.toHexString
import kotlin.math.atan2
import android.graphics.Color as AndroidColor
@Composable
fun ColorPicker(
value: Color,
onValueChanged: (Color) -> Unit,
modifier: Modifier = Modifier,
) {
val (hue, sat, vl) = remember(value) {
val hsv = FloatArray(3)
val r = value.red * 255f
val g = value.green * 255f
val b = value.blue * 255f
AndroidColor.RGBToHSV(r.toInt(), g.toInt(), b.toInt(), hsv)
hsv
}
Column(modifier = modifier) {
BoxWithConstraints(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 32.dp)
.aspectRatio(1f)
) {
val width = this.maxWidth
val height = this.maxHeight
Canvas(
modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectDragGestures(
onDrag = { change, it ->
val (x, y) = change.position
val angle = atan2(
y.toDouble() - height.toPx() / 2,
x.toDouble() - width.toPx() / 2,
)
val h = (Math.toDegrees(angle) + 360f) % 360f
onValueChanged(Color.hsv(h.toFloat(), sat, vl))
}
)
}
.pointerInput(Unit) {
detectTapGestures {
val (x, y) = it
val angle = atan2(
y.toDouble() - height.toPx() / 2,
x.toDouble() - width.toPx() / 2,
)
val h = (Math.toDegrees(angle) + 360f) % 360f
onValueChanged(Color.hsv(h.toFloat(), sat, vl))
}
}
.padding(8.dp)
) {
drawCircle(
brush = Brush.sweepGradient(
colors = listOf(
Color.Red,
Color.Yellow,
Color.Green,
Color.Cyan,
Color.Blue,
Color.Magenta,
Color.Red
)
),
style = Stroke(20.dp.toPx())
)
drawCircle(
color = value,
style = Fill,
center = center,
radius = size.minDimension / 2 - 18.dp.toPx()
)
}
Box(
modifier = Modifier
.fillMaxSize()
.rotate(hue),
) {
Box(
modifier = Modifier
.size(16.dp)
.shadow(1.dp, CircleShape)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.surface)
.align(AbsoluteAlignment.CenterRight)
)
}
}
Slider(
modifier = Modifier.padding(top = 16.dp),
value = sat,
onValueChange = {
onValueChanged(Color.hsv(hue, it, vl))
},
track = {
Canvas(
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
) {
drawRoundRect(
brush = Brush.horizontalGradient(
colors = listOf(
Color.hsv(hue, 0f, 1f),
Color.hsv(hue, 1f, 1f)
)
),
style = Fill,
cornerRadius = CornerRadius(10.dp.toPx(), 10.dp.toPx())
)
}
},
thumb = {
Box(
modifier = Modifier
.padding(vertical = 2.dp, horizontal = 8.dp)
.size(16.dp)
.shadow(1.dp, CircleShape)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.surface)
)
}
)
Slider(
modifier = Modifier,
value = vl,
onValueChange = {
onValueChanged(Color.hsv(hue, sat, it))
},
track = {
Canvas(
modifier = Modifier
.fillMaxWidth()
.height(20.dp)
) {
drawRoundRect(
brush = Brush.horizontalGradient(
colors = listOf(
Color.hsv(hue, sat, 0f),
Color.hsv(hue, sat, 1f)
)
),
style = Fill,
cornerRadius = CornerRadius(10.dp.toPx(), 10.dp.toPx())
)
}
},
thumb = {
Box(
modifier = Modifier
.padding(vertical = 2.dp, horizontal = 8.dp)
.size(16.dp)
.shadow(1.dp, CircleShape)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.surface)
)
}
)
var hexValue by remember(value) {
mutableStateOf(
value.toHexString().substring(1)
)
}
OutlinedTextField(
modifier = Modifier.padding(top = 16.dp).padding(horizontal = 16.dp),
value = hexValue,
onValueChange = {
if (Regex("[0-9a-fA-F]{0,6}").matches(it)) {
hexValue = it
if (it.length == 6) {
val hex = it.toIntOrNull(16) ?: return@OutlinedTextField
val color = Color(hex).copy(alpha = 1f)
onValueChanged(color)
}
}
},
prefix = {
Text(
text = "#",
)
}
)
}
}

View File

@ -8,7 +8,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.godaddy.android.colorpicker.ClassicColorPicker
import de.mm20.launcher2.ui.component.colorpicker.ColorPicker
import de.mm20.launcher2.ui.ktx.toHexString
@Composable
@ -51,35 +51,9 @@ fun ColorPreference(
Column(
modifier = Modifier.fillMaxWidth()
) {
ClassicColorPicker(
color = value ?: Color.Black,
onColorChanged = {
color = it.toColor()
},
showAlphaBar = false,
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
)
var hexValue by remember(color) {
mutableStateOf(
color?.toHexString() ?: "#000000"
)
}
TextField(
modifier = Modifier.padding(top = 16.dp),
value = hexValue,
onValueChange = {
hexValue = it
if (Regex("#[0-9a-fA-F]{6}").matches(it)) {
val hex = it.substring(1).toIntOrNull(16) ?: return@TextField
color = Color(hex).copy(alpha = 1f)
}
}
)
ColorPicker(value = color ?: Color.Black, onValueChanged = {
color = it
})
}
},
confirmButton = {

View File

@ -169,14 +169,6 @@ val OpenSourceLicenses = arrayOf(
licenseText = R.raw.license_apache_2,
url = "https://coil-kt.github.io/coil/"
),
OpenSourceLibrary(
name = "compose-color-picker",
description = "A component that provides an HSV color picker, written in Jetpack compose.",
copyrightNote = "Copyright (c) 2021GoDaddy Operating Company, LLC.",
licenseName = R.string.mit_license_name,
licenseText = R.raw.license_mit,
url = "https://github.com/godaddy/compose-color-picker"
),
OpenSourceLibrary(
name = "Apache Commons Text",
description = "Apache Commons Text is a library focused on algorithms working on strings. ",

View File

@ -186,9 +186,6 @@ dependencyResolutionManagement {
library("coil.compose", "io.coil-kt", "coil-compose")
.versionRef("coil")
library("composecolorpicker", "com.godaddy.android.colorpicker", "compose-color-picker")
.version("0.7.0")
library("leakcanary", "com.squareup.leakcanary", "leakcanary-android")
.version("2.10")