import 'package:flutter/material.dart'; import 'package:manager_app/l10n/app_localizations.dart'; import 'package:manager_app/Components/message_notification.dart'; import 'package:manager_app/Components/translation_input_and_resource_container.dart'; import 'package:manager_app/Components/translation_input_container.dart'; import 'package:manager_app/constants.dart'; import 'package:manager_api_new/api.dart'; import 'package:collection/collection.dart'; /// Le modal de traduction — l'interface la plus utilisée de l'app. /// /// `isHTML` décide du corps : Quill quand le champ accepte du HTML, champ /// simple sinon. C'est la fusion avec l'ancien `multi_input_modal.dart`, qui /// faisait le même travail dans une deuxième implémentation. void showMultiStringInputHTML(String label, String modalLabel, bool isTitle, List values, List newValues, Function onGetResult, int maxLines, List? resourceTypes, BuildContext context, bool isMandatory, {bool isHTML = true}) { showDialog( useRootNavigator: false, context: context, builder: (BuildContext context) { final l = AppLocalizations.of(context)!; final translated = newValues .where((t) => (t.value ?? '').trim().isNotEmpty) .length; return Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kRadiusShell), side: const BorderSide(color: kLine), ), clipBehavior: Clip.antiAlias, insetPadding: const EdgeInsets.symmetric(horizontal: 60, vertical: kSpace7), child: ConstrainedBox( constraints: BoxConstraints( maxWidth: 780, maxHeight: MediaQuery.of(context).size.height - 48), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( padding: const EdgeInsets.fromLTRB(kSpace6, kSpace5, kSpace4, kSpace5), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: kTitleCard), // Plusieurs appelants passent le même texte aux deux // paramètres (les messages de score du quiz) : on ne // l'écrit pas deux fois. if (modalLabel.trim() != label.trim()) Text(modalLabel, style: kSubtitleCard), ], ), ), Container( padding: const EdgeInsets.symmetric( horizontal: kSpace3, vertical: kSpace1), decoration: BoxDecoration( color: kSurface3, borderRadius: BorderRadius.circular(kRadiusPill), ), child: Text( l.translatedLanguagesCount(translated, newValues.length), style: const TextStyle(fontSize: 11, color: kInk2)), ), IconButton( icon: const Icon(Icons.close, size: 20, color: kInk3), tooltip: l.cancel, onPressed: () { onGetResult(values); Navigator.of(context).pop(); }, ), ], ), ), const Divider(height: 1, thickness: 1, color: kLineSoft), Flexible( child: Padding( padding: const EdgeInsets.fromLTRB(kSpace6, kSpace5, kSpace6, kSpace5), child: TranslationInputContainer( isTitle: isTitle, values: values, newValues: newValues, onGetResult: onGetResult, maxLines: maxLines, resourceTypes: resourceTypes, isHTML: isHTML, ), ), ), Container( padding: const EdgeInsets.all(kSpace4), decoration: const BoxDecoration( color: kSurface2, border: Border(top: BorderSide(color: kLineSoft)), ), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () { onGetResult(values); Navigator.of(context).pop(); }, child: Text(l.cancel, style: const TextStyle(fontSize: 13, color: kInk2)), ), const SizedBox(width: kSpace2), FilledButton( onPressed: () { Function deepEq = const DeepCollectionEquality().equals; if (!deepEq(values, newValues)) { if (isMandatory && newValues.any((label) => label.value == null || label.value!.trim() == "")) { showNotification(kPrimaryColor, kWhite, l.translationIncomplete, context, null); } else { onGetResult(newValues); Navigator.of(context).pop(); } } else { Navigator.of(context).pop(); } }, style: FilledButton.styleFrom( backgroundColor: kPrimaryColor, padding: const EdgeInsets.symmetric( horizontal: kSpace5, vertical: kSpace3), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kRadiusPill)), ), child: Text(l.validate, style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w600)), ), ], ), ), ], ), ), ); }, ); } /// Le même modal, pour les traductions qui portent aussi une ressource /// (message de score d'un quiz, fichier PDF, message de jeu). Même coquille, /// corps différent. void showMultiStringInputAndResourceHTML(String label, String modalLabel, bool isTitle, List values, List newValues, Function onGetResult, int maxLines, List? resourceTypes, BuildContext context) { showDialog( useRootNavigator: false, context: context, builder: (BuildContext context) { final l = AppLocalizations.of(context)!; final translated = newValues.where((t) => (t.value ?? '').trim().isNotEmpty).length; return Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kRadiusShell), side: const BorderSide(color: kLine), ), clipBehavior: Clip.antiAlias, insetPadding: const EdgeInsets.symmetric(horizontal: 60, vertical: kSpace7), child: ConstrainedBox( constraints: BoxConstraints( maxWidth: 780, maxHeight: MediaQuery.of(context).size.height - 48), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( padding: const EdgeInsets.fromLTRB(kSpace6, kSpace5, kSpace4, kSpace5), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: kTitleCard), // Plusieurs appelants passent le même texte aux deux // paramètres (les messages de score du quiz) : on ne // l'écrit pas deux fois. if (modalLabel.trim() != label.trim()) Text(modalLabel, style: kSubtitleCard), ], ), ), Container( padding: const EdgeInsets.symmetric( horizontal: kSpace3, vertical: kSpace1), decoration: BoxDecoration( color: kSurface3, borderRadius: BorderRadius.circular(kRadiusPill), ), child: Text( l.translatedLanguagesCount(translated, newValues.length), style: const TextStyle(fontSize: 11, color: kInk2)), ), IconButton( icon: const Icon(Icons.close, size: 20, color: kInk3), tooltip: l.cancel, onPressed: () { onGetResult(values); Navigator.of(context).pop(); }, ), ], ), ), const Divider(height: 1, thickness: 1, color: kLineSoft), Flexible( child: Padding( padding: const EdgeInsets.fromLTRB(kSpace6, kSpace5, kSpace6, kSpace5), child: TranslationInputAndResourceContainer( isTitle: isTitle, values: values, newValues: newValues, onGetResult: onGetResult, maxLines: maxLines, resourceTypes: resourceTypes, ), ), ), Container( padding: const EdgeInsets.all(kSpace4), decoration: const BoxDecoration( color: kSurface2, border: Border(top: BorderSide(color: kLineSoft)), ), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () { onGetResult(values); Navigator.of(context).pop(); }, child: Text(l.cancel, style: const TextStyle(fontSize: 13, color: kInk2)), ), const SizedBox(width: kSpace2), FilledButton( onPressed: () { Function deepEq = const DeepCollectionEquality().equals; if (!deepEq(values, newValues)) { if (newValues.any((label) => label.value == null || label.value!.trim() == "")) { showNotification(kPrimaryColor, kWhite, l.translationIncomplete, context, null); } else { onGetResult(newValues); Navigator.of(context).pop(); } } else { Navigator.of(context).pop(); } }, style: FilledButton.styleFrom( backgroundColor: kPrimaryColor, padding: const EdgeInsets.symmetric( horizontal: kSpace5, vertical: kSpace3), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(kRadiusPill)), ), child: Text(l.validate, style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w600)), ), ], ), ), ], ), ), ); }, ); }