276 lines
12 KiB
Dart

import 'package:flutter/material.dart';
import 'package:manager_api_new/api.dart';
import 'package:manager_app/constants.dart';
import 'package:manager_app/Components/rounded_button.dart';
import 'package:manager_app/Components/multi_string_input_container.dart';
import 'package:manager_app/Components/check_input_container.dart';
import 'showNewOrUpdateGuidedStep.dart';
void showNewOrUpdateGuidedPath(
BuildContext context,
GuidedPathDTO? path,
String parentId,
bool isEvent,
bool isEscapeMode,
Function(GuidedPathDTO) onSave,
) {
GuidedPathDTO workingPath = path != null
? GuidedPathDTO.fromJson(path.toJson())!
: GuidedPathDTO(
title: [],
description: [],
steps: [],
order: 0,
);
showDialog(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
final double screenWidth = MediaQuery.of(context).size.width;
final double screenHeight = MediaQuery.of(context).size.height;
final double dialogWidth = screenWidth * 0.82;
// contentWidth = dialogWidth minus the 24px padding on each side
final double contentWidth = dialogWidth - 48;
final double halfWidth = (contentWidth - 20) / 2;
final double thirdWidth = (contentWidth - 40) / 3;
return Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Container(
width: dialogWidth,
constraints: BoxConstraints(maxHeight: screenHeight * 0.88),
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// -- Titre du dialog --
Text(
path == null ? "Nouveau Parcours" : "Modifier le Parcours",
style: TextStyle(
color: kPrimaryColor,
fontSize: 20,
fontWeight: FontWeight.bold),
),
SizedBox(height: 16),
// -- Corps scrollable --
Flexible(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Titre + Description côte à côte
Row(
children: [
SizedBox(
width: halfWidth,
child: MultiStringInputContainer(
label: "Titre :",
modalLabel: "Titre du parcours",
initialValue: workingPath.title ?? [],
onGetResult: (val) =>
setState(() => workingPath.title = val),
maxLines: 1,
isTitle: true,
),
),
SizedBox(width: 20),
SizedBox(
width: halfWidth,
child: MultiStringInputContainer(
label: "Description :",
modalLabel: "Description du parcours",
initialValue: workingPath.description ?? [],
onGetResult: (val) => setState(
() => workingPath.description = val),
maxLines: 1,
isTitle: false,
),
),
],
),
Divider(height: 24),
// Options
Row(
children: [
SizedBox(
width: thirdWidth,
child: CheckInputContainer(
label: "Linéaire :",
isChecked: workingPath.isLinear ?? false,
onChanged: (val) => setState(
() => workingPath.isLinear = val),
),
),
SizedBox(width: 20),
SizedBox(
width: thirdWidth,
child: CheckInputContainer(
label: "Réussite requise :",
isChecked:
workingPath.requireSuccessToAdvance ??
false,
onChanged: (val) => setState(() => workingPath
.requireSuccessToAdvance = val),
),
),
SizedBox(width: 20),
SizedBox(
width: thirdWidth,
child: CheckInputContainer(
label: "Cacher les suivantes :",
isChecked:
workingPath.hideNextStepsUntilComplete ??
false,
onChanged: (val) => setState(() => workingPath
.hideNextStepsUntilComplete = val),
),
),
],
),
Divider(height: 24),
// Étapes
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Étapes du parcours",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15)),
IconButton(
icon: Icon(Icons.add_circle_outline,
color: kSuccess),
onPressed: () {
showNewOrUpdateGuidedStep(
context,
null,
workingPath.id ?? "temp",
isEscapeMode,
(newStep) {
setState(() {
workingPath.steps = [
...(workingPath.steps ?? []),
newStep
];
});
},
);
},
),
],
),
if (workingPath.steps?.isEmpty ?? true)
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Text(
"Aucun point/étape configuré.",
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.grey[600]),
),
)
else
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: workingPath.steps!.length,
itemBuilder: (context, index) {
final step = workingPath.steps![index];
return ListTile(
leading:
CircleAvatar(child: Text("${index + 1}")),
title: Text(
step.title != null && step.title!.isNotEmpty
? step.title!
.firstWhere(
(t) => t.language == 'FR',
orElse: () =>
step.title![0])
.value ??
"Étape $index"
: "Étape $index",
),
subtitle: Text(
"${step.quizQuestions?.length ?? 0} question(s)"),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(Icons.edit,
color: kPrimaryColor),
onPressed: () {
showNewOrUpdateGuidedStep(
context,
step,
workingPath.id ?? "temp",
isEscapeMode,
(updatedStep) {
setState(() {
workingPath.steps![index] =
updatedStep;
});
},
);
},
),
IconButton(
icon: Icon(Icons.delete, color: kError),
onPressed: () {
setState(() {
workingPath.steps!.removeAt(index);
});
},
),
],
),
);
},
),
],
),
),
),
SizedBox(height: 16),
// -- Boutons --
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizedBox(
height: 46,
child: RoundedButton(
text: "Annuler",
press: () => Navigator.pop(context),
color: kSecond,
fontSize: 15,
horizontal: 24,
),
),
SizedBox(width: 12),
SizedBox(
height: 46,
child: RoundedButton(
text: "Sauvegarder",
press: () {
onSave(workingPath);
Navigator.pop(context);
},
color: kPrimaryColor,
fontSize: 15,
horizontal: 24,
),
),
],
),
],
),
),
);
},
);
},
);
}