diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..2bfe0010 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,28 @@ +# Read by IntelliJ, Android Studio, VS Code and ktlint alike, which is what makes this +# the file that actually governs formatting. +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 4 + +[*.{kt,kts}] +ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL +# Trailing commas keep the diff for a new parameter to a single added line, instead of +# also touching the line before it. +ij_kotlin_allow_trailing_comma = true +ij_kotlin_allow_trailing_comma_on_call_site = true + +[*.{yml,yaml,json}] +indent_size = 2 + +[*.md] +# Two trailing spaces are a hard line break in Markdown, so they must survive. +trim_trailing_whitespace = false + +[*.bat] +end_of_line = crlf diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..e5c9e0c9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,32 @@ +# Every text file is stored with LF in the repository and checked out with LF, whatever +# operating system the contributor is on. Without this, a Windows checkout can commit CRLF +# and the next Linux contributor sees a whole-file diff that changes nothing. +* text=auto eol=lf + +# Windows batch files are the exception: cmd.exe expects CRLF, so these are checked out +# with CRLF while still being stored as LF. +*.bat text eol=crlf +*.cmd text eol=crlf + +# Marked binary so no line-ending normalisation is ever attempted on them. This matters: +# a CRLF pass that treats a jar or a PNG as text rewrites bytes inside the compressed +# stream and silently corrupts the file. +*.jar binary +*.klib binary +*.zip binary +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.webp binary +*.ico binary +*.ttf binary +*.otf binary +*.woff binary +*.woff2 binary +*.keystore binary +*.jks binary + +# Generated, and noisy in review. +kotlin-js-store/** linguist-generated=true +colorpicker/api/** linguist-generated=true diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/ArgbInt.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/ArgbInt.kt index 9f7fe9ce..6b816d6f 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/ArgbInt.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/ArgbInt.kt @@ -28,9 +28,9 @@ public fun Int.toRgbColor(): RgbColor = RgbColor( internal fun argb(alpha: Int, red: Int, green: Int, blue: Int): Int = ((alpha.coerceIn(0, 255) and 0xFF) shl 24) or - ((red.coerceIn(0, 255) and 0xFF) shl 16) or - ((green.coerceIn(0, 255) and 0xFF) shl 8) or - (blue.coerceIn(0, 255) and 0xFF) + ((red.coerceIn(0, 255) and 0xFF) shl 16) or + ((green.coerceIn(0, 255) and 0xFF) shl 8) or + (blue.coerceIn(0, 255) and 0xFF) internal fun setAlphaComponent(color: Int, alpha: Int): Int = (color and 0x00FFFFFF) or ((alpha.coerceIn(0, 255) and 0xFF) shl 24) diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/HexConversions.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/HexConversions.kt index 99f1bce5..2e344065 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/HexConversions.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/HexConversions.kt @@ -56,6 +56,7 @@ public fun String.toRgbColorOrNull(): RgbColor? { append(char) } } + 6 -> "FF$hex" 8 -> hex else -> return null diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/HslConversions.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/HslConversions.kt index c2171bbf..dfd5328d 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/HslConversions.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/HslConversions.kt @@ -21,12 +21,29 @@ public fun HslColor.toRgb(): RgbColor { val b: Float when (hueSegment) { - 0 -> { r = c + m; g = x + m; b = m } - 1 -> { r = x + m; g = c + m; b = m } - 2 -> { r = m; g = c + m; b = x + m } - 3 -> { r = m; g = x + m; b = c + m } - 4 -> { r = x + m; g = m; b = c + m } - else -> { r = c + m; g = m; b = x + m } + 0 -> { + r = c + m; g = x + m; b = m + } + + 1 -> { + r = x + m; g = c + m; b = m + } + + 2 -> { + r = m; g = c + m; b = x + m + } + + 3 -> { + r = m; g = x + m; b = c + m + } + + 4 -> { + r = x + m; g = m; b = c + m + } + + else -> { + r = c + m; g = m; b = x + m + } } return RgbColor( diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/RgbConversions.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/RgbConversions.kt index 5d23c1ca..1ee25c90 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/RgbConversions.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/conversion/RgbConversions.kt @@ -12,7 +12,7 @@ import codes.side.colorpicker.model.RgbColor internal fun RgbColor.contrastColor(): RgbColor { // WCAG relative luminance on linearized sRGB channels. val luminance = 0.2126 * linearize(red.toDouble()) + - 0.7152 * linearize(green.toDouble()) + - 0.0722 * linearize(blue.toDouble()) + 0.7152 * linearize(green.toDouble()) + + 0.0722 * linearize(blue.toDouble()) return if (luminance > 0.179) RgbColor.Black else RgbColor.White } diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/CmykColor.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/CmykColor.kt index b5a4159a..8fdf1710 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/CmykColor.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/CmykColor.kt @@ -35,22 +35,29 @@ public class CmykColor( // "+ 0f" normalizes -0.0f to 0.0f so equality can't split on signed zero. /** Cyan channel in `0..1`. */ public val cyan: Float = cyan + 0f + /** Magenta channel in `0..1`. */ public val magenta: Float = magenta + 0f + /** Yellow channel in `0..1`. */ public val yellow: Float = yellow + 0f + /** Key (black) channel in `0..1`. */ public val key: Float = key + 0f override val alpha: Float = alpha + 0f /** [cyan] scaled to `0..100` percent and rounded to the nearest integer. */ public val intCyan: Int get() = (cyan * 100f).roundToInt() + /** [magenta] scaled to `0..100` percent and rounded to the nearest integer. */ public val intMagenta: Int get() = (magenta * 100f).roundToInt() + /** [yellow] scaled to `0..100` percent and rounded to the nearest integer. */ public val intYellow: Int get() = (yellow * 100f).roundToInt() + /** [key] scaled to `0..100` percent and rounded to the nearest integer. */ public val intKey: Int get() = (key * 100f).roundToInt() + /** [alpha] scaled to `0..255` and rounded to the nearest integer. */ public val intAlpha: Int get() = (alpha * 255f).roundToInt() @@ -61,16 +68,17 @@ public class CmykColor( yellow: Float = this.yellow, key: Float = this.key, alpha: Float = this.alpha, - ): CmykColor = CmykColor(cyan = cyan, magenta = magenta, yellow = yellow, key = key, alpha = alpha) + ): CmykColor = + CmykColor(cyan = cyan, magenta = magenta, yellow = yellow, key = key, alpha = alpha) override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is CmykColor) return false return cyan == other.cyan && - magenta == other.magenta && - yellow == other.yellow && - key == other.key && - alpha == other.alpha + magenta == other.magenta && + yellow == other.yellow && + key == other.key && + alpha == other.alpha } override fun hashCode(): Int { @@ -88,6 +96,7 @@ public class CmykColor( public companion object { /** Opaque black. */ public val Black: CmykColor = CmykColor(0f, 0f, 0f, 1f) + /** Opaque white. */ public val White: CmykColor = CmykColor(0f, 0f, 0f, 0f) @@ -96,7 +105,13 @@ public class CmykColor( * [key] in `0..100` percent, [alpha] in `0..255`. Unlike the constructor, * out-of-range values are clamped instead of throwing. */ - public fun fromInt(cyan: Int, magenta: Int, yellow: Int, key: Int, alpha: Int = 255): CmykColor = CmykColor( + public fun fromInt( + cyan: Int, + magenta: Int, + yellow: Int, + key: Int, + alpha: Int = 255, + ): CmykColor = CmykColor( cyan = (cyan / 100f).coerceIn(0f, 1f), magenta = (magenta / 100f).coerceIn(0f, 1f), yellow = (yellow / 100f).coerceIn(0f, 1f), diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/HslColor.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/HslColor.kt index 6cf54395..88f157e1 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/HslColor.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/HslColor.kt @@ -35,18 +35,23 @@ public class HslColor( // "+ 0f" normalizes -0.0f to 0.0f so equality can't split on signed zero. /** Hue in degrees, in `0..360` (exclusive) after normalization. */ public val hue: Float = if (hue == 360f) 0f else hue + 0f + /** Saturation in `0..1`. */ public val saturation: Float = saturation + 0f + /** Lightness in `0..1`. */ public val lightness: Float = lightness + 0f override val alpha: Float = alpha + 0f /** [hue] in degrees, rounded to the nearest integer. */ public val intHue: Int get() = hue.roundToInt() + /** [saturation] scaled to `0..100` percent and rounded to the nearest integer. */ public val intSaturation: Int get() = (saturation * 100f).roundToInt() + /** [lightness] scaled to `0..100` percent and rounded to the nearest integer. */ public val intLightness: Int get() = (lightness * 100f).roundToInt() + /** [alpha] scaled to `0..255` and rounded to the nearest integer. */ public val intAlpha: Int get() = (alpha * 255f).roundToInt() @@ -62,9 +67,9 @@ public class HslColor( if (this === other) return true if (other !is HslColor) return false return hue == other.hue && - saturation == other.saturation && - lightness == other.lightness && - alpha == other.alpha + saturation == other.saturation && + lightness == other.lightness && + alpha == other.alpha } override fun hashCode(): Int { @@ -81,8 +86,10 @@ public class HslColor( public companion object { /** Opaque black. */ public val Black: HslColor = HslColor(hue = 0f, saturation = 0f, lightness = 0f) + /** Opaque white. */ public val White: HslColor = HslColor(hue = 0f, saturation = 0f, lightness = 1f) + /** Opaque pure red. */ public val Red: HslColor = HslColor(hue = 0f, saturation = 1f, lightness = 0.5f) @@ -91,11 +98,12 @@ public class HslColor( * [saturation] and [lightness] in `0..100` percent, [alpha] in `0..255`. * Unlike the constructor, out-of-range values are clamped instead of throwing. */ - public fun fromInt(hue: Int, saturation: Int, lightness: Int, alpha: Int = 255): HslColor = HslColor( - hue = hue.toFloat().coerceIn(0f, 360f), - saturation = (saturation / 100f).coerceIn(0f, 1f), - lightness = (lightness / 100f).coerceIn(0f, 1f), - alpha = (alpha / 255f).coerceIn(0f, 1f), - ) + public fun fromInt(hue: Int, saturation: Int, lightness: Int, alpha: Int = 255): HslColor = + HslColor( + hue = hue.toFloat().coerceIn(0f, 360f), + saturation = (saturation / 100f).coerceIn(0f, 1f), + lightness = (lightness / 100f).coerceIn(0f, 1f), + alpha = (alpha / 255f).coerceIn(0f, 1f), + ) } } diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/LabColor.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/LabColor.kt index 3e485457..3dffa919 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/LabColor.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/LabColor.kt @@ -33,18 +33,23 @@ public class LabColor( // "+ 0f" normalizes -0.0f to 0.0f so equality can't split on signed zero. /** Lightness (L*) in `0..100`. */ public val l: Float = l + 0f + /** Green-red axis (a*) in `-128..127`; negative is green, positive is red. */ public val a: Float = a + 0f + /** Blue-yellow axis (b*) in `-128..127`; negative is blue, positive is yellow. */ public val b: Float = b + 0f override val alpha: Float = alpha + 0f /** [l] rounded to the nearest integer. */ public val intL: Int get() = l.roundToInt() + /** [a] rounded to the nearest integer. */ public val intA: Int get() = a.roundToInt() + /** [b] rounded to the nearest integer. */ public val intB: Int get() = b.roundToInt() + /** [alpha] scaled to `0..255` and rounded to the nearest integer. */ public val intAlpha: Int get() = (alpha * 255f).roundToInt() @@ -60,9 +65,9 @@ public class LabColor( if (this === other) return true if (other !is LabColor) return false return l == other.l && - a == other.a && - b == other.b && - alpha == other.alpha + a == other.a && + b == other.b && + alpha == other.alpha } override fun hashCode(): Int { @@ -79,6 +84,7 @@ public class LabColor( public companion object { /** Opaque black. */ public val Black: LabColor = LabColor(l = 0f, a = 0f, b = 0f) + /** Opaque white. */ public val White: LabColor = LabColor(l = 100f, a = 0f, b = 0f) diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/RgbColor.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/RgbColor.kt index ead39951..a0337291 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/RgbColor.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/model/RgbColor.kt @@ -33,18 +33,23 @@ public class RgbColor( // "+ 0f" normalizes -0.0f to 0.0f so equality can't split on signed zero. /** Red channel in `0..1`. */ public val red: Float = red + 0f + /** Green channel in `0..1`. */ public val green: Float = green + 0f + /** Blue channel in `0..1`. */ public val blue: Float = blue + 0f override val alpha: Float = alpha + 0f /** [red] scaled to `0..255` and rounded to the nearest integer. */ public val intRed: Int get() = (red * 255f).roundToInt() + /** [green] scaled to `0..255` and rounded to the nearest integer. */ public val intGreen: Int get() = (green * 255f).roundToInt() + /** [blue] scaled to `0..255` and rounded to the nearest integer. */ public val intBlue: Int get() = (blue * 255f).roundToInt() + /** [alpha] scaled to `0..255` and rounded to the nearest integer. */ public val intAlpha: Int get() = (alpha * 255f).roundToInt() @@ -60,9 +65,9 @@ public class RgbColor( if (this === other) return true if (other !is RgbColor) return false return red == other.red && - green == other.green && - blue == other.blue && - alpha == other.alpha + green == other.green && + blue == other.blue && + alpha == other.alpha } override fun hashCode(): Int { @@ -79,12 +84,16 @@ public class RgbColor( public companion object { /** Opaque black. */ public val Black: RgbColor = RgbColor(0f, 0f, 0f) + /** Opaque white. */ public val White: RgbColor = RgbColor(1f, 1f, 1f) + /** Opaque pure red. */ public val Red: RgbColor = RgbColor(1f, 0f, 0f) + /** Opaque pure green. */ public val Green: RgbColor = RgbColor(0f, 1f, 0f) + /** Opaque pure blue. */ public val Blue: RgbColor = RgbColor(0f, 0f, 1f) diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/state/SaveableColorPickerState.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/state/SaveableColorPickerState.kt index e75457f1..d52c1da8 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/state/SaveableColorPickerState.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/state/SaveableColorPickerState.kt @@ -100,7 +100,7 @@ internal val ColorPickerStateSaver = Saver( } } color?.let { ColorPickerState(it) } - } + }, ) /** diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/CmykSliders.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/CmykSliders.kt index c6fc60dd..6b86ece7 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/CmykSliders.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/CmykSliders.kt @@ -49,14 +49,30 @@ public fun CyanSlider( when (coloringMode) { ColoringMode.Independent -> persistentListOf(Color.White, PureCyan) ColoringMode.Contextual -> persistentListOf( - CmykColor(cyan = 0f, magenta = cmyk.magenta, yellow = cmyk.yellow, key = cmyk.key).toComposeColor(), - CmykColor(cyan = 1f, magenta = cmyk.magenta, yellow = cmyk.yellow, key = cmyk.key).toComposeColor(), + CmykColor( + cyan = 0f, + magenta = cmyk.magenta, + yellow = cmyk.yellow, + key = cmyk.key, + ).toComposeColor(), + CmykColor( + cyan = 1f, + magenta = cmyk.magenta, + yellow = cmyk.yellow, + key = cmyk.key, + ).toComposeColor(), ) } } val thumbColor = remember(cmyk, coloringMode) { when (coloringMode) { - ColoringMode.Independent -> CmykColor(cyan = cmyk.cyan, magenta = 0f, yellow = 0f, key = 0f).toComposeColor() + ColoringMode.Independent -> CmykColor( + cyan = cmyk.cyan, + magenta = 0f, + yellow = 0f, + key = 0f, + ).toComposeColor() + ColoringMode.Contextual -> cmyk.toComposeColor() } } @@ -114,14 +130,30 @@ public fun MagentaSlider( when (coloringMode) { ColoringMode.Independent -> persistentListOf(Color.White, PureMagenta) ColoringMode.Contextual -> persistentListOf( - CmykColor(cyan = cmyk.cyan, magenta = 0f, yellow = cmyk.yellow, key = cmyk.key).toComposeColor(), - CmykColor(cyan = cmyk.cyan, magenta = 1f, yellow = cmyk.yellow, key = cmyk.key).toComposeColor(), + CmykColor( + cyan = cmyk.cyan, + magenta = 0f, + yellow = cmyk.yellow, + key = cmyk.key, + ).toComposeColor(), + CmykColor( + cyan = cmyk.cyan, + magenta = 1f, + yellow = cmyk.yellow, + key = cmyk.key, + ).toComposeColor(), ) } } val thumbColor = remember(cmyk, coloringMode) { when (coloringMode) { - ColoringMode.Independent -> CmykColor(cyan = 0f, magenta = cmyk.magenta, yellow = 0f, key = 0f).toComposeColor() + ColoringMode.Independent -> CmykColor( + cyan = 0f, + magenta = cmyk.magenta, + yellow = 0f, + key = 0f, + ).toComposeColor() + ColoringMode.Contextual -> cmyk.toComposeColor() } } @@ -179,14 +211,30 @@ public fun YellowSlider( when (coloringMode) { ColoringMode.Independent -> persistentListOf(Color.White, PureYellow) ColoringMode.Contextual -> persistentListOf( - CmykColor(cyan = cmyk.cyan, magenta = cmyk.magenta, yellow = 0f, key = cmyk.key).toComposeColor(), - CmykColor(cyan = cmyk.cyan, magenta = cmyk.magenta, yellow = 1f, key = cmyk.key).toComposeColor(), + CmykColor( + cyan = cmyk.cyan, + magenta = cmyk.magenta, + yellow = 0f, + key = cmyk.key, + ).toComposeColor(), + CmykColor( + cyan = cmyk.cyan, + magenta = cmyk.magenta, + yellow = 1f, + key = cmyk.key, + ).toComposeColor(), ) } } val thumbColor = remember(cmyk, coloringMode) { when (coloringMode) { - ColoringMode.Independent -> CmykColor(cyan = 0f, magenta = 0f, yellow = cmyk.yellow, key = 0f).toComposeColor() + ColoringMode.Independent -> CmykColor( + cyan = 0f, + magenta = 0f, + yellow = cmyk.yellow, + key = 0f, + ).toComposeColor() + ColoringMode.Contextual -> cmyk.toComposeColor() } } @@ -244,14 +292,30 @@ public fun KeySlider( when (coloringMode) { ColoringMode.Independent -> persistentListOf(Color.White, Color.Black) ColoringMode.Contextual -> persistentListOf( - CmykColor(cyan = cmyk.cyan, magenta = cmyk.magenta, yellow = cmyk.yellow, key = 0f).toComposeColor(), - CmykColor(cyan = cmyk.cyan, magenta = cmyk.magenta, yellow = cmyk.yellow, key = 1f).toComposeColor(), + CmykColor( + cyan = cmyk.cyan, + magenta = cmyk.magenta, + yellow = cmyk.yellow, + key = 0f, + ).toComposeColor(), + CmykColor( + cyan = cmyk.cyan, + magenta = cmyk.magenta, + yellow = cmyk.yellow, + key = 1f, + ).toComposeColor(), ) } } val thumbColor = remember(cmyk, coloringMode) { when (coloringMode) { - ColoringMode.Independent -> CmykColor(cyan = 0f, magenta = 0f, yellow = 0f, key = cmyk.key).toComposeColor() + ColoringMode.Independent -> CmykColor( + cyan = 0f, + magenta = 0f, + yellow = 0f, + key = cmyk.key, + ).toComposeColor() + ColoringMode.Contextual -> cmyk.toComposeColor() } } diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/GradientTrack.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/GradientTrack.kt index 62ced18a..6c3d3ffb 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/GradientTrack.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/GradientTrack.kt @@ -22,8 +22,8 @@ import androidx.compose.ui.graphics.Path import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.drawscope.clipPath import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import codes.side.colorpicker.theme.ColorPickerDefaults import kotlinx.collections.immutable.ImmutableList @@ -125,7 +125,7 @@ internal fun GradientTrack( bottomLeft = CornerRadius.Zero, topRight = CornerRadius(insideCornerSize), bottomRight = CornerRadius(insideCornerSize), - ) + ), ) } @@ -140,7 +140,7 @@ internal fun GradientTrack( bottomLeft = CornerRadius(insideCornerSize), topRight = CornerRadius.Zero, bottomRight = CornerRadius.Zero, - ) + ), ) } diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/HslColorPicker.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/HslColorPicker.kt index 0de82971..9a0e2831 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/HslColorPicker.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/HslColorPicker.kt @@ -39,8 +39,18 @@ public fun HslColorPicker( verticalArrangement = Arrangement.spacedBy(12.dp), ) { HueSlider(state = state, coloringMode = coloringMode, colors = colors, shapes = shapes) - SaturationSlider(state = state, coloringMode = coloringMode, colors = colors, shapes = shapes) - LightnessSlider(state = state, coloringMode = coloringMode, colors = colors, shapes = shapes) + SaturationSlider( + state = state, + coloringMode = coloringMode, + colors = colors, + shapes = shapes, + ) + LightnessSlider( + state = state, + coloringMode = coloringMode, + colors = colors, + shapes = shapes, + ) if (showAlpha) { AlphaSlider(state = state, colors = colors, shapes = shapes) } diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/HslSliders.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/HslSliders.kt index 72702b5f..4ac51168 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/HslSliders.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/HslSliders.kt @@ -73,7 +73,12 @@ public fun HueSlider( } val thumbColor = remember(hsl, coloringMode) { when (coloringMode) { - ColoringMode.Independent -> HslColor(hue = hsl.hue, saturation = 1f, lightness = 0.5f).toComposeColor() + ColoringMode.Independent -> HslColor( + hue = hsl.hue, + saturation = 1f, + lightness = 0.5f, + ).toComposeColor() + ColoringMode.Contextual -> hsl.toComposeColor() } } @@ -133,15 +138,29 @@ public fun SaturationSlider( Color.Gray, HslColor(hue = hsl.hue, saturation = 1f, lightness = 0.5f).toComposeColor(), ) + ColoringMode.Contextual -> persistentListOf( - HslColor(hue = hsl.hue, saturation = 0f, lightness = hsl.lightness).toComposeColor(), - HslColor(hue = hsl.hue, saturation = 1f, lightness = hsl.lightness).toComposeColor(), + HslColor( + hue = hsl.hue, + saturation = 0f, + lightness = hsl.lightness, + ).toComposeColor(), + HslColor( + hue = hsl.hue, + saturation = 1f, + lightness = hsl.lightness, + ).toComposeColor(), ) } } val thumbColor = remember(hsl, coloringMode) { when (coloringMode) { - ColoringMode.Independent -> HslColor(hue = hsl.hue, saturation = hsl.saturation, lightness = 0.5f).toComposeColor() + ColoringMode.Independent -> HslColor( + hue = hsl.hue, + saturation = hsl.saturation, + lightness = 0.5f, + ).toComposeColor() + ColoringMode.Contextual -> hsl.toComposeColor() } } @@ -202,16 +221,26 @@ public fun LightnessSlider( HslColor(hue = hsl.hue, saturation = 1f, lightness = 0.5f).toComposeColor(), Color.White, ) + ColoringMode.Contextual -> persistentListOf( Color.Black, - HslColor(hue = hsl.hue, saturation = hsl.saturation, lightness = 0.5f).toComposeColor(), + HslColor( + hue = hsl.hue, + saturation = hsl.saturation, + lightness = 0.5f, + ).toComposeColor(), Color.White, ) } } val thumbColor = remember(hsl, coloringMode) { when (coloringMode) { - ColoringMode.Independent -> HslColor(hue = hsl.hue, saturation = 1f, lightness = hsl.lightness).toComposeColor() + ColoringMode.Independent -> HslColor( + hue = hsl.hue, + saturation = 1f, + lightness = hsl.lightness, + ).toComposeColor() + ColoringMode.Contextual -> hsl.toComposeColor() } } diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/LabColorPicker.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/LabColorPicker.kt index 63bd3e71..81611a84 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/LabColorPicker.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/LabColorPicker.kt @@ -33,7 +33,12 @@ public fun LabColorPicker( modifier = modifier, verticalArrangement = Arrangement.spacedBy(12.dp), ) { - LightnessLabSlider(state = state, coloringMode = coloringMode, colors = colors, shapes = shapes) + LightnessLabSlider( + state = state, + coloringMode = coloringMode, + colors = colors, + shapes = shapes, + ) LabASlider(state = state, coloringMode = coloringMode, colors = colors, shapes = shapes) LabBSlider(state = state, coloringMode = coloringMode, colors = colors, shapes = shapes) if (showAlpha) { diff --git a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/RgbSliders.kt b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/RgbSliders.kt index 81d3bf4b..6e77ea60 100644 --- a/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/RgbSliders.kt +++ b/colorpicker/src/commonMain/kotlin/codes/side/colorpicker/ui/RgbSliders.kt @@ -52,7 +52,12 @@ public fun RedSlider( } val thumbColor = remember(rgb, coloringMode) { when (coloringMode) { - ColoringMode.Independent -> RgbColor(red = rgb.red, green = 0f, blue = 0f).toComposeColor() + ColoringMode.Independent -> RgbColor( + red = rgb.red, + green = 0f, + blue = 0f, + ).toComposeColor() + ColoringMode.Contextual -> rgb.toComposeColor() } } @@ -117,7 +122,12 @@ public fun GreenSlider( } val thumbColor = remember(rgb, coloringMode) { when (coloringMode) { - ColoringMode.Independent -> RgbColor(red = 0f, green = rgb.green, blue = 0f).toComposeColor() + ColoringMode.Independent -> RgbColor( + red = 0f, + green = rgb.green, + blue = 0f, + ).toComposeColor() + ColoringMode.Contextual -> rgb.toComposeColor() } } @@ -182,7 +192,12 @@ public fun BlueSlider( } val thumbColor = remember(rgb, coloringMode) { when (coloringMode) { - ColoringMode.Independent -> RgbColor(red = 0f, green = 0f, blue = rgb.blue).toComposeColor() + ColoringMode.Independent -> RgbColor( + red = 0f, + green = 0f, + blue = rgb.blue, + ).toComposeColor() + ColoringMode.Contextual -> rgb.toComposeColor() } } diff --git a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ArgbIntTest.kt b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ArgbIntTest.kt index 44b9b114..93d481fd 100644 --- a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ArgbIntTest.kt +++ b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ArgbIntTest.kt @@ -10,9 +10,21 @@ class ArgbIntTest { private fun assertIntRgbEqual(expected: RgbColor, actual: RgbColor) { assertEquals(expected.intRed, actual.intRed, "red: ${expected.intRed} vs ${actual.intRed}") - assertEquals(expected.intGreen, actual.intGreen, "green: ${expected.intGreen} vs ${actual.intGreen}") - assertEquals(expected.intBlue, actual.intBlue, "blue: ${expected.intBlue} vs ${actual.intBlue}") - assertEquals(expected.intAlpha, actual.intAlpha, "alpha: ${expected.intAlpha} vs ${actual.intAlpha}") + assertEquals( + expected.intGreen, + actual.intGreen, + "green: ${expected.intGreen} vs ${actual.intGreen}", + ) + assertEquals( + expected.intBlue, + actual.intBlue, + "blue: ${expected.intBlue} vs ${actual.intBlue}", + ) + assertEquals( + expected.intAlpha, + actual.intAlpha, + "alpha: ${expected.intAlpha} vs ${actual.intAlpha}", + ) } // ---- Pack & unpack ---- diff --git a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ChainConversionsTest.kt b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ChainConversionsTest.kt index 965bbd4a..86962cbf 100644 --- a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ChainConversionsTest.kt +++ b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ChainConversionsTest.kt @@ -14,7 +14,12 @@ class ChainConversionsTest { private val eps = 2e-5f private val labEps = 0.5f // LAB uses transcendental functions, needs wider tolerance - private fun assertNear(expected: Float, actual: Float, tolerance: Float = eps, msg: String = "") { + private fun assertNear( + expected: Float, + actual: Float, + tolerance: Float = eps, + msg: String = "", + ) { assertTrue( abs(expected - actual) <= tolerance, "$msg expected=$expected actual=$actual diff=${abs(expected - actual)}" @@ -111,7 +116,12 @@ class ChainConversionsTest { val original = HslColor(hue = 210.5f, saturation = 0.47f, lightness = 0.63f) val roundTripped = original.toRgb().toHsl() assertNear(original.hue, roundTripped.hue, tolerance = eps, msg = "hue") - assertNear(original.saturation, roundTripped.saturation, tolerance = eps, msg = "saturation") + assertNear( + original.saturation, + roundTripped.saturation, + tolerance = eps, + msg = "saturation", + ) assertNear(original.lightness, roundTripped.lightness, tolerance = eps, msg = "lightness") } @@ -120,7 +130,12 @@ class ChainConversionsTest { val original = HslColor(hue = 33.7f, saturation = 0.22f, lightness = 0.77f) val roundTripped = original.toRgb().toHsl() assertNear(original.hue, roundTripped.hue, tolerance = eps, msg = "hue") - assertNear(original.saturation, roundTripped.saturation, tolerance = eps, msg = "saturation") + assertNear( + original.saturation, + roundTripped.saturation, + tolerance = eps, + msg = "saturation", + ) assertNear(original.lightness, roundTripped.lightness, tolerance = eps, msg = "lightness") } @@ -129,7 +144,12 @@ class ChainConversionsTest { val original = HslColor(hue = 275.3f, saturation = 0.85f, lightness = 0.31f) val roundTripped = original.toRgb().toHsl() assertNear(original.hue, roundTripped.hue, tolerance = eps, msg = "hue") - assertNear(original.saturation, roundTripped.saturation, tolerance = eps, msg = "saturation") + assertNear( + original.saturation, + roundTripped.saturation, + tolerance = eps, + msg = "saturation", + ) assertNear(original.lightness, roundTripped.lightness, tolerance = eps, msg = "lightness") } @@ -138,7 +158,12 @@ class ChainConversionsTest { val original = HslColor(hue = 5.5f, saturation = 0.91f, lightness = 0.44f) val roundTripped = original.toRgb().toHsl() assertNear(original.hue, roundTripped.hue, tolerance = eps, msg = "hue") - assertNear(original.saturation, roundTripped.saturation, tolerance = eps, msg = "saturation") + assertNear( + original.saturation, + roundTripped.saturation, + tolerance = eps, + msg = "saturation", + ) assertNear(original.lightness, roundTripped.lightness, tolerance = eps, msg = "lightness") } @@ -147,7 +172,12 @@ class ChainConversionsTest { val original = HslColor(hue = 185.2f, saturation = 0.63f, lightness = 0.52f) val roundTripped = original.toRgb().toHsl() assertNear(original.hue, roundTripped.hue, tolerance = eps, msg = "hue") - assertNear(original.saturation, roundTripped.saturation, tolerance = eps, msg = "saturation") + assertNear( + original.saturation, + roundTripped.saturation, + tolerance = eps, + msg = "saturation", + ) assertNear(original.lightness, roundTripped.lightness, tolerance = eps, msg = "lightness") } diff --git a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/CmykConversionsTest.kt b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/CmykConversionsTest.kt index 24b57959..2d94b055 100644 --- a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/CmykConversionsTest.kt +++ b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/CmykConversionsTest.kt @@ -11,8 +11,16 @@ class CmykConversionsTest { private val eps = 1e-5f - private fun assertNear(expected: Float, actual: Float, tolerance: Float = eps, msg: String = "") { - assertTrue(abs(expected - actual) <= tolerance, "$msg expected=$expected actual=$actual diff=${abs(expected - actual)}") + private fun assertNear( + expected: Float, + actual: Float, + tolerance: Float = eps, + msg: String = "", + ) { + assertTrue( + abs(expected - actual) <= tolerance, + "$msg expected=$expected actual=$actual diff=${abs(expected - actual)}", + ) } // ---- CMYK -> RGB known colors ---- diff --git a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ComposeColorExtTest.kt b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ComposeColorExtTest.kt index 511dad69..b01ff92d 100644 --- a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ComposeColorExtTest.kt +++ b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/ComposeColorExtTest.kt @@ -13,7 +13,10 @@ import kotlin.test.assertTrue class ComposeColorExtTest { private fun assertNear(expected: Float, actual: Float, tolerance: Float, msg: String = "") { - assertTrue(abs(expected - actual) <= tolerance, "$msg expected=$expected actual=$actual diff=${abs(expected - actual)}") + assertTrue( + abs(expected - actual) <= tolerance, + "$msg expected=$expected actual=$actual diff=${abs(expected - actual)}", + ) } // ---- sRGB round-trips ---- @@ -55,7 +58,10 @@ class ComposeColorExtTest { val rgb = p3.toRgbColor() // The raw P3 channel values must have gone through a real sRGB conversion assertTrue(abs(rgb.red - 0.5f) > 0.001f, "red should differ from raw P3 value: ${rgb.red}") - assertTrue(rgb.blue > rgb.green, "hue ordering preserved: blue=${rgb.blue} green=${rgb.green}") + assertTrue( + rgb.blue > rgb.green, + "hue ordering preserved: blue=${rgb.blue} green=${rgb.green}", + ) assertEquals(1f, rgb.alpha) } diff --git a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/HexConversionsTest.kt b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/HexConversionsTest.kt index b27e1c6e..8bde8797 100644 --- a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/HexConversionsTest.kt +++ b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/HexConversionsTest.kt @@ -135,7 +135,10 @@ class HexConversionsTest { @Test fun strictParseThrowsWithOffendingString() { val exception = assertFailsWith { "nope".toRgbColor() } - assertTrue(exception.message!!.contains("nope"), "message should contain the input: ${exception.message}") + assertTrue( + exception.message!!.contains("nope"), + "message should contain the input: ${exception.message}", + ) } // ---- Round-trips ---- diff --git a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/HslConversionsTest.kt b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/HslConversionsTest.kt index 8d8df74c..2c66b43b 100644 --- a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/HslConversionsTest.kt +++ b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/HslConversionsTest.kt @@ -11,8 +11,16 @@ class HslConversionsTest { private val eps = 5e-5f - private fun assertNear(expected: Float, actual: Float, tolerance: Float = eps, msg: String = "") { - assertTrue(abs(expected - actual) <= tolerance, "$msg expected=$expected actual=$actual diff=${abs(expected - actual)}") + private fun assertNear( + expected: Float, + actual: Float, + tolerance: Float = eps, + msg: String = "", + ) { + assertTrue( + abs(expected - actual) <= tolerance, + "$msg expected=$expected actual=$actual diff=${abs(expected - actual)}", + ) } // ---- HSL -> RGB primary colors ---- @@ -207,10 +215,22 @@ class HslConversionsTest { val hsl = HslColor(hue = 180f, saturation = 0.5f, lightness = 0.4f, alpha = 200f / 255f) val restored = hsl.toArgbInt().toHslColor() // ARGB int round-trip quantizes to 8-bit, so allow +-1 int unit tolerance - assertTrue(abs(hsl.intHue - restored.intHue) <= 1, "hue: ${hsl.intHue} vs ${restored.intHue}") - assertTrue(abs(hsl.intSaturation - restored.intSaturation) <= 1, "sat: ${hsl.intSaturation} vs ${restored.intSaturation}") - assertTrue(abs(hsl.intLightness - restored.intLightness) <= 1, "light: ${hsl.intLightness} vs ${restored.intLightness}") - assertTrue(abs(hsl.intAlpha - restored.intAlpha) <= 1, "alpha: ${hsl.intAlpha} vs ${restored.intAlpha}") + assertTrue( + abs(hsl.intHue - restored.intHue) <= 1, + "hue: ${hsl.intHue} vs ${restored.intHue}", + ) + assertTrue( + abs(hsl.intSaturation - restored.intSaturation) <= 1, + "sat: ${hsl.intSaturation} vs ${restored.intSaturation}", + ) + assertTrue( + abs(hsl.intLightness - restored.intLightness) <= 1, + "light: ${hsl.intLightness} vs ${restored.intLightness}", + ) + assertTrue( + abs(hsl.intAlpha - restored.intAlpha) <= 1, + "alpha: ${hsl.intAlpha} vs ${restored.intAlpha}", + ) } @Test diff --git a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/LabConversionsTest.kt b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/LabConversionsTest.kt index e46ac914..4ad3df7c 100644 --- a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/LabConversionsTest.kt +++ b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/conversion/LabConversionsTest.kt @@ -10,11 +10,20 @@ import kotlin.test.assertTrue class LabConversionsTest { private val eps = 1e-5f + // LAB uses transcendental functions so needs a slightly wider tolerance private val labEps = 0.5f - private fun assertNear(expected: Float, actual: Float, tolerance: Float = eps, msg: String = "") { - assertTrue(abs(expected - actual) <= tolerance, "$msg expected=$expected actual=$actual diff=${abs(expected - actual)}") + private fun assertNear( + expected: Float, + actual: Float, + tolerance: Float = eps, + msg: String = "", + ) { + assertTrue( + abs(expected - actual) <= tolerance, + "$msg expected=$expected actual=$actual diff=${abs(expected - actual)}", + ) } // ---- LAB -> RGB known colors ---- diff --git a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/CmykColorTest.kt b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/CmykColorTest.kt index 3899b034..6c9c516a 100644 --- a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/CmykColorTest.kt +++ b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/CmykColorTest.kt @@ -72,7 +72,8 @@ class CmykColorTest { @Test fun intAccessorsMidValues() { - val c = CmykColor(cyan = 0.5f, magenta = 0.25f, yellow = 0.75f, key = 0.1f, alpha = 128f / 255f) + val c = + CmykColor(cyan = 0.5f, magenta = 0.25f, yellow = 0.75f, key = 0.1f, alpha = 128f / 255f) assertEquals(50, c.intCyan) assertEquals(25, c.intMagenta) assertEquals(75, c.intYellow) diff --git a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/HslColorTest.kt b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/HslColorTest.kt index 245e27b1..dc3772a0 100644 --- a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/HslColorTest.kt +++ b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/HslColorTest.kt @@ -147,7 +147,10 @@ class HslColorTest { @Test fun intHueRoundsCorrectly() { val hsl = HslColor(hue = 210.5f) - assertEquals(211, hsl.intHue) // roundToInt rounds 210.5 -> 211 (banker's toward even on .5, but 210.5 -> 211 is nearest) + assertEquals( + 211, + hsl.intHue, + ) // roundToInt rounds 210.5 -> 211 (banker's toward even on .5, but 210.5 -> 211 is nearest) } // ---- Companion constants ---- diff --git a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/RgbColorTest.kt b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/RgbColorTest.kt index 34a778ee..4801b080 100644 --- a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/RgbColorTest.kt +++ b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/model/RgbColorTest.kt @@ -53,7 +53,8 @@ class RgbColorTest { @Test fun intAccessors() { - val rgb = RgbColor(red = 128f / 255f, green = 64f / 255f, blue = 32f / 255f, alpha = 200f / 255f) + val rgb = + RgbColor(red = 128f / 255f, green = 64f / 255f, blue = 32f / 255f, alpha = 200f / 255f) assertEquals(128, rgb.intRed) assertEquals(64, rgb.intGreen) assertEquals(32, rgb.intBlue) diff --git a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/state/ColorPickerStateTest.kt b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/state/ColorPickerStateTest.kt index d3c445cd..54a27325 100644 --- a/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/state/ColorPickerStateTest.kt +++ b/colorpicker/src/commonTest/kotlin/codes/side/colorpicker/state/ColorPickerStateTest.kt @@ -7,6 +7,12 @@ import codes.side.colorpicker.model.CmykColor import codes.side.colorpicker.model.HslColor import codes.side.colorpicker.model.LabColor import codes.side.colorpicker.model.RgbColor +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.take +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest import kotlin.math.abs import kotlin.test.Test import kotlin.test.assertEquals @@ -16,18 +22,17 @@ import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertSame import kotlin.test.assertTrue -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.take -import kotlinx.coroutines.flow.toList -import kotlinx.coroutines.launch -import kotlinx.coroutines.test.UnconfinedTestDispatcher -import kotlinx.coroutines.test.runTest class ColorPickerStateTest { private val eps = 1e-5f - private fun assertNear(expected: Float, actual: Float, tolerance: Float = eps, msg: String = "") { + private fun assertNear( + expected: Float, + actual: Float, + tolerance: Float = eps, + msg: String = "", + ) { assertTrue( abs(expected - actual) <= tolerance, "$msg expected=$expected actual=$actual diff=${abs(expected - actual)}" @@ -278,7 +283,8 @@ class ColorPickerStateTest { @Test fun updateHuePreservesSaturationAndLightness() { - val state = createState(HslColor(hue = 0f, saturation = 0.8f, lightness = 0.6f, alpha = 0.784f)) + val state = + createState(HslColor(hue = 0f, saturation = 0.8f, lightness = 0.6f, alpha = 0.784f)) state.updateHue(120f) assertEquals(0.8f, state.hslColor.saturation) assertEquals(0.6f, state.hslColor.lightness) @@ -296,7 +302,8 @@ class ColorPickerStateTest { @Test fun updateSaturationPreservesHueAndLightness() { - val state = createState(HslColor(hue = 200f, saturation = 0.5f, lightness = 0.6f, alpha = 0.9f)) + val state = + createState(HslColor(hue = 200f, saturation = 0.5f, lightness = 0.6f, alpha = 0.9f)) state.updateSaturation(0.3f) assertEquals(200f, state.hslColor.hue) assertEquals(0.6f, state.hslColor.lightness) @@ -366,7 +373,8 @@ class ColorPickerStateTest { @Test fun updateFromCmykReadsBackTheExactInstance() { val state = createState() - val cmyk = CmykColor(cyan = 0.1f, magenta = 1f / 3f, yellow = 0.7f, key = 0.9f, alpha = 0.3f) + val cmyk = + CmykColor(cyan = 0.1f, magenta = 1f / 3f, yellow = 0.7f, key = 0.9f, alpha = 0.3f) state.updateFromCmyk(cmyk) assertSame(cmyk, state.cmykColor) assertSame(cmyk, state.pickerColor) @@ -543,7 +551,14 @@ class ColorPickerStateTest { @Test fun saverRoundTripHsl() { - val original = ColorPickerState(HslColor(hue = 210f, saturation = 0.4f, lightness = 0.6f, alpha = 0.5f)) + val original = ColorPickerState( + HslColor( + hue = 210f, + saturation = 0.4f, + lightness = 0.6f, + alpha = 0.5f, + ), + ) val restored = assertNotNull(ColorPickerStateSaver.restore(saveToArray(original))) assertIs(restored.pickerColor) assertEquals(original.pickerColor, restored.pickerColor) @@ -551,7 +566,8 @@ class ColorPickerStateTest { @Test fun saverRoundTripRgb() { - val original = ColorPickerState(RgbColor(red = 0.1f, green = 0.2f, blue = 0.3f, alpha = 0.4f)) + val original = + ColorPickerState(RgbColor(red = 0.1f, green = 0.2f, blue = 0.3f, alpha = 0.4f)) val restored = assertNotNull(ColorPickerStateSaver.restore(saveToArray(original))) assertIs(restored.pickerColor) assertEquals(original.pickerColor, restored.pickerColor) @@ -559,7 +575,15 @@ class ColorPickerStateTest { @Test fun saverRoundTripCmyk() { - val original = ColorPickerState(CmykColor(cyan = 0.1f, magenta = 0.2f, yellow = 0.3f, key = 0.4f, alpha = 0.5f)) + val original = ColorPickerState( + CmykColor( + cyan = 0.1f, + magenta = 0.2f, + yellow = 0.3f, + key = 0.4f, + alpha = 0.5f, + ), + ) val restored = assertNotNull(ColorPickerStateSaver.restore(saveToArray(original))) assertIs(restored.pickerColor) assertEquals(original.pickerColor, restored.pickerColor) @@ -574,13 +598,18 @@ class ColorPickerStateTest { } private fun assertBitIdentical(expected: Float, actual: Float, msg: String) { - assertEquals(expected.toRawBits(), actual.toRawBits(), "$msg expected=$expected actual=$actual") + assertEquals( + expected.toRawBits(), + actual.toRawBits(), + "$msg expected=$expected actual=$actual", + ) } @Test fun saverRoundTripPreservesExactBitsHsl() { val hsl = HslColor(hue = 123.456f, saturation = 0.1f, lightness = 1f / 3f, alpha = 0.7f) - val restored = assertNotNull(ColorPickerStateSaver.restore(saveToArray(ColorPickerState(hsl)))) + val restored = + assertNotNull(ColorPickerStateSaver.restore(saveToArray(ColorPickerState(hsl)))) val color = assertIs(restored.pickerColor) assertBitIdentical(hsl.hue, color.hue, "hue") assertBitIdentical(hsl.saturation, color.saturation, "saturation") @@ -591,7 +620,8 @@ class ColorPickerStateTest { @Test fun saverRoundTripPreservesExactBitsRgb() { val rgb = RgbColor(red = 0.1f, green = 1f / 3f, blue = 0.7f, alpha = 0.9f) - val restored = assertNotNull(ColorPickerStateSaver.restore(saveToArray(ColorPickerState(rgb)))) + val restored = + assertNotNull(ColorPickerStateSaver.restore(saveToArray(ColorPickerState(rgb)))) val color = assertIs(restored.pickerColor) assertBitIdentical(rgb.red, color.red, "red") assertBitIdentical(rgb.green, color.green, "green") @@ -601,8 +631,10 @@ class ColorPickerStateTest { @Test fun saverRoundTripPreservesExactBitsCmyk() { - val cmyk = CmykColor(cyan = 0.1f, magenta = 1f / 3f, yellow = 0.7f, key = 0.9f, alpha = 0.3f) - val restored = assertNotNull(ColorPickerStateSaver.restore(saveToArray(ColorPickerState(cmyk)))) + val cmyk = + CmykColor(cyan = 0.1f, magenta = 1f / 3f, yellow = 0.7f, key = 0.9f, alpha = 0.3f) + val restored = + assertNotNull(ColorPickerStateSaver.restore(saveToArray(ColorPickerState(cmyk)))) val color = assertIs(restored.pickerColor) assertBitIdentical(cmyk.cyan, color.cyan, "cyan") assertBitIdentical(cmyk.magenta, color.magenta, "magenta") @@ -614,7 +646,8 @@ class ColorPickerStateTest { @Test fun saverRoundTripPreservesExactBitsLab() { val lab = LabColor(l = 33.333f, a = -12.7f, b = 64.1f, alpha = 0.6f) - val restored = assertNotNull(ColorPickerStateSaver.restore(saveToArray(ColorPickerState(lab)))) + val restored = + assertNotNull(ColorPickerStateSaver.restore(saveToArray(ColorPickerState(lab)))) val color = assertIs(restored.pickerColor) assertBitIdentical(lab.l, color.l, "l") assertBitIdentical(lab.a, color.a, "a") diff --git a/colorpicker/src/jvmTest/kotlin/codes/side/colorpicker/ui/ComponentRenderingTest.kt b/colorpicker/src/jvmTest/kotlin/codes/side/colorpicker/ui/ComponentRenderingTest.kt index aa5aa434..12e6316e 100644 --- a/colorpicker/src/jvmTest/kotlin/codes/side/colorpicker/ui/ComponentRenderingTest.kt +++ b/colorpicker/src/jvmTest/kotlin/codes/side/colorpicker/ui/ComponentRenderingTest.kt @@ -52,7 +52,7 @@ class ComponentRenderingTest { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { AlphaSlider( state = ColorPickerState( - HslColor(hue = 0f, saturation = 1f, lightness = 0.5f, alpha = 0f) + HslColor(hue = 0f, saturation = 1f, lightness = 0.5f, alpha = 0f), ), modifier = Modifier.size(width = 300.dp, height = 80.dp).testTag("alpha"), ) @@ -78,7 +78,13 @@ class ComponentRenderingTest { setContent { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { HueSlider( - state = ColorPickerState(HslColor(hue = 180f, saturation = 1f, lightness = 0.5f)), + state = ColorPickerState( + HslColor( + hue = 180f, + saturation = 1f, + lightness = 0.5f, + ), + ), coloringMode = ColoringMode.Contextual, modifier = Modifier.size(width = 300.dp, height = 60.dp).testTag("hue"), ) @@ -105,7 +111,13 @@ class ComponentRenderingTest { setContent { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { HueSlider( - state = ColorPickerState(HslColor(hue = 180f, saturation = 1f, lightness = 0.5f)), + state = ColorPickerState( + HslColor( + hue = 180f, + saturation = 1f, + lightness = 0.5f, + ), + ), modifier = Modifier.size(width = 300.dp, height = 60.dp).testTag("hue"), thumb = { source -> received = source diff --git a/info/Project.xml b/info/Project.xml deleted file mode 100644 index 5dc28e5c..00000000 --- a/info/Project.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - - - - - - - - -
- - - - xmlns:android - - ^$ - - - -
-
- - - - xmlns:.* - - ^$ - - - BY_NAME - -
-
- - - - .*:id - - http://schemas.android.com/apk/res/android - - - -
-
- - - - .*:name - - http://schemas.android.com/apk/res/android - - - -
-
- - - - name - - ^$ - - - -
-
- - - - style - - ^$ - - - -
-
- - - - .* - - ^$ - - - BY_NAME - -
-
- - - - .* - - http://schemas.android.com/apk/res/android - - - ANDROID_ATTRIBUTE_ORDER - -
-
- - - - .* - - .* - - - BY_NAME - -
-
-
-
- - -
\ No newline at end of file diff --git a/kotlin-js-store/wasm/yarn.lock b/kotlin-js-store/wasm/yarn.lock index 62b6bd5f..5f4567d6 100644 --- a/kotlin-js-store/wasm/yarn.lock +++ b/kotlin-js-store/wasm/yarn.lock @@ -1,8 +1,8 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@js-joda/core@3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@js-joda/core/-/core-3.2.0.tgz#3e61e21b7b2b8a6be746df1335cf91d70db2a273" - integrity sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg== +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@js-joda/core@3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@js-joda/core/-/core-3.2.0.tgz#3e61e21b7b2b8a6be746df1335cf91d70db2a273" + integrity sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg== diff --git a/sample/shared/src/commonMain/kotlin/codes/side/colorpicker/sample/SampleApp.kt b/sample/shared/src/commonMain/kotlin/codes/side/colorpicker/sample/SampleApp.kt index 15ec4f5e..6d29e059 100644 --- a/sample/shared/src/commonMain/kotlin/codes/side/colorpicker/sample/SampleApp.kt +++ b/sample/shared/src/commonMain/kotlin/codes/side/colorpicker/sample/SampleApp.kt @@ -1,10 +1,10 @@ package codes.side.colorpicker.sample +import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.background -import androidx.compose.foundation.interaction.collectIsPressedAsState -import androidx.compose.foundation.interaction.collectIsDraggedAsState import androidx.compose.foundation.interaction.InteractionSource -import androidx.compose.animation.core.animateDpAsState +import androidx.compose.foundation.interaction.collectIsDraggedAsState +import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -266,7 +266,7 @@ private fun SquareThumb(color: Color, interaction: InteractionSource) { .shadow(elevation, shape) .background(ring, shape) .padding(5.dp) - .background(fill, RoundedCornerShape(11.dp)) + .background(fill, RoundedCornerShape(11.dp)), ) } diff --git a/screenshot-tests/src/screenshotTest/kotlin/codes/side/colorpicker/screenshot/ColorPickerPreviews.kt b/screenshot-tests/src/screenshotTest/kotlin/codes/side/colorpicker/screenshot/ColorPickerPreviews.kt index 90838501..5be57ae8 100644 --- a/screenshot-tests/src/screenshotTest/kotlin/codes/side/colorpicker/screenshot/ColorPickerPreviews.kt +++ b/screenshot-tests/src/screenshotTest/kotlin/codes/side/colorpicker/screenshot/ColorPickerPreviews.kt @@ -1,10 +1,10 @@ package codes.side.colorpicker.screenshot +import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.background -import androidx.compose.foundation.interaction.collectIsPressedAsState -import androidx.compose.foundation.interaction.collectIsDraggedAsState import androidx.compose.foundation.interaction.InteractionSource -import androidx.compose.animation.core.animateDpAsState +import androidx.compose.foundation.interaction.collectIsDraggedAsState +import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -64,7 +64,9 @@ private fun Frame(content: @Composable () -> Unit) { MaterialTheme(colorScheme = darkColorScheme()) { Surface(modifier = Modifier.fillMaxSize()) { Column( - modifier = Modifier.fillMaxSize().padding(16.dp), + modifier = Modifier + .fillMaxSize() + .padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterVertically), ) { content() } } @@ -152,7 +154,7 @@ private fun SquareThumb(color: Color, interaction: InteractionSource) { .shadow(elevation, shape) .background(ring, shape) .padding(5.dp) - .background(fill, RoundedCornerShape(11.dp)) + .background(fill, RoundedCornerShape(11.dp)), ) } @@ -182,6 +184,8 @@ fun CustomThumbPreview() = Frame { fun SwatchPreview() = Frame { ColorSwatch( color = Seed.copy(alpha = 0.55f).toComposeColor(), - modifier = Modifier.fillMaxWidth().height(80.dp), + modifier = Modifier + .fillMaxWidth() + .height(80.dp), ) }