Skip to content

Update dependency com.github.skydoves:colorpicker-compose to v1.3.0 - #1039

Merged
DennisBauer merged 1 commit into
mainfrom
renovate/colorpicker
Sep 18, 2026
Merged

DennisBauer merged 1 commit into
mainfrom
renovate/colorpicker

Conversation

@renovate

@renovate renovate Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
com.github.skydoves:colorpicker-compose 1.2.0 → 1.3.0 age confidence

Release Notes

skydoves/colorpicker-compose (com.github.skydoves:colorpicker-compose)

v1.3.0

Compare Source

Upgrading

ColorPickerController no longer takes a CoroutineScope. The constructor parameter defaulted to GlobalScope, and the only thing the scope was used for was collecting the color flow, which ColorPicker launched with Dispatchers.Main. On desktop that dispatcher only exists when something on the runtime classpath brings kotlinx-coroutines-swing along, so a picker in a plain Compose Desktop window went down on a missing Main dispatcher the moment it composed. Pickers and sliders now collect on the composition's own scope through rememberCoroutineScope(), which is the scope that was already the right answer.

ColorPickerController(myScope) // before
ColorPickerController()        // after

rememberColorPickerController() is unchanged, so most code needs nothing. A color change still arrives asynchronously; it is dispatched by the composition rather than posted to Dispatchers.Main.

Two behaviours changed in ways a test might notice. A tap on ImageColorPicker that lands beside a letterboxed palette, or on a pixel with an alpha of zero, now reports nothing at all instead of the nearest edge pixel. And a tap at a given x on a slider maps to a slightly different value than it used to, because the track now reserves the thumb radius at each end; the two ends are exactly 0f and 1f, and the midpoint is still 0.5f.


Added
  • onColorPickingFinished on HsvColorPicker and ImageColorPicker. onColorChanged fires for every step of a drag, so there was no way to tell a live preview apart from a finished choice, and analytics events piled up dozens deep per gesture. The new callback fires once, when a tap lands or a drag ends, carrying the ColorEnvelope the pick settled on. Same shape as onValueChangeFinished on the Compose slider. (#​142)
  • orientation on every slider. AlphaSlider, BrightnessSlider, HueSlider and SaturationSlider take orientation: SliderOrientation, Horizontal by default. A Vertical slider fills the height it is given and runs bottom to top, the way a fader does, so the Modifier.rotate(-90f) inside a clipToBounds + wrapContentSize(unbounded = true) box that the issue thread had been passing around is no longer needed. The gesture detector, the gradient shader and the thumb position all follow the orientation. (#​15)
  • onColorChanged on AlphaSlider, BrightnessSlider and SaturationSlider. Only ColorPicker collected controller.getColorFlow(), so a slider used without a picker beside it never reported anything to its caller. (#​148)
  • A desktop demo app, at :demo:desktopApp, and the wasm demo moved under :demo:wasmApp so every platform runs the same MainScreen. The demo picks images through a multiplatform file picker now, which is what made a desktop image picker possible at all. Thanks @​sproctor. (#​182)
  • A test suite, 120 tests. The library had none. commonTest covers the color math, the geometry helpers and the controller; desktopTest composes the real components in a headless Skiko scene through runComposeUiTest, drives them with touch input, and reads pixels back out of captureToImage for the things that are only visible once drawn. Every fix below ships with a test that fails without it. CI runs them on every pull request, including one stacked on another.
  • Docs pages for HueSlider and SaturationSlider, which both shipped in 1.2.0 with no page on the documentation site.
Fixed
  • A picker disabled before its first layout pass no longer takes the app down. The canvasSize setter carried the selected point across a resize by scaling it, and on the very first assignment the previous size is Size.Zero, so 0f * width / 0f produced Offset(NaN, NaN). That is exactly Offset.Unspecified, and Offset.getX throws on it. setup() normally overwrote the point a moment later, but selectByCoordinate returns early while enabled is false, so with controller.enabled = false set during composition the NaN survived into Canvas.drawCircle and the app crashed on launch with IllegalStateException: Offset is unspecified. The setter now centers the point when there is no previous size to scale from. (#​116)
  • A palette rebuilt during composition no longer snaps the selection back to the center. ImageColorPicker re-runs controller.setup { } whenever the palette's identity changes, and a palette built inline in the composable, which is what bitmap.asImageBitmap() in a LaunchedEffect-free body does, is a new instance on every recomposition. setup() then re-selected its initial position, so the indicator jumped to the middle of the image every time the selected color drove a recomposition. Only the first setup() moves the selection now; a later one keeps the point and re-resolves the color under it. (#​115)
  • initialColor keeps its value and its alpha. HsvColorPicker mapped the initial color to a hue and saturation coordinate and stopped there, and the palette color at a coordinate is always Color.hsv(h, s, 1f). applyHSVFactors only consults brightness when a BrightnessSlider is attached, so the v component was dropped and every initial color came back at full brightness: Color(0xFF000080) displayed as 0xFF0000FF, which is why the report was phrased as blue being forced to FF. It affected any color whose largest channel was below 1f. The picker replays the whole color after setup now. (#​123)
  • selectByColor before the first layout is applied instead of dropped. Called from a LaunchedEffect(Unit), which is where a text field bound to a hex code naturally puts it, there was no canvas to map the color onto and no coordinate function installed yet, so the call silently did nothing and the picker then overwrote it with its own initial position. The controller holds the request and replays it as soon as a picker registers itself. The coordinate math for the colors in the original report, (0, 1, 1) and #​55aa00, was already correct after the multiplatform rewrite; this was the part that was still broken. (#​52)
  • A new wheelImageBitmap repaints. ColorPicker handed the bitmap to the controller exactly once, inside if (!initialized) on the first layout pass, so a caller rebuilding the wheel per frame to follow the selected color kept seeing the very first one. controller.wheelBitmap is snapshot state now and is kept in step with the parameter, so writing it invalidates the canvas. BrightnessSlider never had the bug because it draws its wheel straight from the parameter. (#​124)
  • Taps that land outside the palette are ignored. A palette scaled with PaletteContentScale.FIT leaves bands above and below, or beside, itself, and the picker used to coerceIn a point in one of those bands into the bitmap and report the nearest edge pixel, so tapping empty space handed back a color. Fully transparent pixels came back as a selection too. Both now leave the selection where it is. This is what the original Android-only version did through its Color.Transparent guard, and restoring it resolves the transparent pixel TODO the multiplatform rewrite left behind. The pixel lookup also moved from roundToInt to floor, so a canvas point names the pixel actually drawn under it rather than the one half a pixel over. (#​69, #​145)
  • The slider thumb stays inside its track. The thumb center sat at position * width, so at 0f and 1f half of it hung off the end and the RoundedCornerShape clip cut it away, which is the half circle in the screenshot on the issue. The track reserves the thumb radius, or half the wheel bitmap's width, at each end now, and the tap and drag mapping uses the same travel so the value under the thumb is the value you get. (#​77)
  • A standalone slider draws. The track paint took its color, and with it its alpha, from controller.pureSelectedColor, which is Color.Transparent until something is selected. A slider used without a picker was therefore painted at alpha zero: the whole control was invisible except its thumb, which reads as the slider doing nothing. The shader supplies every color the track draws, so the paint no longer takes one from the controller. BrightnessSlider also assumed full saturation when building its gradient and painted a black to red ramp where a controller with nothing selected should give black to white, which is exactly the greyscale case the request was about. (#​148)
  • A slider that leaves the composition stops holding the color. isAttachedAlphaSlider and its two siblings were set to true from a SideEffect and never set back, so a slider hidden behind a switch kept its last value folded into every color the picker reported afterwards: with a brightness slider dragged to 0.05 and then hidden, tapping full red on the wheel still produced Color(0.047, 0, 0). The sliders report their lifecycle through a DisposableEffect now, and the controller hands the component back to the palette color when the last one leaves. Thanks @​Azerlag for the fix. The controller counts the sliders rather than flagging them, because a flag goes wrong as soon as two sliders of the same kind share a controller and the first one out clears it while the other is still on screen. (#​195)
  • A non uniform resize keeps the indicator on the wheel. Scaling the selected point on each axis independently pulls it off a circle as soon as the canvas aspect ratio changes. The controller hands the scaled point back to the picker and takes the position it reports, which resolves the second of the two TODOs the rewrite left in place.
  • Slider and AlphaTile backgrounds are no longer rebuilt on every recomposition, and the slider no longer writes controller state from inside drawIntoCanvas. The background ImageBitmap lived in a plain local that was null after any recomposition until the next remeasure, and the initialColor bootstrap ran in the draw phase.
  • HueSlider's onColorChanged documents the range it actually reports. The KDoc said 0f..360f; the callback has always been handed the position along the slider in 0f..1f. The value is coerced now, so a drag past the end no longer reports above 1f. The documented range was corrected rather than the value, because changing the number would break anyone who wrote against what shipped in 1.2.0.
Changed
  • Gradle 9.7.1, AGP 9.4.0, Kotlin 2.4.20, Compose Multiplatform 1.12.0, binary compatibility validator 0.18.2, macrobenchmark off its alpha, and Spotless 6.21.0 to 8.10.2. Compose 1.12.0 requires compileSdk 37. Spotless 8 brings a newer ktlint, which needs telling that a @Composable is named like a type.
Docs
  • The README and the documentation site examples compile again. The controller's wheel customization functions became plain properties and setPaletteContentScale was replaced by a parameter on ImageColorPicker at some point, and neither surface was updated, so controller.setWheelRadius(40.dp) and friends were unresolved references. Thanks @​iprashantpanwar. (#​192)
  • Every API page on the documentation site matches its real signature. The picker pages listed wheelRadius, wheelColor and wheelAlpha as parameters of HsvColorPicker and ImageColorPicker, which are controller properties, and left out drawOnPosSelected, drawDefaultWheelIndicator, previewImagePainter, onStart and onFinish entirely.
  • Typos and misplaced KDoc across the slider components. Thanks @​iprashantpanwar. (#​191)

Full Changelog: skydoves/colorpicker-compose@1.2.0...1.3.0


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate Bot added the dependencies Pull requests that update a dependency file label Sep 16, 2026
@coderabbitai

coderabbitai Bot commented Sep 16, 2026

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: c874dde9-4984-4365-b7b3-bd47801a85ee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@DennisBauer
DennisBauer merged commit e1e1d57 into main Sep 18, 2026
4 checks passed
@DennisBauer
DennisBauer deleted the renovate/colorpicker branch September 18, 2026 05:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant