Skip to content

Commit 8661197

Browse files
committed
feat: add inner shadow
1 parent 63e5416 commit 8661197

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

app/src/main/java/to/bitkit/ui/components/Button.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import androidx.compose.ui.tooling.preview.Preview
3737
import androidx.compose.ui.unit.Dp
3838
import androidx.compose.ui.unit.dp
3939
import to.bitkit.ui.shared.util.gradientBackground
40+
import to.bitkit.ui.shared.util.innerShadow
4041
import to.bitkit.ui.theme.AppThemeSurface
4142
import to.bitkit.ui.theme.Colors
4243

@@ -92,6 +93,11 @@ fun PrimaryButton(
9293
Modifier.gradientBackground(startColor = Colors.Gray4, endColor = Colors.Gray5)
9394
}
9495
)
96+
.innerShadow(
97+
color = Colors.White.copy(alpha = if (isPressed) 0.1f else 0.05f),
98+
blurRadius = 4.dp,
99+
shape = shape
100+
)
95101
.then(if (enabled) Modifier else Modifier.alpha(0.32f))
96102
.clickable(
97103
onClick = onClick,

app/src/main/java/to/bitkit/ui/shared/util/Modifiers.kt

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,20 @@ import androidx.compose.runtime.mutableStateOf
1717
import androidx.compose.runtime.remember
1818
import androidx.compose.ui.Modifier
1919
import androidx.compose.ui.composed
20+
import androidx.compose.ui.draw.drawWithContent
21+
import androidx.compose.ui.geometry.Offset
22+
import androidx.compose.ui.geometry.Size
2023
import androidx.compose.ui.graphics.Brush
2124
import androidx.compose.ui.graphics.Color
25+
import androidx.compose.ui.graphics.Outline
26+
import androidx.compose.ui.graphics.Path
27+
import androidx.compose.ui.graphics.Shape
28+
import androidx.compose.ui.graphics.drawscope.clipPath
2229
import androidx.compose.ui.graphics.graphicsLayer
2330
import androidx.compose.ui.input.pointer.pointerInput
31+
import androidx.compose.ui.platform.LocalDensity
32+
import androidx.compose.ui.unit.Dp
33+
import androidx.compose.ui.unit.dp
2434
import to.bitkit.ui.theme.Colors
2535

2636
/**
@@ -79,6 +89,56 @@ fun Modifier.gradientBackground(startColor: Color = Colors.Gray6, endColor: Colo
7989
)
8090
}
8191

92+
/**
93+
* Draws an inner highlight at the top edge to create depth/volume effect.
94+
* Matches iOS shadow: .shadow(color: shadowColor, radius: 0, x: 0, y: -1)
95+
*
96+
* @param color The highlight color (typically white with alpha)
97+
* @param blurRadius The blur radius for soft edges (use 0.dp for sharp, 2-4.dp for smooth)
98+
* @param shape The shape to clip the highlight to (must match parent shape)
99+
*/
100+
fun Modifier.innerShadow(
101+
color: Color,
102+
blurRadius: Dp = 4.dp,
103+
shape: Shape,
104+
): Modifier = composed {
105+
val density = LocalDensity.current
106+
val blurRadiusPx = with(density) { blurRadius.toPx() }
107+
108+
this.drawWithContent {
109+
// Draw content first (gradient, etc)
110+
drawContent()
111+
112+
// Get shape outline for clipping
113+
val outline = shape.createOutline(size, layoutDirection, density)
114+
115+
// Convert outline to path
116+
val path = when (outline) {
117+
is Outline.Rectangle -> Path().apply { addRect(outline.rect) }
118+
is Outline.Rounded -> Path().apply { addRoundRect(outline.roundRect) }
119+
is Outline.Generic -> outline.path
120+
}
121+
122+
// Clip to shape and draw top edge highlight with soft gradient
123+
clipPath(path) {
124+
drawRect(
125+
brush = Brush.verticalGradient(
126+
colors = listOf(
127+
color,
128+
color.copy(alpha = color.alpha * 0.7f),
129+
color.copy(alpha = color.alpha * 0.3f),
130+
Color.Transparent
131+
),
132+
startY = 0f,
133+
endY = blurRadiusPx * 2.5f
134+
),
135+
topLeft = Offset(0f, 0f),
136+
size = Size(size.width, blurRadiusPx * 2.5f)
137+
)
138+
}
139+
}
140+
}
141+
82142
fun Modifier.blockPointerInputPassthrough(): Modifier {
83143
return this.pointerInput(Unit) {
84144
awaitPointerEventScope {

0 commit comments

Comments
 (0)