From 4fa62ecf5cdc47c58239d92f92bc78a589c769e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mate=C4=8Dn=C3=BD?= Date: Fri, 20 Oct 2023 17:16:34 +0200 Subject: [PATCH] Add option to define custom switch icons --- .../kiwi/orbit/compose/ui/controls/Switch.kt | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/ui/src/androidMain/kotlin/kiwi/orbit/compose/ui/controls/Switch.kt b/ui/src/androidMain/kotlin/kiwi/orbit/compose/ui/controls/Switch.kt index 987614edf..90481ea6a 100644 --- a/ui/src/androidMain/kotlin/kiwi/orbit/compose/ui/controls/Switch.kt +++ b/ui/src/androidMain/kotlin/kiwi/orbit/compose/ui/controls/Switch.kt @@ -34,17 +34,22 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.paint import androidx.compose.ui.draw.shadow import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp +import kiwi.orbit.compose.icons.Icons import kiwi.orbit.compose.ui.OrbitTheme import kiwi.orbit.compose.ui.controls.internal.OrbitPreviews import kiwi.orbit.compose.ui.controls.internal.Preview @@ -60,6 +65,25 @@ public fun Switch( modifier: Modifier = Modifier, enabled: Boolean = true, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, +) { + Switch( + checked = checked, + onCheckedChange = onCheckedChange, + modifier = modifier, + icon = null, + enabled = enabled, + interactionSource = interactionSource, + ) +} + +@Composable +public fun Switch( + checked: Boolean, + onCheckedChange: ((Boolean) -> Unit)?, + icon: Painter?, + modifier: Modifier = Modifier, + enabled: Boolean = true, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, ) { val density = LocalDensity.current val toggleableModifier = @@ -107,6 +131,7 @@ public fun Switch( SwitchImpl( checked = checked, enabled = enabled, + icon = icon, state = swipeableState, interactionSource = interactionSource, ) @@ -117,6 +142,7 @@ public fun Switch( private fun BoxScope.SwitchImpl( checked: Boolean, enabled: Boolean, + icon: Painter?, state: SwipeableV2State, interactionSource: InteractionSource, ) { @@ -152,6 +178,12 @@ private fun BoxScope.SwitchImpl( } }, ) + SwitchTrack(mainColor) + SwitchThumb(state, interactionSource, enabled, elevation, icon, mainColor) +} + +@Composable +private fun BoxScope.SwitchTrack(mainColor: Color) { Canvas( Modifier .align(Alignment.Center) @@ -159,6 +191,17 @@ private fun BoxScope.SwitchImpl( ) { drawTrack(mainColor, TrackWidth.toPx(), TrackStrokeWidth.toPx()) } +} + +@Composable +private fun BoxScope.SwitchThumb( + state: SwipeableV2State, + interactionSource: InteractionSource, + enabled: Boolean, + elevation: Dp, + icon: Painter?, + mainColor: Color, +) { Spacer( Modifier .align(Alignment.CenterStart) @@ -186,7 +229,15 @@ private fun BoxScope.SwitchImpl( ) .background(OrbitTheme.colors.surface.main, CircleShape) .padding((ThumbDiameter - ThumbInnerDiameter - ThumbStrokeWidth * 2) / 2) - .background(mainColor, CircleShape), + .then( + if (icon != null) { + Modifier.paint(painter = icon, colorFilter = ColorFilter.tint(mainColor)) + } else { + Modifier + .padding(ThumbInnerPadding) + .background(mainColor, CircleShape) + }, + ), ) } @@ -235,7 +286,8 @@ private val TrackWidth = SwitchWidth - SwitchPadding * 2 private val TrackStrokeWidth = SwitchHeight - SwitchPadding * 2 private val ThumbDiameter = SwitchHeight private val ThumbStrokeWidth = 0.5.dp -private val ThumbInnerDiameter = 10.dp +private val ThumbInnerDiameter = 16.dp +private val ThumbInnerPadding = 3.dp private val ThumbRippleRadius = 24.dp private val AnimationSpec = TweenSpec(durationMillis = 100) @@ -255,6 +307,7 @@ internal fun SwitchPreview() { Switch( checked = true, onCheckedChange = {}, + icon = Icons.Circle, ) Switch( checked = false,