Wip changements fantastiquement rapide d'antigravity, très bonne base mais du wip
This commit is contained in:
parent
9e06afb29e
commit
ded4620bf2
144
lib/Components/geometry_input_container.dart
Normal file
144
lib/Components/geometry_input_container.dart
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_api_new/api.dart';
|
||||||
|
import 'package:manager_app/Components/map_geometry_picker.dart';
|
||||||
|
import 'package:manager_app/constants.dart';
|
||||||
|
|
||||||
|
class GeometryInputContainer extends StatelessWidget {
|
||||||
|
final String label;
|
||||||
|
final GeometryDTO? initialGeometry;
|
||||||
|
final String? initialColor;
|
||||||
|
final Function(GeometryDTO, String) onSave;
|
||||||
|
final Color color;
|
||||||
|
final bool isSmall;
|
||||||
|
|
||||||
|
GeometryInputContainer({
|
||||||
|
required this.label,
|
||||||
|
this.initialGeometry,
|
||||||
|
this.initialColor,
|
||||||
|
required this.onSave,
|
||||||
|
this.color = kPrimaryColor,
|
||||||
|
this.isSmall = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
String typeInfo = initialGeometry?.type ?? "Aucun";
|
||||||
|
int pointCount = 0;
|
||||||
|
if (initialGeometry?.coordinates != null) {
|
||||||
|
if (initialGeometry!.type == "Point") {
|
||||||
|
pointCount = 1;
|
||||||
|
} else if (initialGeometry!.coordinates is List) {
|
||||||
|
pointCount = (initialGeometry!.coordinates as List).length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.symmetric(vertical: 4),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 150,
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: isSmall ? size.width * 0.15 : size.width * 0.25,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => MapGeometryPicker(
|
||||||
|
initialGeometry: initialGeometry,
|
||||||
|
initialColor: initialColor,
|
||||||
|
onSave: onSave,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(29),
|
||||||
|
border: Border.all(color: kSecond),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
_getIconForType(initialGeometry?.type),
|
||||||
|
color: color,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
initialGeometry != null
|
||||||
|
? "$typeInfo ($pointCount pts)"
|
||||||
|
: "Définir",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: initialGeometry != null ? kBlack : kSecond,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (initialColor != null)
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 8,
|
||||||
|
height: 8,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _parseColor(initialColor!),
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 4),
|
||||||
|
Text(initialColor!,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 9, color: Colors.grey)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Icon(Icons.edit, color: kSecond, size: 16),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
IconData _getIconForType(String? type) {
|
||||||
|
switch (type) {
|
||||||
|
case "Point":
|
||||||
|
return Icons.location_on;
|
||||||
|
case "LineString":
|
||||||
|
return Icons.show_chart;
|
||||||
|
case "Polygon":
|
||||||
|
return Icons.pentagon;
|
||||||
|
default:
|
||||||
|
return Icons.map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Color _parseColor(String hex) {
|
||||||
|
try {
|
||||||
|
return Color(int.parse(hex.replaceFirst('#', '0xFF')));
|
||||||
|
} catch (e) {
|
||||||
|
return kPrimaryColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
361
lib/Components/map_geometry_picker.dart
Normal file
361
lib/Components/map_geometry_picker.dart
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
|
import 'package:latlong2/latlong.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/color_picker.dart';
|
||||||
|
|
||||||
|
class MapGeometryPicker extends StatefulWidget {
|
||||||
|
final GeometryDTO? initialGeometry;
|
||||||
|
final String? initialColor;
|
||||||
|
final Function(GeometryDTO, String) onSave;
|
||||||
|
|
||||||
|
MapGeometryPicker({
|
||||||
|
this.initialGeometry,
|
||||||
|
this.initialColor,
|
||||||
|
required this.onSave,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MapGeometryPickerState createState() => _MapGeometryPickerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MapGeometryPickerState extends State<MapGeometryPicker> {
|
||||||
|
List<LatLng> points = [];
|
||||||
|
String currentType = "Point";
|
||||||
|
Color selectedColor = kPrimaryColor;
|
||||||
|
final MapController _mapController = MapController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
if (widget.initialGeometry != null) {
|
||||||
|
currentType = widget.initialGeometry!.type ?? "Point";
|
||||||
|
_parseInitialGeometry();
|
||||||
|
}
|
||||||
|
if (widget.initialColor != null) {
|
||||||
|
try {
|
||||||
|
selectedColor = _hexToColor(widget.initialColor!);
|
||||||
|
} catch (e) {
|
||||||
|
selectedColor = kPrimaryColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Color _hexToColor(String hex) {
|
||||||
|
hex = hex.replaceFirst('#', '');
|
||||||
|
if (hex.length == 6) hex = 'FF' + hex;
|
||||||
|
return Color(int.parse(hex, radix: 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _parseInitialGeometry() {
|
||||||
|
if (widget.initialGeometry?.coordinates == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (currentType == "Point") {
|
||||||
|
var coords = widget.initialGeometry!.coordinates as List<dynamic>;
|
||||||
|
points = [LatLng(coords[0].toDouble(), coords[1].toDouble())];
|
||||||
|
} else if (currentType == "LineString" || currentType == "Polygon") {
|
||||||
|
var list = widget.initialGeometry!.coordinates as List<dynamic>;
|
||||||
|
points = list.map((e) {
|
||||||
|
var pair = e as List<dynamic>;
|
||||||
|
return LatLng(pair[0].toDouble(), pair[1].toDouble());
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Error parsing geometry: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleTap(TapPosition tapPosition, LatLng latLng) {
|
||||||
|
setState(() {
|
||||||
|
if (currentType == "Point") {
|
||||||
|
points = [latLng];
|
||||||
|
} else {
|
||||||
|
points.add(latLng);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
GeometryDTO _buildGeometry() {
|
||||||
|
if (currentType == "Point") {
|
||||||
|
return GeometryDTO(
|
||||||
|
type: "Point",
|
||||||
|
coordinates: points.isNotEmpty
|
||||||
|
? [points[0].latitude, points[0].longitude]
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return GeometryDTO(
|
||||||
|
type: currentType,
|
||||||
|
coordinates: points.map((e) => [e.latitude, e.longitude]).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _colorToHex(Color color) {
|
||||||
|
return '#${color.value.toRadixString(16).padLeft(8, '0').substring(2)}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
return Dialog(
|
||||||
|
insetPadding: EdgeInsets.all(20),
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||||
|
child: Container(
|
||||||
|
width: size.width * 0.9,
|
||||||
|
height: size.height * 0.9,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
color: kPrimaryColor,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text("Éditeur de Géométrie",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold)),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.palette, color: Colors.white),
|
||||||
|
onPressed: () {
|
||||||
|
showColorPicker(selectedColor, (Color color) {
|
||||||
|
setState(() => selectedColor = color);
|
||||||
|
}, context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.delete, color: Colors.white),
|
||||||
|
onPressed: () => setState(() => points.clear()),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.close, color: Colors.white),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Wrap(
|
||||||
|
spacing: 12,
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
children: [
|
||||||
|
_buildTypeButton("Point", Icons.location_on),
|
||||||
|
_buildTypeButton("LineString", Icons.show_chart),
|
||||||
|
_buildTypeButton("Polygon", Icons.pentagon),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
_getInstructions(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontStyle: FontStyle.italic, color: Colors.grey[600]),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
FlutterMap(
|
||||||
|
key: _mapKey,
|
||||||
|
mapController: _mapController,
|
||||||
|
options: MapOptions(
|
||||||
|
initialCenter: points.isNotEmpty
|
||||||
|
? points[0]
|
||||||
|
: LatLng(50.429333, 4.891434),
|
||||||
|
initialZoom: 14,
|
||||||
|
onTap: _handleTap,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
TileLayer(
|
||||||
|
urlTemplate:
|
||||||
|
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||||
|
),
|
||||||
|
if (currentType == "Polygon" && points.length >= 3)
|
||||||
|
PolygonLayer(
|
||||||
|
polygons: [
|
||||||
|
Polygon(
|
||||||
|
points: points,
|
||||||
|
color: selectedColor.withOpacity(0.3),
|
||||||
|
borderStrokeWidth: 2,
|
||||||
|
borderColor: selectedColor,
|
||||||
|
isFilled: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (currentType == "LineString" && points.length >= 2)
|
||||||
|
PolylineLayer(
|
||||||
|
polylines: [
|
||||||
|
Polyline(
|
||||||
|
points: points,
|
||||||
|
color: selectedColor,
|
||||||
|
strokeWidth: 4,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
MarkerLayer(
|
||||||
|
markers: points.asMap().entries.map((entry) {
|
||||||
|
int idx = entry.key;
|
||||||
|
LatLng p = entry.value;
|
||||||
|
return Marker(
|
||||||
|
point: p,
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
child: GestureDetector(
|
||||||
|
onPanUpdate: (details) {
|
||||||
|
_handleDrag(idx, details);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
border: Border.all(
|
||||||
|
color: selectedColor, width: 2),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
blurRadius: 4,
|
||||||
|
color: Colors.black26,
|
||||||
|
offset: Offset(0, 2))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Icon(Icons.circle,
|
||||||
|
color: selectedColor, size: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black12,
|
||||||
|
blurRadius: 4,
|
||||||
|
offset: Offset(0, -2))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: 45,
|
||||||
|
child: RoundedButton(
|
||||||
|
text: "Annuler",
|
||||||
|
color: Colors.grey[200]!,
|
||||||
|
textColor: Colors.black87,
|
||||||
|
press: () => Navigator.pop(context),
|
||||||
|
fontSize: 16,
|
||||||
|
horizontal: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 12),
|
||||||
|
Container(
|
||||||
|
height: 45,
|
||||||
|
child: RoundedButton(
|
||||||
|
text: "Sauvegarder",
|
||||||
|
color: kPrimaryColor,
|
||||||
|
press: () {
|
||||||
|
widget.onSave(
|
||||||
|
_buildGeometry(), _colorToHex(selectedColor));
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
fontSize: 16,
|
||||||
|
horizontal: 32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getInstructions() {
|
||||||
|
switch (currentType) {
|
||||||
|
case "Point":
|
||||||
|
return "Touchez la carte pour placer le point. Faites glisser le point pour le déplacer.";
|
||||||
|
case "LineString":
|
||||||
|
return "Touchez la carte pour ajouter des points à la ligne. Faites glisser un point pour le déplacer.";
|
||||||
|
case "Polygon":
|
||||||
|
return "Touchez la carte pour définir les sommets du polygone. Faites glisser un sommet pour le déplacer.";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final GlobalKey _mapKey = GlobalKey();
|
||||||
|
|
||||||
|
void _handleDrag(int index, DragUpdateDetails details) {
|
||||||
|
if (index < 0 || index >= points.length) return;
|
||||||
|
|
||||||
|
final RenderBox? mapBox =
|
||||||
|
_mapKey.currentContext?.findRenderObject() as RenderBox?;
|
||||||
|
if (mapBox != null) {
|
||||||
|
final Offset localOffset = mapBox.globalToLocal(details.globalPosition);
|
||||||
|
try {
|
||||||
|
LatLng newLatLng = _mapController.camera
|
||||||
|
.pointToLatLng(math.Point(localOffset.dx, localOffset.dy));
|
||||||
|
setState(() {
|
||||||
|
points[index] = newLatLng;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
print("Error dragging point: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTypeButton(String type, IconData icon) {
|
||||||
|
bool isSelected = currentType == type;
|
||||||
|
return ChoiceChip(
|
||||||
|
label: Text(type == "LineString"
|
||||||
|
? "Ligne"
|
||||||
|
: type == "Polygon"
|
||||||
|
? "Polygone"
|
||||||
|
: "Point"),
|
||||||
|
avatar: Icon(icon,
|
||||||
|
size: 18, color: isSelected ? Colors.white : kPrimaryColor),
|
||||||
|
selected: isSelected,
|
||||||
|
onSelected: (val) {
|
||||||
|
if (val) {
|
||||||
|
setState(() {
|
||||||
|
currentType = type;
|
||||||
|
if (currentType == "Point" && points.length > 1) {
|
||||||
|
points = [points[0]];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectedColor: kPrimaryColor,
|
||||||
|
labelStyle: TextStyle(color: isSelected ? Colors.white : kPrimaryColor),
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,8 +11,8 @@ class RoundedButton extends StatelessWidget {
|
|||||||
final double? vertical;
|
final double? vertical;
|
||||||
final double? horizontal;
|
final double? horizontal;
|
||||||
|
|
||||||
const RoundedButton({
|
const RoundedButton(
|
||||||
Key? key,
|
{Key? key,
|
||||||
required this.text,
|
required this.text,
|
||||||
required this.press,
|
required this.press,
|
||||||
this.icon,
|
this.icon,
|
||||||
@ -20,28 +20,24 @@ class RoundedButton extends StatelessWidget {
|
|||||||
this.textColor = kWhite,
|
this.textColor = kWhite,
|
||||||
required this.fontSize,
|
required this.fontSize,
|
||||||
this.vertical,
|
this.vertical,
|
||||||
this.horizontal
|
this.horizontal})
|
||||||
}) : super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
//Size size = MediaQuery.of(context).size;
|
|
||||||
return TextButton(
|
return TextButton(
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
padding: MaterialStateProperty.resolveWith((states) => EdgeInsets.symmetric(vertical: this.vertical != null ? this.vertical! : 25, horizontal: this.horizontal != null ? this.horizontal!: (icon == null ? 85 : 30))),
|
padding: MaterialStateProperty.all(EdgeInsets.symmetric(
|
||||||
backgroundColor: MaterialStateColor.resolveWith((states) => color),
|
vertical: vertical ?? 12,
|
||||||
|
horizontal: horizontal ?? (icon == null ? 20 : 15),
|
||||||
|
)),
|
||||||
|
backgroundColor: MaterialStateProperty.all(color),
|
||||||
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
||||||
RoundedRectangleBorder(
|
RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(30.0),
|
borderRadius: BorderRadius.circular(30.0),
|
||||||
)
|
))),
|
||||||
)
|
onPressed: () => {press()},
|
||||||
),
|
child: getValue(icon));
|
||||||
|
|
||||||
onPressed: () => {
|
|
||||||
press()
|
|
||||||
},
|
|
||||||
child: getValue(icon)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue(icon) {
|
getValue(icon) {
|
||||||
@ -52,15 +48,16 @@ class RoundedButton extends StatelessWidget {
|
|||||||
Center(
|
Center(
|
||||||
child: AutoSizeText(
|
child: AutoSizeText(
|
||||||
text,
|
text,
|
||||||
style: new TextStyle(color: textColor, fontSize: fontSize, fontWeight: FontWeight.w400),
|
style: new TextStyle(
|
||||||
|
color: textColor,
|
||||||
|
fontSize: fontSize,
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
maxFontSize: fontSize,
|
maxFontSize: fontSize,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(width: 10),
|
||||||
width: 10
|
|
||||||
),
|
|
||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
color: textColor,
|
color: textColor,
|
||||||
@ -71,7 +68,8 @@ class RoundedButton extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
return AutoSizeText(
|
return AutoSizeText(
|
||||||
text,
|
text,
|
||||||
style: new TextStyle(color: textColor, fontSize: fontSize, fontWeight: FontWeight.w400),
|
style: new TextStyle(
|
||||||
|
color: textColor, fontSize: fontSize, fontWeight: FontWeight.w400),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,19 +1,17 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_api_new/api.dart';
|
||||||
|
import 'package:manager_app/constants.dart';
|
||||||
import 'package:manager_app/Components/check_input_container.dart';
|
import 'package:manager_app/Components/check_input_container.dart';
|
||||||
import 'package:manager_app/Components/multi_string_input_container.dart';
|
import 'package:manager_app/Components/multi_string_input_container.dart';
|
||||||
import 'package:manager_app/Components/resource_input_container.dart';
|
|
||||||
import 'package:manager_api_new/api.dart';
|
|
||||||
import 'package:manager_app/Components/single_select_container.dart';
|
import 'package:manager_app/Components/single_select_container.dart';
|
||||||
import 'dart:convert';
|
import 'showNewOrUpdateEventAgenda.dart';
|
||||||
|
|
||||||
import 'package:manager_app/constants.dart';
|
|
||||||
|
|
||||||
class AgendaConfig extends StatefulWidget {
|
class AgendaConfig extends StatefulWidget {
|
||||||
final String? color;
|
final String? color;
|
||||||
final String? label;
|
final String? label;
|
||||||
final AgendaDTO initialValue;
|
final AgendaDTO initialValue;
|
||||||
final ValueChanged<AgendaDTO> onChanged;
|
final ValueChanged<AgendaDTO> onChanged;
|
||||||
|
|
||||||
const AgendaConfig({
|
const AgendaConfig({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.color,
|
this.color,
|
||||||
@ -31,14 +29,13 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
AgendaDTO test = widget.initialValue;
|
|
||||||
agendaDTO = test;
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
agendaDTO = widget.initialValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Size size = MediaQuery.of(context).size;
|
//Size size = MediaQuery.of(context).size;
|
||||||
|
|
||||||
var mapProviderIn = "";
|
var mapProviderIn = "";
|
||||||
switch (agendaDTO.agendaMapProvider) {
|
switch (agendaDTO.agendaMapProvider) {
|
||||||
@ -53,17 +50,16 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SingleChildScrollView(
|
return Column(
|
||||||
child: Padding(
|
children: [
|
||||||
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Container(
|
|
||||||
height: size.height * 0.3,
|
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
CheckInputContainer(
|
CheckInputContainer(
|
||||||
label: "En ligne :",
|
label: "En ligne :",
|
||||||
isChecked: agendaDTO.isOnlineAgenda!,
|
isChecked: agendaDTO.isOnlineAgenda ?? true,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
agendaDTO.isOnlineAgenda = value;
|
agendaDTO.isOnlineAgenda = value;
|
||||||
@ -75,8 +71,9 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
label: "Service carte :",
|
label: "Service carte :",
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
initialValue: mapProviderIn,
|
initialValue: mapProviderIn,
|
||||||
inputValues: map_providers,
|
inputValues: ["Google", "MapBox"],
|
||||||
onChanged: (String value) {
|
onChanged: (String value) {
|
||||||
|
setState(() {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case "Google":
|
case "Google":
|
||||||
agendaDTO.agendaMapProvider = MapProvider.Google;
|
agendaDTO.agendaMapProvider = MapProvider.Google;
|
||||||
@ -86,22 +83,21 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
widget.onChanged(agendaDTO);
|
widget.onChanged(agendaDTO);
|
||||||
}
|
});
|
||||||
|
},
|
||||||
),
|
),
|
||||||
|
if (agendaDTO.isOnlineAgenda == true)
|
||||||
MultiStringInputContainer(
|
MultiStringInputContainer(
|
||||||
label: "Fichiers json :",
|
label: "Fichiers json :",
|
||||||
resourceTypes: [ResourceType.Json, ResourceType.JsonUrl],
|
resourceTypes: [ResourceType.Json, ResourceType.JsonUrl],
|
||||||
modalLabel: "JSON",
|
modalLabel: "JSON",
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: agendaDTO.resourceIds!,
|
initialValue: agendaDTO.resourceIds ?? [],
|
||||||
isTitle: false,
|
isTitle: false,
|
||||||
onGetResult: (value) {
|
onGetResult: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (agendaDTO.resourceIds != value) {
|
|
||||||
agendaDTO.resourceIds = value;
|
agendaDTO.resourceIds = value;
|
||||||
//save(true, articleDTO, appContext);
|
|
||||||
widget.onChanged(agendaDTO);
|
widget.onChanged(agendaDTO);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
@ -109,17 +105,99 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (agendaDTO.isOnlineAgenda == false) ...[
|
||||||
|
Divider(),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text("Évènements Manuels",
|
||||||
|
style:
|
||||||
|
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
|
ElevatedButton.icon(
|
||||||
|
icon: Icon(Icons.add),
|
||||||
|
label: Text("Ajouter un évènement"),
|
||||||
|
onPressed: () {
|
||||||
|
showNewOrUpdateEventAgenda(
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
agendaDTO.id ?? "temp",
|
||||||
|
(newEvent) {
|
||||||
|
setState(() {
|
||||||
|
agendaDTO.events = [
|
||||||
|
...(agendaDTO.events ?? []),
|
||||||
|
newEvent
|
||||||
|
];
|
||||||
|
widget.onChanged(agendaDTO);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: kSuccess, foregroundColor: kWhite),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: (agendaDTO.events == null || agendaDTO.events!.isEmpty)
|
||||||
|
? Center(
|
||||||
|
child: Text("Aucun évènement manuel",
|
||||||
|
style: TextStyle(fontStyle: FontStyle.italic)))
|
||||||
|
: ListView.builder(
|
||||||
|
itemCount: agendaDTO.events!.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final event = agendaDTO.events![index];
|
||||||
|
return Card(
|
||||||
|
margin:
|
||||||
|
EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(event.label
|
||||||
|
?.firstWhere((t) => t.language == 'FR',
|
||||||
|
orElse: () => event.label![0])
|
||||||
|
.value ??
|
||||||
|
"Évènement $index"),
|
||||||
|
subtitle:
|
||||||
|
Text(event.address?.address ?? "Pas d'adresse"),
|
||||||
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.edit, color: kPrimaryColor),
|
||||||
|
onPressed: () {
|
||||||
|
showNewOrUpdateEventAgenda(
|
||||||
|
context,
|
||||||
|
event,
|
||||||
|
agendaDTO.id ?? "temp",
|
||||||
|
(updatedEvent) {
|
||||||
|
setState(() {
|
||||||
|
agendaDTO.events![index] = updatedEvent;
|
||||||
|
widget.onChanged(agendaDTO);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.delete, color: kError),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
agendaDTO.events!.removeAt(index);
|
||||||
|
widget.onChanged(agendaDTO);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
/*return ResourceInputContainer(
|
},
|
||||||
label: "Fichier JSON :",
|
),
|
||||||
initialValue: agendaDTO.resourceId == null ? '': agendaDTO.resourceId,
|
),
|
||||||
inResourceTypes: [ResourceType.Json, ResourceType.JsonUrl],
|
],
|
||||||
onChanged: (ResourceDTO resourceDTO) {
|
],
|
||||||
agendaDTO.resourceUrl = resourceDTO.url;
|
);
|
||||||
agendaDTO.resourceId = resourceDTO.id;
|
|
||||||
widget.onChanged(jsonEncode(agendaDTO).toString());
|
|
||||||
}
|
|
||||||
);*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,208 @@
|
|||||||
|
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/string_input_container.dart';
|
||||||
|
import 'package:manager_app/Components/geometry_input_container.dart';
|
||||||
|
|
||||||
|
void showNewOrUpdateEventAgenda(
|
||||||
|
BuildContext context,
|
||||||
|
EventAgendaDTO? event,
|
||||||
|
String agendaId,
|
||||||
|
Function(EventAgendaDTO) onSave,
|
||||||
|
) {
|
||||||
|
EventAgendaDTO workingEvent = event != null
|
||||||
|
? EventAgendaDTO.fromJson(event.toJson())!
|
||||||
|
: EventAgendaDTO(
|
||||||
|
label: [],
|
||||||
|
description: [],
|
||||||
|
sectionAgendaId: agendaId,
|
||||||
|
address: EventAgendaDTOAddress(
|
||||||
|
address: "",
|
||||||
|
city: "",
|
||||||
|
country: "",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
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.78;
|
||||||
|
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: [
|
||||||
|
Text(
|
||||||
|
event == null ? "Nouvel Évènement" : "Modifier l'Évènement",
|
||||||
|
style: TextStyle(
|
||||||
|
color: kPrimaryColor,
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
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 de l'évènement",
|
||||||
|
initialValue: workingEvent.label ?? [],
|
||||||
|
onGetResult: (val) =>
|
||||||
|
setState(() => workingEvent.label = val),
|
||||||
|
maxLines: 1,
|
||||||
|
isTitle: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 20),
|
||||||
|
SizedBox(
|
||||||
|
width: halfWidth,
|
||||||
|
child: MultiStringInputContainer(
|
||||||
|
label: "Description :",
|
||||||
|
modalLabel: "Description de l'évènement",
|
||||||
|
initialValue: workingEvent.description ?? [],
|
||||||
|
onGetResult: (val) => setState(
|
||||||
|
() => workingEvent.description = val),
|
||||||
|
maxLines: 5,
|
||||||
|
isTitle: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Divider(height: 24),
|
||||||
|
// Site | Tel | Email
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: thirdWidth,
|
||||||
|
child: StringInputContainer(
|
||||||
|
label: "Site Web :",
|
||||||
|
initialValue: workingEvent.website ?? "",
|
||||||
|
onChanged: (val) => setState(
|
||||||
|
() => workingEvent.website = val),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 20),
|
||||||
|
SizedBox(
|
||||||
|
width: thirdWidth,
|
||||||
|
child: StringInputContainer(
|
||||||
|
label: "Téléphone :",
|
||||||
|
initialValue: workingEvent.phone ?? "",
|
||||||
|
onChanged: (val) =>
|
||||||
|
setState(() => workingEvent.phone = val),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 20),
|
||||||
|
SizedBox(
|
||||||
|
width: thirdWidth,
|
||||||
|
child: StringInputContainer(
|
||||||
|
label: "Email :",
|
||||||
|
initialValue: workingEvent.email ?? "",
|
||||||
|
onChanged: (val) =>
|
||||||
|
setState(() => workingEvent.email = val),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Divider(height: 24),
|
||||||
|
Text("Localisation / Géométrie",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
StringInputContainer(
|
||||||
|
label: "Adresse (Texte) :",
|
||||||
|
initialValue: workingEvent.address?.address ?? "",
|
||||||
|
onChanged: (val) {
|
||||||
|
setState(() {
|
||||||
|
if (workingEvent.address == null)
|
||||||
|
workingEvent.address =
|
||||||
|
EventAgendaDTOAddress();
|
||||||
|
workingEvent.address!.address = val;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
GeometryInputContainer(
|
||||||
|
label: "Emplacement sur la carte :",
|
||||||
|
initialGeometry: workingEvent.address?.geometry !=
|
||||||
|
null
|
||||||
|
? GeometryDTO.fromJson(
|
||||||
|
workingEvent.address!.geometry!.toJson())
|
||||||
|
: null,
|
||||||
|
initialColor: workingEvent.address?.polyColor,
|
||||||
|
onSave: (geo, color) {
|
||||||
|
setState(() {
|
||||||
|
if (workingEvent.address == null)
|
||||||
|
workingEvent.address =
|
||||||
|
EventAgendaDTOAddress();
|
||||||
|
workingEvent.address!.geometry =
|
||||||
|
EventAddressDTOGeometry.fromJson(
|
||||||
|
geo.toJson());
|
||||||
|
workingEvent.address!.polyColor = color;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
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(workingEvent);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
color: kPrimaryColor,
|
||||||
|
fontSize: 15,
|
||||||
|
horizontal: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,253 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_api_new/api.dart';
|
||||||
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'showNewOrUpdateProgrammeBlock.dart';
|
||||||
|
|
||||||
|
class EventConfig extends StatefulWidget {
|
||||||
|
final SectionEventDTO initialValue;
|
||||||
|
final ValueChanged<SectionEventDTO> onChanged;
|
||||||
|
|
||||||
|
const EventConfig({
|
||||||
|
Key? key,
|
||||||
|
required this.initialValue,
|
||||||
|
required this.onChanged,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_EventConfigState createState() => _EventConfigState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EventConfigState extends State<EventConfig> {
|
||||||
|
late SectionEventDTO eventDTO;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
eventDTO = widget.initialValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ListTile(
|
||||||
|
title: Text("Date de début"),
|
||||||
|
subtitle: Text(eventDTO.startDate != null
|
||||||
|
? DateFormat('dd/MM/yyyy HH:mm')
|
||||||
|
.format(eventDTO.startDate!)
|
||||||
|
: "Non définie"),
|
||||||
|
trailing: Icon(Icons.calendar_today),
|
||||||
|
onTap: () async {
|
||||||
|
DateTime initialDate = eventDTO.startDate ?? DateTime.now();
|
||||||
|
if (initialDate.isBefore(DateTime(2000))) {
|
||||||
|
initialDate = DateTime.now();
|
||||||
|
}
|
||||||
|
DateTime? picked = await showDatePicker(
|
||||||
|
context: context,
|
||||||
|
initialDate: initialDate,
|
||||||
|
firstDate: DateTime(2000),
|
||||||
|
lastDate: DateTime(2100),
|
||||||
|
builder: (context, child) {
|
||||||
|
return Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
colorScheme: ColorScheme.light(
|
||||||
|
primary: kPrimaryColor,
|
||||||
|
onPrimary: kWhite,
|
||||||
|
onSurface: kSecond,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: child!,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (picked != null) {
|
||||||
|
TimeOfDay? time = await showTimePicker(
|
||||||
|
context: context,
|
||||||
|
initialTime: TimeOfDay.fromDateTime(
|
||||||
|
eventDTO.startDate ?? DateTime.now()),
|
||||||
|
builder: (context, child) {
|
||||||
|
return Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
colorScheme: ColorScheme.light(
|
||||||
|
primary: kPrimaryColor,
|
||||||
|
onPrimary: kWhite,
|
||||||
|
onSurface: kSecond,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: child!,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (time != null) {
|
||||||
|
setState(() {
|
||||||
|
eventDTO.startDate = DateTime(picked.year,
|
||||||
|
picked.month, picked.day, time.hour, time.minute);
|
||||||
|
widget.onChanged(eventDTO);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListTile(
|
||||||
|
title: Text("Date de fin"),
|
||||||
|
subtitle: Text(eventDTO.endDate != null
|
||||||
|
? DateFormat('dd/MM/yyyy HH:mm').format(eventDTO.endDate!)
|
||||||
|
: "Non définie"),
|
||||||
|
trailing: Icon(Icons.calendar_today),
|
||||||
|
onTap: () async {
|
||||||
|
DateTime initialDate = eventDTO.endDate ??
|
||||||
|
DateTime.now().add(Duration(days: 1));
|
||||||
|
if (initialDate.isBefore(DateTime(2000))) {
|
||||||
|
initialDate = DateTime.now().add(Duration(days: 1));
|
||||||
|
}
|
||||||
|
DateTime? picked = await showDatePicker(
|
||||||
|
context: context,
|
||||||
|
initialDate: initialDate,
|
||||||
|
firstDate: DateTime(2000),
|
||||||
|
lastDate: DateTime(2100),
|
||||||
|
builder: (context, child) {
|
||||||
|
return Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
colorScheme: ColorScheme.light(
|
||||||
|
primary: kPrimaryColor,
|
||||||
|
onPrimary: kWhite,
|
||||||
|
onSurface: kSecond,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: child!,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (picked != null) {
|
||||||
|
TimeOfDay? time = await showTimePicker(
|
||||||
|
context: context,
|
||||||
|
initialTime: TimeOfDay.fromDateTime(eventDTO.endDate ??
|
||||||
|
DateTime.now().add(Duration(days: 1))),
|
||||||
|
builder: (context, child) {
|
||||||
|
return Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
colorScheme: ColorScheme.light(
|
||||||
|
primary: kPrimaryColor,
|
||||||
|
onPrimary: kWhite,
|
||||||
|
onSurface: kSecond,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: child!,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (time != null) {
|
||||||
|
setState(() {
|
||||||
|
eventDTO.endDate = DateTime(picked.year, picked.month,
|
||||||
|
picked.day, time.hour, time.minute);
|
||||||
|
widget.onChanged(eventDTO);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text("Programme",
|
||||||
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
|
ElevatedButton.icon(
|
||||||
|
icon: Icon(Icons.add),
|
||||||
|
label: Text("Ajouter un bloc"),
|
||||||
|
onPressed: () {
|
||||||
|
showNewOrUpdateProgrammeBlock(
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
(newBlock) {
|
||||||
|
setState(() {
|
||||||
|
eventDTO.programme = [
|
||||||
|
...(eventDTO.programme ?? []),
|
||||||
|
newBlock
|
||||||
|
];
|
||||||
|
widget.onChanged(eventDTO);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: kSuccess, foregroundColor: kWhite),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: (eventDTO.programme == null || eventDTO.programme!.isEmpty)
|
||||||
|
? Center(
|
||||||
|
child: Text("Aucun bloc de programme défini",
|
||||||
|
style: TextStyle(fontStyle: FontStyle.italic)))
|
||||||
|
: ListView.builder(
|
||||||
|
itemCount: eventDTO.programme!.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final block = eventDTO.programme![index];
|
||||||
|
return Card(
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(
|
||||||
|
block.title != null && block.title!.isNotEmpty
|
||||||
|
? block.title!
|
||||||
|
.firstWhere((t) => t.language == 'FR',
|
||||||
|
orElse: () => block.title![0])
|
||||||
|
.value ??
|
||||||
|
"Bloc ${index + 1}"
|
||||||
|
: "Bloc ${index + 1}"),
|
||||||
|
subtitle: Text(
|
||||||
|
"${block.startTime != null ? DateFormat('HH:mm').format(block.startTime!) : '??'} - ${block.endTime != null ? DateFormat('HH:mm').format(block.endTime!) : '??'}"),
|
||||||
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.edit, color: kPrimaryColor),
|
||||||
|
onPressed: () {
|
||||||
|
showNewOrUpdateProgrammeBlock(
|
||||||
|
context,
|
||||||
|
block,
|
||||||
|
(updatedBlock) {
|
||||||
|
setState(() {
|
||||||
|
eventDTO.programme![index] = updatedBlock;
|
||||||
|
widget.onChanged(eventDTO);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.delete, color: kError),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
eventDTO.programme!.removeAt(index);
|
||||||
|
widget.onChanged(eventDTO);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,235 @@
|
|||||||
|
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:intl/intl.dart';
|
||||||
|
|
||||||
|
void showNewOrUpdateProgrammeBlock(
|
||||||
|
BuildContext context,
|
||||||
|
ProgrammeBlock? block,
|
||||||
|
Function(ProgrammeBlock) onSave,
|
||||||
|
) {
|
||||||
|
ProgrammeBlock workingBlock = block != null
|
||||||
|
? ProgrammeBlock.fromJson(block.toJson())!
|
||||||
|
: ProgrammeBlock(
|
||||||
|
title: [],
|
||||||
|
description: [],
|
||||||
|
startTime: DateTime.now(),
|
||||||
|
endTime: DateTime.now().add(Duration(hours: 1)),
|
||||||
|
);
|
||||||
|
|
||||||
|
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.7;
|
||||||
|
final double contentWidth = dialogWidth - 48;
|
||||||
|
final double halfWidth = (contentWidth - 20) / 2;
|
||||||
|
|
||||||
|
return Dialog(
|
||||||
|
shape:
|
||||||
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||||
|
child: Container(
|
||||||
|
width: dialogWidth,
|
||||||
|
constraints: BoxConstraints(maxHeight: screenHeight * 0.85),
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
block == null
|
||||||
|
? "Nouveau Bloc de Programme"
|
||||||
|
: "Modifier le Bloc",
|
||||||
|
style: TextStyle(
|
||||||
|
color: kPrimaryColor,
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
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 bloc",
|
||||||
|
initialValue: workingBlock.title ?? [],
|
||||||
|
onGetResult: (val) =>
|
||||||
|
setState(() => workingBlock.title = val),
|
||||||
|
maxLines: 1,
|
||||||
|
isTitle: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 20),
|
||||||
|
SizedBox(
|
||||||
|
width: halfWidth,
|
||||||
|
child: MultiStringInputContainer(
|
||||||
|
label: "Description :",
|
||||||
|
modalLabel: "Description du bloc",
|
||||||
|
initialValue: workingBlock.description ?? [],
|
||||||
|
onGetResult: (val) => setState(
|
||||||
|
() => workingBlock.description = val),
|
||||||
|
maxLines: 1,
|
||||||
|
isTitle: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Divider(height: 24),
|
||||||
|
// Heures côte à côte
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: halfWidth,
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(Icons.schedule,
|
||||||
|
color: kPrimaryColor),
|
||||||
|
title: Text("Heure de début"),
|
||||||
|
subtitle: Text(
|
||||||
|
workingBlock.startTime != null
|
||||||
|
? DateFormat('HH:mm')
|
||||||
|
.format(workingBlock.startTime!)
|
||||||
|
: "Non définie",
|
||||||
|
style: TextStyle(
|
||||||
|
color: kPrimaryColor,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
TimeOfDay? time = await showTimePicker(
|
||||||
|
context: context,
|
||||||
|
initialTime: TimeOfDay.fromDateTime(
|
||||||
|
workingBlock.startTime ??
|
||||||
|
DateTime.now()),
|
||||||
|
builder: (context, child) {
|
||||||
|
return Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
colorScheme: ColorScheme.light(
|
||||||
|
primary: kPrimaryColor,
|
||||||
|
onPrimary: kWhite,
|
||||||
|
onSurface: kSecond,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: child!,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (time != null) {
|
||||||
|
setState(() {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
workingBlock.startTime = DateTime(
|
||||||
|
now.year,
|
||||||
|
now.month,
|
||||||
|
now.day,
|
||||||
|
time.hour,
|
||||||
|
time.minute);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 20),
|
||||||
|
SizedBox(
|
||||||
|
width: halfWidth,
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(Icons.schedule_outlined,
|
||||||
|
color: kPrimaryColor),
|
||||||
|
title: Text("Heure de fin"),
|
||||||
|
subtitle: Text(
|
||||||
|
workingBlock.endTime != null
|
||||||
|
? DateFormat('HH:mm')
|
||||||
|
.format(workingBlock.endTime!)
|
||||||
|
: "Non définie",
|
||||||
|
style: TextStyle(
|
||||||
|
color: kPrimaryColor,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
TimeOfDay? time = await showTimePicker(
|
||||||
|
context: context,
|
||||||
|
initialTime: TimeOfDay.fromDateTime(
|
||||||
|
workingBlock.endTime ??
|
||||||
|
DateTime.now()
|
||||||
|
.add(Duration(hours: 1))),
|
||||||
|
builder: (context, child) {
|
||||||
|
return Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
colorScheme: ColorScheme.light(
|
||||||
|
primary: kPrimaryColor,
|
||||||
|
onPrimary: kWhite,
|
||||||
|
onSurface: kSecond,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: child!,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (time != null) {
|
||||||
|
setState(() {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
workingBlock.endTime = DateTime(
|
||||||
|
now.year,
|
||||||
|
now.month,
|
||||||
|
now.day,
|
||||||
|
time.hour,
|
||||||
|
time.minute);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
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(workingBlock);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
color: kPrimaryColor,
|
||||||
|
fontSize: 15,
|
||||||
|
horizontal: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -4,8 +4,7 @@ import 'package:manager_app/Components/multi_string_input_and_resource_container
|
|||||||
import 'package:manager_app/Components/number_input_container.dart';
|
import 'package:manager_app/Components/number_input_container.dart';
|
||||||
import 'package:manager_app/Components/resource_input_container.dart';
|
import 'package:manager_app/Components/resource_input_container.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'dart:convert';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/parcours_config.dart';
|
||||||
|
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
|
||||||
class GameConfig extends StatefulWidget {
|
class GameConfig extends StatefulWidget {
|
||||||
@ -30,33 +29,73 @@ class _GameConfigState extends State<GameConfig> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
GameDTO test = widget.initialValue;
|
gameDTO = widget.initialValue;
|
||||||
/*if(test.puzzleImage == null) {
|
gameDTO.rows = gameDTO.rows ?? 3;
|
||||||
test.puzzleImage = ResourceDTO();
|
gameDTO.cols = gameDTO.cols ?? 3;
|
||||||
}*/
|
gameDTO.gameType = gameDTO.gameType ?? GameTypes.number0;
|
||||||
gameDTO = test;
|
|
||||||
gameDTO.rows = gameDTO.rows == null ? 3 : gameDTO.rows;
|
|
||||||
gameDTO.cols = gameDTO.cols == null ? 3 : gameDTO.cols;
|
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Center(
|
return Column(
|
||||||
child: Column(
|
children: [
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text("Type de Jeu : ",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
|
||||||
|
DropdownButton<GameTypes>(
|
||||||
|
value: gameDTO.gameType,
|
||||||
|
items: [
|
||||||
|
DropdownMenuItem(
|
||||||
|
value: GameTypes.number0, child: Text("Puzzle")),
|
||||||
|
DropdownMenuItem(
|
||||||
|
value: GameTypes.number1, child: Text("Puzzle Glissant")),
|
||||||
|
DropdownMenuItem(
|
||||||
|
value: GameTypes.number2, child: Text("Escape Game")),
|
||||||
|
],
|
||||||
|
onChanged: (val) {
|
||||||
|
setState(() {
|
||||||
|
gameDTO.gameType = val;
|
||||||
|
widget.onChanged(gameDTO);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (gameDTO.gameType == GameTypes.number2) ...[
|
||||||
|
// Escape Mode: Parcours Config
|
||||||
|
Expanded(
|
||||||
|
child: ParcoursConfig(
|
||||||
|
initialValue: gameDTO.guidedPaths ?? [],
|
||||||
|
parentId: gameDTO.id!,
|
||||||
|
isEvent: false,
|
||||||
|
isEscapeMode: true,
|
||||||
|
onChanged: (paths) {
|
||||||
|
setState(() {
|
||||||
|
gameDTO.guidedPaths = paths;
|
||||||
|
widget.onChanged(gameDTO);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
] else ...[
|
||||||
|
// Regular Puzzle Mode
|
||||||
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
ResourceInputContainer(
|
ResourceInputContainer(
|
||||||
label: "Image du puzzle :",
|
label: "Image du puzzle :",
|
||||||
initialValue: gameDTO.puzzleImageId == null ? '': gameDTO.puzzleImageId,
|
initialValue: gameDTO.puzzleImageId ?? '',
|
||||||
onChanged: (ResourceDTO resourceDTO) {
|
onChanged: (ResourceDTO resourceDTO) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if(resourceDTO.id == null)
|
if (resourceDTO.id == null) {
|
||||||
{
|
|
||||||
gameDTO.puzzleImageId = null;
|
gameDTO.puzzleImageId = null;
|
||||||
gameDTO.puzzleImage = null;
|
gameDTO.puzzleImage = null;
|
||||||
} else {
|
} else {
|
||||||
@ -65,7 +104,7 @@ class _GameConfigState extends State<GameConfig> {
|
|||||||
}
|
}
|
||||||
widget.onChanged(gameDTO);
|
widget.onChanged(gameDTO);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
height: 100,
|
height: 100,
|
||||||
@ -74,19 +113,23 @@ class _GameConfigState extends State<GameConfig> {
|
|||||||
modalLabel: "Message départ",
|
modalLabel: "Message départ",
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: gameDTO.messageDebut != null ? gameDTO.messageDebut! : [],
|
initialValue: gameDTO.messageDebut ?? [],
|
||||||
resourceTypes: [ResourceType.Image, ResourceType.ImageUrl, ResourceType.VideoUrl, ResourceType.Video, ResourceType.Audio],
|
resourceTypes: [
|
||||||
|
ResourceType.Image,
|
||||||
|
ResourceType.ImageUrl,
|
||||||
|
ResourceType.VideoUrl,
|
||||||
|
ResourceType.Video,
|
||||||
|
ResourceType.Audio
|
||||||
|
],
|
||||||
onGetResult: (value) {
|
onGetResult: (value) {
|
||||||
if (gameDTO.messageDebut != value) {
|
|
||||||
setState(() {
|
setState(() {
|
||||||
gameDTO.messageDebut = value;
|
gameDTO.messageDebut = value;
|
||||||
widget.onChanged(gameDTO);
|
widget.onChanged(gameDTO);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
},
|
},
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
isTitle: false
|
isTitle: false,
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
height: 100,
|
height: 100,
|
||||||
@ -95,19 +138,23 @@ class _GameConfigState extends State<GameConfig> {
|
|||||||
modalLabel: "Message fin",
|
modalLabel: "Message fin",
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: gameDTO.messageFin != null ? gameDTO.messageFin! : [],
|
initialValue: gameDTO.messageFin ?? [],
|
||||||
resourceTypes: [ResourceType.Image, ResourceType.ImageUrl, ResourceType.VideoUrl, ResourceType.Video, ResourceType.Audio],
|
resourceTypes: [
|
||||||
|
ResourceType.Image,
|
||||||
|
ResourceType.ImageUrl,
|
||||||
|
ResourceType.VideoUrl,
|
||||||
|
ResourceType.Video,
|
||||||
|
ResourceType.Audio
|
||||||
|
],
|
||||||
onGetResult: (value) {
|
onGetResult: (value) {
|
||||||
if (gameDTO.messageFin != value) {
|
|
||||||
setState(() {
|
setState(() {
|
||||||
gameDTO.messageFin = value;
|
gameDTO.messageFin = value;
|
||||||
widget.onChanged(gameDTO);
|
widget.onChanged(gameDTO);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
},
|
},
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
isTitle: false
|
isTitle: false,
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -118,7 +165,7 @@ class _GameConfigState extends State<GameConfig> {
|
|||||||
height: 100,
|
height: 100,
|
||||||
child: NumberInputContainer(
|
child: NumberInputContainer(
|
||||||
label: "Nombre de lignes :",
|
label: "Nombre de lignes :",
|
||||||
initialValue: gameDTO.rows!,
|
initialValue: gameDTO.rows ?? 3,
|
||||||
isSmall: true,
|
isSmall: true,
|
||||||
maxLength: 2,
|
maxLength: 2,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@ -128,7 +175,8 @@ class _GameConfigState extends State<GameConfig> {
|
|||||||
widget.onChanged(gameDTO);
|
widget.onChanged(gameDTO);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(Colors.orange, kWhite, 'Cela doit être un chiffre', context, null);
|
showNotification(Colors.orange, kWhite,
|
||||||
|
'Cela doit être un chiffre', context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -137,7 +185,7 @@ class _GameConfigState extends State<GameConfig> {
|
|||||||
height: 100,
|
height: 100,
|
||||||
child: NumberInputContainer(
|
child: NumberInputContainer(
|
||||||
label: "Nombre de colonnes :",
|
label: "Nombre de colonnes :",
|
||||||
initialValue: gameDTO.cols!,
|
initialValue: gameDTO.cols ?? 3,
|
||||||
isSmall: true,
|
isSmall: true,
|
||||||
maxLength: 2,
|
maxLength: 2,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@ -147,14 +195,18 @@ class _GameConfigState extends State<GameConfig> {
|
|||||||
widget.onChanged(gameDTO);
|
widget.onChanged(gameDTO);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(Colors.orange, kWhite, 'Cela doit être un chiffre', context, null);
|
showNotification(Colors.orange, kWhite,
|
||||||
|
'Cela doit être un chiffre', context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import 'package:manager_app/Components/confirmation_dialog.dart';
|
|||||||
import 'package:manager_app/Components/geoloc_input_container.dart';
|
import 'package:manager_app/Components/geoloc_input_container.dart';
|
||||||
import 'package:manager_app/Components/common_loader.dart';
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
import 'package:manager_app/Components/multi_select_dropdown_language_container.dart';
|
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/category_input_container.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/category_input_container.dart';
|
||||||
import 'package:manager_app/Components/dropDown_input_container.dart';
|
import 'package:manager_app/Components/dropDown_input_container.dart';
|
||||||
@ -17,12 +16,11 @@ import 'package:manager_app/Components/single_select_container.dart';
|
|||||||
import 'package:manager_app/Components/slider_input_container.dart';
|
import 'package:manager_app/Components/slider_input_container.dart';
|
||||||
import 'package:manager_app/Components/string_input_container.dart';
|
import 'package:manager_app/Components/string_input_container.dart';
|
||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/showNewOrUpdateGeoPoint.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/showNewOrUpdateGeoPoint.dart';
|
||||||
import 'package:html/parser.dart' show parse;
|
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/client.dart';
|
import 'package:manager_app/client.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'dart:convert';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/parcours_config.dart';
|
||||||
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -52,7 +50,8 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
|
|
||||||
String filterSearch = '';
|
String filterSearch = '';
|
||||||
|
|
||||||
final ValueNotifier<List<int>?> selectedCategoriesNotifier = ValueNotifier([]);
|
final ValueNotifier<List<int>?> selectedCategoriesNotifier =
|
||||||
|
ValueNotifier([]);
|
||||||
final ValueNotifier<String?> searchNotifier = ValueNotifier("");
|
final ValueNotifier<String?> searchNotifier = ValueNotifier("");
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -126,7 +125,25 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return DefaultTabController(
|
||||||
|
length: 2,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
TabBar(
|
||||||
|
labelColor: kPrimaryColor,
|
||||||
|
unselectedLabelColor: Colors.grey,
|
||||||
|
indicatorColor: kPrimaryColor,
|
||||||
|
tabs: [
|
||||||
|
Tab(icon: Icon(Icons.map), text: "Points d'Intérêt"),
|
||||||
|
Tab(icon: Icon(Icons.route), text: "Parcours"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 500, // Reduced from 550 to 500 to avoid 8.5px overflow
|
||||||
|
child: TabBarView(
|
||||||
|
children: [
|
||||||
|
// Tab 1: Configuration & Points
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -137,7 +154,8 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
SingleSelectContainer(
|
SingleSelectContainer(
|
||||||
label: "Service :",
|
label: "Service :",
|
||||||
@ -147,31 +165,38 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
onChanged: (String value) {
|
onChanged: (String value) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case "Google":
|
case "Google":
|
||||||
mapDTO.mapProvider = MapProvider.Google;
|
mapDTO.mapProvider =
|
||||||
|
MapProvider.Google;
|
||||||
break;
|
break;
|
||||||
case "MapBox":
|
case "MapBox":
|
||||||
mapDTO.mapProvider = MapProvider.MapBox;
|
mapDTO.mapProvider =
|
||||||
|
MapProvider.MapBox;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//widget.onChanged(jsonEncode(mapDTO).toString());
|
|
||||||
widget.onChanged(mapDTO);
|
widget.onChanged(mapDTO);
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
GeolocInputContainer(
|
GeolocInputContainer(
|
||||||
label: "Point de centrage:",
|
label: "Point de centrage:",
|
||||||
initialValue: mapDTO.centerLatitude != null && mapDTO.centerLongitude != null ? LatLong(double.parse(mapDTO.centerLatitude!), double.parse(mapDTO.centerLongitude!)) : null,
|
initialValue:
|
||||||
|
mapDTO.centerLatitude != null &&
|
||||||
|
mapDTO.centerLongitude != null
|
||||||
|
? LatLong(
|
||||||
|
double.parse(
|
||||||
|
mapDTO.centerLatitude!),
|
||||||
|
double.parse(
|
||||||
|
mapDTO.centerLongitude!))
|
||||||
|
: null,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
onChanged: (LatLong? localisation) {
|
onChanged: (LatLong? localisation) {
|
||||||
if (localisation != null) {
|
if (localisation != null) {
|
||||||
mapDTO.centerLongitude = localisation.longitude.toString();
|
mapDTO.centerLongitude =
|
||||||
mapDTO.centerLatitude = localisation.latitude.toString();
|
localisation.longitude.toString();
|
||||||
|
mapDTO.centerLatitude =
|
||||||
|
localisation.latitude.toString();
|
||||||
}
|
}
|
||||||
//widget.onChanged(jsonEncode(mapDTO).toString());
|
|
||||||
widget.onChanged(mapDTO);
|
widget.onChanged(mapDTO);
|
||||||
},
|
},
|
||||||
isSmall: true
|
isSmall: true),
|
||||||
),
|
|
||||||
// Icon
|
|
||||||
ResourceInputContainer(
|
ResourceInputContainer(
|
||||||
label: "Icône:",
|
label: "Icône:",
|
||||||
initialValue: mapDTO.iconResourceId,
|
initialValue: mapDTO.iconResourceId,
|
||||||
@ -185,25 +210,21 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
mapDTO.iconResourceId = resource.id;
|
mapDTO.iconResourceId = resource.id;
|
||||||
mapDTO.iconSource = resource.url;
|
mapDTO.iconSource = resource.url;
|
||||||
}
|
}
|
||||||
//widget.onChanged(jsonEncode(mapDTO).toString());
|
|
||||||
widget.onChanged(mapDTO);
|
widget.onChanged(mapDTO);
|
||||||
},
|
},
|
||||||
isSmall: true
|
isSmall: true),
|
||||||
),
|
]),
|
||||||
]
|
|
||||||
),
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
if (mapDTO.mapProvider == MapProvider.Google)
|
if (mapDTO.mapProvider == MapProvider.Google)
|
||||||
// Map Type
|
|
||||||
DropDownInputContainer(
|
DropDownInputContainer(
|
||||||
label: "Type:",
|
label: "Type:",
|
||||||
values: map_types,
|
values: map_types,
|
||||||
initialValue: mapType,
|
initialValue: mapType,
|
||||||
onChange: (String? value) {
|
onChange: (String? value) {
|
||||||
mapDTO.mapType = MapTypeApp.fromJson(value);
|
mapDTO.mapType =
|
||||||
//widget.onChanged(jsonEncode(mapDTO).toString());
|
MapTypeApp.fromJson(value);
|
||||||
widget.onChanged(mapDTO);
|
widget.onChanged(mapDTO);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -213,21 +234,21 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
values: map_types_mapBox,
|
values: map_types_mapBox,
|
||||||
initialValue: mapTypeMapBox,
|
initialValue: mapTypeMapBox,
|
||||||
onChange: (String? value) {
|
onChange: (String? value) {
|
||||||
mapDTO.mapTypeMapbox = MapTypeMapBox.fromJson(value);
|
mapDTO.mapTypeMapbox =
|
||||||
//widget.onChanged(jsonEncode(mapDTO).toString());
|
MapTypeMapBox.fromJson(value);
|
||||||
widget.onChanged(mapDTO);
|
widget.onChanged(mapDTO);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
// Zoom
|
|
||||||
SliderInputContainer(
|
SliderInputContainer(
|
||||||
label: "Zoom:",
|
label: "Zoom:",
|
||||||
initialValue: mapDTO.zoom != null ? mapDTO.zoom!.toDouble() : 18,
|
initialValue: mapDTO.zoom != null
|
||||||
|
? mapDTO.zoom!.toDouble()
|
||||||
|
: 18,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 30,
|
max: 30,
|
||||||
onChanged: (double value) {
|
onChanged: (double value) {
|
||||||
mapDTO.zoom = value.toInt();
|
mapDTO.zoom = value.toInt();
|
||||||
//widget.onChanged(jsonEncode(mapDTO).toString());
|
|
||||||
widget.onChanged(mapDTO);
|
widget.onChanged(mapDTO);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -235,18 +256,21 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
height: 70,
|
height: 70,
|
||||||
child: CategoryInputContainer(
|
child: CategoryInputContainer(
|
||||||
label: "Catégories :",
|
label: "Catégories :",
|
||||||
initialValue: mapDTO.categories != null ? mapDTO.categories! : [],
|
initialValue: mapDTO.categories != null
|
||||||
|
? mapDTO.categories!
|
||||||
|
: [],
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
onChanged: (List<CategorieDTO>? value) {
|
onChanged: (List<CategorieDTO>? value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
mapDTO.categories = value;
|
mapDTO.categories = value;
|
||||||
|
|
||||||
//update point's category
|
|
||||||
if (mapDTO.points != null) {
|
if (mapDTO.points != null) {
|
||||||
mapDTO.points!.forEach((p) {
|
mapDTO.points!.forEach((p) {
|
||||||
// Check if category still exist - Delete
|
if (p.categorieId != null &&
|
||||||
if(p.categorieId != null && !mapDTO.categories!.map((c) => c.id).any((e) => e != null && e == p.categorieId))
|
!mapDTO.categories!
|
||||||
{
|
.map((c) => c.id)
|
||||||
|
.any((e) =>
|
||||||
|
e != null &&
|
||||||
|
e == p.categorieId)) {
|
||||||
p.categorieId = null;
|
p.categorieId = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -262,63 +286,143 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
FutureBuilder(
|
FutureBuilder(
|
||||||
future: getGeoPoints((appContext.getContext() as ManagerAppContext).clientAPI!),
|
future: getGeoPoints(
|
||||||
|
(appContext.getContext() as ManagerAppContext)
|
||||||
|
.clientAPI!),
|
||||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
if (snapshot.connectionState ==
|
||||||
|
ConnectionState.waiting) {
|
||||||
return Center(child: CommonLoader());
|
return Center(child: CommonLoader());
|
||||||
} else {
|
} else {
|
||||||
if(snapshot.connectionState == ConnectionState.done)
|
if (snapshot.connectionState ==
|
||||||
{
|
ConnectionState.done) {
|
||||||
mapDTO.points = snapshot.data;
|
mapDTO.points = snapshot.data;
|
||||||
pointsToShow = mapDTO.points!;
|
pointsToShow = mapDTO.points!;
|
||||||
pointsToShow.sort((a, b) => a.title!.firstWhere((t) => t.language == 'FR').value!.toLowerCase().compareTo(b.title!.firstWhere((t) => t.language == 'FR').value!.toLowerCase()));
|
pointsToShow.sort((a, b) => a.title!
|
||||||
selectedCategoriesNotifier.value = mapDTO.categories!.map((categorie) => categorie.id!).toList();
|
.firstWhere((t) => t.language == 'FR')
|
||||||
|
.value!
|
||||||
|
.toLowerCase()
|
||||||
|
.compareTo(b.title!
|
||||||
|
.firstWhere((t) => t.language == 'FR')
|
||||||
|
.value!
|
||||||
|
.toLowerCase()));
|
||||||
|
selectedCategoriesNotifier.value = mapDTO
|
||||||
|
.categories!
|
||||||
|
.map((categorie) => categorie.id!)
|
||||||
|
.toList();
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(25),
|
borderRadius: BorderRadius.circular(25),
|
||||||
border: Border.all(width: 1.5, color: kSecond)
|
border: Border.all(
|
||||||
),
|
width: 1.5, color: kSecond)),
|
||||||
child: Stack(
|
child: Stack(children: [
|
||||||
children: [
|
|
||||||
Container(
|
Container(
|
||||||
constraints: BoxConstraints(minHeight: 100),
|
constraints:
|
||||||
|
BoxConstraints(minHeight: 100),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(top: 95, left: 10, right: 10, bottom: 10),
|
padding: const EdgeInsets.only(
|
||||||
child: ValueListenableBuilder<String?>(
|
top: 95,
|
||||||
valueListenable: searchNotifier,
|
left: 10,
|
||||||
builder: (context, searchValue, child) {
|
right: 10,
|
||||||
return ValueListenableBuilder<List<int>?>(
|
bottom: 10),
|
||||||
valueListenable: selectedCategoriesNotifier,
|
child:
|
||||||
builder: (context, selectedCategories, child) {
|
ValueListenableBuilder<String?>(
|
||||||
if(selectedCategories == null || selectedCategories.length == 0) {
|
valueListenable:
|
||||||
pointsToShow = mapDTO.points!.where((point) => point.categorieId == null).toList();
|
searchNotifier,
|
||||||
|
builder: (context,
|
||||||
|
searchValue, child) {
|
||||||
|
return ValueListenableBuilder<
|
||||||
|
List<int>?>(
|
||||||
|
valueListenable:
|
||||||
|
selectedCategoriesNotifier,
|
||||||
|
builder: (context,
|
||||||
|
selectedCategories,
|
||||||
|
child) {
|
||||||
|
if (selectedCategories ==
|
||||||
|
null ||
|
||||||
|
selectedCategories
|
||||||
|
.length ==
|
||||||
|
0) {
|
||||||
|
pointsToShow = mapDTO
|
||||||
|
.points!
|
||||||
|
.where((point) =>
|
||||||
|
point
|
||||||
|
.categorieId ==
|
||||||
|
null)
|
||||||
|
.toList();
|
||||||
} else {
|
} else {
|
||||||
pointsToShow = mapDTO.points!.where((point) => selectedCategories.any((tps) => point.categorieId == null || point.categorieId == tps)).toList();
|
pointsToShow = mapDTO
|
||||||
|
.points!
|
||||||
|
.where((point) =>
|
||||||
|
selectedCategories.any((tps) =>
|
||||||
|
point.categorieId ==
|
||||||
|
null ||
|
||||||
|
point.categorieId ==
|
||||||
|
tps))
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
pointsToShow = searchValue != null && searchValue.trim().isNotEmpty ? pointsToShow.where((GeoPointDTO pointGeo) => removeDiacritics(pointGeo.title!.firstWhere((t) => t.language == "FR").value!.toUpperCase()).contains(removeDiacritics(searchValue.toUpperCase()))).toList() : pointsToShow;
|
pointsToShow = searchValue !=
|
||||||
|
null &&
|
||||||
|
searchValue
|
||||||
|
.trim()
|
||||||
|
.isNotEmpty
|
||||||
|
? pointsToShow
|
||||||
|
.where((GeoPointDTO pointGeo) => removeDiacritics(pointGeo
|
||||||
|
.title!
|
||||||
|
.firstWhere((t) =>
|
||||||
|
t.language ==
|
||||||
|
"FR")
|
||||||
|
.value!
|
||||||
|
.toUpperCase())
|
||||||
|
.contains(
|
||||||
|
removeDiacritics(
|
||||||
|
searchValue.toUpperCase())))
|
||||||
|
.toList()
|
||||||
|
: pointsToShow;
|
||||||
|
|
||||||
return GridView.builder(
|
return GridView
|
||||||
shrinkWrap: true,
|
.builder(
|
||||||
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 8),
|
shrinkWrap:
|
||||||
itemCount: pointsToShow.length,
|
true,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
gridDelegate:
|
||||||
return
|
new SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
Container(
|
crossAxisCount:
|
||||||
decoration: boxDecoration(pointsToShow[index], appContext),
|
8),
|
||||||
padding: const EdgeInsets.all(5),
|
itemCount:
|
||||||
margin: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
|
pointsToShow
|
||||||
child: getElement(index, pointsToShow[index], size, appContext),
|
.length,
|
||||||
|
itemBuilder:
|
||||||
|
(BuildContext
|
||||||
|
context,
|
||||||
|
int index) {
|
||||||
|
return Container(
|
||||||
|
decoration: boxDecoration(
|
||||||
|
pointsToShow[
|
||||||
|
index],
|
||||||
|
appContext),
|
||||||
|
padding:
|
||||||
|
const EdgeInsets
|
||||||
|
.all(
|
||||||
|
5),
|
||||||
|
margin: EdgeInsets.symmetric(
|
||||||
|
vertical:
|
||||||
|
10,
|
||||||
|
horizontal:
|
||||||
|
10),
|
||||||
|
child: getElement(
|
||||||
|
index,
|
||||||
|
pointsToShow[
|
||||||
|
index],
|
||||||
|
size,
|
||||||
|
appContext),
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
);
|
});
|
||||||
}
|
}),
|
||||||
);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
@ -336,22 +440,52 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
label: null,
|
label: null,
|
||||||
color: kSecond,
|
color: kSecond,
|
||||||
width: size.width * 0.45,
|
width: size.width * 0.45,
|
||||||
initialValue: mapDTO.categories!.where((cat) => selectedCategoriesNotifier.value!.contains(cat.id)).map((categorie) => categorie.label!.firstWhere((element) => element.language == 'FR').value!).toList(),
|
initialValue: mapDTO.categories!
|
||||||
|
.where((cat) =>
|
||||||
|
selectedCategoriesNotifier
|
||||||
|
.value!
|
||||||
|
.contains(cat.id))
|
||||||
|
.map((categorie) => categorie
|
||||||
|
.label!
|
||||||
|
.firstWhere((element) =>
|
||||||
|
element.language ==
|
||||||
|
'FR')
|
||||||
|
.value!)
|
||||||
|
.toList(),
|
||||||
isMultiple: true,
|
isMultiple: true,
|
||||||
isHTMLLabel: true,
|
isHTMLLabel: true,
|
||||||
values: mapDTO.categories!.map((categorie) => categorie.label!.firstWhere((element) => element.language == 'FR').value!).toList(),
|
values: mapDTO.categories!
|
||||||
|
.map((categorie) => categorie
|
||||||
|
.label!
|
||||||
|
.firstWhere((element) =>
|
||||||
|
element.language ==
|
||||||
|
'FR')
|
||||||
|
.value!)
|
||||||
|
.toList(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
var tempOutput = new List<String>.from(value);
|
var tempOutput =
|
||||||
selectedCategoriesNotifier.value = mapDTO.categories!.where((c) => tempOutput.contains(c.label!.firstWhere((element) => element.language == 'FR').value!)).map((cat) => cat.id!).toList();
|
new List<String>.from(value);
|
||||||
|
selectedCategoriesNotifier.value =
|
||||||
|
mapDTO.categories!
|
||||||
|
.where((c) => tempOutput
|
||||||
|
.contains(c.label!
|
||||||
|
.firstWhere(
|
||||||
|
(element) =>
|
||||||
|
element
|
||||||
|
.language ==
|
||||||
|
'FR')
|
||||||
|
.value!))
|
||||||
|
.map((cat) => cat.id!)
|
||||||
|
.toList();
|
||||||
},
|
},
|
||||||
)
|
)),
|
||||||
),
|
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 0,
|
top: 0,
|
||||||
right: 150,
|
right: 150,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: size.height * 0.1,
|
height: size.height * 0.1,
|
||||||
constraints: BoxConstraints(minHeight: 85),
|
constraints:
|
||||||
|
BoxConstraints(minHeight: 85),
|
||||||
child: StringInputContainer(
|
child: StringInputContainer(
|
||||||
label: "Recherche:",
|
label: "Recherche:",
|
||||||
isSmall: true,
|
isSmall: true,
|
||||||
@ -369,42 +503,44 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showNewOrUpdateGeoPoint(
|
showNewOrUpdateGeoPoint(
|
||||||
mapDTO,
|
mapDTO, null,
|
||||||
null,
|
|
||||||
(GeoPointDTO geoPoint) async {
|
(GeoPointDTO geoPoint) async {
|
||||||
/*setState(() {
|
|
||||||
mapDTO.points!.add(geoPoint);
|
|
||||||
mapDTO.points!.sort((a, b) => a.title!.firstWhere((t) => t.language == 'FR').value!.toLowerCase().compareTo(b.title!.firstWhere((t) => t.language == 'FR').value!.toLowerCase()));
|
|
||||||
|
|
||||||
if(selectedCategoriesNotifier.value == null || selectedCategoriesNotifier.value!.length == 0) {
|
|
||||||
//pointsToShow = mapDTO.points!.where((point) => point.categorie == null).toList();
|
|
||||||
pointsToShow = mapDTO.points!.where((point) => point.categorieId == null).toList();
|
|
||||||
} else {
|
|
||||||
//pointsToShow = mapDTO.points!.where((point) => selectedCategories!.any((tps) => point.categorie == null || point.categorie?.label?.firstWhere((lab) => lab.language == 'FR').value == tps)).toList();
|
|
||||||
pointsToShow = mapDTO.points!.where((point) => selectedCategoriesNotifier.value!.any((tps) => point.categorieId == null || point.categorieId == tps)).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
//widget.onChanged(jsonEncode(mapDTO).toString());
|
|
||||||
widget.onChanged(mapDTO);
|
|
||||||
});*/
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionMapApi!.sectionMapCreate(mapDTO.id!, geoPoint);
|
await (appContext.getContext()
|
||||||
showNotification(kSuccess, kWhite, 'Le point géographique a été créé avec succès', context, null);
|
as ManagerAppContext)
|
||||||
|
.clientAPI!
|
||||||
|
.sectionMapApi!
|
||||||
|
.sectionMapCreate(
|
||||||
|
mapDTO.id!, geoPoint);
|
||||||
|
showNotification(
|
||||||
|
kSuccess,
|
||||||
|
kWhite,
|
||||||
|
'Le point géographique a été créé avec succès',
|
||||||
|
context,
|
||||||
|
null);
|
||||||
setState(() {
|
setState(() {
|
||||||
// refresh ui
|
// refresh ui
|
||||||
print("Refresh UI");
|
print("Refresh UI");
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors de la création du point géographique', context, null);
|
showNotification(
|
||||||
|
kError,
|
||||||
|
kWhite,
|
||||||
|
'Une erreur est survenue lors de la création du point géographique',
|
||||||
|
context,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
},
|
}, appContext, context);
|
||||||
appContext,
|
|
||||||
context);
|
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
height: MediaQuery.of(context).size.width * 0.04,
|
height: MediaQuery.of(context)
|
||||||
width: MediaQuery.of(context).size.width * 0.04,
|
.size
|
||||||
|
.width *
|
||||||
|
0.04,
|
||||||
|
width: MediaQuery.of(context)
|
||||||
|
.size
|
||||||
|
.width *
|
||||||
|
0.04,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
color: kTextLightColor,
|
color: kTextLightColor,
|
||||||
@ -413,13 +549,15 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kSuccess,
|
color: kSuccess,
|
||||||
shape: BoxShape.rectangle,
|
shape: BoxShape.rectangle,
|
||||||
borderRadius: BorderRadius.circular(20.0),
|
borderRadius:
|
||||||
|
BorderRadius.circular(20.0),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: kSecond,
|
color: kSecond,
|
||||||
spreadRadius: 0.5,
|
spreadRadius: 0.5,
|
||||||
blurRadius: 5,
|
blurRadius: 5,
|
||||||
offset: Offset(0, 1.5), // changes position of shadow
|
offset: Offset(0,
|
||||||
|
1.5), // changes position of shadow
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -430,10 +568,30 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Center(child: Text("Une erreur est survenue lors de la récupération des points géographiques"),);
|
return Center(
|
||||||
}
|
child: Text(
|
||||||
|
"Une erreur est survenue lors de la récupération des points géographiques"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Tab 2: Parcours
|
||||||
|
ParcoursConfig(
|
||||||
|
initialValue: mapDTO.guidedPaths ?? [],
|
||||||
|
parentId: mapDTO.id!,
|
||||||
|
isEvent: false,
|
||||||
|
onChanged: (paths) {
|
||||||
|
setState(() {
|
||||||
|
mapDTO.guidedPaths = paths;
|
||||||
|
widget.onChanged(mapDTO);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -441,7 +599,8 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<GeoPointDTO>?> getGeoPoints(Client client) async {
|
Future<List<GeoPointDTO>?> getGeoPoints(Client client) async {
|
||||||
List<GeoPointDTO>? geoPoints = await client.sectionMapApi!.sectionMapGetAllGeoPointsFromSection(widget.initialValue.id!);
|
List<GeoPointDTO>? geoPoints = await client.sectionMapApi!
|
||||||
|
.sectionMapGetAllGeoPointsFromSection(widget.initialValue.id!);
|
||||||
return geoPoints ?? [];
|
return geoPoints ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,13 +614,15 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: HtmlWidget(
|
child: HtmlWidget(
|
||||||
point != null ? point.title == null ? "" : point.title![0].value! : "",
|
point != null
|
||||||
|
? point.title == null
|
||||||
|
? ""
|
||||||
|
: point.title![0].value!
|
||||||
|
: "",
|
||||||
//textAlign: TextAlign.left,
|
//textAlign: TextAlign.left,
|
||||||
customStylesBuilder: (element) {
|
customStylesBuilder: (element) {
|
||||||
return {'text-align': 'center'};
|
return {'text-align': 'center'};
|
||||||
},
|
}, textStyle: TextStyle(fontSize: 20)),
|
||||||
textStyle: TextStyle(fontSize: 20)
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
@ -478,19 +639,30 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
left: 0,
|
left: 0,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showNewOrUpdateGeoPoint(
|
showNewOrUpdateGeoPoint(mapDTO, pointsToShow[index],
|
||||||
mapDTO,
|
|
||||||
pointsToShow[index],
|
|
||||||
(GeoPointDTO geoPoint) async {
|
(GeoPointDTO geoPoint) async {
|
||||||
try {
|
try {
|
||||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionMapApi!.sectionMapUpdate(geoPoint);
|
await (appContext.getContext() as ManagerAppContext)
|
||||||
showNotification(kSuccess, kWhite, 'Le point géographique a été mis à jour avec succès', context, null);
|
.clientAPI!
|
||||||
|
.sectionMapApi!
|
||||||
|
.sectionMapUpdate(geoPoint);
|
||||||
|
showNotification(
|
||||||
|
kSuccess,
|
||||||
|
kWhite,
|
||||||
|
'Le point géographique a été mis à jour avec succès',
|
||||||
|
context,
|
||||||
|
null);
|
||||||
setState(() {
|
setState(() {
|
||||||
// refresh ui
|
// refresh ui
|
||||||
print("Refresh UI");
|
print("Refresh UI");
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors de la mise à jour du point géographique', context, null);
|
showNotification(
|
||||||
|
kError,
|
||||||
|
kWhite,
|
||||||
|
'Une erreur est survenue lors de la mise à jour du point géographique',
|
||||||
|
context,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*setState(() {
|
/*setState(() {
|
||||||
@ -503,16 +675,13 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
//widget.onChanged(jsonEncode(mapDTO).toString());
|
//widget.onChanged(jsonEncode(mapDTO).toString());
|
||||||
widget.onChanged(mapDTO);
|
widget.onChanged(mapDTO);
|
||||||
});*/
|
});*/
|
||||||
},
|
}, appContext, context);
|
||||||
appContext,
|
|
||||||
context);
|
|
||||||
},
|
},
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.edit,
|
Icons.edit,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
size: 20.0,
|
size: 20.0,
|
||||||
)
|
)),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
@ -521,30 +690,38 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
onTap: () async {
|
onTap: () async {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir supprimer ce point géographique ?",
|
"Êtes-vous sûr de vouloir supprimer ce point géographique ?",
|
||||||
() {},
|
() {}, () async {
|
||||||
() async {
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var pointToRemove = pointsToShow[index];
|
var pointToRemove = pointsToShow[index];
|
||||||
(appContext.getContext() as ManagerAppContext).clientAPI!.sectionMapApi!.sectionMapDelete(pointToRemove.id!);
|
(appContext.getContext() as ManagerAppContext)
|
||||||
showNotification(kSuccess, kWhite, 'Le point géographique a été supprimé avec succès', context, null);
|
.clientAPI!
|
||||||
|
.sectionMapApi!
|
||||||
|
.sectionMapDelete(pointToRemove.id!);
|
||||||
|
showNotification(
|
||||||
|
kSuccess,
|
||||||
|
kWhite,
|
||||||
|
'Le point géographique a été supprimé avec succès',
|
||||||
|
context,
|
||||||
|
null);
|
||||||
// refresh UI
|
// refresh UI
|
||||||
setState(() {
|
setState(() {
|
||||||
print("Refresh UI");
|
print("Refresh UI");
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors de la suppression du point géographique', context, null);
|
showNotification(
|
||||||
|
kError,
|
||||||
|
kWhite,
|
||||||
|
'Une erreur est survenue lors de la suppression du point géographique',
|
||||||
|
context,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
},
|
}, context);
|
||||||
context
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.delete,
|
Icons.delete,
|
||||||
color: kError,
|
color: kError,
|
||||||
size: 20.0,
|
size: 20.0,
|
||||||
)
|
)),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -552,7 +729,6 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
boxDecoration(GeoPointDTO geoPointDTO, appContext) {
|
boxDecoration(GeoPointDTO geoPointDTO, appContext) {
|
||||||
return BoxDecoration(
|
return BoxDecoration(
|
||||||
color: kBackgroundColor,
|
color: kBackgroundColor,
|
||||||
|
|||||||
@ -1,19 +1,18 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:location_picker_flutter_map/location_picker_flutter_map.dart';
|
import 'package:manager_app/Components/geometry_input_container.dart';
|
||||||
import 'package:manager_app/Components/dropDown_input_container_categories.dart';
|
import 'package:manager_app/Components/dropDown_input_container_categories.dart';
|
||||||
import 'package:manager_app/Components/common_loader.dart';
|
|
||||||
import 'package:manager_app/Components/multi_string_input_container.dart';
|
import 'package:manager_app/Components/multi_string_input_container.dart';
|
||||||
import 'package:manager_app/Components/resource_input_container.dart';
|
import 'package:manager_app/Components/resource_input_container.dart';
|
||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/Components/string_input_container.dart';
|
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/geopoint_image_list.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/geopoint_image_list.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO, Function getResult, AppContext appContext, BuildContext context) {
|
void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO,
|
||||||
GeoPointDTO geoPointDTO = new GeoPointDTO();
|
Function getResult, AppContext appContext, BuildContext context) {
|
||||||
|
GeoPointDTO geoPointDTO = GeoPointDTO();
|
||||||
|
|
||||||
if (inputGeoPointDTO != null) {
|
if (inputGeoPointDTO != null) {
|
||||||
geoPointDTO = inputGeoPointDTO;
|
geoPointDTO = inputGeoPointDTO;
|
||||||
@ -21,262 +20,222 @@ void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO, Funct
|
|||||||
geoPointDTO.title = <TranslationDTO>[];
|
geoPointDTO.title = <TranslationDTO>[];
|
||||||
geoPointDTO.description = <TranslationDTO>[];
|
geoPointDTO.description = <TranslationDTO>[];
|
||||||
geoPointDTO.contents = <ContentDTO>[];
|
geoPointDTO.contents = <ContentDTO>[];
|
||||||
|
geoPointDTO.schedules = <TranslationDTO>[];
|
||||||
|
geoPointDTO.prices = <TranslationDTO>[];
|
||||||
|
geoPointDTO.phone = <TranslationDTO>[];
|
||||||
|
geoPointDTO.email = <TranslationDTO>[];
|
||||||
|
geoPointDTO.site = <TranslationDTO>[];
|
||||||
|
|
||||||
ManagerAppContext managerAppContext = appContext.getContext();
|
ManagerAppContext managerAppContext = appContext.getContext();
|
||||||
managerAppContext.selectedConfiguration!.languages!.forEach((element) {
|
managerAppContext.selectedConfiguration!.languages!.forEach((element) {
|
||||||
var translationDTO = new TranslationDTO();
|
var translationDTO = TranslationDTO();
|
||||||
translationDTO.language = element;
|
translationDTO.language = element;
|
||||||
translationDTO.value = "";
|
translationDTO.value = "";
|
||||||
geoPointDTO.title!.add(translationDTO);
|
geoPointDTO.title!.add(translationDTO);
|
||||||
geoPointDTO.description!.add(translationDTO);
|
geoPointDTO.description!.add(translationDTO);
|
||||||
|
geoPointDTO.schedules!.add(translationDTO);
|
||||||
|
geoPointDTO.prices!.add(translationDTO);
|
||||||
|
geoPointDTO.phone!.add(translationDTO);
|
||||||
|
geoPointDTO.email!.add(translationDTO);
|
||||||
|
geoPointDTO.site!.add(translationDTO);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultPosition = LatLong(50.429333, 4.891434); // Default Namur
|
|
||||||
var pointPosition;
|
|
||||||
|
|
||||||
if(geoPointDTO.geometry != null) {
|
|
||||||
switch(geoPointDTO.geometry!.type) {
|
|
||||||
case "Point":
|
|
||||||
var coordinates = geoPointDTO.geometry!.coordinates as List<dynamic>;
|
|
||||||
pointPosition = LatLong(coordinates.first, coordinates.last);
|
|
||||||
break;
|
|
||||||
case "LineString":
|
|
||||||
pointPosition = LatLong(50.429333, 4.891434); // TODO default Namur
|
|
||||||
break;
|
|
||||||
case "Polygon":
|
|
||||||
pointPosition = LatLong(50.429333, 4.891434); // TODO default Namur
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LatLong initPosition = geoPointDTO.geometry == null ? defaultPosition : pointPosition;
|
|
||||||
|
|
||||||
Size size = MediaQuery.of(context).size;
|
|
||||||
showDialog(
|
showDialog(
|
||||||
builder: (BuildContext context) => AlertDialog(
|
context: context,
|
||||||
shape: RoundedRectangleBorder(
|
builder: (BuildContext context) {
|
||||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
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.88;
|
||||||
|
final double contentWidth =
|
||||||
|
dialogWidth - 48; // 24px padding each side
|
||||||
|
final double thirdWidth = (contentWidth - 40) / 3;
|
||||||
|
|
||||||
|
return Dialog(
|
||||||
|
shape:
|
||||||
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||||
|
child: Container(
|
||||||
|
width: dialogWidth,
|
||||||
|
constraints: BoxConstraints(maxHeight: screenHeight * 0.9),
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Titre du dialog
|
||||||
|
Text(
|
||||||
|
"Point géographique / Zone",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: kPrimaryColor),
|
||||||
),
|
),
|
||||||
content: Container(
|
SizedBox(height: 16),
|
||||||
width: size.width *0.85,
|
// Corps scrollable
|
||||||
|
Flexible(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text("Point géographique", style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
// Géométrie
|
||||||
Column(
|
GeometryInputContainer(
|
||||||
children: [
|
label: "Géométrie (Point/Ligne/Zone) :",
|
||||||
Container(
|
initialGeometry: geoPointDTO.geometry,
|
||||||
width: size.width *0.75,
|
initialColor: geoPointDTO.polyColor,
|
||||||
height: 350,
|
onSave: (geometry, color) {
|
||||||
child: FlutterLocationPicker(
|
setState(() {
|
||||||
initZoom: 14,
|
geoPointDTO.geometry = geometry;
|
||||||
initPosition: initPosition,
|
geoPointDTO.polyColor = color;
|
||||||
minZoomLevel: 0,
|
});
|
||||||
maxZoomLevel: 17,
|
|
||||||
markerIcon: const Icon(
|
|
||||||
Icons.location_pin,
|
|
||||||
color: kPrimaryColor,
|
|
||||||
size: 50,
|
|
||||||
),
|
|
||||||
loadingWidget: CommonLoader(iconSize: 40.0),
|
|
||||||
searchBarHintColor: kPrimaryColor,
|
|
||||||
mapLoadingBackgroundColor: kSecond,
|
|
||||||
zoomButtonsBackgroundColor: kPrimaryColor,
|
|
||||||
zoomButtonsColor: Colors.white,
|
|
||||||
locationButtonBackgroundColor: kPrimaryColor,
|
|
||||||
locationButtonsColor: Colors.white,
|
|
||||||
countryFilter: "be, fr",
|
|
||||||
trackMyPosition: false,
|
|
||||||
searchBarHintText: "Chercher une localisation",
|
|
||||||
searchBarTextColor: Colors.black,
|
|
||||||
searchBarBackgroundColor: Colors.white,
|
|
||||||
showSelectLocationButton : true,
|
|
||||||
selectLocationButtonText: "Choisir cette localisation",
|
|
||||||
selectedLocationButtonTextstyle: const TextStyle(fontSize: 18, color: kPrimaryColor),
|
|
||||||
mapLanguage: 'fr',
|
|
||||||
onError: (e) => print(e),
|
|
||||||
selectLocationButtonLeadingIcon: const Icon(Icons.check, color: kPrimaryColor),
|
|
||||||
onPicked: (pickedData) {
|
|
||||||
geoPointDTO.geometry = new GeometryDTO(type: "Point", coordinates: [pickedData.latLong.latitude, pickedData.latLong.longitude]);
|
|
||||||
},
|
},
|
||||||
onChanged: (pickedData) {
|
|
||||||
print("onChanged");
|
|
||||||
geoPointDTO.geometry = new GeometryDTO(type: "Point", coordinates: [pickedData.latLong.latitude, pickedData.latLong.longitude]);
|
|
||||||
/*print(pickedData.latLong.latitude);
|
|
||||||
print(pickedData.latLong.longitude);
|
|
||||||
print(pickedData.address);
|
|
||||||
print(pickedData.addressData);*/
|
|
||||||
},
|
|
||||||
showContributorBadgeForOSM: false,
|
|
||||||
),
|
),
|
||||||
),
|
SizedBox(height: 12),
|
||||||
/*Row(
|
// Ligne 1 : Titre | Description | Site
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 100,
|
width: thirdWidth,
|
||||||
child: StringInputContainer(
|
|
||||||
isSmall: true,
|
|
||||||
label: "Latitude (#.#):",
|
|
||||||
initialValue: geoPointDTO.latitude,
|
|
||||||
onChanged: (value) {
|
|
||||||
geoPointDTO.latitude = value;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 100,
|
|
||||||
child: StringInputContainer(
|
|
||||||
isSmall: true,
|
|
||||||
label: "Longitude (#.#):",
|
|
||||||
initialValue: geoPointDTO.longitude,
|
|
||||||
onChanged: (value) {
|
|
||||||
geoPointDTO.longitude = value;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),*/
|
|
||||||
Container(
|
|
||||||
height: 100,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Titre affiché:",
|
label: "Titre :",
|
||||||
modalLabel: "Titre",
|
modalLabel: "Titre",
|
||||||
fontSize: 20,
|
fontSize: 16,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: geoPointDTO.title != null ? geoPointDTO.title! : [],
|
initialValue: geoPointDTO.title ?? [],
|
||||||
onGetResult: (value) {
|
onGetResult: (value) {
|
||||||
if (geoPointDTO.title != value) {
|
|
||||||
geoPointDTO.title = value;
|
geoPointDTO.title = value;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
isTitle: true
|
isTitle: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
SizedBox(width: 20),
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
SizedBox(
|
||||||
|
width: thirdWidth,
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Description affichée:",
|
label: "Description :",
|
||||||
modalLabel: "Description",
|
modalLabel: "Description",
|
||||||
fontSize: 20,
|
fontSize: 16,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: geoPointDTO.description != null ? geoPointDTO.description! : [],
|
initialValue: geoPointDTO.description ?? [],
|
||||||
isMandatory: false,
|
isMandatory: false,
|
||||||
onGetResult: (value) {
|
onGetResult: (value) {
|
||||||
if (geoPointDTO.description != value) {
|
|
||||||
geoPointDTO.description = value;
|
geoPointDTO.description = value;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
isTitle: false
|
isTitle: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
SizedBox(width: 20),
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
SizedBox(
|
||||||
|
width: thirdWidth,
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Site :",
|
label: "Site :",
|
||||||
modalLabel: "Site web",
|
modalLabel: "Site web",
|
||||||
fontSize: 20,
|
fontSize: 16,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: geoPointDTO.site != null ? geoPointDTO.site! : [],
|
initialValue: geoPointDTO.site ?? [],
|
||||||
isMandatory: false,
|
isMandatory: false,
|
||||||
onGetResult: (value) {
|
onGetResult: (value) {
|
||||||
if (geoPointDTO.site != value) {
|
|
||||||
geoPointDTO.site = value;
|
geoPointDTO.site = value;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
isTitle: true
|
isTitle: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
SizedBox(height: 12),
|
||||||
Container(
|
// Ligne 2 : Prix | Tel | Email
|
||||||
height: 100,
|
Row(
|
||||||
width: double.infinity,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: [
|
children: [
|
||||||
Container(
|
SizedBox(
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
width: thirdWidth,
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Prix :",
|
label: "Prix :",
|
||||||
modalLabel: "Prix",
|
modalLabel: "Prix",
|
||||||
fontSize: 20,
|
fontSize: 16,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: geoPointDTO.prices != null ? geoPointDTO.prices! : [],
|
initialValue: geoPointDTO.prices ?? [],
|
||||||
isMandatory: false,
|
isMandatory: false,
|
||||||
onGetResult: (value) {
|
onGetResult: (value) {
|
||||||
if (geoPointDTO.prices != value) {
|
|
||||||
geoPointDTO.prices = value;
|
geoPointDTO.prices = value;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
isTitle: false
|
isTitle: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
SizedBox(width: 20),
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
SizedBox(
|
||||||
|
width: thirdWidth,
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Téléphone:",
|
label: "Tel :",
|
||||||
modalLabel: "Téléphone",
|
modalLabel: "Téléphone",
|
||||||
fontSize: 20,
|
fontSize: 16,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: geoPointDTO.phone != null ? geoPointDTO.phone! : [],
|
initialValue: geoPointDTO.phone ?? [],
|
||||||
isMandatory: false,
|
isMandatory: false,
|
||||||
onGetResult: (value) {
|
onGetResult: (value) {
|
||||||
if (geoPointDTO.phone != value) {
|
|
||||||
geoPointDTO.phone = value;
|
geoPointDTO.phone = value;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
isTitle: true
|
isTitle: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
SizedBox(width: 20),
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
SizedBox(
|
||||||
|
width: thirdWidth,
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Email :",
|
label: "Email :",
|
||||||
modalLabel: "Email",
|
modalLabel: "Email",
|
||||||
fontSize: 20,
|
fontSize: 16,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: geoPointDTO.email != null ? geoPointDTO.email! : [],
|
initialValue: geoPointDTO.email ?? [],
|
||||||
isMandatory: false,
|
isMandatory: false,
|
||||||
onGetResult: (value) {
|
onGetResult: (value) {
|
||||||
if (geoPointDTO.email != value) {
|
|
||||||
geoPointDTO.email = value;
|
geoPointDTO.email = value;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
isTitle: true
|
isTitle: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
SizedBox(height: 12),
|
||||||
Container(
|
// Ligne 3 : Horaires | Image | Catégorie
|
||||||
height: 100,
|
Row(
|
||||||
width: double.infinity,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: [
|
children: [
|
||||||
ResourceInputContainer(
|
SizedBox(
|
||||||
label: "Image principal:",
|
width: thirdWidth,
|
||||||
initialValue: geoPointDTO.imageResourceId != null ? geoPointDTO.imageResourceId : null,
|
child: MultiStringInputContainer(
|
||||||
|
label: "Horaires :",
|
||||||
|
modalLabel: "Horaires d'ouverture",
|
||||||
|
fontSize: 16,
|
||||||
|
isHTML: true,
|
||||||
|
color: kPrimaryColor,
|
||||||
|
initialValue: geoPointDTO.schedules ?? [],
|
||||||
|
isMandatory: false,
|
||||||
|
onGetResult: (value) {
|
||||||
|
geoPointDTO.schedules = value;
|
||||||
|
},
|
||||||
|
maxLines: 1,
|
||||||
|
isTitle: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 20),
|
||||||
|
SizedBox(
|
||||||
|
width: thirdWidth,
|
||||||
|
child: ResourceInputContainer(
|
||||||
|
label: "Image :",
|
||||||
|
initialValue: geoPointDTO.imageResourceId,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
onChanged: (ResourceDTO resource) {
|
onChanged: (ResourceDTO resource) {
|
||||||
if (resource.id == null) {
|
if (resource.id == null) {
|
||||||
@ -288,29 +247,33 @@ void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO, Funct
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if(mapDTO.categories != null && mapDTO.categories!.isNotEmpty)
|
),
|
||||||
Container(
|
SizedBox(width: 20),
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
if (mapDTO.categories != null &&
|
||||||
|
mapDTO.categories!.isNotEmpty)
|
||||||
|
SizedBox(
|
||||||
|
width: thirdWidth,
|
||||||
child: DropDownInputContainerCategories(
|
child: DropDownInputContainerCategories(
|
||||||
label: "Choisir une catégorie:",
|
label: "Catégorie :",
|
||||||
categories: mapDTO.categories!,
|
categories: mapDTO.categories!,
|
||||||
initialValue: geoPointDTO.categorieId,
|
initialValue: geoPointDTO.categorieId,
|
||||||
onChange: (CategorieDTO? value) {
|
onChange: (CategorieDTO? value) {
|
||||||
if(value != null && value.order != -1)
|
if (value != null && value.order != -1) {
|
||||||
{
|
|
||||||
geoPointDTO.categorieId = value.id;
|
geoPointDTO.categorieId = value.id;
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
geoPointDTO.categorieId = null;
|
geoPointDTO.categorieId = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
|
else
|
||||||
|
SizedBox(width: thirdWidth),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
SizedBox(height: 12),
|
||||||
|
// Liste de contenus
|
||||||
Container(
|
Container(
|
||||||
height: size.height * 0.33,
|
height: screenHeight * 0.28,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: kWhite,
|
color: kWhite,
|
||||||
shape: BoxShape.rectangle,
|
shape: BoxShape.rectangle,
|
||||||
@ -321,7 +284,7 @@ void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO, Funct
|
|||||||
color: kSecond,
|
color: kSecond,
|
||||||
spreadRadius: 0.5,
|
spreadRadius: 0.5,
|
||||||
blurRadius: 5,
|
blurRadius: 5,
|
||||||
offset: Offset(0, 1.5), // changes position of shadow
|
offset: Offset(0, 1.5),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -334,19 +297,15 @@ void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO, Funct
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
SizedBox(height: 16),
|
||||||
actions: <Widget>[
|
// Boutons
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Align(
|
SizedBox(
|
||||||
alignment: AlignmentDirectional.bottomEnd,
|
height: 46,
|
||||||
child: Container(
|
|
||||||
width: 175,
|
|
||||||
height: 70,
|
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Annuler",
|
text: "Annuler",
|
||||||
icon: Icons.undo,
|
icon: Icons.undo,
|
||||||
@ -357,34 +316,38 @@ void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO, Funct
|
|||||||
}
|
}
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
fontSize: 20,
|
fontSize: 15,
|
||||||
|
horizontal: 24,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
SizedBox(width: 12),
|
||||||
Align(
|
SizedBox(
|
||||||
alignment: AlignmentDirectional.bottomEnd,
|
height: 46,
|
||||||
child: Container(
|
|
||||||
width: geoPointDTO != null ? 220: 150,
|
|
||||||
height: 70,
|
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: geoPointDTO != null ? "Sauvegarder" : "Créer",
|
text:
|
||||||
|
geoPointDTO.id != null ? "Sauvegarder" : "Créer",
|
||||||
icon: Icons.check,
|
icon: Icons.check,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
press: () {
|
press: () {
|
||||||
//print("TODO");
|
if (geoPointDTO.geometry != null &&
|
||||||
if (geoPointDTO.geometry != null && geoPointDTO.geometry!.coordinates != null) {
|
geoPointDTO.geometry!.coordinates != null) {
|
||||||
getResult(geoPointDTO);
|
getResult(geoPointDTO);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fontSize: 20,
|
fontSize: 15,
|
||||||
),
|
horizontal: 24,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
), context: context
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,156 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_api_new/api.dart';
|
||||||
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/showNewOrUpdateGuidedPath.dart';
|
||||||
|
|
||||||
|
class ParcoursConfig extends StatefulWidget {
|
||||||
|
final List<GuidedPathDTO> initialValue;
|
||||||
|
final String parentId;
|
||||||
|
final bool isEvent;
|
||||||
|
final bool isEscapeMode;
|
||||||
|
final ValueChanged<List<GuidedPathDTO>> onChanged;
|
||||||
|
|
||||||
|
const ParcoursConfig({
|
||||||
|
Key? key,
|
||||||
|
required this.initialValue,
|
||||||
|
required this.parentId,
|
||||||
|
required this.isEvent,
|
||||||
|
this.isEscapeMode = false,
|
||||||
|
required this.onChanged,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ParcoursConfigState createState() => _ParcoursConfigState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ParcoursConfigState extends State<ParcoursConfig> {
|
||||||
|
late List<GuidedPathDTO> paths;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
paths = List.from(widget.initialValue);
|
||||||
|
paths.sort((a, b) => (a.order ?? 0).compareTo(b.order ?? 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text("Parcours Guidés",
|
||||||
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
|
ElevatedButton.icon(
|
||||||
|
icon: Icon(Icons.add),
|
||||||
|
label: Text("Ajouter un parcours"),
|
||||||
|
onPressed: () {
|
||||||
|
showNewOrUpdateGuidedPath(
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
widget.parentId,
|
||||||
|
widget.isEvent,
|
||||||
|
widget.isEscapeMode,
|
||||||
|
(newPath) {
|
||||||
|
setState(() {
|
||||||
|
newPath.order = paths.length;
|
||||||
|
paths.add(newPath);
|
||||||
|
widget.onChanged(paths);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: kSuccess, foregroundColor: kWhite),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: paths.isEmpty
|
||||||
|
? Center(
|
||||||
|
child: Text("Aucun parcours configuré",
|
||||||
|
style: TextStyle(fontStyle: FontStyle.italic)))
|
||||||
|
: ReorderableListView.builder(
|
||||||
|
buildDefaultDragHandles: false,
|
||||||
|
itemCount: paths.length,
|
||||||
|
onReorder: (oldIndex, newIndex) {
|
||||||
|
setState(() {
|
||||||
|
if (newIndex > oldIndex) newIndex -= 1;
|
||||||
|
final item = paths.removeAt(oldIndex);
|
||||||
|
paths.insert(newIndex, item);
|
||||||
|
for (int i = 0; i < paths.length; i++) {
|
||||||
|
paths[i].order = i;
|
||||||
|
}
|
||||||
|
widget.onChanged(paths);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final path = paths[index];
|
||||||
|
return Card(
|
||||||
|
key: ValueKey(path.id ?? index.toString()),
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||||
|
child: ListTile(
|
||||||
|
leading: CircleAvatar(
|
||||||
|
child: Text("${index + 1}"),
|
||||||
|
backgroundColor: kPrimaryColor,
|
||||||
|
foregroundColor: kWhite),
|
||||||
|
title: Text(path.title != null && path.title!.isNotEmpty
|
||||||
|
? path.title!
|
||||||
|
.firstWhere((t) => t.language == 'FR',
|
||||||
|
orElse: () => path.title![0])
|
||||||
|
.value ??
|
||||||
|
"Parcours sans titre"
|
||||||
|
: "Parcours sans titre"),
|
||||||
|
subtitle: Text("${path.steps?.length ?? 0} étapes"),
|
||||||
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.edit, color: kPrimaryColor),
|
||||||
|
onPressed: () {
|
||||||
|
showNewOrUpdateGuidedPath(
|
||||||
|
context,
|
||||||
|
path,
|
||||||
|
widget.parentId,
|
||||||
|
widget.isEvent,
|
||||||
|
widget.isEscapeMode,
|
||||||
|
(updatedPath) {
|
||||||
|
setState(() {
|
||||||
|
paths[index] = updatedPath;
|
||||||
|
widget.onChanged(paths);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.delete, color: kError),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
paths.removeAt(index);
|
||||||
|
for (int i = 0; i < paths.length; i++) {
|
||||||
|
paths[i].order = i;
|
||||||
|
}
|
||||||
|
widget.onChanged(paths);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ReorderableDragStartListener(
|
||||||
|
index: index,
|
||||||
|
child: Icon(Icons.drag_handle),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,275 @@
|
|||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,265 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_api_new/api.dart';
|
||||||
|
import 'package:manager_app/Components/confirmation_dialog.dart';
|
||||||
|
import 'package:manager_app/Components/geometry_input_container.dart';
|
||||||
|
import 'package:manager_app/Components/multi_string_input_container.dart';
|
||||||
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'showNewOrUpdateQuizQuestion.dart';
|
||||||
|
|
||||||
|
void showNewOrUpdateGuidedStep(
|
||||||
|
BuildContext context,
|
||||||
|
GuidedStepDTO? step,
|
||||||
|
String pathId,
|
||||||
|
bool isEscapeMode,
|
||||||
|
Function(GuidedStepDTO) onSave,
|
||||||
|
) {
|
||||||
|
GuidedStepDTO workingStep = step != null
|
||||||
|
? GuidedStepDTO.fromJson(step.toJson())!
|
||||||
|
: GuidedStepDTO(
|
||||||
|
title: [],
|
||||||
|
description: [],
|
||||||
|
quizQuestions: [],
|
||||||
|
order: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Convert EventAddressDTOGeometry to GeometryDTO via JSON for the geometry picker
|
||||||
|
GeometryDTO? _toGeometryDTO(EventAddressDTOGeometry? geo) {
|
||||||
|
if (geo == null) return null;
|
||||||
|
return GeometryDTO.fromJson(geo.toJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
EventAddressDTOGeometry? _toEventGeometry(GeometryDTO? geo) {
|
||||||
|
if (geo == null) return null;
|
||||||
|
return EventAddressDTOGeometry.fromJson(geo.toJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
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.75;
|
||||||
|
final double contentWidth = dialogWidth - 48;
|
||||||
|
final double halfWidth = (contentWidth - 20) / 2;
|
||||||
|
|
||||||
|
return Dialog(
|
||||||
|
shape:
|
||||||
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||||
|
child: Container(
|
||||||
|
width: dialogWidth,
|
||||||
|
constraints: BoxConstraints(maxHeight: screenHeight * 0.85),
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
step == null ? "Nouvelle Étape" : "Modifier l'Étape",
|
||||||
|
style: TextStyle(
|
||||||
|
color: kPrimaryColor,
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
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 de l'étape",
|
||||||
|
initialValue: workingStep.title ?? [],
|
||||||
|
onGetResult: (val) =>
|
||||||
|
setState(() => workingStep.title = val),
|
||||||
|
maxLines: 1,
|
||||||
|
isTitle: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 20),
|
||||||
|
SizedBox(
|
||||||
|
width: halfWidth,
|
||||||
|
child: MultiStringInputContainer(
|
||||||
|
label: "Description :",
|
||||||
|
modalLabel: "Description de l'étape",
|
||||||
|
initialValue: workingStep.description ?? [],
|
||||||
|
onGetResult: (val) => setState(
|
||||||
|
() => workingStep.description = val),
|
||||||
|
maxLines: 1,
|
||||||
|
isTitle: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Divider(height: 24),
|
||||||
|
// Géométrie — conversion JSON entre les deux types GeoDTO
|
||||||
|
GeometryInputContainer(
|
||||||
|
label: "Emplacement de l'étape :",
|
||||||
|
initialGeometry:
|
||||||
|
_toGeometryDTO(workingStep.geometry),
|
||||||
|
initialColor: null,
|
||||||
|
onSave: (geometry, color) {
|
||||||
|
setState(() {
|
||||||
|
workingStep.geometry =
|
||||||
|
_toEventGeometry(geometry);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// Questions — uniquement en mode Escape Game
|
||||||
|
if (isEscapeMode) ...[
|
||||||
|
Divider(height: 24),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text("Questions / Défis",
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 15)),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.add_circle_outline,
|
||||||
|
color: kSuccess),
|
||||||
|
onPressed: () {
|
||||||
|
showNewOrUpdateQuizQuestion(
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
workingStep.id ?? "temp",
|
||||||
|
isEscapeMode,
|
||||||
|
(newQuestion) {
|
||||||
|
setState(() {
|
||||||
|
workingStep.quizQuestions = [
|
||||||
|
...(workingStep.quizQuestions ??
|
||||||
|
[]),
|
||||||
|
newQuestion
|
||||||
|
];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (workingStep.quizQuestions == null ||
|
||||||
|
workingStep.quizQuestions!.isEmpty)
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: Text(
|
||||||
|
"Aucune question configurée.",
|
||||||
|
style: TextStyle(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
color: Colors.grey[600]),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
ListView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: workingStep.quizQuestions!.length,
|
||||||
|
itemBuilder: (context, qIndex) {
|
||||||
|
final question =
|
||||||
|
workingStep.quizQuestions![qIndex];
|
||||||
|
return ListTile(
|
||||||
|
dense: true,
|
||||||
|
title: Text(question.label.isNotEmpty
|
||||||
|
? question.label
|
||||||
|
.firstWhere(
|
||||||
|
(t) => t.language == 'FR',
|
||||||
|
orElse: () =>
|
||||||
|
question.label[0])
|
||||||
|
.value ??
|
||||||
|
"Question $qIndex"
|
||||||
|
: "Question $qIndex"),
|
||||||
|
subtitle: Text(
|
||||||
|
"Type: ${question.validationQuestionType?.value == 2 ? 'Puzzle' : question.validationQuestionType?.value == 1 ? 'QCM' : 'Texte'}"),
|
||||||
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.edit,
|
||||||
|
size: 18, color: kPrimaryColor),
|
||||||
|
onPressed: () {
|
||||||
|
showNewOrUpdateQuizQuestion(
|
||||||
|
context,
|
||||||
|
question,
|
||||||
|
workingStep.id ?? "temp",
|
||||||
|
isEscapeMode,
|
||||||
|
(updatedQuestion) {
|
||||||
|
setState(() {
|
||||||
|
workingStep.quizQuestions![
|
||||||
|
qIndex] = updatedQuestion;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.delete,
|
||||||
|
size: 18, color: kError),
|
||||||
|
onPressed: () {
|
||||||
|
showConfirmationDialog(
|
||||||
|
"Supprimer cette question ?",
|
||||||
|
() {},
|
||||||
|
() => setState(() => workingStep
|
||||||
|
.quizQuestions!
|
||||||
|
.removeAt(qIndex)),
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
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(workingStep);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
color: kPrimaryColor,
|
||||||
|
fontSize: 15,
|
||||||
|
horizontal: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,390 @@
|
|||||||
|
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/resource_input_container.dart';
|
||||||
|
import 'package:manager_app/Components/number_input_container.dart';
|
||||||
|
import 'package:manager_app/Components/check_input_container.dart';
|
||||||
|
|
||||||
|
// Conversions between TranslationDTO and TranslationAndResourceDTO
|
||||||
|
// (ResponseDTO.label uses TranslationAndResourceDTO, but we use MultiStringInputContainer
|
||||||
|
// which requires TranslationDTO — the resource field is not needed for quiz responses)
|
||||||
|
List<TranslationDTO> _toTranslationList(
|
||||||
|
List<TranslationAndResourceDTO>? list) =>
|
||||||
|
(list ?? [])
|
||||||
|
.map((t) => TranslationDTO(language: t.language, value: t.value))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
List<TranslationAndResourceDTO> _fromTranslationList(
|
||||||
|
List<TranslationDTO> list) =>
|
||||||
|
list
|
||||||
|
.map((t) =>
|
||||||
|
TranslationAndResourceDTO(language: t.language, value: t.value))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
// Creates an empty ResponseDTO; labels are populated by MultiStringInputContainer
|
||||||
|
ResponseDTO _emptyResponse({bool isGood = false, int order = 0}) =>
|
||||||
|
ResponseDTO(label: [], isGood: isGood, order: order);
|
||||||
|
|
||||||
|
void showNewOrUpdateQuizQuestion(
|
||||||
|
BuildContext context,
|
||||||
|
QuizQuestion? question,
|
||||||
|
String stepId,
|
||||||
|
bool isEscapeMode,
|
||||||
|
Function(QuizQuestion) onSave,
|
||||||
|
) {
|
||||||
|
// QuizQuestion.label is List<TranslationAndResourceDTO> — convert for display
|
||||||
|
List<TranslationDTO> workingLabel = _toTranslationList(
|
||||||
|
question != null && question.label.isNotEmpty
|
||||||
|
? question.label
|
||||||
|
: [TranslationAndResourceDTO(language: 'FR', value: '')]);
|
||||||
|
|
||||||
|
List<ResponseDTO> workingResponses =
|
||||||
|
question != null && question.responses.isNotEmpty
|
||||||
|
? question.responses
|
||||||
|
.map((r) => ResponseDTO.fromJson(r.toJson())!)
|
||||||
|
.toList()
|
||||||
|
: [];
|
||||||
|
|
||||||
|
QuizQuestion workingQuestion = QuizQuestion(
|
||||||
|
id: question?.id ?? 0,
|
||||||
|
label: _fromTranslationList(workingLabel), // kept in sync below
|
||||||
|
responses: workingResponses,
|
||||||
|
validationQuestionType:
|
||||||
|
question?.validationQuestionType ?? QuestionType.number0,
|
||||||
|
puzzleImageId: question?.puzzleImageId,
|
||||||
|
puzzleImage: question?.puzzleImage,
|
||||||
|
puzzleRows: question?.puzzleRows,
|
||||||
|
puzzleCols: question?.puzzleCols,
|
||||||
|
isSlidingPuzzle: question?.isSlidingPuzzle,
|
||||||
|
order: question?.order ?? 0,
|
||||||
|
guidedStepId: question?.guidedStepId ?? stepId,
|
||||||
|
);
|
||||||
|
|
||||||
|
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.65;
|
||||||
|
final double contentWidth = dialogWidth - 48;
|
||||||
|
final double halfWidth = (contentWidth - 20) / 2;
|
||||||
|
|
||||||
|
void ensureSimpleResponse() {
|
||||||
|
if (workingQuestion.responses.isEmpty) {
|
||||||
|
workingQuestion.responses
|
||||||
|
.add(_emptyResponse(isGood: true, order: 0));
|
||||||
|
}
|
||||||
|
workingQuestion.responses[0].isGood = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Dialog(
|
||||||
|
shape:
|
||||||
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||||
|
child: Container(
|
||||||
|
width: dialogWidth,
|
||||||
|
constraints: BoxConstraints(maxHeight: screenHeight * 0.85),
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
question == null
|
||||||
|
? "Nouvelle Question"
|
||||||
|
: "Modifier la Question",
|
||||||
|
style: TextStyle(
|
||||||
|
color: kPrimaryColor,
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
Flexible(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// --- Intitulé (multi-langue via MultiStringInputContainer) ---
|
||||||
|
MultiStringInputContainer(
|
||||||
|
label: "Question posée :",
|
||||||
|
modalLabel: "Intitulé de la question",
|
||||||
|
initialValue: workingLabel,
|
||||||
|
onGetResult: (val) => setState(() {
|
||||||
|
workingLabel = val;
|
||||||
|
workingQuestion.label = _fromTranslationList(val);
|
||||||
|
}),
|
||||||
|
maxLines: 3,
|
||||||
|
isTitle: false,
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
|
||||||
|
// --- Type ---
|
||||||
|
Text("Type de validation :",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
DropdownButton<QuestionType>(
|
||||||
|
value: workingQuestion.validationQuestionType,
|
||||||
|
items: [
|
||||||
|
DropdownMenuItem(
|
||||||
|
value: QuestionType.number0,
|
||||||
|
child: Text("Simple (texte attendu)")),
|
||||||
|
DropdownMenuItem(
|
||||||
|
value: QuestionType.number1,
|
||||||
|
child: Text("Choix multiples (QCM)")),
|
||||||
|
DropdownMenuItem(
|
||||||
|
value: QuestionType.number2,
|
||||||
|
child: Text("Puzzle")),
|
||||||
|
],
|
||||||
|
onChanged: (val) => setState(() {
|
||||||
|
workingQuestion.validationQuestionType = val;
|
||||||
|
workingQuestion.responses = [];
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
|
||||||
|
// =========================================
|
||||||
|
// Type 0 : Simple texte
|
||||||
|
// =========================================
|
||||||
|
if (workingQuestion.validationQuestionType ==
|
||||||
|
QuestionType.number0) ...[
|
||||||
|
Divider(height: 24),
|
||||||
|
Text("Réponse attendue :",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
Builder(builder: (_) {
|
||||||
|
ensureSimpleResponse();
|
||||||
|
final List<TranslationDTO> respLabel =
|
||||||
|
_toTranslationList(
|
||||||
|
workingQuestion.responses[0].label);
|
||||||
|
return MultiStringInputContainer(
|
||||||
|
label: "",
|
||||||
|
modalLabel: "Réponse attendue",
|
||||||
|
initialValue: respLabel,
|
||||||
|
onGetResult: (val) => setState(() {
|
||||||
|
workingQuestion.responses[0].label =
|
||||||
|
_fromTranslationList(val);
|
||||||
|
workingQuestion.responses[0].isGood = true;
|
||||||
|
}),
|
||||||
|
maxLines: 1,
|
||||||
|
isTitle: true,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
"La validation se fait par comparaison (insensible à la casse).",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
color: Colors.grey[600]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
// =========================================
|
||||||
|
// Type 1 : QCM
|
||||||
|
// =========================================
|
||||||
|
if (workingQuestion.validationQuestionType ==
|
||||||
|
QuestionType.number1) ...[
|
||||||
|
Divider(height: 24),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text("Réponses possibles :",
|
||||||
|
style:
|
||||||
|
TextStyle(fontWeight: FontWeight.bold)),
|
||||||
|
TextButton.icon(
|
||||||
|
icon: Icon(Icons.add_circle_outline,
|
||||||
|
color: kSuccess),
|
||||||
|
label: Text("Ajouter",
|
||||||
|
style: TextStyle(color: kSuccess)),
|
||||||
|
onPressed: () => setState(() =>
|
||||||
|
workingQuestion.responses.add(
|
||||||
|
_emptyResponse(
|
||||||
|
order: workingQuestion
|
||||||
|
.responses.length))),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (workingQuestion.responses.isEmpty)
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: Text(
|
||||||
|
"Aucune réponse définie. Ajoutez-en au moins une.",
|
||||||
|
style: TextStyle(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
color: Colors.grey[600]),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Column(
|
||||||
|
children: List.generate(
|
||||||
|
workingQuestion.responses.length, (i) {
|
||||||
|
final resp = workingQuestion.responses[i];
|
||||||
|
final List<TranslationDTO> respLabel =
|
||||||
|
_toTranslationList(resp.label);
|
||||||
|
return Card(
|
||||||
|
margin: const EdgeInsets.only(bottom: 8),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8, vertical: 4),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
// Checkbox bonne réponse
|
||||||
|
Tooltip(
|
||||||
|
message: resp.isGood == true
|
||||||
|
? "Bonne réponse ✓"
|
||||||
|
: "Mauvaise réponse",
|
||||||
|
child: Checkbox(
|
||||||
|
value: resp.isGood ?? false,
|
||||||
|
activeColor: kSuccess,
|
||||||
|
onChanged: (val) => setState(
|
||||||
|
() => resp.isGood = val),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Traductions (via MultiStringInputContainer)
|
||||||
|
Expanded(
|
||||||
|
child: MultiStringInputContainer(
|
||||||
|
label: "Réponse ${i + 1} :",
|
||||||
|
modalLabel: "Réponse ${i + 1}",
|
||||||
|
initialValue: respLabel,
|
||||||
|
onGetResult: (val) => setState(
|
||||||
|
() => resp.label =
|
||||||
|
_fromTranslationList(
|
||||||
|
val)),
|
||||||
|
maxLines: 1,
|
||||||
|
isTitle: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Supprimer
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.delete_outline,
|
||||||
|
color: kError, size: 20),
|
||||||
|
onPressed: () => setState(() =>
|
||||||
|
workingQuestion.responses
|
||||||
|
.removeAt(i)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
"✓ = bonne réponse. Plusieurs peuvent être correctes.",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
color: Colors.grey[600]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
// =========================================
|
||||||
|
// Type 2 : Puzzle
|
||||||
|
// =========================================
|
||||||
|
if (workingQuestion.validationQuestionType ==
|
||||||
|
QuestionType.number2) ...[
|
||||||
|
Divider(height: 24),
|
||||||
|
Text("Configuration du Puzzle",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
ResourceInputContainer(
|
||||||
|
label: "Image du puzzle :",
|
||||||
|
initialValue: workingQuestion.puzzleImageId,
|
||||||
|
onChanged: (res) => setState(() {
|
||||||
|
workingQuestion.puzzleImageId = res.id;
|
||||||
|
workingQuestion.puzzleImage =
|
||||||
|
Resource.fromJson(res.toJson());
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: halfWidth,
|
||||||
|
child: NumberInputContainer(
|
||||||
|
label: "Lignes :",
|
||||||
|
initialValue:
|
||||||
|
workingQuestion.puzzleRows ?? 3,
|
||||||
|
onChanged: (val) => setState(() =>
|
||||||
|
workingQuestion.puzzleRows =
|
||||||
|
int.tryParse(val) ?? 3),
|
||||||
|
isSmall: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 20),
|
||||||
|
SizedBox(
|
||||||
|
width: halfWidth,
|
||||||
|
child: NumberInputContainer(
|
||||||
|
label: "Colonnes :",
|
||||||
|
initialValue:
|
||||||
|
workingQuestion.puzzleCols ?? 3,
|
||||||
|
onChanged: (val) => setState(() =>
|
||||||
|
workingQuestion.puzzleCols =
|
||||||
|
int.tryParse(val) ?? 3),
|
||||||
|
isSmall: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
CheckInputContainer(
|
||||||
|
label: "Puzzle glissant (Sliding) :",
|
||||||
|
isChecked:
|
||||||
|
workingQuestion.isSlidingPuzzle ?? false,
|
||||||
|
onChanged: (val) => setState(
|
||||||
|
() => workingQuestion.isSlidingPuzzle = val),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
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: () {
|
||||||
|
for (int i = 0;
|
||||||
|
i < workingQuestion.responses.length;
|
||||||
|
i++) {
|
||||||
|
workingQuestion.responses[i].order = i;
|
||||||
|
}
|
||||||
|
onSave(workingQuestion);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
color: kPrimaryColor,
|
||||||
|
fontSize: 15,
|
||||||
|
horizontal: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -39,6 +39,7 @@ import 'package:pasteboard/pasteboard.dart';
|
|||||||
import 'dart:html' as html;
|
import 'dart:html' as html;
|
||||||
|
|
||||||
import 'SubSection/Weather/weather_config.dart';
|
import 'SubSection/Weather/weather_config.dart';
|
||||||
|
import 'SubSection/Event/event_config.dart';
|
||||||
|
|
||||||
class SectionDetailScreen extends StatefulWidget {
|
class SectionDetailScreen extends StatefulWidget {
|
||||||
final String id;
|
final String id;
|
||||||
@ -61,7 +62,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
Object? rawSectionData;
|
Object? rawSectionData;
|
||||||
|
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
future: getSection(widget.id, (appContext.getContext() as ManagerAppContext).clientAPI!),
|
future: getSection(widget.id,
|
||||||
|
(appContext.getContext() as ManagerAppContext).clientAPI!),
|
||||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
rawSectionData = snapshot.data;
|
rawSectionData = snapshot.data;
|
||||||
@ -72,7 +74,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
sectionDTO = nullableSection;
|
sectionDTO = nullableSection;
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
bodySection(rawSectionData, size, appContext, context, globalKey),
|
bodySection(
|
||||||
|
rawSectionData, size, appContext, context, globalKey),
|
||||||
Align(
|
Align(
|
||||||
alignment: AlignmentDirectional.bottomCenter,
|
alignment: AlignmentDirectional.bottomCenter,
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -83,23 +86,22 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Center(child: Text("Une erreur est survenue lors de la récupération de la section"));
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
"Une erreur est survenue lors de la récupération de la section"));
|
||||||
}
|
}
|
||||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||||
return Text("No data");
|
return Text("No data");
|
||||||
} else {
|
} else {
|
||||||
return Center(
|
return Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
height: size.height * 0.2,
|
height: size.height * 0.2, child: CommonLoader()));
|
||||||
child: CommonLoader()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget bodySection(Object? rawSectionDTO, Size size, AppContext appContext, BuildContext context, GlobalKey globalKey) {
|
Widget bodySection(Object? rawSectionDTO, Size size, AppContext appContext,
|
||||||
|
BuildContext context, GlobalKey globalKey) {
|
||||||
ManagerAppContext managerAppContext = appContext.getContext();
|
ManagerAppContext managerAppContext = appContext.getContext();
|
||||||
//SectionDTO? sectionDTO = SectionDTO.fromJson(rawSectionDTO);
|
//SectionDTO? sectionDTO = SectionDTO.fromJson(rawSectionDTO);
|
||||||
|
|
||||||
@ -131,26 +133,33 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
size: 25,
|
size: 25,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(sectionDTO.label!, style: TextStyle(fontSize: 30, fontWeight: FontWeight.w400)),
|
Text(sectionDTO.label!,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 30,
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
//if((appContext.getContext() as ManagerAppContext).selectedConfiguration!.isMobile!)
|
//if((appContext.getContext() as ManagerAppContext).selectedConfiguration!.isMobile!)
|
||||||
DownloadPDF(sections: [sectionDTO]),
|
DownloadPDF(sections: [sectionDTO]),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(5.0),
|
padding: const EdgeInsets.all(5.0),
|
||||||
child: Text(DateFormat('dd/MM/yyyy').format(sectionDTO.dateCreation!), style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200)),
|
child: Text(
|
||||||
|
DateFormat('dd/MM/yyyy')
|
||||||
|
.format(sectionDTO.dateCreation!),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15, fontWeight: FontWeight.w200)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)),
|
||||||
),
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(5.0),
|
padding: const EdgeInsets.all(5.0),
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: AlignmentDirectional.centerEnd,
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ManagerAppContext managerAppContext = appContext.getContext();
|
ManagerAppContext managerAppContext =
|
||||||
|
appContext.getContext();
|
||||||
managerAppContext.selectedSection = null;
|
managerAppContext.selectedSection = null;
|
||||||
appContext.setContext(managerAppContext);
|
appContext.setContext(managerAppContext);
|
||||||
},
|
},
|
||||||
@ -159,9 +168,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
Icons.arrow_back,
|
Icons.arrow_back,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
size: 50.0,
|
size: 50.0,
|
||||||
)
|
))),
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@ -190,9 +197,15 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
children: [
|
children: [
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
var image = await _captureAndSharePng(globalKey, sectionDTO.id!);
|
var image = await _captureAndSharePng(
|
||||||
|
globalKey, sectionDTO.id!);
|
||||||
await readAndWriteFiles(image);
|
await readAndWriteFiles(image);
|
||||||
showNotification(kSuccess, kWhite, 'Ce QR code a été copié dans le presse papier', context, null);
|
showNotification(
|
||||||
|
kSuccess,
|
||||||
|
kWhite,
|
||||||
|
'Ce QR code a été copié dans le presse papier',
|
||||||
|
context,
|
||||||
|
null);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: size.width * 0.1,
|
width: size.width * 0.1,
|
||||||
@ -200,15 +213,21 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
child: RepaintBoundary(
|
child: RepaintBoundary(
|
||||||
key: globalKey,
|
key: globalKey,
|
||||||
child: QrImageView(
|
child: QrImageView(
|
||||||
padding: EdgeInsets.only(left: 5.0, top: 5.0, bottom: 5.0, right: 5.0),
|
padding: EdgeInsets.only(
|
||||||
data: "${managerAppContext.host!.replaceFirst("api", "web")}/${managerAppContext.instanceId}/${managerAppContext.selectedConfiguration!.id}/${sectionDTO.id!}",
|
left: 5.0,
|
||||||
|
top: 5.0,
|
||||||
|
bottom: 5.0,
|
||||||
|
right: 5.0),
|
||||||
|
data:
|
||||||
|
"${managerAppContext.host!.replaceFirst("api", "web")}/${managerAppContext.instanceId}/${managerAppContext.selectedConfiguration!.id}/${sectionDTO.id!}",
|
||||||
version: QrVersions.auto,
|
version: QrVersions.auto,
|
||||||
size: 50.0,
|
size: 50.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SelectableText(sectionDTO.id!, style: new TextStyle(fontSize: 15))
|
SelectableText(sectionDTO.id!,
|
||||||
|
style: new TextStyle(fontSize: 15))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
CheckInputContainer(
|
CheckInputContainer(
|
||||||
@ -224,14 +243,21 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
if (sectionDTO.isBeacon!)
|
if (sectionDTO.isBeacon!)
|
||||||
NumberInputContainer(
|
NumberInputContainer(
|
||||||
label: "Identifiant Beacon :",
|
label: "Identifiant Beacon :",
|
||||||
initialValue: sectionDTO.beaconId != null ? sectionDTO.beaconId! : 0,
|
initialValue: sectionDTO.beaconId != null
|
||||||
|
? sectionDTO.beaconId!
|
||||||
|
: 0,
|
||||||
isSmall: true,
|
isSmall: true,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
try {
|
try {
|
||||||
sectionDTO.beaconId = int.parse(value);
|
sectionDTO.beaconId = int.parse(value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('BeaconId not a number');
|
print('BeaconId not a number');
|
||||||
showNotification(Colors.orange, kWhite, 'Cela doit être un chiffre', context, null);
|
showNotification(
|
||||||
|
Colors.orange,
|
||||||
|
kWhite,
|
||||||
|
'Cela doit être un chiffre',
|
||||||
|
context,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -326,8 +352,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
//color: Colors.lightGreen,
|
//color: Colors.lightGreen,
|
||||||
borderRadius: BorderRadius.circular(30),
|
borderRadius: BorderRadius.circular(30),
|
||||||
border: Border.all(width: 1.5, color: kSecond)
|
border: Border.all(width: 1.5, color: kSecond)),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -386,10 +411,12 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
|
|
||||||
Future<void> cancel(AppContext appContext) async {
|
Future<void> cancel(AppContext appContext) async {
|
||||||
ManagerAppContext managerAppContext = appContext.getContext();
|
ManagerAppContext managerAppContext = appContext.getContext();
|
||||||
Object? rawData = await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionApi!.sectionGetDetail(sectionDTO.id!);
|
Object? rawData = await (appContext.getContext() as ManagerAppContext)
|
||||||
|
.clientAPI!
|
||||||
|
.sectionApi!
|
||||||
|
.sectionGetDetail(sectionDTO.id!);
|
||||||
var nullableSection = SectionDTO.fromJson(rawData);
|
var nullableSection = SectionDTO.fromJson(rawData);
|
||||||
if(nullableSection != null)
|
if (nullableSection != null) {
|
||||||
{
|
|
||||||
managerAppContext.selectedSection = nullableSection!;
|
managerAppContext.selectedSection = nullableSection!;
|
||||||
appContext.setContext(managerAppContext);
|
appContext.setContext(managerAppContext);
|
||||||
}
|
}
|
||||||
@ -397,22 +424,22 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
|
|
||||||
Future<void> delete(AppContext appContext) async {
|
Future<void> delete(AppContext appContext) async {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir supprimer cette section ?",
|
"Êtes-vous sûr de vouloir supprimer cette section ?", () {}, () async {
|
||||||
() {},
|
|
||||||
() async {
|
|
||||||
ManagerAppContext managerAppContext = appContext.getContext();
|
ManagerAppContext managerAppContext = appContext.getContext();
|
||||||
await managerAppContext.clientAPI!.sectionApi!.sectionDelete(sectionDTO.id!);
|
await managerAppContext.clientAPI!.sectionApi!
|
||||||
|
.sectionDelete(sectionDTO.id!);
|
||||||
managerAppContext.selectedSection = null;
|
managerAppContext.selectedSection = null;
|
||||||
appContext.setContext(managerAppContext);
|
appContext.setContext(managerAppContext);
|
||||||
},
|
}, context);
|
||||||
context
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> save(bool isTraduction, AppContext appContext) async {
|
Future<void> save(bool isTraduction, AppContext appContext) async {
|
||||||
updateSectionDetail();
|
updateSectionDetail();
|
||||||
|
|
||||||
var sectionResult = await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionApi!.sectionUpdate(sectionDetailDTO);
|
var sectionResult = await (appContext.getContext() as ManagerAppContext)
|
||||||
|
.clientAPI!
|
||||||
|
.sectionApi!
|
||||||
|
.sectionUpdate(sectionDetailDTO);
|
||||||
SectionDTO? section = SectionDTO.fromJson(sectionResult);
|
SectionDTO? section = SectionDTO.fromJson(sectionResult);
|
||||||
|
|
||||||
ManagerAppContext managerAppContext = appContext.getContext();
|
ManagerAppContext managerAppContext = appContext.getContext();
|
||||||
@ -420,9 +447,15 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
appContext.setContext(managerAppContext);
|
appContext.setContext(managerAppContext);
|
||||||
|
|
||||||
if (isTraduction) {
|
if (isTraduction) {
|
||||||
showNotification(kSuccess, kWhite, 'Les traductions de la section ont été sauvegardées avec succès', context, null);
|
showNotification(
|
||||||
|
kSuccess,
|
||||||
|
kWhite,
|
||||||
|
'Les traductions de la section ont été sauvegardées avec succès',
|
||||||
|
context,
|
||||||
|
null);
|
||||||
} else {
|
} else {
|
||||||
showNotification(kSuccess, kWhite, 'La section a été sauvegardée avec succès', context, null);
|
showNotification(kSuccess, kWhite,
|
||||||
|
'La section a été sauvegardée avec succès', context, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,19 +562,28 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
sectionDetailDTO = updatedWeather;
|
sectionDetailDTO = updatedWeather;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
case SectionType.Event:
|
||||||
|
SectionEventDTO eventDTO = SectionEventDTO.fromJson(rawSectionData)!;
|
||||||
|
sectionDetailDTO = eventDTO;
|
||||||
|
return EventConfig(
|
||||||
|
initialValue: eventDTO,
|
||||||
|
onChanged: (SectionEventDTO updatedEvent) {
|
||||||
|
sectionDetailDTO = updatedEvent;
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSectionDetail() {
|
updateSectionDetail() {
|
||||||
switch(sectionDTO.type)
|
switch (sectionDTO.type) {
|
||||||
{
|
|
||||||
case SectionType.Map:
|
case SectionType.Map:
|
||||||
(sectionDetailDTO as MapDTO).id = sectionDTO.id;
|
(sectionDetailDTO as MapDTO).id = sectionDTO.id;
|
||||||
(sectionDetailDTO as MapDTO).order = sectionDTO.order;
|
(sectionDetailDTO as MapDTO).order = sectionDTO.order;
|
||||||
(sectionDetailDTO as MapDTO).dateCreation = sectionDTO.dateCreation;
|
(sectionDetailDTO as MapDTO).dateCreation = sectionDTO.dateCreation;
|
||||||
(sectionDetailDTO as MapDTO).type = sectionDTO.type;
|
(sectionDetailDTO as MapDTO).type = sectionDTO.type;
|
||||||
(sectionDetailDTO as MapDTO).instanceId = sectionDTO.instanceId;
|
(sectionDetailDTO as MapDTO).instanceId = sectionDTO.instanceId;
|
||||||
(sectionDetailDTO as MapDTO).configurationId = sectionDTO.configurationId;
|
(sectionDetailDTO as MapDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
(sectionDetailDTO as MapDTO).isSubSection = sectionDTO.isSubSection;
|
(sectionDetailDTO as MapDTO).isSubSection = sectionDTO.isSubSection;
|
||||||
(sectionDetailDTO as MapDTO).parentId = sectionDTO.parentId;
|
(sectionDetailDTO as MapDTO).parentId = sectionDTO.parentId;
|
||||||
(sectionDetailDTO as MapDTO).label = sectionDTO.label;
|
(sectionDetailDTO as MapDTO).label = sectionDTO.label;
|
||||||
@ -561,7 +603,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
(sectionDetailDTO as SliderDTO).dateCreation = sectionDTO.dateCreation;
|
(sectionDetailDTO as SliderDTO).dateCreation = sectionDTO.dateCreation;
|
||||||
(sectionDetailDTO as SliderDTO).type = sectionDTO.type;
|
(sectionDetailDTO as SliderDTO).type = sectionDTO.type;
|
||||||
(sectionDetailDTO as SliderDTO).instanceId = sectionDTO.instanceId;
|
(sectionDetailDTO as SliderDTO).instanceId = sectionDTO.instanceId;
|
||||||
(sectionDetailDTO as SliderDTO).configurationId = sectionDTO.configurationId;
|
(sectionDetailDTO as SliderDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
(sectionDetailDTO as SliderDTO).isSubSection = sectionDTO.isSubSection;
|
(sectionDetailDTO as SliderDTO).isSubSection = sectionDTO.isSubSection;
|
||||||
(sectionDetailDTO as SliderDTO).parentId = sectionDTO.parentId;
|
(sectionDetailDTO as SliderDTO).parentId = sectionDTO.parentId;
|
||||||
(sectionDetailDTO as SliderDTO).label = sectionDTO.label;
|
(sectionDetailDTO as SliderDTO).label = sectionDTO.label;
|
||||||
@ -581,7 +624,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
(sectionDetailDTO as VideoDTO).dateCreation = sectionDTO.dateCreation;
|
(sectionDetailDTO as VideoDTO).dateCreation = sectionDTO.dateCreation;
|
||||||
(sectionDetailDTO as VideoDTO).type = sectionDTO.type;
|
(sectionDetailDTO as VideoDTO).type = sectionDTO.type;
|
||||||
(sectionDetailDTO as VideoDTO).instanceId = sectionDTO.instanceId;
|
(sectionDetailDTO as VideoDTO).instanceId = sectionDTO.instanceId;
|
||||||
(sectionDetailDTO as VideoDTO).configurationId = sectionDTO.configurationId;
|
(sectionDetailDTO as VideoDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
(sectionDetailDTO as VideoDTO).isSubSection = sectionDTO.isSubSection;
|
(sectionDetailDTO as VideoDTO).isSubSection = sectionDTO.isSubSection;
|
||||||
(sectionDetailDTO as VideoDTO).parentId = sectionDTO.parentId;
|
(sectionDetailDTO as VideoDTO).parentId = sectionDTO.parentId;
|
||||||
(sectionDetailDTO as VideoDTO).label = sectionDTO.label;
|
(sectionDetailDTO as VideoDTO).label = sectionDTO.label;
|
||||||
@ -601,7 +645,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
(sectionDetailDTO as WebDTO).dateCreation = sectionDTO.dateCreation;
|
(sectionDetailDTO as WebDTO).dateCreation = sectionDTO.dateCreation;
|
||||||
(sectionDetailDTO as WebDTO).type = sectionDTO.type;
|
(sectionDetailDTO as WebDTO).type = sectionDTO.type;
|
||||||
(sectionDetailDTO as WebDTO).instanceId = sectionDTO.instanceId;
|
(sectionDetailDTO as WebDTO).instanceId = sectionDTO.instanceId;
|
||||||
(sectionDetailDTO as WebDTO).configurationId = sectionDTO.configurationId;
|
(sectionDetailDTO as WebDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
(sectionDetailDTO as WebDTO).isSubSection = sectionDTO.isSubSection;
|
(sectionDetailDTO as WebDTO).isSubSection = sectionDTO.isSubSection;
|
||||||
(sectionDetailDTO as WebDTO).parentId = sectionDTO.parentId;
|
(sectionDetailDTO as WebDTO).parentId = sectionDTO.parentId;
|
||||||
(sectionDetailDTO as WebDTO).label = sectionDTO.label;
|
(sectionDetailDTO as WebDTO).label = sectionDTO.label;
|
||||||
@ -621,7 +666,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
(sectionDetailDTO as MenuDTO).dateCreation = sectionDTO.dateCreation;
|
(sectionDetailDTO as MenuDTO).dateCreation = sectionDTO.dateCreation;
|
||||||
(sectionDetailDTO as MenuDTO).type = sectionDTO.type;
|
(sectionDetailDTO as MenuDTO).type = sectionDTO.type;
|
||||||
(sectionDetailDTO as MenuDTO).instanceId = sectionDTO.instanceId;
|
(sectionDetailDTO as MenuDTO).instanceId = sectionDTO.instanceId;
|
||||||
(sectionDetailDTO as MenuDTO).configurationId = sectionDTO.configurationId;
|
(sectionDetailDTO as MenuDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
(sectionDetailDTO as MenuDTO).isSubSection = sectionDTO.isSubSection;
|
(sectionDetailDTO as MenuDTO).isSubSection = sectionDTO.isSubSection;
|
||||||
(sectionDetailDTO as MenuDTO).parentId = sectionDTO.parentId;
|
(sectionDetailDTO as MenuDTO).parentId = sectionDTO.parentId;
|
||||||
(sectionDetailDTO as MenuDTO).label = sectionDTO.label;
|
(sectionDetailDTO as MenuDTO).label = sectionDTO.label;
|
||||||
@ -641,7 +687,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
(sectionDetailDTO as QuizDTO).dateCreation = sectionDTO.dateCreation;
|
(sectionDetailDTO as QuizDTO).dateCreation = sectionDTO.dateCreation;
|
||||||
(sectionDetailDTO as QuizDTO).type = sectionDTO.type;
|
(sectionDetailDTO as QuizDTO).type = sectionDTO.type;
|
||||||
(sectionDetailDTO as QuizDTO).instanceId = sectionDTO.instanceId;
|
(sectionDetailDTO as QuizDTO).instanceId = sectionDTO.instanceId;
|
||||||
(sectionDetailDTO as QuizDTO).configurationId = sectionDTO.configurationId;
|
(sectionDetailDTO as QuizDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
(sectionDetailDTO as QuizDTO).isSubSection = sectionDTO.isSubSection;
|
(sectionDetailDTO as QuizDTO).isSubSection = sectionDTO.isSubSection;
|
||||||
(sectionDetailDTO as QuizDTO).parentId = sectionDTO.parentId;
|
(sectionDetailDTO as QuizDTO).parentId = sectionDTO.parentId;
|
||||||
(sectionDetailDTO as QuizDTO).label = sectionDTO.label;
|
(sectionDetailDTO as QuizDTO).label = sectionDTO.label;
|
||||||
@ -661,7 +708,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
(sectionDetailDTO as ArticleDTO).dateCreation = sectionDTO.dateCreation;
|
(sectionDetailDTO as ArticleDTO).dateCreation = sectionDTO.dateCreation;
|
||||||
(sectionDetailDTO as ArticleDTO).type = sectionDTO.type;
|
(sectionDetailDTO as ArticleDTO).type = sectionDTO.type;
|
||||||
(sectionDetailDTO as ArticleDTO).instanceId = sectionDTO.instanceId;
|
(sectionDetailDTO as ArticleDTO).instanceId = sectionDTO.instanceId;
|
||||||
(sectionDetailDTO as ArticleDTO).configurationId = sectionDTO.configurationId;
|
(sectionDetailDTO as ArticleDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
(sectionDetailDTO as ArticleDTO).isSubSection = sectionDTO.isSubSection;
|
(sectionDetailDTO as ArticleDTO).isSubSection = sectionDTO.isSubSection;
|
||||||
(sectionDetailDTO as ArticleDTO).parentId = sectionDTO.parentId;
|
(sectionDetailDTO as ArticleDTO).parentId = sectionDTO.parentId;
|
||||||
(sectionDetailDTO as ArticleDTO).label = sectionDTO.label;
|
(sectionDetailDTO as ArticleDTO).label = sectionDTO.label;
|
||||||
@ -681,7 +729,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
(sectionDetailDTO as PdfDTO).dateCreation = sectionDTO.dateCreation;
|
(sectionDetailDTO as PdfDTO).dateCreation = sectionDTO.dateCreation;
|
||||||
(sectionDetailDTO as PdfDTO).type = sectionDTO.type;
|
(sectionDetailDTO as PdfDTO).type = sectionDTO.type;
|
||||||
(sectionDetailDTO as PdfDTO).instanceId = sectionDTO.instanceId;
|
(sectionDetailDTO as PdfDTO).instanceId = sectionDTO.instanceId;
|
||||||
(sectionDetailDTO as PdfDTO).configurationId = sectionDTO.configurationId;
|
(sectionDetailDTO as PdfDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
(sectionDetailDTO as PdfDTO).isSubSection = sectionDTO.isSubSection;
|
(sectionDetailDTO as PdfDTO).isSubSection = sectionDTO.isSubSection;
|
||||||
(sectionDetailDTO as PdfDTO).parentId = sectionDTO.parentId;
|
(sectionDetailDTO as PdfDTO).parentId = sectionDTO.parentId;
|
||||||
(sectionDetailDTO as PdfDTO).label = sectionDTO.label;
|
(sectionDetailDTO as PdfDTO).label = sectionDTO.label;
|
||||||
@ -701,7 +750,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
(sectionDetailDTO as GameDTO).dateCreation = sectionDTO.dateCreation;
|
(sectionDetailDTO as GameDTO).dateCreation = sectionDTO.dateCreation;
|
||||||
(sectionDetailDTO as GameDTO).type = sectionDTO.type;
|
(sectionDetailDTO as GameDTO).type = sectionDTO.type;
|
||||||
(sectionDetailDTO as GameDTO).instanceId = sectionDTO.instanceId;
|
(sectionDetailDTO as GameDTO).instanceId = sectionDTO.instanceId;
|
||||||
(sectionDetailDTO as GameDTO).configurationId = sectionDTO.configurationId;
|
(sectionDetailDTO as GameDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
(sectionDetailDTO as GameDTO).isSubSection = sectionDTO.isSubSection;
|
(sectionDetailDTO as GameDTO).isSubSection = sectionDTO.isSubSection;
|
||||||
(sectionDetailDTO as GameDTO).parentId = sectionDTO.parentId;
|
(sectionDetailDTO as GameDTO).parentId = sectionDTO.parentId;
|
||||||
(sectionDetailDTO as GameDTO).label = sectionDTO.label;
|
(sectionDetailDTO as GameDTO).label = sectionDTO.label;
|
||||||
@ -721,7 +771,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
(sectionDetailDTO as AgendaDTO).dateCreation = sectionDTO.dateCreation;
|
(sectionDetailDTO as AgendaDTO).dateCreation = sectionDTO.dateCreation;
|
||||||
(sectionDetailDTO as AgendaDTO).type = sectionDTO.type;
|
(sectionDetailDTO as AgendaDTO).type = sectionDTO.type;
|
||||||
(sectionDetailDTO as AgendaDTO).instanceId = sectionDTO.instanceId;
|
(sectionDetailDTO as AgendaDTO).instanceId = sectionDTO.instanceId;
|
||||||
(sectionDetailDTO as AgendaDTO).configurationId = sectionDTO.configurationId;
|
(sectionDetailDTO as AgendaDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
(sectionDetailDTO as AgendaDTO).isSubSection = sectionDTO.isSubSection;
|
(sectionDetailDTO as AgendaDTO).isSubSection = sectionDTO.isSubSection;
|
||||||
(sectionDetailDTO as AgendaDTO).parentId = sectionDTO.parentId;
|
(sectionDetailDTO as AgendaDTO).parentId = sectionDTO.parentId;
|
||||||
(sectionDetailDTO as AgendaDTO).label = sectionDTO.label;
|
(sectionDetailDTO as AgendaDTO).label = sectionDTO.label;
|
||||||
@ -741,7 +792,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
(sectionDetailDTO as WeatherDTO).dateCreation = sectionDTO.dateCreation;
|
(sectionDetailDTO as WeatherDTO).dateCreation = sectionDTO.dateCreation;
|
||||||
(sectionDetailDTO as WeatherDTO).type = sectionDTO.type;
|
(sectionDetailDTO as WeatherDTO).type = sectionDTO.type;
|
||||||
(sectionDetailDTO as WeatherDTO).instanceId = sectionDTO.instanceId;
|
(sectionDetailDTO as WeatherDTO).instanceId = sectionDTO.instanceId;
|
||||||
(sectionDetailDTO as WeatherDTO).configurationId = sectionDTO.configurationId;
|
(sectionDetailDTO as WeatherDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
(sectionDetailDTO as WeatherDTO).isSubSection = sectionDTO.isSubSection;
|
(sectionDetailDTO as WeatherDTO).isSubSection = sectionDTO.isSubSection;
|
||||||
(sectionDetailDTO as WeatherDTO).parentId = sectionDTO.parentId;
|
(sectionDetailDTO as WeatherDTO).parentId = sectionDTO.parentId;
|
||||||
(sectionDetailDTO as WeatherDTO).label = sectionDTO.label;
|
(sectionDetailDTO as WeatherDTO).label = sectionDTO.label;
|
||||||
@ -755,6 +807,33 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
(sectionDetailDTO as WeatherDTO).longitude = sectionDTO.longitude;
|
(sectionDetailDTO as WeatherDTO).longitude = sectionDTO.longitude;
|
||||||
(sectionDetailDTO as WeatherDTO).meterZoneGPS = sectionDTO.meterZoneGPS;
|
(sectionDetailDTO as WeatherDTO).meterZoneGPS = sectionDTO.meterZoneGPS;
|
||||||
break;
|
break;
|
||||||
|
case SectionType.Event:
|
||||||
|
(sectionDetailDTO as SectionEventDTO).id = sectionDTO.id;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).order = sectionDTO.order;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).dateCreation =
|
||||||
|
sectionDTO.dateCreation;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).type = sectionDTO.type;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).instanceId =
|
||||||
|
sectionDTO.instanceId;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).configurationId =
|
||||||
|
sectionDTO.configurationId;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).isSubSection =
|
||||||
|
sectionDTO.isSubSection;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).parentId = sectionDTO.parentId;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).label = sectionDTO.label;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).title = sectionDTO.title;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).description =
|
||||||
|
sectionDTO.description;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).imageId = sectionDTO.imageId;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).imageSource =
|
||||||
|
sectionDTO.imageSource;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).isBeacon = sectionDTO.isBeacon;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).beaconId = sectionDTO.beaconId;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).latitude = sectionDTO.latitude;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).longitude = sectionDTO.longitude;
|
||||||
|
(sectionDetailDTO as SectionEventDTO).meterZoneGPS =
|
||||||
|
sectionDTO.meterZoneGPS;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -763,16 +842,17 @@ Future<Object?> getSection(String sectionId, Client client) async {
|
|||||||
try {
|
try {
|
||||||
Object? section = await client.sectionApi!.sectionGetDetail(sectionId);
|
Object? section = await client.sectionApi!.sectionGetDetail(sectionId);
|
||||||
return section;
|
return section;
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Uint8List?> _captureAndSharePng(GlobalKey globalKey, String sectionId) async {
|
Future<Uint8List?> _captureAndSharePng(
|
||||||
|
GlobalKey globalKey, String sectionId) async {
|
||||||
try {
|
try {
|
||||||
RenderRepaintBoundary ? boundary = globalKey.currentContext!.findRenderObject()! as RenderRepaintBoundary;
|
RenderRepaintBoundary? boundary =
|
||||||
|
globalKey.currentContext!.findRenderObject()! as RenderRepaintBoundary;
|
||||||
var image = await boundary.toImage();
|
var image = await boundary.toImage();
|
||||||
ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
|
ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
|
||||||
Uint8List pngBytes = byteData!.buffer.asUint8List();
|
Uint8List pngBytes = byteData!.buffer.asUint8List();
|
||||||
@ -782,7 +862,6 @@ Future<Uint8List?> _captureAndSharePng(GlobalKey globalKey, String sectionId) as
|
|||||||
a.click();
|
a.click();
|
||||||
|
|
||||||
return pngBytes;
|
return pngBytes;
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -8,20 +8,23 @@ import 'package:manager_app/app_context.dart';
|
|||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
Future<SectionDTO?> showNewSection(String configurationId, AppContext appContext, BuildContext contextBuild, bool isSubSection) {
|
Future<SectionDTO?> showNewSection(String configurationId,
|
||||||
|
AppContext appContext, BuildContext contextBuild, bool isSubSection) {
|
||||||
SectionDTO sectionDTO = new SectionDTO();
|
SectionDTO sectionDTO = new SectionDTO();
|
||||||
sectionDTO.label = "";
|
sectionDTO.label = "";
|
||||||
sectionDTO.configurationId = configurationId;
|
sectionDTO.configurationId = configurationId;
|
||||||
sectionDTO.isSubSection = isSubSection;
|
sectionDTO.isSubSection = isSubSection;
|
||||||
sectionDTO.parentId = isSubSection ? (appContext.getContext() as ManagerAppContext).selectedSection!.id : null;
|
sectionDTO.isActive = true;
|
||||||
|
sectionDTO.parentId = isSubSection
|
||||||
|
? (appContext.getContext() as ManagerAppContext).selectedSection!.id
|
||||||
|
: null;
|
||||||
Size size = MediaQuery.of(contextBuild).size;
|
Size size = MediaQuery.of(contextBuild).size;
|
||||||
sectionDTO.type = SectionType.Map;
|
sectionDTO.type = SectionType.Map;
|
||||||
|
|
||||||
var section = showDialog<SectionDTO?>(
|
var section = showDialog<SectionDTO?>(
|
||||||
builder: (BuildContext context) => AlertDialog(
|
builder: (BuildContext context) => AlertDialog(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
borderRadius: BorderRadius.all(Radius.circular(20.0))),
|
||||||
),
|
|
||||||
content: SingleChildScrollView(
|
content: SingleChildScrollView(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 750,
|
width: 750,
|
||||||
@ -30,7 +33,12 @@ Future<SectionDTO?> showNewSection(String configurationId, AppContext appContext
|
|||||||
constraints: BoxConstraints(minHeight: 300, minWidth: 300),
|
constraints: BoxConstraints(minHeight: 300, minWidth: 300),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Text(isSubSection? "Nouvelle sous section": "Nouvelle section", style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
Text(
|
||||||
|
isSubSection
|
||||||
|
? "Nouvelle sous section"
|
||||||
|
: "Nouvelle section",
|
||||||
|
style: new TextStyle(
|
||||||
|
fontSize: 25, fontWeight: FontWeight.w400)),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@ -45,7 +53,13 @@ Future<SectionDTO?> showNewSection(String configurationId, AppContext appContext
|
|||||||
),
|
),
|
||||||
DropDownInputContainer(
|
DropDownInputContainer(
|
||||||
label: "Type:",
|
label: "Type:",
|
||||||
values: isSubSection ? section_types.where((sectionType) => sectionType != "Menu").toList(): section_types.toList(), // Todo get menu by enum type
|
values: isSubSection
|
||||||
|
? section_types
|
||||||
|
.where(
|
||||||
|
(sectionType) => sectionType != "Menu")
|
||||||
|
.toList()
|
||||||
|
: section_types
|
||||||
|
.toList(), // Todo get menu by enum type
|
||||||
initialValue: "Map",
|
initialValue: "Map",
|
||||||
onChange: (String? value) {
|
onChange: (String? value) {
|
||||||
sectionDTO.type = SectionType.fromJson(value);
|
sectionDTO.type = SectionType.fromJson(value);
|
||||||
@ -99,12 +113,18 @@ Future<SectionDTO?> showNewSection(String configurationId, AppContext appContext
|
|||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
press: () {
|
press: () {
|
||||||
if(sectionDTO.label != null && sectionDTO.label!.length > 2) {
|
if (sectionDTO.label != null &&
|
||||||
|
sectionDTO.label!.length > 2) {
|
||||||
//onYes();
|
//onYes();
|
||||||
Navigator.of(context).pop(sectionDTO);
|
Navigator.of(context).pop(sectionDTO);
|
||||||
//create(sectionDTO, appContext, context, isSubSection, sendSubSection);
|
//create(sectionDTO, appContext, context, isSubSection, sendSubSection);
|
||||||
} else {
|
} else {
|
||||||
showNotification(Colors.orange, kWhite, 'Veuillez spécifier un nom pour la nouvelle section', context, null);
|
showNotification(
|
||||||
|
Colors.orange,
|
||||||
|
kWhite,
|
||||||
|
'Veuillez spécifier un nom pour la nouvelle section',
|
||||||
|
context,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
@ -114,19 +134,21 @@ Future<SectionDTO?> showNewSection(String configurationId, AppContext appContext
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
), context: contextBuild
|
),
|
||||||
);
|
context: contextBuild);
|
||||||
|
|
||||||
return section;
|
return section;
|
||||||
}
|
}
|
||||||
|
|
||||||
void create(SectionDTO sectionDTO, AppContext appContext, BuildContext context, bool isSubSection, Function? sendSubSection) async {
|
void create(SectionDTO sectionDTO, AppContext appContext, BuildContext context,
|
||||||
|
bool isSubSection, Function? sendSubSection) async {
|
||||||
if (sectionDTO.label != null) {
|
if (sectionDTO.label != null) {
|
||||||
ManagerAppContext managerAppContext = appContext.getContext();
|
ManagerAppContext managerAppContext = appContext.getContext();
|
||||||
sectionDTO.instanceId = managerAppContext.instanceId;
|
sectionDTO.instanceId = managerAppContext.instanceId;
|
||||||
sectionDTO.isBeacon = false;
|
sectionDTO.isBeacon = false;
|
||||||
sectionDTO.dateCreation = DateTime.now();
|
sectionDTO.dateCreation = DateTime.now();
|
||||||
SectionDTO? newSection = await managerAppContext.clientAPI!.sectionApi!.sectionCreate(sectionDTO);
|
SectionDTO? newSection = await managerAppContext.clientAPI!.sectionApi!
|
||||||
|
.sectionCreate(sectionDTO);
|
||||||
|
|
||||||
if (!isSubSection) {
|
if (!isSubSection) {
|
||||||
/*if (managerAppContext.selectedConfiguration.sectionIds == null) {
|
/*if (managerAppContext.selectedConfiguration.sectionIds == null) {
|
||||||
@ -134,7 +156,8 @@ void create(SectionDTO sectionDTO, AppContext appContext, BuildContext context,
|
|||||||
}
|
}
|
||||||
managerAppContext.selectedConfiguration.sectionIds.add(newSection.id);*/
|
managerAppContext.selectedConfiguration.sectionIds.add(newSection.id);*/
|
||||||
appContext.setContext(managerAppContext);
|
appContext.setContext(managerAppContext);
|
||||||
showNotification(kSuccess, kWhite, 'La section a été créée avec succès !', context, null);
|
showNotification(kSuccess, kWhite, 'La section a été créée avec succès !',
|
||||||
|
context, null);
|
||||||
} else {
|
} else {
|
||||||
sendSubSection!(newSection);
|
sendSubSection!(newSection);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,7 @@ class GameDTO {
|
|||||||
this.rows,
|
this.rows,
|
||||||
this.cols,
|
this.cols,
|
||||||
this.gameType,
|
this.gameType,
|
||||||
|
this.guidedPaths = const [],
|
||||||
});
|
});
|
||||||
|
|
||||||
String? id;
|
String? id;
|
||||||
@ -135,6 +136,8 @@ class GameDTO {
|
|||||||
///
|
///
|
||||||
GameTypes? gameType;
|
GameTypes? gameType;
|
||||||
|
|
||||||
|
List<GuidedPathDTO>? guidedPaths;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
@ -164,7 +167,8 @@ class GameDTO {
|
|||||||
other.puzzleImageId == puzzleImageId &&
|
other.puzzleImageId == puzzleImageId &&
|
||||||
other.rows == rows &&
|
other.rows == rows &&
|
||||||
other.cols == cols &&
|
other.cols == cols &&
|
||||||
other.gameType == gameType;
|
other.gameType == gameType &&
|
||||||
|
_deepEquality.equals(other.guidedPaths, guidedPaths);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
@ -194,11 +198,12 @@ class GameDTO {
|
|||||||
(puzzleImageId == null ? 0 : puzzleImageId!.hashCode) +
|
(puzzleImageId == null ? 0 : puzzleImageId!.hashCode) +
|
||||||
(rows == null ? 0 : rows!.hashCode) +
|
(rows == null ? 0 : rows!.hashCode) +
|
||||||
(cols == null ? 0 : cols!.hashCode) +
|
(cols == null ? 0 : cols!.hashCode) +
|
||||||
(gameType == null ? 0 : gameType!.hashCode);
|
(gameType == null ? 0 : gameType!.hashCode) +
|
||||||
|
(guidedPaths == null ? 0 : guidedPaths!.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() =>
|
String toString() =>
|
||||||
'GameDTO[id=$id, label=$label, title=$title, description=$description, isActive=$isActive, imageId=$imageId, imageSource=$imageSource, configurationId=$configurationId, isSubSection=$isSubSection, parentId=$parentId, type=$type, dateCreation=$dateCreation, order=$order, instanceId=$instanceId, latitude=$latitude, longitude=$longitude, meterZoneGPS=$meterZoneGPS, isBeacon=$isBeacon, beaconId=$beaconId, messageDebut=$messageDebut, messageFin=$messageFin, puzzleImage=$puzzleImage, puzzleImageId=$puzzleImageId, rows=$rows, cols=$cols, gameType=$gameType]';
|
'GameDTO[id=$id, label=$label, title=$title, description=$description, isActive=$isActive, imageId=$imageId, imageSource=$imageSource, configurationId=$configurationId, isSubSection=$isSubSection, parentId=$parentId, type=$type, dateCreation=$dateCreation, order=$order, instanceId=$instanceId, latitude=$latitude, longitude=$longitude, meterZoneGPS=$meterZoneGPS, isBeacon=$isBeacon, beaconId=$beaconId, messageDebut=$messageDebut, messageFin=$messageFin, puzzleImage=$puzzleImage, puzzleImageId=$puzzleImageId, rows=$rows, cols=$cols, gameType=$gameType, guidedPaths=$guidedPaths]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
@ -213,12 +218,12 @@ class GameDTO {
|
|||||||
json[r'label'] = null;
|
json[r'label'] = null;
|
||||||
}
|
}
|
||||||
if (this.title != null) {
|
if (this.title != null) {
|
||||||
json[r'title'] = this.title;
|
json[r'title'] = this.title!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'title'] = null;
|
json[r'title'] = null;
|
||||||
}
|
}
|
||||||
if (this.description != null) {
|
if (this.description != null) {
|
||||||
json[r'description'] = this.description;
|
json[r'description'] = this.description!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'description'] = null;
|
json[r'description'] = null;
|
||||||
}
|
}
|
||||||
@ -298,12 +303,13 @@ class GameDTO {
|
|||||||
json[r'beaconId'] = null;
|
json[r'beaconId'] = null;
|
||||||
}
|
}
|
||||||
if (this.messageDebut != null) {
|
if (this.messageDebut != null) {
|
||||||
json[r'messageDebut'] = this.messageDebut;
|
json[r'messageDebut'] =
|
||||||
|
this.messageDebut!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'messageDebut'] = null;
|
json[r'messageDebut'] = null;
|
||||||
}
|
}
|
||||||
if (this.messageFin != null) {
|
if (this.messageFin != null) {
|
||||||
json[r'messageFin'] = this.messageFin;
|
json[r'messageFin'] = this.messageFin!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'messageFin'] = null;
|
json[r'messageFin'] = null;
|
||||||
}
|
}
|
||||||
@ -332,6 +338,11 @@ class GameDTO {
|
|||||||
} else {
|
} else {
|
||||||
json[r'gameType'] = null;
|
json[r'gameType'] = null;
|
||||||
}
|
}
|
||||||
|
if (this.guidedPaths != null) {
|
||||||
|
json[r'guidedPaths'] = this.guidedPaths!.map((v) => v.toJson()).toList();
|
||||||
|
} else {
|
||||||
|
json[r'guidedPaths'] = null;
|
||||||
|
}
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,6 +394,7 @@ class GameDTO {
|
|||||||
rows: mapValueOfType<int>(json, r'rows'),
|
rows: mapValueOfType<int>(json, r'rows'),
|
||||||
cols: mapValueOfType<int>(json, r'cols'),
|
cols: mapValueOfType<int>(json, r'cols'),
|
||||||
gameType: GameTypes.fromJson(json[r'gameType']),
|
gameType: GameTypes.fromJson(json[r'gameType']),
|
||||||
|
guidedPaths: GuidedPathDTO.listFromJson(json[r'guidedPaths']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -19,6 +19,7 @@ class GuidedPathDTO {
|
|||||||
this.description = const [],
|
this.description = const [],
|
||||||
this.sectionMapId,
|
this.sectionMapId,
|
||||||
this.sectionEventId,
|
this.sectionEventId,
|
||||||
|
this.sectionGameId,
|
||||||
this.isLinear,
|
this.isLinear,
|
||||||
this.requireSuccessToAdvance,
|
this.requireSuccessToAdvance,
|
||||||
this.hideNextStepsUntilComplete,
|
this.hideNextStepsUntilComplete,
|
||||||
@ -38,6 +39,8 @@ class GuidedPathDTO {
|
|||||||
|
|
||||||
String? sectionEventId;
|
String? sectionEventId;
|
||||||
|
|
||||||
|
String? sectionGameId;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Please note: This property should have been non-nullable! Since the specification file
|
/// Please note: This property should have been non-nullable! Since the specification file
|
||||||
/// does not include a default value (using the "default:" property), however, the generated
|
/// does not include a default value (using the "default:" property), however, the generated
|
||||||
@ -82,6 +85,7 @@ class GuidedPathDTO {
|
|||||||
_deepEquality.equals(other.description, description) &&
|
_deepEquality.equals(other.description, description) &&
|
||||||
other.sectionMapId == sectionMapId &&
|
other.sectionMapId == sectionMapId &&
|
||||||
other.sectionEventId == sectionEventId &&
|
other.sectionEventId == sectionEventId &&
|
||||||
|
other.sectionGameId == sectionGameId &&
|
||||||
other.isLinear == isLinear &&
|
other.isLinear == isLinear &&
|
||||||
other.requireSuccessToAdvance == requireSuccessToAdvance &&
|
other.requireSuccessToAdvance == requireSuccessToAdvance &&
|
||||||
other.hideNextStepsUntilComplete == hideNextStepsUntilComplete &&
|
other.hideNextStepsUntilComplete == hideNextStepsUntilComplete &&
|
||||||
@ -97,6 +101,7 @@ class GuidedPathDTO {
|
|||||||
(description == null ? 0 : description!.hashCode) +
|
(description == null ? 0 : description!.hashCode) +
|
||||||
(sectionMapId == null ? 0 : sectionMapId!.hashCode) +
|
(sectionMapId == null ? 0 : sectionMapId!.hashCode) +
|
||||||
(sectionEventId == null ? 0 : sectionEventId!.hashCode) +
|
(sectionEventId == null ? 0 : sectionEventId!.hashCode) +
|
||||||
|
(sectionGameId == null ? 0 : sectionGameId!.hashCode) +
|
||||||
(isLinear == null ? 0 : isLinear!.hashCode) +
|
(isLinear == null ? 0 : isLinear!.hashCode) +
|
||||||
(requireSuccessToAdvance == null
|
(requireSuccessToAdvance == null
|
||||||
? 0
|
? 0
|
||||||
@ -109,7 +114,7 @@ class GuidedPathDTO {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() =>
|
String toString() =>
|
||||||
'GuidedPathDTO[id=$id, instanceId=$instanceId, title=$title, description=$description, sectionMapId=$sectionMapId, sectionEventId=$sectionEventId, isLinear=$isLinear, requireSuccessToAdvance=$requireSuccessToAdvance, hideNextStepsUntilComplete=$hideNextStepsUntilComplete, order=$order, steps=$steps]';
|
'GuidedPathDTO[id=$id, instanceId=$instanceId, title=$title, description=$description, sectionMapId=$sectionMapId, sectionEventId=$sectionEventId, sectionGameId=$sectionGameId, isLinear=$isLinear, requireSuccessToAdvance=$requireSuccessToAdvance, hideNextStepsUntilComplete=$hideNextStepsUntilComplete, order=$order, steps=$steps]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
@ -124,12 +129,12 @@ class GuidedPathDTO {
|
|||||||
json[r'instanceId'] = null;
|
json[r'instanceId'] = null;
|
||||||
}
|
}
|
||||||
if (this.title != null) {
|
if (this.title != null) {
|
||||||
json[r'title'] = this.title;
|
json[r'title'] = this.title!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'title'] = null;
|
json[r'title'] = null;
|
||||||
}
|
}
|
||||||
if (this.description != null) {
|
if (this.description != null) {
|
||||||
json[r'description'] = this.description;
|
json[r'description'] = this.description!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'description'] = null;
|
json[r'description'] = null;
|
||||||
}
|
}
|
||||||
@ -143,6 +148,11 @@ class GuidedPathDTO {
|
|||||||
} else {
|
} else {
|
||||||
json[r'sectionEventId'] = null;
|
json[r'sectionEventId'] = null;
|
||||||
}
|
}
|
||||||
|
if (this.sectionGameId != null) {
|
||||||
|
json[r'sectionGameId'] = this.sectionGameId;
|
||||||
|
} else {
|
||||||
|
json[r'sectionGameId'] = null;
|
||||||
|
}
|
||||||
if (this.isLinear != null) {
|
if (this.isLinear != null) {
|
||||||
json[r'isLinear'] = this.isLinear;
|
json[r'isLinear'] = this.isLinear;
|
||||||
} else {
|
} else {
|
||||||
@ -164,7 +174,7 @@ class GuidedPathDTO {
|
|||||||
json[r'order'] = null;
|
json[r'order'] = null;
|
||||||
}
|
}
|
||||||
if (this.steps != null) {
|
if (this.steps != null) {
|
||||||
json[r'steps'] = this.steps;
|
json[r'steps'] = this.steps!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'steps'] = null;
|
json[r'steps'] = null;
|
||||||
}
|
}
|
||||||
@ -198,6 +208,7 @@ class GuidedPathDTO {
|
|||||||
description: TranslationDTO.listFromJson(json[r'description']),
|
description: TranslationDTO.listFromJson(json[r'description']),
|
||||||
sectionMapId: mapValueOfType<String>(json, r'sectionMapId'),
|
sectionMapId: mapValueOfType<String>(json, r'sectionMapId'),
|
||||||
sectionEventId: mapValueOfType<String>(json, r'sectionEventId'),
|
sectionEventId: mapValueOfType<String>(json, r'sectionEventId'),
|
||||||
|
sectionGameId: mapValueOfType<String>(json, r'sectionGameId'),
|
||||||
isLinear: mapValueOfType<bool>(json, r'isLinear'),
|
isLinear: mapValueOfType<bool>(json, r'isLinear'),
|
||||||
requireSuccessToAdvance:
|
requireSuccessToAdvance:
|
||||||
mapValueOfType<bool>(json, r'requireSuccessToAdvance'),
|
mapValueOfType<bool>(json, r'requireSuccessToAdvance'),
|
||||||
|
|||||||
@ -47,7 +47,7 @@ class GuidedStepDTO {
|
|||||||
|
|
||||||
List<TranslationDTO>? description;
|
List<TranslationDTO>? description;
|
||||||
|
|
||||||
EventAddressDTOGeometry? geometry;
|
GeometryDTO? geometry;
|
||||||
|
|
||||||
double? zoneRadiusMeters;
|
double? zoneRadiusMeters;
|
||||||
|
|
||||||
@ -151,12 +151,12 @@ class GuidedStepDTO {
|
|||||||
json[r'order'] = null;
|
json[r'order'] = null;
|
||||||
}
|
}
|
||||||
if (this.title != null) {
|
if (this.title != null) {
|
||||||
json[r'title'] = this.title;
|
json[r'title'] = this.title!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'title'] = null;
|
json[r'title'] = null;
|
||||||
}
|
}
|
||||||
if (this.description != null) {
|
if (this.description != null) {
|
||||||
json[r'description'] = this.description;
|
json[r'description'] = this.description!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'description'] = null;
|
json[r'description'] = null;
|
||||||
}
|
}
|
||||||
@ -206,12 +206,14 @@ class GuidedStepDTO {
|
|||||||
json[r'timerSeconds'] = null;
|
json[r'timerSeconds'] = null;
|
||||||
}
|
}
|
||||||
if (this.timerExpiredMessage != null) {
|
if (this.timerExpiredMessage != null) {
|
||||||
json[r'timerExpiredMessage'] = this.timerExpiredMessage;
|
json[r'timerExpiredMessage'] =
|
||||||
|
this.timerExpiredMessage!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'timerExpiredMessage'] = null;
|
json[r'timerExpiredMessage'] = null;
|
||||||
}
|
}
|
||||||
if (this.quizQuestions != null) {
|
if (this.quizQuestions != null) {
|
||||||
json[r'quizQuestions'] = this.quizQuestions;
|
json[r'quizQuestions'] =
|
||||||
|
this.quizQuestions!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'quizQuestions'] = null;
|
json[r'quizQuestions'] = null;
|
||||||
}
|
}
|
||||||
@ -244,7 +246,7 @@ class GuidedStepDTO {
|
|||||||
order: mapValueOfType<int>(json, r'order'),
|
order: mapValueOfType<int>(json, r'order'),
|
||||||
title: TranslationDTO.listFromJson(json[r'title']),
|
title: TranslationDTO.listFromJson(json[r'title']),
|
||||||
description: TranslationDTO.listFromJson(json[r'description']),
|
description: TranslationDTO.listFromJson(json[r'description']),
|
||||||
geometry: EventAddressDTOGeometry.fromJson(json[r'geometry']),
|
geometry: GeometryDTO.fromJson(json[r'geometry']),
|
||||||
zoneRadiusMeters: mapValueOfType<double>(json, r'zoneRadiusMeters'),
|
zoneRadiusMeters: mapValueOfType<double>(json, r'zoneRadiusMeters'),
|
||||||
imageUrl: mapValueOfType<String>(json, r'imageUrl'),
|
imageUrl: mapValueOfType<String>(json, r'imageUrl'),
|
||||||
triggerGeoPointId: mapValueOfType<int>(json, r'triggerGeoPointId'),
|
triggerGeoPointId: mapValueOfType<int>(json, r'triggerGeoPointId'),
|
||||||
|
|||||||
@ -42,6 +42,8 @@ class MapDTO {
|
|||||||
this.categories = const [],
|
this.categories = const [],
|
||||||
this.centerLatitude,
|
this.centerLatitude,
|
||||||
this.centerLongitude,
|
this.centerLongitude,
|
||||||
|
this.isParcours,
|
||||||
|
this.guidedPaths = const [],
|
||||||
});
|
});
|
||||||
|
|
||||||
String? id;
|
String? id;
|
||||||
@ -132,6 +134,10 @@ class MapDTO {
|
|||||||
|
|
||||||
String? centerLongitude;
|
String? centerLongitude;
|
||||||
|
|
||||||
|
bool? isParcours;
|
||||||
|
|
||||||
|
List<GuidedPathDTO>? guidedPaths;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
@ -164,7 +170,9 @@ class MapDTO {
|
|||||||
other.iconSource == iconSource &&
|
other.iconSource == iconSource &&
|
||||||
_deepEquality.equals(other.categories, categories) &&
|
_deepEquality.equals(other.categories, categories) &&
|
||||||
other.centerLatitude == centerLatitude &&
|
other.centerLatitude == centerLatitude &&
|
||||||
other.centerLongitude == centerLongitude;
|
other.centerLongitude == centerLongitude &&
|
||||||
|
other.isParcours == isParcours &&
|
||||||
|
_deepEquality.equals(other.guidedPaths, guidedPaths);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
@ -197,11 +205,13 @@ class MapDTO {
|
|||||||
(iconSource == null ? 0 : iconSource!.hashCode) +
|
(iconSource == null ? 0 : iconSource!.hashCode) +
|
||||||
(categories == null ? 0 : categories!.hashCode) +
|
(categories == null ? 0 : categories!.hashCode) +
|
||||||
(centerLatitude == null ? 0 : centerLatitude!.hashCode) +
|
(centerLatitude == null ? 0 : centerLatitude!.hashCode) +
|
||||||
(centerLongitude == null ? 0 : centerLongitude!.hashCode);
|
(centerLongitude == null ? 0 : centerLongitude!.hashCode) +
|
||||||
|
(isParcours == null ? 0 : isParcours!.hashCode) +
|
||||||
|
(guidedPaths == null ? 0 : guidedPaths!.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() =>
|
String toString() =>
|
||||||
'MapDTO[id=$id, label=$label, title=$title, description=$description, isActive=$isActive, imageId=$imageId, imageSource=$imageSource, configurationId=$configurationId, isSubSection=$isSubSection, parentId=$parentId, type=$type, dateCreation=$dateCreation, order=$order, instanceId=$instanceId, latitude=$latitude, longitude=$longitude, meterZoneGPS=$meterZoneGPS, isBeacon=$isBeacon, beaconId=$beaconId, zoom=$zoom, mapType=$mapType, mapTypeMapbox=$mapTypeMapbox, mapProvider=$mapProvider, points=$points, iconResourceId=$iconResourceId, iconSource=$iconSource, categories=$categories, centerLatitude=$centerLatitude, centerLongitude=$centerLongitude]';
|
'MapDTO[id=$id, label=$label, title=$title, description=$description, isActive=$isActive, imageId=$imageId, imageSource=$imageSource, configurationId=$configurationId, isSubSection=$isSubSection, parentId=$parentId, type=$type, dateCreation=$dateCreation, order=$order, instanceId=$instanceId, latitude=$latitude, longitude=$longitude, meterZoneGPS=$meterZoneGPS, isBeacon=$isBeacon, beaconId=$beaconId, zoom=$zoom, mapType=$mapType, mapTypeMapbox=$mapTypeMapbox, mapProvider=$mapProvider, points=$points, iconResourceId=$iconResourceId, iconSource=$iconSource, categories=$categories, centerLatitude=$centerLatitude, centerLongitude=$centerLongitude, isParcours=$isParcours, guidedPaths=$guidedPaths]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
@ -216,12 +226,12 @@ class MapDTO {
|
|||||||
json[r'label'] = null;
|
json[r'label'] = null;
|
||||||
}
|
}
|
||||||
if (this.title != null) {
|
if (this.title != null) {
|
||||||
json[r'title'] = this.title;
|
json[r'title'] = this.title!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'title'] = null;
|
json[r'title'] = null;
|
||||||
}
|
}
|
||||||
if (this.description != null) {
|
if (this.description != null) {
|
||||||
json[r'description'] = this.description;
|
json[r'description'] = this.description!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'description'] = null;
|
json[r'description'] = null;
|
||||||
}
|
}
|
||||||
@ -321,7 +331,7 @@ class MapDTO {
|
|||||||
json[r'mapProvider'] = null;
|
json[r'mapProvider'] = null;
|
||||||
}
|
}
|
||||||
if (this.points != null) {
|
if (this.points != null) {
|
||||||
json[r'points'] = this.points;
|
json[r'points'] = this.points!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'points'] = null;
|
json[r'points'] = null;
|
||||||
}
|
}
|
||||||
@ -336,7 +346,7 @@ class MapDTO {
|
|||||||
json[r'iconSource'] = null;
|
json[r'iconSource'] = null;
|
||||||
}
|
}
|
||||||
if (this.categories != null) {
|
if (this.categories != null) {
|
||||||
json[r'categories'] = this.categories;
|
json[r'categories'] = this.categories!.map((v) => v.toJson()).toList();
|
||||||
} else {
|
} else {
|
||||||
json[r'categories'] = null;
|
json[r'categories'] = null;
|
||||||
}
|
}
|
||||||
@ -350,6 +360,16 @@ class MapDTO {
|
|||||||
} else {
|
} else {
|
||||||
json[r'centerLongitude'] = null;
|
json[r'centerLongitude'] = null;
|
||||||
}
|
}
|
||||||
|
if (this.isParcours != null) {
|
||||||
|
json[r'isParcours'] = this.isParcours;
|
||||||
|
} else {
|
||||||
|
json[r'isParcours'] = null;
|
||||||
|
}
|
||||||
|
if (this.guidedPaths != null) {
|
||||||
|
json[r'guidedPaths'] = this.guidedPaths!.map((v) => v.toJson()).toList();
|
||||||
|
} else {
|
||||||
|
json[r'guidedPaths'] = null;
|
||||||
|
}
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,6 +423,8 @@ class MapDTO {
|
|||||||
categories: CategorieDTO.listFromJson(json[r'categories']),
|
categories: CategorieDTO.listFromJson(json[r'categories']),
|
||||||
centerLatitude: mapValueOfType<String>(json, r'centerLatitude'),
|
centerLatitude: mapValueOfType<String>(json, r'centerLatitude'),
|
||||||
centerLongitude: mapValueOfType<String>(json, r'centerLongitude'),
|
centerLongitude: mapValueOfType<String>(json, r'centerLongitude'),
|
||||||
|
isParcours: mapValueOfType<bool>(json, r'isParcours'),
|
||||||
|
guidedPaths: GuidedPathDTO.listFromJson(json[r'guidedPaths']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -447,7 +447,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.1"
|
version: "1.5.1"
|
||||||
flutter_map:
|
flutter_map:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_map
|
name: flutter_map
|
||||||
sha256: "87cc8349b8fa5dccda5af50018c7374b6645334a0d680931c1fe11bce88fa5bb"
|
sha256: "87cc8349b8fa5dccda5af50018c7374b6645334a0d680931c1fe11bce88fa5bb"
|
||||||
@ -737,7 +737,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.13"
|
version: "0.4.13"
|
||||||
latlong2:
|
latlong2:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: latlong2
|
name: latlong2
|
||||||
sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
|
sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
|
||||||
|
|||||||
@ -49,6 +49,8 @@ dependencies:
|
|||||||
multi_select_flutter: ^4.1.3
|
multi_select_flutter: ^4.1.3
|
||||||
youtube_player_iframe: ^5.0.0
|
youtube_player_iframe: ^5.0.0
|
||||||
location_picker_flutter_map: ^3.0.1
|
location_picker_flutter_map: ^3.0.1
|
||||||
|
flutter_map: ^6.2.1
|
||||||
|
latlong2: ^0.9.1
|
||||||
go_router: ^16.2.0
|
go_router: ^16.2.0
|
||||||
|
|
||||||
#msix: ^2.1.3
|
#msix: ^2.1.3
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user