feat(ui): Implement reorder mode for shopping lists

Extends the reorder mode functionality to the main shopping lists screen.

- A long press on a shopping list card now activates reorder mode.
- In this mode, drag handles are shown on both the left and right sides of each card to support left- and right-handed use.
- Other actions (edit, delete, navigation) are disabled while in reorder mode.
- Navigating away from the screen via the drawer correctly disables the reorder mode.
This commit is contained in:
2025-10-12 21:52:33 +02:00
parent 69cdc03277
commit 6b80a06c2f
2 changed files with 30 additions and 13 deletions

View File

@@ -156,6 +156,7 @@ fun AppShell(
label = { Text(stringResource(id = screen.titleRes)) },
selected = screen == currentScreen,
onClick = {
shoppingListsViewModel.disableReorderMode()
currentScreen = screen
selectedListId = null
scope.launch { drawerState.close() }

View File

@@ -5,6 +5,7 @@ import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -66,6 +67,7 @@ fun ShoppingListsScreen(
onEditList: (ShoppingListWithItems) -> Unit
) {
val uiState by viewModel.uiState.collectAsState()
val isReorderMode by viewModel.isReorderMode.collectAsState()
val coroutineScope = rememberCoroutineScope()
Column(
@@ -91,10 +93,17 @@ fun ShoppingListsScreen(
viewModel.deleteList(it.shoppingList)
}
},
modifier = Modifier
.clickable { onListClick(listWithItems.shoppingList.id) },
modifier = Modifier.pointerInput(isReorderMode) {
if (!isReorderMode) {
detectTapGestures(
onLongPress = { viewModel.enableReorderMode() },
onTap = { onListClick(listWithItems.shoppingList.id) }
)
}
},
scope = this,
isDragging = isDragging
isDragging = isDragging,
isReorderMode = isReorderMode
)
}
}
@@ -112,16 +121,14 @@ fun ShoppingListCard(
onDeleteList: (ShoppingListWithItems) -> Unit,
modifier: Modifier = Modifier,
scope: ReorderableCollectionItemScope,
isDragging: Boolean
isDragging: Boolean,
isReorderMode: Boolean
) {
val elevation = animateDpAsState(if (isDragging) 0.dp else 0.dp, label = "elevation")
val elevation = animateDpAsState(if (isDragging) 4.dp else 1.dp, label = "elevation")
val scale = animateFloatAsState(if (isDragging) 1.05f else 1.0f, label = "scale")
val backgroundColor = animateColorAsState(
if (isDragging) MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.7f)
else Color.Transparent, label = "backgroundColor"
)
Card(
modifier = with(scope) { modifier.draggableHandle() }
modifier = modifier
.fillMaxWidth()
.padding(vertical = 4.dp, horizontal = 16.dp)
.graphicsLayer {
@@ -129,7 +136,6 @@ fun ShoppingListCard(
scaleY = scale.value
}
.shadow(elevation.value)
.background(backgroundColor.value)
) {
Column(modifier = Modifier.padding(16.dp)) {
Row(
@@ -137,17 +143,27 @@ fun ShoppingListCard(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
if (isReorderMode) {
IconButton(modifier = with(scope) { Modifier.draggableHandle() }, onClick = {}) {
Icon(Icons.Rounded.DragHandle, contentDescription = "Reorder")
}
}
Text(
text = listWithItems.shoppingList.name,
style = MaterialTheme.typography.titleMedium,
modifier = Modifier.weight(1f)
)
IconButton(onClick = { onEditList(listWithItems) }) {
IconButton(onClick = { onEditList(listWithItems) }, enabled = !isReorderMode) {
Icon(Icons.Default.Edit, contentDescription = stringResource(R.string.edit_list))
}
IconButton(onClick = { onDeleteList(listWithItems) }) {
IconButton(onClick = { onDeleteList(listWithItems) }, enabled = !isReorderMode) {
Icon(Icons.Default.Delete, contentDescription = stringResource(R.string.delete_list))
}
if (isReorderMode) {
IconButton(modifier = with(scope) { Modifier.draggableHandle() }, onClick = {}) {
Icon(Icons.Rounded.DragHandle, contentDescription = "Reorder")
}
}
}
}
}