Regroupe la configuration de carte en deux blocs (Carte / Points d'interet), ajoute le filtre par categorie et l'editeur de point geographique, et passe les ecrans Users et les jauges de quota par AppLocalizations (FR/EN/NL). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
153 lines
5.3 KiB
Dart
153 lines
5.3 KiB
Dart
import 'package:diacritic/diacritic.dart';
|
||
import 'package:manager_app/l10n/app_localizations.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:manager_app/Components/message_notification.dart';
|
||
import 'package:manager_app/Components/rounded_input_field.dart';
|
||
import 'package:manager_app/Models/managerContext.dart';
|
||
import 'package:manager_app/Screens/Configurations/listView_card_section.dart';
|
||
import 'package:manager_app/Screens/Configurations/new_section_popup.dart';
|
||
import 'package:manager_app/app_context.dart';
|
||
import 'package:manager_app/constants.dart';
|
||
import 'package:manager_api_new/api.dart';
|
||
import 'package:provider/provider.dart';
|
||
|
||
/// Grille des sections d'une configuration, réordonnable.
|
||
///
|
||
/// Elle était une liste horizontale enfermée dans `0,3 × hauteur d'écran` :
|
||
/// 30 % de l'écran réservés quoi qu'il arrive, et les sections au-delà de la
|
||
/// huitième hors champ à droite sans indice. Ici la grille se remplit sur toute
|
||
/// la largeur et la hauteur suit le contenu.
|
||
///
|
||
/// Le réordonnancement se fait par la poignée de chaque tuile
|
||
/// (`Draggable` → `DragTarget`) : `ReorderableListView` ne sait pas faire de
|
||
/// grille, et la maquette interdit une dépendance nouvelle.
|
||
class SectionReorderList extends StatefulWidget {
|
||
final String configurationId;
|
||
final List<SectionDTO> sectionsIn;
|
||
final ValueChanged<List<SectionDTO>> onChangedOrder;
|
||
final Function askReload;
|
||
const SectionReorderList({
|
||
Key? key,
|
||
required this.configurationId,
|
||
required this.sectionsIn,
|
||
required this.onChangedOrder,
|
||
required this.askReload,
|
||
}) : super(key: key);
|
||
|
||
@override
|
||
_SectionReorderListState createState() => _SectionReorderListState();
|
||
}
|
||
|
||
class _SectionReorderListState extends State<SectionReorderList> {
|
||
late List<SectionDTO> sections;
|
||
String filterSearch = '';
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
sections = new List<SectionDTO>.from(widget.sectionsIn);
|
||
}
|
||
|
||
void _onReorder(int oldIndex, int newIndex) {
|
||
setState(() {
|
||
final SectionDTO item = sections.removeAt(oldIndex);
|
||
sections.insert(newIndex, item);
|
||
|
||
var i = 0;
|
||
sections.forEach((section) {
|
||
section.order = i;
|
||
i++;
|
||
});
|
||
|
||
widget.onChangedOrder(sections);
|
||
});
|
||
}
|
||
|
||
Future<void> _createSection(AppContext appContext) async {
|
||
var sectionToCreate =
|
||
await showNewSection(widget.configurationId, appContext, context, false);
|
||
if (sectionToCreate != null) {
|
||
ManagerAppContext managerAppContext = appContext.getContext();
|
||
sectionToCreate.instanceId = managerAppContext.instanceId;
|
||
sectionToCreate.isBeacon = false;
|
||
sectionToCreate.dateCreation = DateTime.now();
|
||
await managerAppContext.clientAPI!.sectionApi!
|
||
.sectionCreate(sectionToCreate);
|
||
showNotification(kSuccess, kWhite,
|
||
AppLocalizations.of(context)!.sectionCreatedSuccess, context, null);
|
||
widget.askReload();
|
||
}
|
||
}
|
||
|
||
/// Retirer une section de l'app sans la supprimer. Le champ existe depuis
|
||
/// toujours côté serveur et les apps visiteur le respectent déjà — il n'avait
|
||
/// simplement aucun geste dans le manager.
|
||
Future<void> _toggleVisibility(
|
||
AppContext appContext, SectionDTO section) async {
|
||
final l = AppLocalizations.of(context)!;
|
||
final newValue = section.isActive == false;
|
||
|
||
setState(() => section.isActive = newValue);
|
||
|
||
try {
|
||
ManagerAppContext managerAppContext = appContext.getContext();
|
||
await managerAppContext.clientAPI!.sectionApi!
|
||
.sectionSetVisibility(section.id!, newValue);
|
||
showNotification(
|
||
kSuccess,
|
||
kWhite,
|
||
newValue ? l.sectionShownSuccess : l.sectionHiddenSuccess,
|
||
context,
|
||
null);
|
||
} catch (e) {
|
||
setState(() => section.isActive = !newValue);
|
||
showNotification(kError, kWhite, l.sectionVisibilityError, context, null);
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final appContext = Provider.of<AppContext>(context);
|
||
final l = AppLocalizations.of(context)!;
|
||
final canEdit = (appContext.getContext() as ManagerAppContext).canEdit;
|
||
|
||
return Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
RoundedInputField(
|
||
hintText: l.searchLabel,
|
||
icon: Icons.search,
|
||
onChanged: (String value) {
|
||
setState(() {
|
||
filterSearch = value;
|
||
filterResource();
|
||
});
|
||
},
|
||
),
|
||
const SizedBox(height: kSpace4),
|
||
SectionGrid(
|
||
sections: sections,
|
||
onReorder: _onReorder,
|
||
onAdd: () => _createSection(appContext),
|
||
onToggleVisibility: canEdit
|
||
? (section) => _toggleVisibility(appContext, section)
|
||
: null,
|
||
onTap: (section, index) {
|
||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
setState(() {
|
||
ManagerAppContext managerAppContext = appContext.getContext();
|
||
managerAppContext.selectedSection = section;
|
||
appContext.setContext(managerAppContext);
|
||
});
|
||
});
|
||
},
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
void filterResource() {
|
||
sections = filterSearch.isEmpty ? widget.sectionsIn: widget.sectionsIn.where((SectionDTO section) => removeDiacritics(section.label!.toUpperCase()).contains(removeDiacritics(filterSearch.toUpperCase()))).toList();
|
||
}
|
||
}
|