diff options
11 files changed, 802 insertions, 28 deletions
@@ -11,7 +11,7 @@ <p align="center"> 🎨 Kotlin Multiplatform color picker library that allows you to get colors from any images like gallery pictures by tapping on the desired color. -Also, it ships with alpha, brightness, hue, and saturation sliders to adjust ARGB and HSV factors, plus gesture lifecycle callbacks for fine-grained interaction handling. +Also, it ships with alpha, brightness, hue, and saturation sliders that run horizontally or vertically to adjust ARGB and HSV factors, plus gesture lifecycle callbacks for fine-grained interaction handling. </p> ## Preview @@ -33,7 +33,7 @@ If you're using Version Catalog, you can configure the dependency by adding it t ```toml [versions] #... -colorpicker = "1.2.0" +colorpicker = "1.3.0" [libraries] #... @@ -45,7 +45,7 @@ Add the dependency below to your **module**'s `build.gradle.kts` file: ```gradle dependencies { - implementation("com.github.skydoves:colorpicker-compose:1.2.0") + implementation("com.github.skydoves:colorpicker-compose:1.3.0") // if you're using Version Catalog implementation(libs.compose.colorpicker) @@ -146,6 +146,10 @@ ImageColorPicker( ) ``` +`FIT` leaves bands beside the palette when the image and the canvas have different shapes, and an +image can carry transparent pixels. Neither has a color to offer, so a tap there leaves the +selection where it was instead of reporting the nearest edge pixel. + <img src="preview/preview2.gif" width="270" align="right"> ### HsvColorPicker diff --git a/buildSrc/src/main/kotlin/com/github/skydoves/colorpicker/compose/Configuration.kt b/buildSrc/src/main/kotlin/com/github/skydoves/colorpicker/compose/Configuration.kt index 085e3c6..eb73a9c 100644 --- a/buildSrc/src/main/kotlin/com/github/skydoves/colorpicker/compose/Configuration.kt +++ b/buildSrc/src/main/kotlin/com/github/skydoves/colorpicker/compose/Configuration.kt @@ -6,10 +6,10 @@ object Configuration { const val minSdk = 21 const val demoMinSdk = 24 const val majorVersion = 1 - const val minorVersion = 2 + const val minorVersion = 3 const val patchVersion = 0 const val versionName = "$majorVersion.$minorVersion.$patchVersion" - const val versionCode = 16 + const val versionCode = 17 const val snapshotVersionName = "$majorVersion.$minorVersion.${patchVersion + 1}-SNAPSHOT" const val artifactGroup = "com.github.skydoves" } diff --git a/docs/src/wasmJsMain/kotlin/docs/DocsApp.kt b/docs/src/wasmJsMain/kotlin/docs/DocsApp.kt index 419b14a..9066866 100644 --- a/docs/src/wasmJsMain/kotlin/docs/DocsApp.kt +++ b/docs/src/wasmJsMain/kotlin/docs/DocsApp.kt @@ -33,7 +33,9 @@ import docs.screen.ApiAlphaTileScreen import docs.screen.ApiBrightnessSliderScreen import docs.screen.ApiControllerScreen import docs.screen.ApiHsvColorPickerScreen +import docs.screen.ApiHueSliderScreen import docs.screen.ApiImageColorPickerScreen +import docs.screen.ApiSaturationSliderScreen import docs.screen.GettingStartedScreen import docs.screen.HomeScreen import docs.screen.InstallationScreen @@ -70,6 +72,8 @@ fun DocsApp() { DocsRoute.ApiImageColorPicker -> ApiImageColorPickerScreen() DocsRoute.ApiAlphaSlider -> ApiAlphaSliderScreen() DocsRoute.ApiBrightnessSlider -> ApiBrightnessSliderScreen() + DocsRoute.ApiHueSlider -> ApiHueSliderScreen() + DocsRoute.ApiSaturationSlider -> ApiSaturationSliderScreen() DocsRoute.ApiAlphaTile -> ApiAlphaTileScreen() DocsRoute.ApiController -> ApiControllerScreen() DocsRoute.Playground -> PlaygroundScreen() diff --git a/docs/src/wasmJsMain/kotlin/docs/navigation/DocsRoute.kt b/docs/src/wasmJsMain/kotlin/docs/navigation/DocsRoute.kt index 3b342d9..dd71af1 100644 --- a/docs/src/wasmJsMain/kotlin/docs/navigation/DocsRoute.kt +++ b/docs/src/wasmJsMain/kotlin/docs/navigation/DocsRoute.kt @@ -24,6 +24,8 @@ sealed class DocsRoute(val path: String, val title: String) { data object ApiImageColorPicker : DocsRoute("/api/image-color-picker", "ImageColorPicker") data object ApiAlphaSlider : DocsRoute("/api/alpha-slider", "AlphaSlider") data object ApiBrightnessSlider : DocsRoute("/api/brightness-slider", "BrightnessSlider") + data object ApiHueSlider : DocsRoute("/api/hue-slider", "HueSlider") + data object ApiSaturationSlider : DocsRoute("/api/saturation-slider", "SaturationSlider") data object ApiAlphaTile : DocsRoute("/api/alpha-tile", "AlphaTile") data object ApiController : DocsRoute("/api/controller", "ColorPickerController") data object Playground : DocsRoute("/playground", "Playground") @@ -35,6 +37,8 @@ sealed class DocsRoute(val path: String, val title: String) { ApiImageColorPicker, ApiAlphaSlider, ApiBrightnessSlider, + ApiHueSlider, + ApiSaturationSlider, ApiAlphaTile, ApiController, ) diff --git a/docs/src/wasmJsMain/kotlin/docs/screen/ApiAlphaSliderScreen.kt b/docs/src/wasmJsMain/kotlin/docs/screen/ApiAlphaSliderScreen.kt index e0df00b..9b5ebf4 100644 --- a/docs/src/wasmJsMain/kotlin/docs/screen/ApiAlphaSliderScreen.kt +++ b/docs/src/wasmJsMain/kotlin/docs/screen/ApiAlphaSliderScreen.kt @@ -140,6 +140,72 @@ fun ApiAlphaSliderScreen() { type = "Dp", description = "Size of each tile in the transparency pattern", ) + ParameterItem( + name = "wheelAlpha", + type = "Float", + description = "Alpha applied to the wheel indicator", + ) + ParameterItem( + name = "wheelPaint", + type = "Paint", + description = "Paint used to draw the wheel indicator", + ) + ParameterItem( + name = "initialColor", + type = "Color?", + description = "Color the slider starts from, or the controller's current color when null", + ) + ParameterItem( + name = "orientation", + type = "SliderOrientation", + description = "Horizontal by default, or Vertical to run bottom to top", + ) + ParameterItem( + name = "onColorChanged", + type = "(ColorEnvelope) -> Unit", + description = "Invoked with the color the controller ends up on, so the slider " + + "works without a picker", + ) + ParameterItem( + name = "onStart", + type = "() -> Unit", + description = "Invoked when the user starts interacting with the slider", + ) + ParameterItem( + name = "onFinish", + type = "() -> Unit", + description = "Invoked when the user stops interacting with the slider", + ) + + Spacer(modifier = Modifier.height(32.dp)) + + // Orientation + Text( + text = "Orientation", + style = DocsTheme.typography.h2, + color = DocsTheme.colors.onBackground, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "Sliders run left to right by default. Pass orientation to stand one up instead, " + + "and it fills the height it is given with the lowest value at the bottom.", + style = DocsTheme.typography.body, + color = DocsTheme.colors.onSurface, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + CodeBlock( + code = """AlphaSlider( + modifier = Modifier + .width(35.dp) + .height(300.dp), + controller = controller, + orientation = SliderOrientation.Vertical, +)""", + ) Spacer(modifier = Modifier.height(32.dp)) diff --git a/docs/src/wasmJsMain/kotlin/docs/screen/ApiAlphaTileScreen.kt b/docs/src/wasmJsMain/kotlin/docs/screen/ApiAlphaTileScreen.kt index 0ba4f59..be8edcd 100644 --- a/docs/src/wasmJsMain/kotlin/docs/screen/ApiAlphaTileScreen.kt +++ b/docs/src/wasmJsMain/kotlin/docs/screen/ApiAlphaTileScreen.kt @@ -94,6 +94,11 @@ fun ApiAlphaTileScreen() { description = "Controller that provides the current color", ) ParameterItem( + name = "selectedColor", + type = "Color", + description = "Color shown over the tiles when no controller is given", + ) + ParameterItem( name = "tileOddColor", type = "Color", description = "Color of odd tiles in the checkered pattern (default: White)", diff --git a/docs/src/wasmJsMain/kotlin/docs/screen/ApiBrightnessSliderScreen.kt b/docs/src/wasmJsMain/kotlin/docs/screen/ApiBrightnessSliderScreen.kt index be4a606..198a8d4 100644 --- a/docs/src/wasmJsMain/kotlin/docs/screen/ApiBrightnessSliderScreen.kt +++ b/docs/src/wasmJsMain/kotlin/docs/screen/ApiBrightnessSliderScreen.kt @@ -125,6 +125,72 @@ fun ApiBrightnessSliderScreen() { type = "ImageBitmap?", description = "Custom image for the wheel indicator", ) + ParameterItem( + name = "wheelAlpha", + type = "Float", + description = "Alpha applied to the wheel indicator", + ) + ParameterItem( + name = "wheelPaint", + type = "Paint", + description = "Paint used to draw the wheel indicator", + ) + ParameterItem( + name = "initialColor", + type = "Color?", + description = "Color the slider starts from, or the controller's current color when null", + ) + ParameterItem( + name = "orientation", + type = "SliderOrientation", + description = "Horizontal by default, or Vertical to run bottom to top", + ) + ParameterItem( + name = "onColorChanged", + type = "(ColorEnvelope) -> Unit", + description = "Invoked with the color the controller ends up on, so the slider " + + "works without a picker", + ) + ParameterItem( + name = "onStart", + type = "() -> Unit", + description = "Invoked when the user starts interacting with the slider", + ) + ParameterItem( + name = "onFinish", + type = "() -> Unit", + description = "Invoked when the user stops interacting with the slider", + ) + + Spacer(modifier = Modifier.height(32.dp)) + + // Orientation + Text( + text = "Orientation", + style = DocsTheme.typography.h2, + color = DocsTheme.colors.onBackground, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "Sliders run left to right by default. Pass orientation to stand one up instead, " + + "and it fills the height it is given with the lowest value at the bottom.", + style = DocsTheme.typography.body, + color = DocsTheme.colors.onSurface, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + CodeBlock( + code = """BrightnessSlider( + modifier = Modifier + .width(35.dp) + .height(300.dp), + controller = controller, + orientation = SliderOrientation.Vertical, +)""", + ) Spacer(modifier = Modifier.height(32.dp)) diff --git a/docs/src/wasmJsMain/kotlin/docs/screen/ApiHsvColorPickerScreen.kt b/docs/src/wasmJsMain/kotlin/docs/screen/ApiHsvColorPickerScreen.kt index 4782975..007c1f9 100644 --- a/docs/src/wasmJsMain/kotlin/docs/screen/ApiHsvColorPickerScreen.kt +++ b/docs/src/wasmJsMain/kotlin/docs/screen/ApiHsvColorPickerScreen.kt @@ -101,33 +101,44 @@ fun ApiHsvColorPickerScreen() { ) ParameterItem( name = "initialColor", - type = "Color", - description = "Initial color to be selected (default: White)", + type = "Color?", + description = "Color selected on the first layout pass, or the center of the wheel when null", ) ParameterItem( - name = "wheelRadius", - type = "Dp", - description = "Radius of the selector wheel indicator", + name = "wheelImageBitmap", + type = "ImageBitmap?", + description = "Custom image drawn in place of the default indicator", ) ParameterItem( - name = "wheelColor", - type = "Color", - description = "Color of the wheel indicator", + name = "drawOnPosSelected", + type = "(DrawScope.() -> Unit)?", + description = "Draws anything you like at the selected position", ) ParameterItem( - name = "wheelAlpha", - type = "Float", - description = "Alpha value of the wheel indicator", + name = "drawDefaultWheelIndicator", + type = "Boolean", + description = "Whether to draw the built in indicator, off by default once you " + + "pass a wheel image or a draw block", ) ParameterItem( - name = "wheelImageBitmap", - type = "ImageBitmap?", - description = "Custom image for the wheel indicator", + name = "onColorChanged", + type = "(ColorEnvelope) -> Unit", + description = "Invoked for every step of a gesture", ) ParameterItem( - name = "onColorChanged", + name = "onColorPickingFinished", type = "(ColorEnvelope) -> Unit", - description = "Callback invoked when color changes", + description = "Invoked once when a tap lands or a drag ends", + ) + ParameterItem( + name = "onStart", + type = "() -> Unit", + description = "Invoked when the user starts interacting with the picker", + ) + ParameterItem( + name = "onFinish", + type = "() -> Unit", + description = "Invoked when the user stops interacting with the picker", ) Spacer(modifier = Modifier.height(32.dp)) @@ -160,6 +171,39 @@ fun ApiHsvColorPickerScreen() { Spacer(modifier = Modifier.height(32.dp)) + Text( + text = "Knowing when a pick is finished", + style = DocsTheme.typography.h2, + color = DocsTheme.colors.onBackground, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "onColorChanged fires for every step of a drag, which is more often than you want " + + "for saving a choice or logging one. onColorPickingFinished fires once, when the " + + "gesture is over.", + style = DocsTheme.typography.body, + color = DocsTheme.colors.onSurface, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + CodeBlock( + code = """HsvColorPicker( + modifier = Modifier.fillMaxWidth().height(450.dp), + controller = controller, + onColorChanged = { colorEnvelope: ColorEnvelope -> + preview(colorEnvelope.color) // every step of the drag + }, + onColorPickingFinished = { colorEnvelope: ColorEnvelope -> + save(colorEnvelope.color) // once, when the finger lifts + }, +)""", + ) + + Spacer(modifier = Modifier.height(32.dp)) + Callout( text = "Note: HsvColorPicker draws its own palette, so setPaletteImageBitmap() on the " + "controller and the paletteContentScale parameter are for ImageColorPicker only.", diff --git a/docs/src/wasmJsMain/kotlin/docs/screen/ApiHueSliderScreen.kt b/docs/src/wasmJsMain/kotlin/docs/screen/ApiHueSliderScreen.kt new file mode 100644 index 0000000..8ee52a1 --- /dev/null +++ b/docs/src/wasmJsMain/kotlin/docs/screen/ApiHueSliderScreen.kt @@ -0,0 +1,277 @@ +/* + * Designed and developed by 2022 skydoves (Jaewoong Eum) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docs.screen + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import docs.component.CodeBlock +import docs.theme.DocsTheme + +@Composable +fun ApiHueSliderScreen() { + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(32.dp), + ) { + Text( + text = "HueSlider", + style = DocsTheme.typography.h1, + color = DocsTheme.colors.onBackground, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "A slider component that allows users to adjust the hue component of the " + + "selected color. The slider displays the full hue wheel as a gradient, running " + + "red, yellow, green, cyan, blue, magenta, and back around to red, so every hue " + + "is reachable in a single drag.", + style = DocsTheme.typography.body, + color = DocsTheme.colors.onSurfaceVariant, + ) + + Spacer(modifier = Modifier.height(32.dp)) + + // Basic Usage + Text( + text = "Basic Usage", + style = DocsTheme.typography.h2, + color = DocsTheme.colors.onBackground, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + CodeBlock( + code = """HueSlider( + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + .height(35.dp), + controller = controller, +)""", + ) + + Spacer(modifier = Modifier.height(32.dp)) + + // Parameters + Text( + text = "Parameters", + style = DocsTheme.typography.h2, + color = DocsTheme.colors.onBackground, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + ParameterItem( + name = "modifier", + type = "Modifier", + description = "Modifier to be applied to the slider (default: Modifier)", + ) + ParameterItem( + name = "controller", + type = "ColorPickerController", + description = "Controller that manages the color picker state (required)", + ) + ParameterItem( + name = "borderRadius", + type = "Dp", + description = "Corner radius of the slider border (default: 6.dp)", + ) + ParameterItem( + name = "borderSize", + type = "Dp", + description = "Thickness of the slider border (default: 5.dp)", + ) + ParameterItem( + name = "borderColor", + type = "Color", + description = "Color of the slider border (default: Color.LightGray)", + ) + ParameterItem( + name = "wheelImageBitmap", + type = "ImageBitmap?", + description = "Custom image drawn instead of the default circular wheel (default: null)", + ) + ParameterItem( + name = "wheelRadius", + type = "Dp", + description = "Radius of the slider wheel indicator (default: 12.dp)", + ) + ParameterItem( + name = "wheelColor", + type = "Color", + description = "Color of the wheel indicator (default: Color.White)", + ) + ParameterItem( + name = "wheelAlpha", + type = "Float", + description = "Alpha value applied to the wheel indicator (default: 1.0f)", + ) + ParameterItem( + name = "wheelPaint", + type = "Paint", + description = "Paint used to draw the wheel indicator " + + "(default: a Paint built from wheelColor and wheelAlpha)", + ) + ParameterItem( + name = "initialColor", + type = "Color?", + description = "Color the slider starts on. When null, the slider follows the " + + "controller's current color (default: null)", + ) + ParameterItem( + name = "orientation", + type = "SliderOrientation", + description = "Whether the slider runs left to right (Horizontal) or bottom to top " + + "(Vertical). A horizontal slider fills the width it is given, a vertical one fills " + + "the height (default: SliderOrientation.Horizontal)", + ) + ParameterItem( + name = "onColorChanged", + type = "(ColorChangeSource, Float) -> Unit", + description = "Callback invoked when the hue changes. It receives the " + + "ColorChangeSource (Tap, Drag, or Programmatic) and the position along the slider " + + "as a Float in 0f..1f. That Float is a normalized position, NOT degrees, so " + + "multiply it by 360f when you need the hue angle (default: no-op)", + ) + ParameterItem( + name = "onStart", + type = "() -> Unit", + description = "Callback invoked when user interaction with the slider starts " + + "(default: no-op)", + ) + ParameterItem( + name = "onFinish", + type = "() -> Unit", + description = "Callback invoked when user interaction with the slider ends " + + "(default: no-op)", + ) + + Spacer(modifier = Modifier.height(32.dp)) + + // Customization + Text( + text = "Customization", + style = DocsTheme.typography.h2, + color = DocsTheme.colors.onBackground, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "You can customize the appearance of the slider:", + style = DocsTheme.typography.body, + color = DocsTheme.colors.onSurface, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + CodeBlock( + code = """HueSlider( + modifier = Modifier + .fillMaxWidth() + .height(35.dp), + controller = controller, + borderRadius = 6.dp, + borderSize = 5.dp, + borderColor = Color.LightGray, + wheelRadius = 30.dp, + wheelColor = Color.White, + wheelAlpha = 1.0f, +)""", + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Text( + text = "Set orientation to SliderOrientation.Vertical to run the slider bottom to " + + "top instead. A vertical slider fills the height it is given, so give it a height " + + "and a width:", + style = DocsTheme.typography.body, + color = DocsTheme.colors.onSurface, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + CodeBlock( + code = """HueSlider( + modifier = Modifier + .height(250.dp) + .width(35.dp), + controller = controller, + orientation = SliderOrientation.Vertical, +)""", + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Text( + text = "Observe the hue while the user drags. The Float reports the position along " + + "the slider in 0f..1f, so convert it to degrees yourself if that is what you need:", + style = DocsTheme.typography.body, + color = DocsTheme.colors.onSurface, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + CodeBlock( + code = """HueSlider( + modifier = Modifier + .fillMaxWidth() + .height(35.dp), + controller = controller, + onColorChanged = { source: ColorChangeSource, position: Float -> + // position is 0f..1f along the slider, not degrees + val hueDegrees = position * 360f + }, + onStart = { isDragging = true }, + onFinish = { isDragging = false }, +)""", + ) + + Spacer(modifier = Modifier.height(32.dp)) + } +} + +@Composable +private fun ParameterItem(name: String, type: String, description: String) { + Column( + modifier = Modifier.padding(vertical = 8.dp), + ) { + Text( + text = "$name: $type", + style = DocsTheme.typography.body, + color = DocsTheme.colors.primary, + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = description, + style = DocsTheme.typography.bodySmall, + color = DocsTheme.colors.onSurfaceVariant, + ) + } +} diff --git a/docs/src/wasmJsMain/kotlin/docs/screen/ApiImageColorPickerScreen.kt b/docs/src/wasmJsMain/kotlin/docs/screen/ApiImageColorPickerScreen.kt index 1b0123c..619c889 100644 --- a/docs/src/wasmJsMain/kotlin/docs/screen/ApiImageColorPickerScreen.kt +++ b/docs/src/wasmJsMain/kotlin/docs/screen/ApiImageColorPickerScreen.kt @@ -110,19 +110,45 @@ fun ApiImageColorPickerScreen() { description = "How to scale the palette image (FIT or CROP)", ) ParameterItem( - name = "wheelRadius", - type = "Dp", - description = "Radius of the selector wheel indicator", + name = "wheelImageBitmap", + type = "ImageBitmap?", + description = "Custom image drawn in place of the default indicator", ) ParameterItem( - name = "wheelColor", - type = "Color", - description = "Color of the wheel indicator", + name = "drawOnPosSelected", + type = "(DrawScope.() -> Unit)?", + description = "Draws anything you like at the selected position", + ) + ParameterItem( + name = "drawDefaultWheelIndicator", + type = "Boolean", + description = "Whether to draw the built in indicator, off by default once you " + + "pass a wheel image or a draw block", + ) + ParameterItem( + name = "previewImagePainter", + type = "Painter?", + description = "Shown instead of the palette in an Android Studio preview", ) ParameterItem( name = "onColorChanged", type = "(ColorEnvelope) -> Unit", - description = "Callback invoked when color changes", + description = "Invoked for every step of a gesture", + ) + ParameterItem( + name = "onColorPickingFinished", + type = "(ColorEnvelope) -> Unit", + description = "Invoked once when a tap lands or a drag ends", + ) + ParameterItem( + name = "onStart", + type = "() -> Unit", + description = "Invoked when the user starts interacting with the picker", + ) + ParameterItem( + name = "onFinish", + type = "() -> Unit", + description = "Invoked when the user stops interacting with the picker", ) Spacer(modifier = Modifier.height(32.dp)) diff --git a/docs/src/wasmJsMain/kotlin/docs/screen/ApiSaturationSliderScreen.kt b/docs/src/wasmJsMain/kotlin/docs/screen/ApiSaturationSliderScreen.kt new file mode 100644 index 0000000..38e7607 --- /dev/null +++ b/docs/src/wasmJsMain/kotlin/docs/screen/ApiSaturationSliderScreen.kt @@ -0,0 +1,278 @@ +/* + * Designed and developed by 2022 skydoves (Jaewoong Eum) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docs.screen + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import docs.component.CodeBlock +import docs.theme.DocsTheme + +@Composable +fun ApiSaturationSliderScreen() { + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(32.dp), + ) { + Text( + text = "SaturationSlider", + style = DocsTheme.typography.h1, + color = DocsTheme.colors.onBackground, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "A slider component that allows users to adjust the saturation component of " + + "the selected color. The slider displays a gradient of the currently selected hue, " + + "running from fully washed out on one end to fully saturated on the other. When a " + + "BrightnessSlider is attached to the same controller, the gradient is drawn at the " + + "current brightness as well.", + style = DocsTheme.typography.body, + color = DocsTheme.colors.onSurfaceVariant, + ) + + Spacer(modifier = Modifier.height(32.dp)) + + // Basic Usage + Text( + text = "Basic Usage", + style = DocsTheme.typography.h2, + color = DocsTheme.colors.onBackground, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + CodeBlock( + code = """SaturationSlider( + modifier = Modifier + .fillMaxWidth() + .padding(10.dp) + .height(35.dp), + controller = controller, +)""", + ) + + Spacer(modifier = Modifier.height(32.dp)) + + // Parameters + Text( + text = "Parameters", + style = DocsTheme.typography.h2, + color = DocsTheme.colors.onBackground, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + ParameterItem( + name = "modifier", + type = "Modifier", + description = "Modifier to be applied to the slider (default: Modifier)", + ) + ParameterItem( + name = "controller", + type = "ColorPickerController", + description = "Controller that manages the color picker state (required)", + ) + ParameterItem( + name = "borderRadius", + type = "Dp", + description = "Corner radius of the slider border (default: 6.dp)", + ) + ParameterItem( + name = "borderSize", + type = "Dp", + description = "Thickness of the slider border (default: 5.dp)", + ) + ParameterItem( + name = "borderColor", + type = "Color", + description = "Color of the slider border (default: Color.LightGray)", + ) + ParameterItem( + name = "wheelImageBitmap", + type = "ImageBitmap?", + description = "Custom image drawn instead of the default circular wheel (default: null)", + ) + ParameterItem( + name = "wheelRadius", + type = "Dp", + description = "Radius of the slider wheel indicator (default: 12.dp)", + ) + ParameterItem( + name = "wheelColor", + type = "Color", + description = "Color of the wheel indicator (default: Color.White)", + ) + ParameterItem( + name = "wheelAlpha", + type = "Float", + description = "Alpha value applied to the wheel indicator (default: 1.0f)", + ) + ParameterItem( + name = "wheelPaint", + type = "Paint", + description = "Paint used to draw the wheel indicator " + + "(default: a Paint built from wheelColor and wheelAlpha)", + ) + ParameterItem( + name = "initialColor", + type = "Color?", + description = "Color the slider starts on. When null, the slider follows the " + + "controller's current color (default: null)", + ) + ParameterItem( + name = "orientation", + type = "SliderOrientation", + description = "Whether the slider runs left to right (Horizontal) or bottom to top " + + "(Vertical). A horizontal slider fills the width it is given, a vertical one fills " + + "the height (default: SliderOrientation.Horizontal)", + ) + ParameterItem( + name = "onColorChanged", + type = "(ColorEnvelope) -> Unit", + description = "Callback invoked with the ColorEnvelope the controller ends up on, " + + "carrying the color, its hex code, whether the change came from the user, and the " + + "ColorChangeSource. This is what makes the slider usable on its own, without a " + + "picker beside it (default: no-op)", + ) + ParameterItem( + name = "onStart", + type = "() -> Unit", + description = "Callback invoked when user interaction with the slider starts " + + "(default: no-op)", + ) + ParameterItem( + name = "onFinish", + type = "() -> Unit", + description = "Callback invoked when user interaction with the slider ends " + + "(default: no-op)", + ) + + Spacer(modifier = Modifier.height(32.dp)) + + // Customization + Text( + text = "Customization", + style = DocsTheme.typography.h2, + color = DocsTheme.colors.onBackground, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "You can customize the appearance of the slider:", + style = DocsTheme.typography.body, + color = DocsTheme.colors.onSurface, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + CodeBlock( + code = """SaturationSlider( + modifier = Modifier + .fillMaxWidth() + .height(35.dp), + controller = controller, + borderRadius = 6.dp, + borderSize = 5.dp, + borderColor = Color.LightGray, + wheelRadius = 30.dp, + wheelColor = Color.White, + wheelAlpha = 1.0f, +)""", + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Text( + text = "Set orientation to SliderOrientation.Vertical to run the slider bottom to " + + "top instead. A vertical slider fills the height it is given, so give it a height " + + "and a width:", + style = DocsTheme.typography.body, + color = DocsTheme.colors.onSurface, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + CodeBlock( + code = """SaturationSlider( + modifier = Modifier + .height(250.dp) + .width(35.dp), + controller = controller, + orientation = SliderOrientation.Vertical, +)""", + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Text( + text = "Because onColorChanged hands you a full ColorEnvelope, the slider can stand " + + "alone as the only color control on the screen:", + style = DocsTheme.typography.body, + color = DocsTheme.colors.onSurface, + ) + + Spacer(modifier = Modifier.height(16.dp)) + + CodeBlock( + code = """SaturationSlider( + modifier = Modifier + .fillMaxWidth() + .height(35.dp), + controller = controller, + onColorChanged = { colorEnvelope: ColorEnvelope -> + selectedColor = colorEnvelope.color + hexCode = colorEnvelope.hexCode + }, + onStart = { isDragging = true }, + onFinish = { isDragging = false }, +)""", + ) + + Spacer(modifier = Modifier.height(32.dp)) + } +} + +@Composable +private fun ParameterItem(name: String, type: String, description: String) { + Column( + modifier = Modifier.padding(vertical = 8.dp), + ) { + Text( + text = "$name: $type", + style = DocsTheme.typography.body, + color = DocsTheme.colors.primary, + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = description, + style = DocsTheme.typography.bodySmall, + color = DocsTheme.colors.onSurfaceVariant, + ) + } +} |
