import 'package:flutter/material.dart'; import 'package:manager_api_new/api.dart'; import 'package:manager_app/constants.dart'; import 'package:manager_app/l10n/app_localizations.dart'; import 'package:manager_app/Components/confirmation_dialog.dart'; import 'package:manager_app/Components/rounded_button.dart'; import 'package:manager_app/Components/multi_string_input_container.dart'; import 'package:intl/intl.dart'; import 'showNewOrUpdateMapAnnotation.dart'; void showNewOrUpdateProgrammeBlock( BuildContext context, ProgrammeBlock? block, Function(ProgrammeBlock) onSave, ) { ProgrammeBlock workingBlock = block != null ? ProgrammeBlock( id: block.id, title: List.from(block.title ?? []), description: List.from(block.description ?? []), startTime: block.startTime, endTime: block.endTime, mapAnnotations: List.from(block.mapAnnotations ?? []), ) : ProgrammeBlock( title: [], description: [], startTime: DateTime.now(), endTime: DateTime.now().add(Duration(hours: 1)), mapAnnotations: [], ); MapAnnotationDTO _toDTO(MapAnnotation a) => MapAnnotationDTO.fromJson(a.toJson())!; MapAnnotation _fromDTO(MapAnnotationDTO a) => MapAnnotation.fromJson(a.toJson())!; showDialog( context: context, builder: (BuildContext context) { return StatefulBuilder( builder: (context, setState) { final double screenWidth = MediaQuery.of(context).size.width; final double screenHeight = MediaQuery.of(context).size.height; final double dialogWidth = screenWidth * 0.7; final double contentWidth = dialogWidth - 48; final double halfWidth = (contentWidth - 20) / 2; return Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Container( width: dialogWidth, constraints: BoxConstraints(maxHeight: screenHeight * 0.85), padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( block == null ? "Nouveau Bloc de Programme" : "Modifier le Bloc", style: TextStyle( color: kPrimaryColor, fontSize: 20, fontWeight: FontWeight.bold), ), SizedBox(height: 16), Flexible( child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Titre + Description côte à côte Row( children: [ SizedBox( width: halfWidth, child: MultiStringInputContainer( label: "Titre :", modalLabel: "Titre du bloc", initialValue: workingBlock.title ?? [], onGetResult: (val) => setState(() => workingBlock.title = val), maxLines: 1, isTitle: true, isHTML: true, ), ), SizedBox(width: 20), SizedBox( width: halfWidth, child: MultiStringInputContainer( label: "Description :", modalLabel: "Description du bloc", initialValue: workingBlock.description ?? [], onGetResult: (val) => setState( () => workingBlock.description = val), maxLines: 1, isTitle: false, isHTML: true, ), ), ], ), Divider(height: 24), // Heures côte à côte Row( children: [ SizedBox( width: halfWidth, child: ListTile( leading: Icon(Icons.schedule, color: kPrimaryColor), title: Text(AppLocalizations.of(context)!.startTimeLabel), subtitle: Text( workingBlock.startTime != null ? DateFormat('HH:mm') .format(workingBlock.startTime!.toLocal()) : AppLocalizations.of(context)!.notDefined, style: TextStyle( color: kPrimaryColor, fontWeight: FontWeight.bold), ), onTap: () async { TimeOfDay? time = await showTimePicker( context: context, initialTime: TimeOfDay.fromDateTime( workingBlock.startTime?.toLocal() ?? DateTime.now()), builder: (context, child) { return Theme( data: Theme.of(context).copyWith( colorScheme: ColorScheme.light( primary: kPrimaryColor, onPrimary: kWhite, onSurface: kSecond, ), ), child: child!, ); }, ); if (time != null) { setState(() { DateTime now = DateTime.now(); workingBlock.startTime = DateTime( now.year, now.month, now.day, time.hour, time.minute); }); } }, ), ), SizedBox(width: 20), SizedBox( width: halfWidth, child: ListTile( leading: Icon(Icons.schedule_outlined, color: kPrimaryColor), title: Text(AppLocalizations.of(context)!.endTimeLabel), subtitle: Text( workingBlock.endTime != null ? DateFormat('HH:mm') .format(workingBlock.endTime!.toLocal()) : AppLocalizations.of(context)!.notDefined, style: TextStyle( color: kPrimaryColor, fontWeight: FontWeight.bold), ), onTap: () async { TimeOfDay? time = await showTimePicker( context: context, initialTime: TimeOfDay.fromDateTime( workingBlock.endTime?.toLocal() ?? DateTime.now() .add(Duration(hours: 1))), builder: (context, child) { return Theme( data: Theme.of(context).copyWith( colorScheme: ColorScheme.light( primary: kPrimaryColor, onPrimary: kWhite, onSurface: kSecond, ), ), child: child!, ); }, ); if (time != null) { setState(() { DateTime now = DateTime.now(); workingBlock.endTime = DateTime( now.year, now.month, now.day, time.hour, time.minute); }); } }, ), ), ], ), Divider(height: 24), // Annotations Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(AppLocalizations.of(context)!.annotationsLabel, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 15)), IconButton( icon: Icon(Icons.add_circle_outline, color: kSuccess), onPressed: () { showNewOrUpdateMapAnnotation( context, null, (newAnnotation) { setState(() { workingBlock.mapAnnotations = [ ...(workingBlock.mapAnnotations ?? []), _fromDTO(newAnnotation), ]; }); }, ); }, ), ], ), if (workingBlock.mapAnnotations == null || workingBlock.mapAnnotations!.isEmpty) Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Text( AppLocalizations.of(context)!.noAnnotationConfigured, style: TextStyle( fontStyle: FontStyle.italic, color: Colors.grey[600]), ), ) else ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: workingBlock.mapAnnotations!.length, itemBuilder: (context, aIndex) { final annotation = workingBlock.mapAnnotations![aIndex]; final label = annotation.label ?.firstWhere( (t) => t.language == 'FR', orElse: () => annotation.label!.first, ) .value ?? "Annotation $aIndex"; return ListTile( dense: true, title: Text(label), subtitle: Text( annotation.geometryType?.value == 1 ? 'Polyline' : annotation.geometryType ?.value == 2 ? 'Circle' : annotation.geometryType ?.value == 3 ? 'Polygon' : 'Point'), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.edit, size: 18, color: kPrimaryColor), onPressed: () { showNewOrUpdateMapAnnotation( context, _toDTO(annotation), (updated) { setState(() { workingBlock.mapAnnotations![ aIndex] = _fromDTO(updated); }); }, ); }, ), IconButton( icon: Icon(Icons.delete, size: 18, color: kError), onPressed: () { showConfirmationDialog( "Supprimer cette annotation ?", () {}, () => setState(() => workingBlock .mapAnnotations! .removeAt(aIndex)), context, ); }, ), ], ), ); }, ), ], ), ), ), SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ SizedBox( height: 46, child: RoundedButton( text: "Annuler", press: () => Navigator.pop(context), color: kSecond, fontSize: 15, horizontal: 24, ), ), SizedBox(width: 12), SizedBox( height: 46, child: RoundedButton( text: "Sauvegarder", press: () { onSave(workingBlock); Navigator.pop(context); }, color: kPrimaryColor, fontSize: 15, horizontal: 24, ), ), ], ), ], ), ), ); }, ); }, ); }