279 lines
25 KiB
Plaintext
279 lines
25 KiB
Plaintext
@OptIn(ExperimentalLayoutApi::class)
|
|
@Composable
|
|
private fun EditTodoDialog(
|
|
state: EditTodoDialogUiState,
|
|
groupNames: List<String>,
|
|
timezoneId: String = TimeZone.getDefault().id,
|
|
onDismiss: () -> Unit,
|
|
onContentChanged: (String) -> Unit,
|
|
onDueDateChanged: (Long?) -> Unit,
|
|
onGroupChanged: (String) -> Unit,
|
|
onNewSubtaskTextChanged: (String) -> Unit,
|
|
onAddSubtask: () -> Unit,
|
|
onRemoveSubtask: (Int) -> Unit,
|
|
onToggleSubtask: (Int) -> Unit,
|
|
onUpdateSubtaskContent: (Int, String) -> Unit,
|
|
onNewTagTextChanged: (String) -> Unit,
|
|
onAddTag: () -> Unit,
|
|
onRemoveTag: (String) -> Unit,
|
|
onSave: () -> Unit
|
|
) {
|
|
val context = androidx.compose.ui.platform.LocalContext.current
|
|
val dialogTitle = if (state.isCreateMode) "??? Nouvelle t??che" else "?????? Modifier la t??che"
|
|
|
|
AlertDialog(
|
|
onDismissRequest = onDismiss,
|
|
title = {
|
|
Row(
|
|
modifier = Modifier.fillMaxWidth(),
|
|
verticalAlignment = Alignment.CenterVertically,
|
|
horizontalArrangement = Arrangement.SpaceBetween
|
|
) {
|
|
Text(dialogTitle)
|
|
IconButton(onClick = onDismiss) {
|
|
Icon(Icons.Default.Close, contentDescription = "Fermer")
|
|
}
|
|
}
|
|
},
|
|
text = {
|
|
Column(
|
|
modifier = Modifier
|
|
.fillMaxWidth()
|
|
.wrapContentHeight()
|
|
.verticalScroll(rememberScrollState()),
|
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
|
) {
|
|
// Content
|
|
OutlinedTextField(
|
|
value = state.content,
|
|
onValueChange = onContentChanged,
|
|
modifier = Modifier.fillMaxWidth(),
|
|
label = { Text("Contenu") },
|
|
singleLine = false,
|
|
maxLines = 4,
|
|
keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Sentences)
|
|
)
|
|
|
|
// Group
|
|
OutlinedTextField(
|
|
value = state.groupName,
|
|
onValueChange = onGroupChanged,
|
|
modifier = Modifier.fillMaxWidth(),
|
|
label = { Text("Groupe") },
|
|
placeholder = { Text("Ex: Famille, Personnel, Projet X...") },
|
|
singleLine = true,
|
|
leadingIcon = { Icon(Icons.Default.Folder, contentDescription = null) }
|
|
)
|
|
|
|
if (groupNames.isNotEmpty()) {
|
|
FlowRow(
|
|
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
|
verticalArrangement = Arrangement.spacedBy(6.dp)
|
|
) {
|
|
groupNames.forEach { group ->
|
|
Surface(
|
|
color = if (state.groupName == group) {
|
|
MaterialTheme.colorScheme.primaryContainer
|
|
} else {
|
|
MaterialTheme.colorScheme.surfaceVariant
|
|
},
|
|
shape = MaterialTheme.shapes.small,
|
|
onClick = { onGroupChanged(group) }
|
|
) {
|
|
Text(
|
|
text = group,
|
|
style = MaterialTheme.typography.labelSmall,
|
|
modifier = Modifier.padding(horizontal = 10.dp, vertical = 6.dp),
|
|
color = if (state.groupName == group) {
|
|
MaterialTheme.colorScheme.onPrimaryContainer
|
|
} else {
|
|
MaterialTheme.colorScheme.onSurfaceVariant
|
|
}
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Due date
|
|
Row(
|
|
modifier = Modifier.fillMaxWidth(),
|
|
horizontalArrangement = Arrangement.SpaceBetween,
|
|
verticalAlignment = Alignment.CenterVertically
|
|
) {
|
|
Text(
|
|
text = state.dueDate?.let { formatDateTime(it, timezoneId) } ?: "Sans ??ch??ance",
|
|
style = MaterialTheme.typography.bodySmall,
|
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
|
)
|
|
Row {
|
|
TextButton(onClick = {
|
|
pickDateTime(context, state.dueDate, timezoneId) { millis -> onDueDateChanged(millis) }
|
|
}) {
|
|
Text("Date")
|
|
}
|
|
if (state.dueDate != null) {
|
|
TextButton(onClick = { onDueDateChanged(null) }) {
|
|
Text("Effacer")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Subtasks
|
|
Text(
|
|
text = "Sous-t??ches",
|
|
style = MaterialTheme.typography.labelLarge,
|
|
fontWeight = FontWeight.Bold,
|
|
color = MaterialTheme.colorScheme.primary
|
|
)
|
|
|
|
state.subtasks.forEachIndexed { index, sub ->
|
|
Row(
|
|
modifier = Modifier.fillMaxWidth(),
|
|
verticalAlignment = Alignment.CenterVertically
|
|
) {
|
|
Checkbox(
|
|
checked = sub.isDone,
|
|
onCheckedChange = { onToggleSubtask(index) },
|
|
modifier = Modifier.size(32.dp)
|
|
)
|
|
OutlinedTextField(
|
|
value = sub.content,
|
|
onValueChange = { onUpdateSubtaskContent(index, it) },
|
|
modifier = Modifier.weight(1f),
|
|
singleLine = true,
|
|
textStyle = MaterialTheme.typography.bodySmall.copy(
|
|
textDecoration = if (sub.isDone) TextDecoration.LineThrough else TextDecoration.None
|
|
)
|
|
)
|
|
IconButton(
|
|
onClick = { onRemoveSubtask(index) },
|
|
modifier = Modifier.size(32.dp)
|
|
) {
|
|
Icon(
|
|
Icons.Default.Close,
|
|
contentDescription = "Supprimer",
|
|
modifier = Modifier.size(16.dp),
|
|
tint = MaterialTheme.colorScheme.error
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add subtask
|
|
Row(
|
|
modifier = Modifier.fillMaxWidth(),
|
|
verticalAlignment = Alignment.CenterVertically
|
|
) {
|
|
OutlinedTextField(
|
|
value = state.newSubtaskText,
|
|
onValueChange = onNewSubtaskTextChanged,
|
|
modifier = Modifier.weight(1f),
|
|
placeholder = { Text("Nouvelle sous-t??che...") },
|
|
singleLine = true,
|
|
keyboardOptions = KeyboardOptions(
|
|
imeAction = ImeAction.Done,
|
|
capitalization = KeyboardCapitalization.Sentences
|
|
),
|
|
keyboardActions = KeyboardActions(onDone = { onAddSubtask() })
|
|
)
|
|
IconButton(onClick = onAddSubtask) {
|
|
Icon(Icons.Default.Add, contentDescription = "Ajouter")
|
|
}
|
|
}
|
|
|
|
// Tags section with add capability
|
|
Text(
|
|
text = "Tags",
|
|
style = MaterialTheme.typography.labelLarge,
|
|
fontWeight = FontWeight.Bold,
|
|
color = MaterialTheme.colorScheme.primary
|
|
)
|
|
|
|
if (state.tags.isNotEmpty()) {
|
|
FlowRow(
|
|
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
|
verticalArrangement = Arrangement.spacedBy(6.dp)
|
|
) {
|
|
state.tags.forEach { tag ->
|
|
Surface(
|
|
color = MaterialTheme.colorScheme.secondaryContainer,
|
|
shape = MaterialTheme.shapes.small,
|
|
onClick = { onRemoveTag(tag) }
|
|
) {
|
|
Row(
|
|
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
|
|
verticalAlignment = Alignment.CenterVertically
|
|
) {
|
|
Text(
|
|
text = "#$tag",
|
|
style = MaterialTheme.typography.labelSmall,
|
|
color = MaterialTheme.colorScheme.onSecondaryContainer
|
|
)
|
|
Spacer(modifier = Modifier.width(4.dp))
|
|
Icon(
|
|
imageVector = Icons.Default.Close,
|
|
contentDescription = "Supprimer le tag",
|
|
modifier = Modifier.size(12.dp),
|
|
tint = MaterialTheme.colorScheme.onSecondaryContainer
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add tag
|
|
Row(
|
|
modifier = Modifier.fillMaxWidth(),
|
|
verticalAlignment = Alignment.CenterVertically
|
|
) {
|
|
OutlinedTextField(
|
|
value = state.newTagText,
|
|
onValueChange = onNewTagTextChanged,
|
|
modifier = Modifier.weight(1f),
|
|
placeholder = { Text("Nouveau tag...") },
|
|
singleLine = true,
|
|
keyboardOptions = KeyboardOptions(
|
|
imeAction = ImeAction.Done,
|
|
capitalization = KeyboardCapitalization.None
|
|
),
|
|
keyboardActions = KeyboardActions(onDone = { onAddTag() })
|
|
)
|
|
IconButton(onClick = onAddTag) {
|
|
Icon(Icons.Default.Add, contentDescription = "Ajouter tag")
|
|
}
|
|
}
|
|
|
|
state.errorMessage?.let { message ->
|
|
Text(
|
|
text = message,
|
|
color = MaterialTheme.colorScheme.error,
|
|
style = MaterialTheme.typography.bodySmall
|
|
)
|
|
}
|
|
}
|
|
},
|
|
confirmButton = {
|
|
TextButton(
|
|
onClick = onSave,
|
|
enabled = !state.isSaving && state.content.isNotBlank()
|
|
) {
|
|
if (state.isSaving) {
|
|
CircularProgressIndicator(modifier = Modifier.size(16.dp), strokeWidth = 2.dp)
|
|
Spacer(modifier = Modifier.width(8.dp))
|
|
}
|
|
Icon(Icons.Default.Check, contentDescription = null)
|
|
Spacer(modifier = Modifier.width(6.dp))
|
|
Text(if (state.isCreateMode) "Cr??er" else "Enregistrer")
|
|
}
|
|
},
|
|
dismissButton = {
|
|
TextButton(onClick = onDismiss) {
|
|
Text("Annuler")
|
|
}
|
|
}
|
|
)
|
|
}
|