289 lines
13 KiB
Dart
289 lines
13 KiB
Dart
import 'dart:convert';
|
|
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(jsonDecode(jsonEncode(path)))!
|
|
: 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: isEscapeMode
|
|
? Text(
|
|
"${step.quizQuestions?.length ?? 0} question(s)")
|
|
: null,
|
|
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: () {
|
|
// Initialise les booleans null → false
|
|
workingPath.isLinear ??= false;
|
|
workingPath.requireSuccessToAdvance ??= false;
|
|
workingPath.hideNextStepsUntilComplete ??= false;
|
|
// Initialise les booleans nuls dans chaque étape
|
|
for (final s in workingPath.steps ?? []) {
|
|
s.isHiddenInitially ??= false;
|
|
s.isStepTimer ??= false;
|
|
s.isStepLocked ??= false;
|
|
}
|
|
onSave(workingPath);
|
|
Navigator.pop(context);
|
|
},
|
|
color: kPrimaryColor,
|
|
fontSize: 15,
|
|
horizontal: 24,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
},
|
|
);
|
|
}
|