Repository navigation
Make the ready-made pickers configurable - #338
Merged
Merged
Conversation
The six full pickers took state, modifier, showAlpha, coloringMode, colors and shapes, and nothing else. The English labels and screen-reader strings could not be changed without rebuilding a picker out of its sliders; the dialog forwarded its own title and buttons but nothing to the picker inside it; the string "enabled" appeared nowhere in the public API, so nothing could be greyed out; trackHeight existed only on the low-level ColorSlider; and the custom thumb the README demonstrates could not be handed to a picker at all, though the prose beside it says every slider takes one. The androidx component guidelines rule out the obvious fix. A String parameter "restricts styling choice" β no AnnotatedString, no icon, no choice of component β and Material 3 takes DatePicker's title and headline as slots for the same reason. So each slider is a slot, defaulted to the channel slider it names, and localizing is replacing one. That leaves what a replacement would otherwise have to re-declare. Rather than a receiver scope, which the same guidelines reserve for layout APIs, colors and shapes move into CompositionLocals read in parameter defaults β the one use those guidelines sanction, on the condition that the read happens in the default so an explicit argument still wins. A picker provides them, so a replaced slot inherits without the call site forwarding anything. ColorPickerDimensions joins them, bundling the loose constants. That is what fixes trackHeight, and it fixes it for all twenty-one channel sliders without adding a parameter to any of them: a slider reads the track height from the theme, so setting it once reaches every one. enabled stays an explicit parameter, because it is state rather than theme and the same guidelines warn against implicit inputs. A picker refuses pointer input at its own level as well as passing enabled down, so a slot replaced to change a label cannot be left live inside a disabled picker by a call site that forgot to forward it. Such a slider is inert but undimmed, which is the one seam in this; the alternative is the implicit input the guidelines warn about. Disabled drawing is a single disabledAlpha on ColorPickerColors rather than a parallel palette, since a picker's track is a gradient of the colours being chosen and there is no fixed colour to swap in. PickerConfigurationTest covers a replaced slot being drawn, inheriting the picker's colours unforwarded, a themed track height reaching a slider, and a disabled picker refusing a drag on a slot that never saw enabled. The last one needs the drag to land on the track to mean anything, so the enabled case is asserted beside it: without that control the disabled assertions pass whether or not the gesture ever reached a slider. The fourteen screenshot references are unchanged.
The pickers gained an enabled parameter with nothing demonstrating it. The sample now carries a switch beside the coloring mode buttons that every slider and plane below reads, so the whole screen greys out together and the difference is something you can look at rather than infer from a parameter list. Two tests come with it, because refusing a gesture and looking refused are separate things and only the first was covered. Both measure how much colour is left in the track and the plane surface β how far apart the channels stay across a row β since dimming over the background flattens that rather than moving it in any one direction. The slider and the plane dim through different code, so they are checked separately. Verified on a Pixel 6 Pro as well: at one colour, with the switch thrown, the plane's saturated corner goes pale while the swatch above it, which belongs to no picker, stays as it was.
The file is about to carry how a disabled control looks as well as whether it takes input, and the old name only covers the second.
Dimming to 38% is the Material convention and it is what a disabled picker did. It is a poor fit for this one control. A picker's track is made of the colours being chosen, so dimming shows paler versions of real colours β a wrong answer rather than an absent one β and alpha composites against a background the library does not own, so the same value pales the track on white and darkens it on black. Draining the colour has neither problem: it is background independent, and grey claims nothing. It is not strictly better either, since a fully grey saturation track can read as a legitimate low-saturation choice rather than as switched off. So both are knobs. disabledAlpha keeps the Material default of 0.38 and disabledSaturation arrives at 1, which leaves colour alone, so nothing changes until a caller asks. Either at its neutral value switches it off, giving dimming, draining, both or neither, and both are applied in one layer so asking for both costs no more than one. disabledAppearance replaces the two alpha layers ColorSlider used, so the labels dim with the track they belong to rather than staying lit above a greyed-out control.
smelfungus
force-pushed
the
feat/picker-configurability
branch
from
September 16, 2026 00:49
16c450d to
fb980a6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The six full pickers took state, modifier, showAlpha, coloringMode, colors and shapes, and nothing else. The English labels and screen-reader strings could not be changed without rebuilding a picker out of its sliders; the dialog forwarded its own title and buttons but nothing to the picker inside it; the string "enabled" appeared nowhere in the public API, so nothing could be greyed out; trackHeight existed only on the low-level ColorSlider; and the custom thumb the README demonstrates could not be handed to a picker at all, though the prose beside it says every slider takes one.
The androidx component guidelines rule out the obvious fix. A String parameter "restricts styling choice" β no AnnotatedString, no icon, no choice of component β and Material 3 takes DatePicker's title and headline as slots for the same reason. So each slider is a slot, defaulted to the channel slider it names, and localizing is replacing one.
That leaves what a replacement would otherwise have to re-declare. Rather than a receiver scope, which the same guidelines reserve for layout APIs, colors and shapes move into CompositionLocals read in parameter defaults β the one use those guidelines sanction, on the condition that the read happens in the default so an explicit argument still wins. A picker provides them, so a replaced slot inherits without the call site forwarding anything.
ColorPickerDimensions joins them, bundling the loose constants. That is what fixes trackHeight, and it fixes it for all twenty-one channel sliders without adding a parameter to any of them: a slider reads the track height from the theme, so setting it once reaches every one.
enabled stays an explicit parameter, because it is state rather than theme and the same guidelines warn against implicit inputs. A picker refuses pointer input at its own level as well as passing enabled down, so a slot replaced to change a label cannot be left live inside a disabled picker by a call site that forgot to forward it. Such a slider is inert but undimmed, which is the one seam in this; the alternative is the implicit input the guidelines warn about. Disabled drawing is a single disabledAlpha on ColorPickerColors rather than a parallel palette, since a picker's track is a gradient of the colours being chosen and there is no fixed colour to swap in.
PickerConfigurationTest covers a replaced slot being drawn, inheriting the picker's colours unforwarded, a themed track height reaching a slider, and a disabled picker refusing a drag on a slot that never saw enabled. The last one needs the drag to land on the track to mean anything, so the enabled case is asserted beside it: without that control the disabled assertions pass whether or not the gesture ever reached a slider.
The fourteen screenshot references are unchanged.