Rewrite color picker
This commit is contained in:
parent
64e7528cb0
commit
7bb16753e0
@ -81,8 +81,6 @@ dependencies {
|
|||||||
|
|
||||||
implementation(libs.androidx.navigation.compose)
|
implementation(libs.androidx.navigation.compose)
|
||||||
|
|
||||||
implementation(libs.composecolorpicker)
|
|
||||||
|
|
||||||
implementation(libs.jsoup)
|
implementation(libs.jsoup)
|
||||||
|
|
||||||
// Legacy dependencies
|
// Legacy dependencies
|
||||||
|
|||||||
@ -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 = "#",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -8,7 +8,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
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
|
import de.mm20.launcher2.ui.ktx.toHexString
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -51,35 +51,9 @@ fun ColorPreference(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
|
ColorPicker(value = color ?: Color.Black, onValueChanged = {
|
||||||
ClassicColorPicker(
|
color = it
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
|
|||||||
@ -169,14 +169,6 @@ val OpenSourceLicenses = arrayOf(
|
|||||||
licenseText = R.raw.license_apache_2,
|
licenseText = R.raw.license_apache_2,
|
||||||
url = "https://coil-kt.github.io/coil/"
|
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(
|
OpenSourceLibrary(
|
||||||
name = "Apache Commons Text",
|
name = "Apache Commons Text",
|
||||||
description = "Apache Commons Text is a library focused on algorithms working on strings. ",
|
description = "Apache Commons Text is a library focused on algorithms working on strings. ",
|
||||||
|
|||||||
@ -186,9 +186,6 @@ dependencyResolutionManagement {
|
|||||||
library("coil.compose", "io.coil-kt", "coil-compose")
|
library("coil.compose", "io.coil-kt", "coil-compose")
|
||||||
.versionRef("coil")
|
.versionRef("coil")
|
||||||
|
|
||||||
library("composecolorpicker", "com.godaddy.android.colorpicker", "compose-color-picker")
|
|
||||||
.version("0.7.0")
|
|
||||||
|
|
||||||
library("leakcanary", "com.squareup.leakcanary", "leakcanary-android")
|
library("leakcanary", "com.squareup.leakcanary", "leakcanary-android")
|
||||||
.version("2.10")
|
.version("2.10")
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user