manager-app/lib/Screens/Configurations/new_section_popup.dart

312 lines
10 KiB
Dart

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<String, List<SectionType>> _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<SectionDTO?> 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<SectionDTO?>(
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<Widget> _buildFamily(
AppLocalizations l, String family, List<SectionType> 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();
}
}