@OptIn(ExperimentalLayoutApi::class) @Composable private fun EditTodoDialog( state: EditTodoDialogUiState, groupNames: List, 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") } } ) }