Skip to content

Commit e5ae864

Browse files
committed
feat(ui): add CornerBasedShape.inset() and use for concentric SlideToConfirm thumb
Add a reusable Shape.inset(Dp) extension that computes concentric corner radii for nested rounded rectangles. Use it in SlideToConfirm so the thumb corners run parallel to the track. Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent cd37620 commit e5ae864

2 files changed

Lines changed: 28 additions & 4 deletions

File tree

ui/components/src/main/kotlin/com/getcode/ui/components/SlideToConfirm.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import androidx.compose.ui.draw.alpha
4444
import androidx.compose.ui.draw.clip
4545
import androidx.compose.ui.graphics.Color
4646
import androidx.compose.ui.graphics.ColorFilter
47+
import androidx.compose.foundation.shape.CornerBasedShape
4748
import androidx.compose.ui.graphics.Shape
4849
import androidx.compose.ui.graphics.lerp
4950
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
@@ -61,6 +62,7 @@ import com.getcode.theme.CodeTheme
6162
import com.getcode.theme.DesignSystem
6263
import com.getcode.theme.White20
6364
import com.getcode.theme.White50
65+
import com.getcode.theme.inset
6466
import com.getcode.ui.theme.CodeCircularProgressIndicator
6567
import kotlinx.coroutines.CoroutineScope
6668
import kotlinx.coroutines.delay
@@ -99,8 +101,6 @@ private object Thumb {
99101
val Size: Dp
100102
@Composable get() = CodeTheme.dimens.grid.x12
101103
val Color = androidx.compose.ui.graphics.Color.White
102-
val Shape: Shape
103-
@Composable get() = CodeTheme.shapes.small
104104
}
105105

106106
private object Track {
@@ -146,7 +146,6 @@ fun SlideToConfirm(
146146
modifier: Modifier = Modifier,
147147
trackShape: Shape = Track.Shape,
148148
trackColor: Color = Track.Color,
149-
thumbShape: Shape = Thumb.Shape,
150149
enabled: Boolean = true,
151150
isLoading: Boolean = false,
152151
isSuccess: Boolean = false,
@@ -167,6 +166,7 @@ fun SlideToConfirm(
167166
val density = LocalDensity.current
168167
val thumbSize = Thumb.Size
169168
val horizontalPadding = CodeTheme.dimens.grid.x1
169+
val thumbShape = (trackShape as? CornerBasedShape)?.inset(horizontalPadding) ?: trackShape
170170
val overhead = with(density) { (2 * horizontalPadding + thumbSize).toPx() }
171171

172172
val swipeState = remember {
@@ -352,7 +352,7 @@ private fun Thumb(
352352
modifier: Modifier = Modifier,
353353
size: Dp = Thumb.Size,
354354
color: Color = Thumb.Color,
355-
shape: Shape = Thumb.Shape,
355+
shape: Shape = Track.Shape,
356356
) {
357357
Box(
358358
modifier = modifier

ui/theme/src/main/kotlin/com/getcode/theme/Shape.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package com.getcode.theme
22

33
import androidx.compose.foundation.shape.CornerBasedShape
4+
import androidx.compose.foundation.shape.CornerSize
45
import androidx.compose.foundation.shape.RoundedCornerShape
56
import androidx.compose.material.Shapes
67
import androidx.compose.runtime.Composable
8+
import androidx.compose.ui.geometry.Size
9+
import androidx.compose.ui.platform.LocalDensity
10+
import androidx.compose.ui.unit.Density
711
import androidx.compose.ui.unit.Dp
812
import androidx.compose.ui.unit.dp
13+
import androidx.compose.ui.unit.max
914
import com.getcode.view.shapes.TriangleCutShape
1015

1116
internal val shapes = Shapes(
@@ -26,3 +31,22 @@ val Shapes.xxl: CornerBasedShape
2631
@Composable
2732
fun Shapes.receipt(step: Dp = CodeTheme.dimens.grid.x2) = TriangleCutShape(step)
2833

34+
/**
35+
* Returns a new [RoundedCornerShape] whose corners are concentric with this shape,
36+
* inset by [inset]. Useful for nested rounded rectangles (e.g. a thumb inside a track)
37+
* where the inner corners should run parallel to the outer ones.
38+
*/
39+
@Composable
40+
fun CornerBasedShape.inset(inset: Dp): RoundedCornerShape {
41+
val density = LocalDensity.current
42+
// Use a large reference size so percentage-based CornerSizes resolve to absolute values.
43+
val ref = Size(10_000f, 10_000f)
44+
fun CornerSize.shrink(): Dp = max(0.dp, with(density) { toPx(ref, this).toDp() } - inset)
45+
return RoundedCornerShape(
46+
topStart = topStart.shrink(),
47+
topEnd = topEnd.shrink(),
48+
bottomEnd = bottomEnd.shrink(),
49+
bottomStart = bottomStart.shrink(),
50+
)
51+
}
52+

0 commit comments

Comments
 (0)