282 lines
12 KiB
Dart
282 lines
12 KiB
Dart
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<TranslationDTO> values, List<TranslationDTO> newValues, Function onGetResult, int maxLines, List<ResourceType>? 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<TranslationAndResourceDTO> values, List<TranslationAndResourceDTO> newValues, Function onGetResult, int maxLines, List<ResourceType>? 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)),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
} |