VerifyScreen: pin scroll shadows to divider edges
Top shadow: 16dp box immediately below the top divider, drawn as a downward gradient. Appears when scrolled past first item. Bottom shadow: 16dp box immediately above the bottom divider, drawn as an upward gradient. Disappears when last item is visible. Content scrolls under both edges — shadows are structural, not floating.
This commit is contained in:
@@ -76,15 +76,16 @@ fun VerifyScreen(state: AppState) {
|
|||||||
|
|
||||||
Spacer(Modifier.height(16.dp))
|
Spacer(Modifier.height(16.dp))
|
||||||
Text("Results", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold)
|
Text("Results", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold)
|
||||||
Spacer(Modifier.height(8.dp))
|
Spacer(Modifier.height(4.dp))
|
||||||
|
HorizontalDivider()
|
||||||
|
|
||||||
// Scrollable results list with top + bottom shadows
|
// Scrollable results list — shadows are pinned to the divider edges
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
val topShadowAlpha by remember {
|
val topShadowAlpha by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
val scrolled = listState.firstVisibleItemScrollOffset +
|
val scrolled = listState.firstVisibleItemScrollOffset +
|
||||||
listState.firstVisibleItemIndex * 80 // approximate
|
listState.firstVisibleItemIndex * 80
|
||||||
(scrolled / 60f).coerceIn(0f, 1f)
|
(scrolled / 60f).coerceIn(0f, 1f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,56 +94,61 @@ fun VerifyScreen(state: AppState) {
|
|||||||
val info = listState.layoutInfo
|
val info = listState.layoutInfo
|
||||||
val lastVisible = info.visibleItemsInfo.lastOrNull()
|
val lastVisible = info.visibleItemsInfo.lastOrNull()
|
||||||
val total = info.totalItemsCount
|
val total = info.totalItemsCount
|
||||||
if (lastVisible == null || lastVisible.index >= total - 1) 0f
|
if (lastVisible == null || lastVisible.index >= total - 1) 0f else 1f
|
||||||
else 1f // snap off at bottom is fine here since it's item-based not pixel
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Top edge: shadow drawn below the divider line above the list
|
||||||
|
if (topShadowAlpha > 0f) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.fillMaxWidth()
|
||||||
|
.height(16.dp)
|
||||||
.drawWithContent {
|
.drawWithContent {
|
||||||
drawContent()
|
drawContent()
|
||||||
// Top shadow — appears when scrolled down
|
|
||||||
if (topShadowAlpha > 0f) {
|
|
||||||
drawRect(
|
drawRect(
|
||||||
brush = Brush.verticalGradient(
|
brush = Brush.verticalGradient(
|
||||||
colors = listOf(
|
colors = listOf(
|
||||||
Color.Black.copy(alpha = 0.08f * topShadowAlpha),
|
Color.Black.copy(alpha = 0.10f * topShadowAlpha),
|
||||||
Color.Transparent,
|
Color.Transparent,
|
||||||
),
|
),
|
||||||
startY = 0f,
|
|
||||||
endY = 24.dp.toPx(),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Bottom shadow — fades as last item approaches view
|
|
||||||
if (bottomShadowAlpha > 0f) {
|
|
||||||
drawRect(
|
|
||||||
brush = Brush.verticalGradient(
|
|
||||||
colors = listOf(
|
|
||||||
Color.Transparent,
|
|
||||||
Color.Black.copy(alpha = 0.08f * bottomShadowAlpha),
|
|
||||||
),
|
|
||||||
startY = size.height - 24.dp.toPx(),
|
|
||||||
endY = size.height,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
) {
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = listState,
|
state = listState,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.weight(1f),
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
|
contentPadding = PaddingValues(vertical = 4.dp),
|
||||||
) {
|
) {
|
||||||
items(r.results, key = { it.photo.devicePath }) { copyResult ->
|
items(r.results, key = { it.photo.devicePath }) { copyResult ->
|
||||||
CopyResultRow(copyResult)
|
CopyResultRow(copyResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bottom edge: shadow drawn above the divider line below the list
|
||||||
|
if (bottomShadowAlpha > 0f) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(16.dp)
|
||||||
|
.drawWithContent {
|
||||||
|
drawContent()
|
||||||
|
drawRect(
|
||||||
|
brush = Brush.verticalGradient(
|
||||||
|
colors = listOf(
|
||||||
|
Color.Transparent,
|
||||||
|
Color.Black.copy(alpha = 0.10f * bottomShadowAlpha),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(Modifier.height(16.dp))
|
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
Spacer(Modifier.height(12.dp))
|
Spacer(Modifier.height(12.dp))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user