import 'package:flutter/material.dart'; import 'package:manager_app/Components/fetch_section_icon.dart'; import 'package:manager_app/l10n/app_localizations.dart'; import 'package:manager_app/Components/message_notification.dart'; import 'package:manager_app/Components/string_input_container.dart'; import 'package:manager_app/Models/managerContext.dart'; import 'package:manager_app/app_context.dart'; import 'package:manager_app/constants.dart'; import 'package:manager_api_new/api.dart'; /// Les 13 types, groupés par famille. C'est la première interface que voit un /// nouveau client : un menu déroulant demandait de connaître les noms avant de /// choisir, la grille les montre. const Map> _sectionFamilies = { "content": [ SectionType.Slider, SectionType.Article, SectionType.Pdf, SectionType.Video, SectionType.Web, ], "places": [ SectionType.Map, SectionType.Parcours, SectionType.Event, ], "interactive": [ SectionType.Quiz, SectionType.Game, SectionType.Menu, ], "practical": [ SectionType.Agenda, SectionType.Weather, ], }; String _familyLabel(AppLocalizations l, String family) { switch (family) { case "content": return l.sectionFamilyContent; case "places": return l.sectionFamilyPlaces; case "interactive": return l.sectionFamilyInteractive; default: return l.sectionFamilyPractical; } } Future showNewSection(String configurationId, AppContext appContext, BuildContext contextBuild, bool isSubSection) { SectionDTO sectionDTO = new SectionDTO(); sectionDTO.label = ""; sectionDTO.configurationId = configurationId; sectionDTO.isSubSection = isSubSection; sectionDTO.isActive = true; sectionDTO.parentId = isSubSection ? (appContext.getContext() as ManagerAppContext).selectedSection!.id : null; sectionDTO.type = SectionType.Map; return showDialog( context: contextBuild, builder: (BuildContext context) => _NewSectionDialog( sectionDTO: sectionDTO, isSubSection: isSubSection, ), ); } class _NewSectionDialog extends StatefulWidget { const _NewSectionDialog({required this.sectionDTO, required this.isSubSection}); final SectionDTO sectionDTO; final bool isSubSection; @override State<_NewSectionDialog> createState() => _NewSectionDialogState(); } class _NewSectionDialogState extends State<_NewSectionDialog> { late SectionType selectedType = widget.sectionDTO.type ?? SectionType.Map; @override Widget build(BuildContext context) { final l = AppLocalizations.of(context)!; return Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kRadiusShell), side: const BorderSide(color: kLine), ), clipBehavior: Clip.antiAlias, child: SizedBox( width: 780, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( padding: const EdgeInsets.fromLTRB(kSpace6, kSpace5, kSpace4, kSpace5), child: Row( children: [ Expanded( child: Text( widget.isSubSection ? l.newSubSection : l.newSection, style: kTitleCard, ), ), IconButton( icon: const Icon(Icons.close, size: 20, color: kInk3), tooltip: l.cancel, onPressed: () => Navigator.of(context).pop(), ), ], ), ), const Divider(height: 1, thickness: 1, color: kLineSoft), Flexible( child: SingleChildScrollView( padding: const EdgeInsets.all(kSpace6), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 340, child: StringInputContainer( label: l.sectionNameLabel, isMandatory: true, initialValue: widget.sectionDTO.label, onChanged: (value) { widget.sectionDTO.label = value; }, ), ), for (final family in _sectionFamilies.entries) ..._buildFamily(l, family.key, family.value), ], ), ), ), Container( padding: const EdgeInsets.all(kSpace4), decoration: const BoxDecoration( color: kSurface2, border: Border(top: BorderSide(color: kLineSoft)), ), child: Row( children: [ Expanded( child: Text(l.sectionTypeFinalWarning, style: kTextHint), ), TextButton( onPressed: () => Navigator.of(context).pop(), child: Text(l.cancel, style: const TextStyle(fontSize: 13, color: kInk2)), ), const SizedBox(width: kSpace2), FilledButton.icon( onPressed: _submit, icon: const Icon(Icons.add, size: 16), label: Text(l.create, style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w600)), style: FilledButton.styleFrom( backgroundColor: kPrimaryColor, padding: const EdgeInsets.symmetric( horizontal: kSpace5, vertical: kSpace3), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kRadiusPill)), ), ), ], ), ), ], ), ), ); } List _buildFamily( AppLocalizations l, String family, List types) { // Une sous-section ne peut pas être un Menu : un menu regroupe des sous-sections. final available = widget.isSubSection ? types.where((type) => type != SectionType.Menu).toList() : types; if (available.isEmpty) return []; return [ Padding( padding: const EdgeInsets.only(top: kSpace7, bottom: kSpace3), child: Text(_familyLabel(l, family), style: kOverline), ), LayoutBuilder( builder: (context, constraints) { const spacing = kSpace4; const minWidth = 178.0; final columns = ((constraints.maxWidth + spacing) / (minWidth + spacing)) .floor() .clamp(1, available.length); final width = (constraints.maxWidth - spacing * (columns - 1)) / columns; return Wrap( spacing: spacing, runSpacing: spacing, children: available .map((type) => SizedBox( width: width, child: _TypeCard( type: type, isSelected: type == selectedType, onTap: () => setState(() { selectedType = type; widget.sectionDTO.type = type; }), ), )) .toList(), ); }, ), ]; } void _submit() { final l = AppLocalizations.of(context)!; if (widget.sectionDTO.label != null && widget.sectionDTO.label!.length > 2) { Navigator.of(context).pop(widget.sectionDTO); } else { showNotification( Colors.orange, kWhite, l.sectionNameRequired, context, null); } } } class _TypeCard extends StatelessWidget { const _TypeCard({ required this.type, required this.isSelected, required this.onTap, }); final SectionType type; final bool isSelected; final VoidCallback onTap; @override Widget build(BuildContext context) { final l = AppLocalizations.of(context)!; return Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(kRadiusCard), onTap: onTap, child: Container( padding: const EdgeInsets.all(kSpace4), decoration: BoxDecoration( color: isSelected ? kSurface3 : kSurface, border: Border.all( color: isSelected ? kPrimaryColor : kLine, width: isSelected ? 1.5 : 1, ), borderRadius: BorderRadius.circular(kRadiusCard), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(getSectionIcon(type), size: 20, color: isSelected ? kPrimaryColor : kInk3), const SizedBox(width: kSpace3), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(getSectionTypeName(l, type), style: kTextSmall), const SizedBox(height: 2), Text(getSectionTypeDescription(l, type), style: kTextHint, maxLines: 2), ], ), ), ], ), ), ), ); } } void create(SectionDTO sectionDTO, AppContext appContext, BuildContext context, bool isSubSection, Function? sendSubSection) async { if (sectionDTO.label != null) { ManagerAppContext managerAppContext = appContext.getContext(); sectionDTO.instanceId = managerAppContext.instanceId; sectionDTO.isBeacon = false; sectionDTO.dateCreation = DateTime.now(); SectionDTO? newSection = await managerAppContext.clientAPI!.sectionApi! .sectionCreate(sectionDTO); if (!isSubSection) { appContext.setContext(managerAppContext); showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.sectionCreatedSuccess, context, null); } else { sendSubSection!(newSection); } Navigator.of(context).pop(); } }