From 168f660446bac0d9006ba5aa4ad5e477a011a892 Mon Sep 17 00:00:00 2001 From: gabriel20xx Date: Sun, 26 Oct 2025 14:20:29 +0100 Subject: [PATCH] feat: improve drag-and-drop functionality by interleaving dividers in ListsScreen and ManageColumnsDialog for better user experience --- .../app/ui/screens/ListDetailScreen.kt | 101 +++++++++--------- .../collabtable/app/ui/screens/ListsScreen.kt | 59 +++++----- 2 files changed, 88 insertions(+), 72 deletions(-) diff --git a/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListDetailScreen.kt b/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListDetailScreen.kt index 0b07240..09ed15d 100644 --- a/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListDetailScreen.kt +++ b/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListDetailScreen.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.ClickableText @@ -2540,48 +2539,56 @@ fun ManageColumnsDialog( .fillMaxWidth() .reorderable(reorderState), state = reorderState.listState, - contentPadding = PaddingValues(16.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), + contentPadding = PaddingValues(horizontal = 8.dp, vertical = 16.dp), + verticalArrangement = Arrangement.spacedBy(0.dp), ) { - itemsIndexed( - items = reorderedFields, - key = { _, field -> field.id }, - ) { index, field -> - ReorderableItem( - reorderState, - key = field.id, - ) { _ -> - Box( - modifier = Modifier.animateItemPlacement(), - ) { - if (index > 0) Divider() - ColumnItem( - field = field, - onEdit = { fieldToEdit = field }, - onDelete = { fieldToDelete = field }, - onMoveUp = { - if (index > 0) { - val item = reorderedFields.removeAt(index) - reorderedFields.add(index - 1, item) - } - }, - onMoveDown = { - if (index < reorderedFields.size - 1) { - val item = reorderedFields.removeAt(index) - reorderedFields.add(index + 1, item) - } - }, - canMoveUp = index > 0, - canMoveDown = index < reorderedFields.size - 1, - dragHandle = { - Icon( - imageVector = Icons.Default.DragHandle, - contentDescription = "Reorder", - modifier = Modifier.detectReorder(reorderState), - tint = MaterialTheme.colorScheme.onSurfaceVariant, - ) - }, - ) + // Interleave dividers as separate Lazy items so dividers don't move with dragged rows + items( + count = reorderedFields.size * 2 - 1, + key = { pos -> + if (pos % 2 == 0) reorderedFields[pos / 2].id else "divider-$pos" + }, + ) { pos -> + if (pos % 2 == 1) { + Divider() + } else { + val index = pos / 2 + val field = reorderedFields[index] + ReorderableItem( + reorderState, + key = field.id, + ) { _ -> + Box( + modifier = Modifier.animateItemPlacement(), + ) { + ColumnItem( + field = field, + onEdit = { fieldToEdit = field }, + onDelete = { fieldToDelete = field }, + onMoveUp = { + if (index > 0) { + val item = reorderedFields.removeAt(index) + reorderedFields.add(index - 1, item) + } + }, + onMoveDown = { + if (index < reorderedFields.size - 1) { + val item = reorderedFields.removeAt(index) + reorderedFields.add(index + 1, item) + } + }, + canMoveUp = index > 0, + canMoveDown = index < reorderedFields.size - 1, + dragHandle = { + Icon( + imageVector = Icons.Default.DragHandle, + contentDescription = "Reorder", + modifier = Modifier.detectReorder(reorderState), + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + }, + ) + } } } } @@ -2681,18 +2688,16 @@ fun ColumnItem( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 12.dp), + .padding(horizontal = 8.dp, vertical = 10.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { // Drag handle - Column(horizontalAlignment = Alignment.CenterHorizontally) { - if (dragHandle != null) { - dragHandle() - } + if (dragHandle != null) { + dragHandle() } - Spacer(modifier = Modifier.width(12.dp)) + Spacer(modifier = Modifier.width(8.dp)) Column(modifier = Modifier.weight(1f)) { Text( diff --git a/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListsScreen.kt b/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListsScreen.kt index 11a57e6..a91e7ae 100644 --- a/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListsScreen.kt +++ b/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListsScreen.kt @@ -2,7 +2,6 @@ package com.collabtable.app.ui.screens -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -14,8 +13,9 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Delete @@ -194,27 +194,38 @@ fun ListsScreen( .fillMaxSize() .reorderable(reorderState), state = reorderState.listState, - contentPadding = PaddingValues(16.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), + contentPadding = PaddingValues(horizontal = 8.dp, vertical = 8.dp), + verticalArrangement = Arrangement.spacedBy(0.dp), ) { - itemsIndexed(working, key = { _, it -> it.id }) { index, list -> - ReorderableItem(reorderState, key = list.id) { _ -> - Box(modifier = Modifier.animateItemPlacement()) { - if (index > 0) Divider() - ListItem( - list = list, - onListClick = { onNavigateToList(list.id) }, - onEditClick = { listToEdit = list }, - onDeleteClick = { listToDelete = list }, - dragHandle = { - Icon( - imageVector = Icons.Default.DragHandle, - contentDescription = "Reorder", - modifier = Modifier.detectReorder(reorderState), - tint = MaterialTheme.colorScheme.onSurfaceVariant, - ) - }, - ) + // Interleave dividers as separate list items so they don't move with dragged rows + items( + count = working.size * 2 - 1, + key = { pos -> + if (pos % 2 == 0) working[pos / 2].id else "divider-$pos" + }, + ) { pos -> + if (pos % 2 == 1) { + Divider() + } else { + val index = pos / 2 + val list = working[index] + ReorderableItem(reorderState, key = list.id) { _ -> + Box(modifier = Modifier.animateItemPlacement()) { + ListItem( + list = list, + onListClick = { onNavigateToList(list.id) }, + onEditClick = { listToEdit = list }, + onDeleteClick = { listToDelete = list }, + dragHandle = { + Icon( + imageVector = Icons.Default.DragHandle, + contentDescription = "Reorder", + modifier = Modifier.detectReorder(reorderState), + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + }, + ) + } } } } @@ -280,14 +291,14 @@ fun ListItem( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 12.dp), + .padding(horizontal = 12.dp, vertical = 8.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { // Drag handle on the far left if (dragHandle != null) { dragHandle() - Spacer(modifier = Modifier.padding(start = 8.dp)) + Spacer(modifier = Modifier.width(8.dp)) } // Table name centered/left and clickable