feat: Add sync functionality to include deleted items in updates

This commit is contained in:
2025-10-24 20:58:54 +02:00
parent 9aa7ed8878
commit 57e1001e1a
6 changed files with 90 additions and 271 deletions
@@ -27,6 +27,7 @@ interface FieldDao {
@Query("DELETE FROM fields WHERE id = :fieldId")
suspend fun deleteField(fieldId: String)
// Get all fields updated since timestamp, including deleted ones for sync
@Query("SELECT * FROM fields WHERE updatedAt >= :since")
suspend fun getFieldsUpdatedSince(since: Long): List<Field>
}
@@ -32,6 +32,7 @@ interface ItemDao {
@Query("DELETE FROM items WHERE id = :itemId")
suspend fun deleteItem(itemId: String)
// Get all items updated since timestamp, including deleted ones for sync
@Query("SELECT * FROM items WHERE updatedAt >= :since")
suspend fun getItemsUpdatedSince(since: Long): List<Item>
}
@@ -32,6 +32,7 @@ interface ListDao {
@Query("DELETE FROM lists WHERE id = :listId")
suspend fun deleteList(listId: String)
// Get all lists updated since timestamp, including deleted ones for sync
@Query("SELECT * FROM lists WHERE updatedAt >= :since")
suspend fun getListsUpdatedSince(since: Long): List<CollabList>
}
@@ -1300,12 +1300,35 @@ fun ManageColumnsDialog(
var showAddField by remember { mutableStateOf(false) }
var fieldToEdit by remember { mutableStateOf<Field?>(null) }
var fieldToDelete by remember { mutableStateOf<Field?>(null) }
val reorderedFields = remember { mutableStateListOf<Field>().apply { addAll(fields) } }
// Update reordered list when fields change
// Use derivedStateOf to keep reorderedFields in sync with fields
val reorderedFields = remember(fields) {
mutableStateListOf<Field>().apply {
clear()
addAll(fields)
}
}
// Watch for changes in fields and update reorderedFields
LaunchedEffect(fields) {
reorderedFields.clear()
reorderedFields.addAll(fields)
val currentIds = reorderedFields.map { it.id }.toSet()
val newIds = fields.map { it.id }.toSet()
// Add new fields
fields.filter { it.id !in currentIds }.forEach { newField ->
reorderedFields.add(newField)
}
// Remove deleted fields
reorderedFields.removeAll { it.id !in newIds }
// Update existing fields (in case of edits)
fields.forEach { updatedField ->
val index = reorderedFields.indexOfFirst { it.id == updatedField.id }
if (index >= 0 && reorderedFields[index] != updatedField) {
reorderedFields[index] = updatedField
}
}
}
Dialog(
@@ -1358,17 +1381,20 @@ fun ManageColumnsDialog(
field = field,
onEdit = { fieldToEdit = field },
onDelete = { fieldToDelete = field },
onDragStart = { _ ->
// Store the dragged item index if needed
},
onDragEnd = { fromIndex, toIndex ->
if (fromIndex != toIndex) {
val item = reorderedFields.removeAt(fromIndex)
reorderedFields.add(toIndex, item)
onMoveUp = {
if (index > 0) {
val item = reorderedFields.removeAt(index)
reorderedFields.add(index - 1, item)
}
},
currentIndex = index,
totalItems = reorderedFields.size
onMoveDown = {
if (index < reorderedFields.size - 1) {
val item = reorderedFields.removeAt(index)
reorderedFields.add(index + 1, item)
}
},
canMoveUp = index > 0,
canMoveDown = index < reorderedFields.size - 1
)
}
}
@@ -1456,52 +1482,17 @@ fun ColumnItem(
field: Field,
onEdit: () -> Unit,
onDelete: () -> Unit,
onDragStart: (Int) -> Unit,
onDragEnd: (Int, Int) -> Unit,
currentIndex: Int,
totalItems: Int
onMoveUp: () -> Unit,
onMoveDown: () -> Unit,
canMoveUp: Boolean,
canMoveDown: Boolean
) {
var isDragging by remember { mutableStateOf(false) }
var dragOffset by remember { mutableStateOf(0f) }
Card(
modifier = Modifier
.fillMaxWidth()
.offset { IntOffset(0, dragOffset.toInt()) }
.pointerInput(Unit) {
detectDragGestures(
onDragStart = {
isDragging = true
onDragStart(currentIndex)
},
onDragEnd = {
val itemHeight = 80.dp.toPx() // Approximate item height with spacing
val movedItems = (dragOffset / itemHeight).toInt()
val targetIndex = (currentIndex + movedItems).coerceIn(0, totalItems - 1)
onDragEnd(currentIndex, targetIndex)
isDragging = false
dragOffset = 0f
},
onDragCancel = {
isDragging = false
dragOffset = 0f
},
onDrag = { change, dragAmount ->
change.consume()
dragOffset += dragAmount.y
}
)
},
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = if (isDragging)
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.7f)
else
MaterialTheme.colorScheme.surfaceVariant
containerColor = MaterialTheme.colorScheme.surfaceVariant
),
elevation = CardDefaults.cardElevation(
defaultElevation = if (isDragging) 8.dp else 1.dp
)
elevation = CardDefaults.cardElevation(defaultElevation = 1.dp)
) {
Row(
modifier = Modifier
@@ -1510,13 +1501,37 @@ fun ColumnItem(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
// Drag handle on the left
Icon(
Icons.Default.Menu,
contentDescription = "Drag to reorder",
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(24.dp)
)
// Move up/down buttons
Column {
IconButton(
onClick = onMoveUp,
enabled = canMoveUp,
modifier = Modifier.size(32.dp)
) {
Icon(
Icons.Default.KeyboardArrowUp,
contentDescription = "Move up",
tint = if (canMoveUp)
MaterialTheme.colorScheme.onSurfaceVariant
else
MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f)
)
}
IconButton(
onClick = onMoveDown,
enabled = canMoveDown,
modifier = Modifier.size(32.dp)
) {
Icon(
Icons.Default.KeyboardArrowDown,
contentDescription = "Move down",
tint = if (canMoveDown)
MaterialTheme.colorScheme.onSurfaceVariant
else
MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f)
)
}
}
Spacer(modifier = Modifier.width(12.dp))