feat: update field editing functionality to include name parameter and improve UI layout in ListDetailScreen and ListsScreen

This commit is contained in:
2025-10-26 14:01:55 +01:00
parent eaa0985b01
commit fb484cd2ba
3 changed files with 128 additions and 130 deletions
@@ -6,6 +6,7 @@ import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -485,8 +486,8 @@ fun ListDetailScreen(
onAddField = { name, fieldType, fieldOptions ->
viewModel.addField(name, fieldType, fieldOptions)
},
onUpdateField = { fieldId, fieldType, fieldOptions ->
viewModel.updateField(fieldId, fieldType, fieldOptions)
onUpdateField = { fieldId, name, fieldType, fieldOptions ->
viewModel.updateField(fieldId, name, fieldType, fieldOptions)
},
onDeleteField = { fieldId ->
viewModel.deleteField(fieldId)
@@ -1461,8 +1462,9 @@ fun AddFieldDialog(
fun EditFieldDialog(
field: Field,
onDismiss: () -> Unit,
onUpdate: (String, String) -> Unit,
onUpdate: (String, String, String) -> Unit,
) {
var name by remember { mutableStateOf(field.name) }
var selectedFieldType by remember { mutableStateOf(field.fieldType ?: "TEXT") }
var dropdownOptions by remember { mutableStateOf(field.getDropdownOptions().joinToString(", ")) }
var currency by remember { mutableStateOf(field.getCurrency()) }
@@ -1470,11 +1472,20 @@ fun EditFieldDialog(
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("Edit Field: ${field.name}") },
title = { Text("Edit Column") },
text = {
Column(
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
// Name
OutlinedTextField(
value = name,
onValueChange = { name = it },
label = { Text("Column Name") },
singleLine = true,
modifier = Modifier.fillMaxWidth(),
)
// Field Type Selector
ExposedDropdownMenuBox(
expanded = expanded,
@@ -1758,9 +1769,9 @@ fun EditFieldDialog(
"RATING" -> currency.trim().ifBlank { "5" }
else -> ""
}
onUpdate(selectedFieldType, options)
onUpdate(name.trim(), selectedFieldType, options)
},
enabled = selectedFieldType !in listOf("DROPDOWN", "AUTOCOMPLETE") || dropdownOptions.isNotBlank(),
enabled = name.isNotBlank() && (selectedFieldType !in listOf("DROPDOWN", "AUTOCOMPLETE") || dropdownOptions.isNotBlank()),
) {
Text("Update")
}
@@ -2425,7 +2436,7 @@ fun ManageColumnsDialog(
fields: List<Field>,
onDismiss: () -> Unit,
onAddField: (String, String, String) -> Unit,
onUpdateField: (String, String, String) -> Unit,
onUpdateField: (String, String, String, String) -> Unit,
onDeleteField: (String) -> Unit,
onReorderFields: (List<Field>) -> Unit,
) {
@@ -2543,6 +2554,7 @@ fun ManageColumnsDialog(
Box(
modifier = Modifier.animateItemPlacement(),
) {
if (index > 0) Divider()
ColumnItem(
field = field,
onEdit = { fieldToEdit = field },
@@ -2623,8 +2635,8 @@ fun ManageColumnsDialog(
EditFieldDialog(
field = field,
onDismiss = { fieldToEdit = null },
onUpdate = { fieldType, fieldOptions ->
onUpdateField(field.id, fieldType, fieldOptions)
onUpdate = { name, fieldType, fieldOptions ->
onUpdateField(field.id, name, fieldType, fieldOptions)
fieldToEdit = null
},
)
@@ -2665,102 +2677,91 @@ fun ColumnItem(
canMoveDown: Boolean,
dragHandle: (@Composable () -> Unit)? = null,
) {
Card(
Row(
modifier =
Modifier
.fillMaxWidth(),
colors =
CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant,
),
elevation = CardDefaults.cardElevation(defaultElevation = 1.dp),
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Row(
modifier =
Modifier
.fillMaxWidth()
.padding(12.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
// Drag handle and optional move buttons
Column(horizontalAlignment = Alignment.CenterHorizontally) {
if (dragHandle != null) {
dragHandle()
}
// Drag handle
Column(horizontalAlignment = Alignment.CenterHorizontally) {
if (dragHandle != null) {
dragHandle()
}
}
Spacer(modifier = Modifier.width(12.dp))
Spacer(modifier = Modifier.width(12.dp))
Column(modifier = Modifier.weight(1f)) {
Text(
text = field.name,
style = MaterialTheme.typography.titleMedium,
)
Text(
text =
when (field.getType()) {
// Text types
com.collabtable.app.data.model.FieldType.TEXT -> "Text"
com.collabtable.app.data.model.FieldType.MULTILINE_TEXT -> "Multiline Text"
Column(modifier = Modifier.weight(1f)) {
Text(
text = field.name,
style = MaterialTheme.typography.titleMedium,
)
Text(
text =
when (field.getType()) {
// Text types
com.collabtable.app.data.model.FieldType.TEXT -> "Text"
com.collabtable.app.data.model.FieldType.MULTILINE_TEXT -> "Multiline Text"
// Number types
com.collabtable.app.data.model.FieldType.NUMBER -> "Number"
com.collabtable.app.data.model.FieldType.CURRENCY -> "Currency (${field.getCurrency()})"
com.collabtable.app.data.model.FieldType.PERCENTAGE -> "Percentage"
// Number types
com.collabtable.app.data.model.FieldType.NUMBER -> "Number"
com.collabtable.app.data.model.FieldType.CURRENCY -> "Currency (${field.getCurrency()})"
com.collabtable.app.data.model.FieldType.PERCENTAGE -> "Percentage"
// Selection types
com.collabtable.app.data.model.FieldType.CHECKBOX -> "Checkbox"
com.collabtable.app.data.model.FieldType.SWITCH -> "Switch"
com.collabtable.app.data.model.FieldType.DROPDOWN ->
"Dropdown (${field.getDropdownOptions().size} options)"
com.collabtable.app.data.model.FieldType.AUTOCOMPLETE ->
"Autocomplete (${field.getAutocompleteOptions().size} options)"
// Selection types
com.collabtable.app.data.model.FieldType.CHECKBOX -> "Checkbox"
com.collabtable.app.data.model.FieldType.SWITCH -> "Switch"
com.collabtable.app.data.model.FieldType.DROPDOWN ->
"Dropdown (${field.getDropdownOptions().size} options)"
com.collabtable.app.data.model.FieldType.AUTOCOMPLETE ->
"Autocomplete (${field.getAutocompleteOptions().size} options)"
// Link types
com.collabtable.app.data.model.FieldType.URL -> "URL"
com.collabtable.app.data.model.FieldType.EMAIL -> "Email"
com.collabtable.app.data.model.FieldType.PHONE -> "Phone"
// Link types
com.collabtable.app.data.model.FieldType.URL -> "URL"
com.collabtable.app.data.model.FieldType.EMAIL -> "Email"
com.collabtable.app.data.model.FieldType.PHONE -> "Phone"
// Date/Time types
com.collabtable.app.data.model.FieldType.DATE -> "Date"
com.collabtable.app.data.model.FieldType.TIME -> "Time"
com.collabtable.app.data.model.FieldType.DATETIME -> "Date & Time"
com.collabtable.app.data.model.FieldType.DURATION -> "Duration"
// Date/Time types
com.collabtable.app.data.model.FieldType.DATE -> "Date"
com.collabtable.app.data.model.FieldType.TIME -> "Time"
com.collabtable.app.data.model.FieldType.DATETIME -> "Date & Time"
com.collabtable.app.data.model.FieldType.DURATION -> "Duration"
// Media types
com.collabtable.app.data.model.FieldType.IMAGE -> "Image"
com.collabtable.app.data.model.FieldType.FILE -> "File"
com.collabtable.app.data.model.FieldType.BARCODE -> "Barcode"
com.collabtable.app.data.model.FieldType.SIGNATURE -> "Signature"
// Media types
com.collabtable.app.data.model.FieldType.IMAGE -> "Image"
com.collabtable.app.data.model.FieldType.FILE -> "File"
com.collabtable.app.data.model.FieldType.BARCODE -> "Barcode"
com.collabtable.app.data.model.FieldType.SIGNATURE -> "Signature"
// Other types
com.collabtable.app.data.model.FieldType.RATING -> "Rating (${field.getMaxRating()} stars)"
com.collabtable.app.data.model.FieldType.COLOR -> "Color"
com.collabtable.app.data.model.FieldType.LOCATION -> "Location"
},
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
// Other types
com.collabtable.app.data.model.FieldType.RATING -> "Rating (${field.getMaxRating()} stars)"
com.collabtable.app.data.model.FieldType.COLOR -> "Color"
com.collabtable.app.data.model.FieldType.LOCATION -> "Location"
},
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
// Edit button
IconButton(onClick = onEdit) {
Icon(
Icons.Default.Edit,
contentDescription = "Edit",
tint = MaterialTheme.colorScheme.primary,
)
}
// Edit button
IconButton(onClick = onEdit) {
Icon(
Icons.Default.Edit,
contentDescription = "Edit",
tint = MaterialTheme.colorScheme.primary,
)
}
// Delete button
IconButton(onClick = onDelete) {
Icon(
Icons.Default.Delete,
contentDescription = "Delete",
tint = MaterialTheme.colorScheme.error,
)
}
// Delete button
IconButton(onClick = onDelete) {
Icon(
Icons.Default.Delete,
contentDescription = "Delete",
tint = MaterialTheme.colorScheme.error,
)
}
}
}
@@ -149,6 +149,7 @@ class ListDetailViewModel(
fun updateField(
fieldId: String,
name: String,
fieldType: String,
fieldOptions: String,
) {
@@ -157,6 +158,7 @@ class ListDetailViewModel(
if (field != null) {
database.fieldDao().updateField(
field.copy(
name = name,
fieldType = fieldType,
fieldOptions = fieldOptions,
updatedAt = System.currentTimeMillis(),
@@ -26,8 +26,8 @@ import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.Sort
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
@@ -200,6 +200,7 @@ fun ListsScreen(
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) },
@@ -275,52 +276,46 @@ fun ListItem(
onDeleteClick: () -> Unit,
dragHandle: (@Composable () -> Unit)? = null,
) {
Card(
Row(
modifier =
Modifier
.fillMaxWidth(),
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Row(
// Drag handle on the far left
if (dragHandle != null) {
dragHandle()
Spacer(modifier = Modifier.padding(start = 8.dp))
}
// Table name centered/left and clickable
Column(
modifier =
Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
.weight(1f)
.clickable(onClick = onListClick),
) {
// Drag handle on the far left
if (dragHandle != null) {
dragHandle()
Spacer(modifier = Modifier.padding(start = 8.dp))
}
Text(text = list.name, style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(2.dp))
}
// Table name centered/left and clickable
Column(
modifier =
Modifier
.weight(1f)
.clickable(onClick = onListClick),
) {
Text(text = list.name, style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(2.dp))
// Actions on the right
Row(verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = onEditClick) {
Icon(
Icons.Default.Edit,
contentDescription = "Edit",
tint = MaterialTheme.colorScheme.primary,
)
}
// Actions on the right
Row(verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = onEditClick) {
Icon(
Icons.Default.Edit,
contentDescription = "Edit",
tint = MaterialTheme.colorScheme.primary,
)
}
IconButton(onClick = onDeleteClick) {
Icon(
Icons.Default.Delete,
contentDescription = "Delete",
tint = MaterialTheme.colorScheme.error,
)
}
IconButton(onClick = onDeleteClick) {
Icon(
Icons.Default.Delete,
contentDescription = "Delete",
tint = MaterialTheme.colorScheme.error,
)
}
}
}