neiam
/waxx
waxx
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
android: scroll the subboard grid vertically
5662d6d · gmorell · 2026-06-25 15:36
Message
{commit_body(@commit)}
Files changed
modified
android/app/src/main/java/org/neiam/waxx/app/ui/BoardScreen.kt
+43
−14
@@ -19,6 +19,7 @@ import androidx.compose.foundation.lazy.LazyColumn
| 19 | 19 | import androidx.compose.foundation.lazy.items |
| 20 | 20 | import androidx.compose.foundation.rememberScrollState |
| 21 | 21 | import androidx.compose.foundation.shape.RoundedCornerShape |
| 22 | +import androidx.compose.foundation.verticalScroll | |
| 22 | 23 | import androidx.compose.ui.input.pointer.pointerInput |
| 23 | 24 | import androidx.compose.ui.layout.ContentScale |
| 24 | 25 | import androidx.compose.ui.layout.onGloballyPositioned |
@@ -353,6 +354,9 @@ private fun Kanban(
| 353 | 354 | } |
| 354 | 355 | |
| 355 | 356 | val scrollState = rememberScrollState() |
| 357 | + // Vertical scroll for the 2-D (subboard) grid so rows past the viewport | |
| 358 | + // aren't clipped. Unused in the 1-D layout (columns scroll themselves). | |
| 359 | + val verticalScrollState = rememberScrollState() | |
| 356 | 360 | var viewportBounds by remember { mutableStateOf<Rect?>(null) } |
| 357 | 361 | val density = LocalDensity.current |
| 358 | 362 | val edgePx = with(density) { 80.dp.toPx() } |
@@ -414,6 +418,7 @@ private fun Kanban(
| 414 | 418 | modifier = modifier |
| 415 | 419 | .onGloballyPositioned { viewportBounds = it.boundsInWindowSafe() } |
| 416 | 420 | .horizontalScroll(scrollState) |
| 421 | + .verticalScroll(verticalScrollState) | |
| 417 | 422 | .padding(horizontal = 8.dp, vertical = 8.dp), |
| 418 | 423 | verticalArrangement = Arrangement.spacedBy(8.dp), |
| 419 | 424 | ) { |
@@ -465,6 +470,7 @@ private fun Kanban(
| 465 | 470 | onOpenCard = onOpenCard, |
| 466 | 471 | onDropFinished = onDropFinished, |
| 467 | 472 | cellWidth = 240.dp, |
| 473 | + cardsScrollable = false, | |
| 468 | 474 | ) |
| 469 | 475 | } |
| 470 | 476 | } |
@@ -485,6 +491,10 @@ private fun StageCell(
| 485 | 491 | onOpenCard: (CardSummary) -> Unit, |
| 486 | 492 | onDropFinished: () -> Unit, |
| 487 | 493 | cellWidth: androidx.compose.ui.unit.Dp = 280.dp, |
| 494 | + // When the whole grid scrolls (2-D subboard layout), cells lay their cards | |
| 495 | + // out non-lazily so we don't nest a vertical scroll inside a vertical | |
| 496 | + // scroll. In the 1-D layout each column scrolls itself, so this stays true. | |
| 497 | + cardsScrollable: Boolean = true, | |
| 488 | 498 | ) { |
| 489 | 499 | val session = dragState.session |
| 490 | 500 | val isSource = session != null && |
@@ -553,20 +563,39 @@ private fun StageCell(
| 553 | 563 | ) |
| 554 | 564 | } |
| 555 | 565 | } else { |
| 556 | − LazyColumn( | |
| 557 | − verticalArrangement = Arrangement.spacedBy(4.dp), | |
| 558 | − contentPadding = PaddingValues(vertical = 2.dp), | |
| 559 | − ) { | |
| 560 | − items(cards.sortedBy { it.position }, key = { it.id }) { c -> | |
| 561 | − CardChip( | |
| 562 | − card = c, | |
| 563 | − fromStageId = stage.id, | |
| 564 | − fromSubboardId = subboard?.id, | |
| 565 | − creds = creds, | |
| 566 | − dragState = dragState, | |
| 567 | − onClick = { onOpenCard(c) }, | |
| 568 | − onDropFinished = onDropFinished, | |
| 569 | − ) | |
| 566 | + val sorted = cards.sortedBy { it.position } | |
| 567 | + if (cardsScrollable) { | |
| 568 | + LazyColumn( | |
| 569 | + verticalArrangement = Arrangement.spacedBy(4.dp), | |
| 570 | + contentPadding = PaddingValues(vertical = 2.dp), | |
| 571 | + ) { | |
| 572 | + items(sorted, key = { it.id }) { c -> | |
| 573 | + CardChip( | |
| 574 | + card = c, | |
| 575 | + fromStageId = stage.id, | |
| 576 | + fromSubboardId = subboard?.id, | |
| 577 | + creds = creds, | |
| 578 | + dragState = dragState, | |
| 579 | + onClick = { onOpenCard(c) }, | |
| 580 | + onDropFinished = onDropFinished, | |
| 581 | + ) | |
| 582 | + } | |
| 583 | + } | |
| 584 | + } else { | |
| 585 | + // Non-lazy: the whole grid scrolls, so nesting a scrollable | |
| 586 | + // list here would crash with infinite height constraints. | |
| 587 | + Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { | |
| 588 | + sorted.forEach { c -> | |
| 589 | + CardChip( | |
| 590 | + card = c, | |
| 591 | + fromStageId = stage.id, | |
| 592 | + fromSubboardId = subboard?.id, | |
| 593 | + creds = creds, | |
| 594 | + dragState = dragState, | |
| 595 | + onClick = { onOpenCard(c) }, | |
| 596 | + onDropFinished = onDropFinished, | |
| 597 | + ) | |
| 598 | + } | |
| 570 | 599 | } |
| 571 | 600 | } |
| 572 | 601 | } |
Parents: f4ed124