From 938b677b6ecc1ea5b189672bfd4074a3a6d59d59 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Mon, 30 Dec 2024 22:14:46 +0100 Subject: [PATCH 01/21] test hamburger bar --- covas_mobile/lib/classes/MyDrawer.dart | 49 ++++++++++++++++++++++++ covas_mobile/lib/pages/ListItemMenu.dart | 2 + 2 files changed, 51 insertions(+) create mode 100644 covas_mobile/lib/classes/MyDrawer.dart diff --git a/covas_mobile/lib/classes/MyDrawer.dart b/covas_mobile/lib/classes/MyDrawer.dart new file mode 100644 index 0000000..4161c00 --- /dev/null +++ b/covas_mobile/lib/classes/MyDrawer.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; + +class MyDrawer extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Drawer( + child: ListView( + padding: EdgeInsets.zero, + children: [ + // Drawer Header + DrawerHeader( + decoration: BoxDecoration( + color: Colors.blue, + ), + child: Text( + 'Menu', + style: TextStyle( + color: Colors.white, + fontSize: 24, + ), + ), + ), + // Drawer Items + ListTile( + leading: Icon(Icons.home), + title: Text('Home'), + onTap: () { + Navigator.pop(context); // Close the drawer + }, + ), + ListTile( + leading: Icon(Icons.settings), + title: Text('Settings'), + onTap: () { + Navigator.pop(context); // Close the drawer + }, + ), + ListTile( + leading: Icon(Icons.info), + title: Text('About'), + onTap: () { + Navigator.pop(context); // Close the drawer + }, + ), + ], + ), + ); + } +} diff --git a/covas_mobile/lib/pages/ListItemMenu.dart b/covas_mobile/lib/pages/ListItemMenu.dart index da85d5c..945dae8 100644 --- a/covas_mobile/lib/pages/ListItemMenu.dart +++ b/covas_mobile/lib/pages/ListItemMenu.dart @@ -5,6 +5,7 @@ import 'dart:convert'; import 'dart:io'; import 'ItemMenu.dart'; import '../classes/events.dart'; +import '../classes/MyDrawer.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:intl/intl.dart'; import 'package:intl/date_symbol_data_local.dart'; @@ -742,6 +743,7 @@ class _MyHomePageState extends State { backgroundColor: Colors.blue, foregroundColor: Colors.white, ), + drawer: MyDrawer(), body: Column( children: [ if (showInputSearch) _buildItemZoneSearchField(), From 43d77f778b36ab203db32519b213109819f3fba4 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Mon, 30 Dec 2024 22:34:17 +0100 Subject: [PATCH 02/21] change alert message --- covas_mobile/lib/classes/alert.dart | 6 ++-- covas_mobile/lib/main.dart | 8 ++--- .../lib/pages/DisplayPictureScreen.dart | 11 +++---- covas_mobile/lib/pages/EditEvent.dart | 20 +++++++------ covas_mobile/lib/pages/ItemMenu.dart | 6 ++-- covas_mobile/lib/pages/MapboxPages.dart | 30 +++++++++++-------- covas_mobile/lib/pages/UpdateEventImage.dart | 19 +++++++----- 7 files changed, 55 insertions(+), 45 deletions(-) diff --git a/covas_mobile/lib/classes/alert.dart b/covas_mobile/lib/classes/alert.dart index 7ca853a..28a03e9 100644 --- a/covas_mobile/lib/classes/alert.dart +++ b/covas_mobile/lib/classes/alert.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -mixin ShowErrorDialog on State { - void showErrorDialog(BuildContext context, String text) { +mixin ShowAlertDialog on State { + void showAlertDialog(BuildContext context, String title, String text) { // Create AlertDialog AlertDialog dialog = AlertDialog( - title: Text("Error"), + title: Text(title), content: Text(text), actions: [ ElevatedButton( diff --git a/covas_mobile/lib/main.dart b/covas_mobile/lib/main.dart index be4b083..4e58520 100644 --- a/covas_mobile/lib/main.dart +++ b/covas_mobile/lib/main.dart @@ -32,7 +32,7 @@ class LoginDemo extends StatefulWidget { _LoginDemoState createState() => _LoginDemoState(); } -class _LoginDemoState extends State with ShowErrorDialog { +class _LoginDemoState extends State with ShowAlertDialog { TextEditingController inputPseudo = TextEditingController(); TextEditingController inputPassword = TextEditingController(); Future _login(BuildContext context) async { @@ -120,13 +120,13 @@ class _LoginDemoState extends State with ShowErrorDialog { } break; } - showErrorDialog(context, text); + showAlertDialog(context, "Erreur serveur", text); } } catch (e) { - showErrorDialog(context, "${e}"); + showAlertDialog(context, "Erreur", "${e}"); } } else { - showErrorDialog(context, "Champ vide"); + showAlertDialog(context, "Erreur", "Champ vide"); } } diff --git a/covas_mobile/lib/pages/DisplayPictureScreen.dart b/covas_mobile/lib/pages/DisplayPictureScreen.dart index b50aaa2..19631a1 100644 --- a/covas_mobile/lib/pages/DisplayPictureScreen.dart +++ b/covas_mobile/lib/pages/DisplayPictureScreen.dart @@ -54,7 +54,7 @@ class DisplayPictureScreen extends StatefulWidget { // A widget that displays the picture taken by the user. class DisplayPictureScreenState extends State - with ShowDescImageAdd, ShowErrorDialog, TickerProviderStateMixin { + with ShowDescImageAdd, ShowAlertDialog, TickerProviderStateMixin { late AnimationController controller; @override void initState() { @@ -80,7 +80,7 @@ class DisplayPictureScreenState extends State Future displayError(String e) async { print("problem gemini : ${e}"); - showErrorDialog(context, + showAlertDialog(context, 'Error IA', "L'IA de Google n'a pas su analyser l'image. Recommecer avec une autre"); } @@ -119,14 +119,15 @@ class DisplayPictureScreenState extends State builder: (_) => ItemMenu(title: events[0]["id"]))); } } else { - showErrorDialog(context, + showAlertDialog(context, 'Erreur de reponse', "response status code update : ${responseGet.statusCode}"); } } else { - showErrorDialog(context, "Erreur de token"); + showAlertDialog(context, "Erreur de reponse", "Erreur de token"); } } catch (e) { - showErrorDialog(context, "Erreur de format de donnée fourni par l'IA"); + showAlertDialog( + context, "Erreur IA", "Erreur de format de donnée fourni par l'IA"); } //showDescImageAddDialog(context, message); diff --git a/covas_mobile/lib/pages/EditEvent.dart b/covas_mobile/lib/pages/EditEvent.dart index 3f95af3..e1b9275 100644 --- a/covas_mobile/lib/pages/EditEvent.dart +++ b/covas_mobile/lib/pages/EditEvent.dart @@ -52,7 +52,7 @@ class EditEvent extends StatefulWidget { } class _EditEventState extends State - with ShowErrorDialog, ShowEventDialog { + with ShowAlertDialog, ShowEventDialog { TextEditingController inputName = TextEditingController(); TextEditingController inputDate = TextEditingController(); @@ -208,7 +208,8 @@ class _EditEventState extends State var events = jsonDecode(utf8.decode(responseGet.bodyBytes)); if (events.length > 0) { if (events[0]["id"] != widget.events!.id) { - showErrorDialog(context, "Evenement deja existant"); + showAlertDialog( + context, "Info evenement", "Evenement deja existant"); } return; @@ -236,7 +237,7 @@ class _EditEventState extends State final status = res.statusCode; print("code status imgbb ${status}"); if (status != 200) { - showErrorDialog(context, "Image non posté"); + showAlertDialog(context, "Erreur image", "Image non posté"); return; } var body = json.decode(utf8.decode(res.bodyBytes)); @@ -306,22 +307,23 @@ class _EditEventState extends State } break; } - showErrorDialog(context, text); + showAlertDialog(context, "Erreur serveur", text); } } else { - showErrorDialog(context, "Aucune donnée geographique"); + showAlertDialog( + context, "Erreur serveur", "Aucune donnée geographique"); } } else { - showErrorDialog(context, "Mapbox non accessible"); + showAlertDialog(context, "Erreur serveur", "Mapbox non accessible"); } } catch (e) { - showErrorDialog(context, "${e}"); + showAlertDialog(context, "Erreur serveur", "${e}"); } } else { - showErrorDialog(context, "Champ vide"); + showAlertDialog(context, "Erreur utilisateur", "Champ vide"); } } else { - showErrorDialog(context, "Evenement non futur"); + showAlertDialog(context, "Erreur evenement", "Evenement non futur"); } } diff --git a/covas_mobile/lib/pages/ItemMenu.dart b/covas_mobile/lib/pages/ItemMenu.dart index daafdc8..b1d4995 100644 --- a/covas_mobile/lib/pages/ItemMenu.dart +++ b/covas_mobile/lib/pages/ItemMenu.dart @@ -67,7 +67,7 @@ class ItemMenu extends StatefulWidget { State createState() => _ItemMenuState(); } -class _ItemMenuState extends State with ShowErrorDialog { +class _ItemMenuState extends State with ShowAlertDialog { String listUser = ""; String eventName = ""; String eventStartDate = ""; @@ -169,10 +169,10 @@ class _ItemMenuState extends State with ShowErrorDialog { } break; } - showErrorDialog(context, text); + showAlertDialog(context, "Erreur serveur", text); } } else { - showErrorDialog(context, "Cache invalide"); + showAlertDialog(context, "Erreur serveur", "Cache invalide"); } setState(() { diff --git a/covas_mobile/lib/pages/MapboxPages.dart b/covas_mobile/lib/pages/MapboxPages.dart index cd9f7a7..8f26b90 100644 --- a/covas_mobile/lib/pages/MapboxPages.dart +++ b/covas_mobile/lib/pages/MapboxPages.dart @@ -42,7 +42,7 @@ class MapboxPages extends StatefulWidget { State createState() => _MapboxPagesState(); } -class _MapboxPagesState extends State with ShowErrorDialog { +class _MapboxPagesState extends State with ShowAlertDialog { late MapboxMapController mapController; late String mapboxAccessToken; List routeCoordinates = []; @@ -63,7 +63,8 @@ class _MapboxPagesState extends State with ShowErrorDialog { void _initToken() { mapboxAccessToken = dotenv.env['MAPBOX_ACCESS_TOKEN'] ?? ''; if (mapboxAccessToken.isEmpty) { - showErrorDialog(context, "Mapbox Access Token is not available."); + showAlertDialog( + context, "Erreur Mapbox", "Mapbox Access Token is not available."); } } @@ -88,7 +89,7 @@ class _MapboxPagesState extends State with ShowErrorDialog { _handleErrorResponse(responseGet.statusCode); } } else { - showErrorDialog(context, "Invalid cache."); + showAlertDialog(context, "Erreur serveur", "Invalid cache."); } } @@ -116,14 +117,15 @@ class _MapboxPagesState extends State with ShowErrorDialog { default: text = "Unknown error."; } - showErrorDialog(context, text); + showAlertDialog(context, "Erreur serveur", text); } Future _getUserLocation() async { try { bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) { - showErrorDialog(context, "Location services are disabled."); + showAlertDialog( + context, "Erreur de service", "Location services are disabled."); return; } @@ -131,13 +133,14 @@ class _MapboxPagesState extends State with ShowErrorDialog { if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { - showErrorDialog(context, "Location permissions are denied."); + showAlertDialog(context, "Erreur de permission", + "Location permissions are denied."); return; } } if (permission == LocationPermission.deniedForever) { - showErrorDialog(context, + showAlertDialog(context, "Erreur de permission", "Location permissions are permanently denied. Enable them in settings."); return; } @@ -171,7 +174,7 @@ class _MapboxPagesState extends State with ShowErrorDialog { _initToken(); _getEventInfo(); } catch (e) { - showErrorDialog(context, "Failed to get user location: $e"); + showAlertDialog(context, "Erreur geo", "Failed to get user location: $e"); } } @@ -191,8 +194,8 @@ class _MapboxPagesState extends State with ShowErrorDialog { }).toList(); }); } else { - showErrorDialog( - context, "Failed to fetch the route: ${response.statusCode}"); + showAlertDialog(context, "Erreur serveur", + "Failed to fetch the route: ${response.statusCode}"); } } @@ -244,8 +247,8 @@ class _MapboxPagesState extends State with ShowErrorDialog { currentRouteLine = null; } if (!isUserPositionInitialized) { - showErrorDialog( - context, "User position is not yet initialized. Try again."); + showAlertDialog(context, "Erreur de position", + "User position is not yet initialized. Try again."); return; } @@ -284,7 +287,8 @@ class _MapboxPagesState extends State with ShowErrorDialog { _zoomToFitRoute(routeCoordinates); } } else { - showErrorDialog(context, "Invalid coordinates or user position."); + showAlertDialog(context, "Erreur de coordonée", + "Invalid coordinates or user position."); } } diff --git a/covas_mobile/lib/pages/UpdateEventImage.dart b/covas_mobile/lib/pages/UpdateEventImage.dart index 83a1c85..46270dc 100644 --- a/covas_mobile/lib/pages/UpdateEventImage.dart +++ b/covas_mobile/lib/pages/UpdateEventImage.dart @@ -44,7 +44,7 @@ class UpdateeventImage extends StatefulWidget { } class _UpdateeventImageState extends State - with ShowErrorDialog, ShowEventDialog { + with ShowAlertDialog, ShowEventDialog { TextEditingController inputName = TextEditingController(); TextEditingController inputDate = TextEditingController(); @@ -156,7 +156,7 @@ class _UpdateeventImageState extends State var endDate = "${endDateFormat}T${endTimepicker.text.replaceAll('-', ':')}"; if (!startDateCompare.isAfter(dateNow)) { - showErrorDialog(context, "Evenement non futur"); + showAlertDialog(context, "Erreur evenement", "Evenement non futur"); return; } @@ -164,7 +164,7 @@ class _UpdateeventImageState extends State var accessToken = prefs.getString("access_token") ?? ""; if (accessToken.isEmpty) { - showErrorDialog(context, "Token d'accès manquant"); + showAlertDialog(context, "Erreur token", "Token d'accès manquant"); return; } @@ -179,13 +179,14 @@ class _UpdateeventImageState extends State final searchboxResponse = await http.get(searchboxUrl); if (searchboxResponse.statusCode != 200) { - showErrorDialog(context, "Erreur lors de la géocodage avec Searchbox"); + showAlertDialog(context, "Erreur map", + "Erreur lors de la géocodage avec Searchbox"); return; } final searchboxData = json.decode(searchboxResponse.body); if (searchboxData['results'].isEmpty) { - showErrorDialog(context, "Lieu introuvable"); + showAlertDialog(context, "Erreur", "Lieu introuvable"); return; } @@ -229,7 +230,8 @@ class _UpdateeventImageState extends State await http.Response.fromStream(await imgbbRequest.send()); if (imgbbResponse.statusCode != 200) { - showErrorDialog(context, "Erreur lors de l'upload d'image"); + showAlertDialog( + context, "Erreur serveur", "Erreur lors de l'upload d'image"); return; } @@ -265,7 +267,7 @@ class _UpdateeventImageState extends State handleHttpError(eventResponse.statusCode, context); } } catch (e) { - showErrorDialog(context, "Erreur: ${e.toString()}"); + showAlertDialog(context, "Erreur", "Erreur: ${e.toString()}"); } } @@ -279,7 +281,8 @@ class _UpdateeventImageState extends State 410: "Token invalide", 500: "Problème interne du serveur", }; - showErrorDialog(context, errorMessages[statusCode] ?? "Erreur inconnue"); + showAlertDialog(context, "Erreur serveur", + errorMessages[statusCode] ?? "Erreur inconnue"); } void start() async { From 8adcd803069d50b40a11360e9aa9084a9aa68f14 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Mon, 30 Dec 2024 22:51:47 +0100 Subject: [PATCH 03/21] message about --- covas_mobile/lib/classes/MyDrawer.dart | 6 ++++-- covas_mobile/lib/classes/alert.dart | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/covas_mobile/lib/classes/MyDrawer.dart b/covas_mobile/lib/classes/MyDrawer.dart index 4161c00..d8b6748 100644 --- a/covas_mobile/lib/classes/MyDrawer.dart +++ b/covas_mobile/lib/classes/MyDrawer.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; +import 'alert.dart'; -class MyDrawer extends StatelessWidget { +class MyDrawer extends StatelessWidget with ShowAlertDialog { @override Widget build(BuildContext context) { return Drawer( @@ -39,7 +40,8 @@ class MyDrawer extends StatelessWidget { leading: Icon(Icons.info), title: Text('About'), onTap: () { - Navigator.pop(context); // Close the drawer + showAlertDialog( + context, 'About', "Version 0.0.1"); // Close the drawer }, ), ], diff --git a/covas_mobile/lib/classes/alert.dart b/covas_mobile/lib/classes/alert.dart index 28a03e9..ed83093 100644 --- a/covas_mobile/lib/classes/alert.dart +++ b/covas_mobile/lib/classes/alert.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -mixin ShowAlertDialog on State { +mixin ShowAlertDialog { void showAlertDialog(BuildContext context, String title, String text) { // Create AlertDialog AlertDialog dialog = AlertDialog( From ef87a8bfe2e8ec2f50bd56e6530d305f015a4334 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Mon, 30 Dec 2024 23:33:51 +0100 Subject: [PATCH 04/21] add logout button + logout function --- covas_mobile/lib/classes/MyDrawer.dart | 76 ++++++++++++++++++++++++ covas_mobile/lib/pages/ListItemMenu.dart | 1 - 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/covas_mobile/lib/classes/MyDrawer.dart b/covas_mobile/lib/classes/MyDrawer.dart index d8b6748..2d95736 100644 --- a/covas_mobile/lib/classes/MyDrawer.dart +++ b/covas_mobile/lib/classes/MyDrawer.dart @@ -1,7 +1,75 @@ import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:http/http.dart' as http; +import 'dart:io'; + import 'alert.dart'; +import '../variable/globals.dart' as globals; + +import '../main.dart'; + class MyDrawer extends StatelessWidget with ShowAlertDialog { + Future logout(BuildContext context) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + var accessToken = prefs.getString("access_token") ?? ""; + + if (accessToken.isNotEmpty) { + var url = Uri.parse("${globals.api}/token"); + + try { + var response = await http.delete(url, headers: { + "Content-Type": "application/json", + HttpHeaders.cookieHeader: "access_token=${accessToken}" + }); + print("Status code logout ${response.statusCode}"); + + if (response.statusCode == 200) { + await prefs.setString("access_token", ""); // Clear the token + Navigator.pushReplacement( + context, MaterialPageRoute(builder: (_) => LoginDemo())); + } else { + switch (response.statusCode) { + case 400: + print("Bad Request: Please check your input."); + showAlertDialog( + context, "Bad Request", "Please check your input."); + break; + case 401: + print("Unauthorized: Invalid credentials."); + showAlertDialog(context, "Unauthorized", "Invalid credentials."); + break; + case 403: + print("Forbidden: You don't have permission."); + showAlertDialog(context, "Forbidden", + "You don't have permission to access this."); + break; + case 404: + print("Not Found: The resource was not found."); + showAlertDialog( + context, "Not Found", "The resource was not found."); + break; + case 500: + print("Server Error: Something went wrong on the server."); + showAlertDialog(context, "Server Error", + "Something went wrong on the server."); + break; + default: + print("Unexpected Error: ${response.statusCode}"); + showAlertDialog(context, "Error", "Unexpected Error occurred."); + break; + } + } + } catch (e) { + print("Error: $e"); + showAlertDialog( + context, "Error", "An error occurred. Please try again."); + } + } else { + showAlertDialog(context, "Error", "Token invalide."); + } + } + @override Widget build(BuildContext context) { return Drawer( @@ -44,6 +112,14 @@ class MyDrawer extends StatelessWidget with ShowAlertDialog { context, 'About', "Version 0.0.1"); // Close the drawer }, ), + ListTile( + leading: Icon(Icons.logout), + title: Text('Log out'), + onTap: () async { + logout(context); +// Close the drawer + }, + ), ], ), ); diff --git a/covas_mobile/lib/pages/ListItemMenu.dart b/covas_mobile/lib/pages/ListItemMenu.dart index 945dae8..eb99976 100644 --- a/covas_mobile/lib/pages/ListItemMenu.dart +++ b/covas_mobile/lib/pages/ListItemMenu.dart @@ -15,7 +15,6 @@ import '../variable/globals.dart' as globals; import 'package:permission_handler/permission_handler.dart'; import "Camera.dart"; import 'package:camera/camera.dart'; -import 'package:textfield_tags/textfield_tags.dart'; void main() { initializeDateFormatting("fr_FR", null).then((_) => runApp(const MyApp())); From ad19ea54d1289d355d300dc036e8c26a7863a343 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Mon, 30 Dec 2024 23:48:03 +0100 Subject: [PATCH 05/21] add account update --- covas_mobile/lib/classes/MyDrawer.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/covas_mobile/lib/classes/MyDrawer.dart b/covas_mobile/lib/classes/MyDrawer.dart index 2d95736..13e2925 100644 --- a/covas_mobile/lib/classes/MyDrawer.dart +++ b/covas_mobile/lib/classes/MyDrawer.dart @@ -104,6 +104,13 @@ class MyDrawer extends StatelessWidget with ShowAlertDialog { Navigator.pop(context); // Close the drawer }, ), + ListTile( + leading: Icon(Icons.account_circle), + title: Text('Update profile'), + onTap: () { + Navigator.pop(context); // Close the drawer + }, + ), ListTile( leading: Icon(Icons.info), title: Text('About'), From ef8b8c96c0df84456b6aca665667d4ef5fa36a95 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Thu, 2 Jan 2025 23:22:25 +0100 Subject: [PATCH 06/21] edit profile wip --- covas_mobile/lib/pages/EditProfile.dart | 701 ++++++++++++++++++++++++ 1 file changed, 701 insertions(+) create mode 100644 covas_mobile/lib/pages/EditProfile.dart diff --git a/covas_mobile/lib/pages/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart new file mode 100644 index 0000000..593d1fe --- /dev/null +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -0,0 +1,701 @@ +import 'package:covas_mobile/pages/CameraEdit.dart'; +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:http/http.dart' as http; +import 'package:intl/intl.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:textfield_tags/textfield_tags.dart'; + +import 'dart:convert'; +import 'dart:io'; + +import 'dart:typed_data'; +import '../classes/events.dart'; + +import 'ItemMenu.dart'; +import 'CameraEdit.dart'; +import 'package:camera/camera.dart'; + +import '../classes/alert.dart'; +import '../classes/eventAdded.dart'; + +import '../variable/globals.dart' as globals; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + Events? events; + + @override + Widget build(BuildContext context) { + return MaterialApp( + debugShowCheckedModeBanner: false, + home: EditProfile(), + ); + } +} + +class EditProfile extends StatefulWidget { + const EditProfile({super.key}); + + @override + _EditProfileState createState() => _EditProfileState(); +} + +class _EditProfileState extends State + with ShowAlertDialog, ShowEventDialog { + TextEditingController inputName = TextEditingController(); + + TextEditingController inputDate = TextEditingController(); + TextEditingController inputDesc = TextEditingController(); + + TextEditingController inputGeo = TextEditingController(); + + TextEditingController startDatepicker = TextEditingController(); + TextEditingController startTimepicker = TextEditingController(); + TextEditingController endDatepicker = TextEditingController(); + TextEditingController endTimepicker = TextEditingController(); + final _stringTagController = StringTagController(); + + DateTime startDate = DateTime.now(); + DateTime endDate = DateTime.now(); + List> suggestions = []; + String geographicalZone = ""; + String imgUrl = ""; + + List initialTags = []; + + final _stringOrgaController = StringTagController(); + List initialOrga = []; + + onTapFunctionDatePicker( + {required BuildContext context, required String position}) async { + DateTime date; + if ((startDatepicker.text.isEmpty) || (endDatepicker.text.isEmpty)) { + date = DateTime.now(); + } else { + date = DateTime.parse(formatDate(startDatepicker.text)); + if (position == "end") { + date = DateTime.parse(formatDate(endDatepicker.text)); + } + } + DateTime? pickedDate = await showDatePicker( + context: context, + firstDate: date, + initialDate: date, + lastDate: DateTime(2104)); + if (pickedDate == null) return; + if (position == "start") { + startDatepicker.text = DateFormat("dd/MM/yyyy").format(pickedDate); + } + if (position == "end") { + endDatepicker.text = DateFormat("dd/MM/yyyy").format(pickedDate); + } + } + + onTapFunctionTimePicker( + {required BuildContext context, required String position}) async { + TimeOfDay time; + + if ((startTimepicker.text.isEmpty) || (endTimepicker.text.isEmpty)) { + time = TimeOfDay.now(); + } else { + DateTime date = new DateTime.now(); + date = date.copyWith( + hour: int.parse(startTimepicker.text.split(":")[0]), + minute: int.parse(startTimepicker.text.split(":")[1])); + time = TimeOfDay.fromDateTime(date); + if (position == "end") { + date = date.copyWith( + hour: int.parse(endTimepicker.text.split(":")[0]), + minute: int.parse(endTimepicker.text.split(":")[1])); + time = TimeOfDay.fromDateTime(date); + } + } + + TimeOfDay? pickedDate = + await showTimePicker(context: context, initialTime: time); + if (pickedDate == null) return; + if (position == "start") { + startTimepicker.text = pickedDate.format(context); + } + if (position == "end") { + endTimepicker.text = pickedDate.format(context); + } + } + + convertNulltoEmptyString(var check) { + if (check == null) { + return ""; + } + return check; + } + + convertNulltoArray(List check) { + if (check == null) { + return []; + } + return check; + } + + String formatDate(String date) { + var splitedDate = date.split("/"); + + var day = splitedDate[0]; + var month = splitedDate[1]; + var year = splitedDate[2]; + + return "${year}-${month}-${day}"; + } + + Future _updateEvent(BuildContext context) async { + var name = inputName.text; + var place = inputGeo.text; + var description = inputDesc.text; + List tags = List.from(_stringTagController.getTags as List); + List organizers = + List.from(_stringOrgaController.getTags as List); + + var startDateFormat = formatDate(startDatepicker.text); + //DateTime startDateCompare = DateTime.parse(startDateFormat); + DateTime dateNow = DateTime.now(); + var endDateFormat = formatDate(endDatepicker.text); + var startDate = + "${startDateFormat}T${startTimepicker.text.replaceAll('-', ':')}"; + var endDate = "${endDateFormat}T${endTimepicker.text.replaceAll('-', ':')}"; + DateTime startDateCompare = DateTime.parse(startDate); + if (startDateCompare.isAfter(dateNow)) { + SharedPreferences prefs = await SharedPreferences.getInstance(); + var accessToken = prefs.getString("access_token") ?? ""; + + if (accessToken.isNotEmpty) { + try { + await dotenv.load(); + final ApiTokenGoogle = dotenv.env['PLACE_API_KEY'] ?? ''; + // Searchbox API for geocoding the place (No session token) + final searchboxUrl = Uri.parse( + 'https://maps.googleapis.com/maps/api/place/textsearch/json?query=${place}&key=${ApiTokenGoogle}'); + + // Perform the request + final searchboxResponse = await http.get(searchboxUrl); + + if (searchboxResponse.statusCode == 200) { + final data = json.decode(searchboxResponse.body); + print("data : ${data}"); + + if (data['results'].isNotEmpty) { + place = data['results'][0]['formatted_address']; + final coordinates = data['results'][0]['geometry']['location']; + final longitude = coordinates["lng"]; // Longitude + final latitude = coordinates["lat"]; // Latitude + var urlGet = Uri.parse( + "${globals.api}/events/search?item=${name}&date_event=${startDate}&min_lat=$latitude&max_lat=$latitude" + "&min_lon=$longitude&max_lon=$longitude"); + + var responseGet = await http.get(urlGet, headers: { + HttpHeaders.cookieHeader: 'access_token=${accessToken}' + }); + if (responseGet.statusCode == 200) { + var events = jsonDecode(utf8.decode(responseGet.bodyBytes)); + if (events.length > 0) { + if (events[0]["id"] != widget.events!.id) { + showAlertDialog( + context, "Info evenement", "Evenement deja existant"); + } + + return; + } + } + + if (widget.imgPath.isNotEmpty) { + final params = { + 'expiration': '15552000', + 'key': dotenv.env["IMGBB_API_KEY"], + }; + print("Post Img"); + final urlPost = Uri.parse('https://api.imgbb.com/1/upload') + .replace(queryParameters: params); + File image = File(widget.imgPath); + Uint8List _bytes = await image.readAsBytes(); + String _base64String = base64.encode(_bytes); + + final req = http.MultipartRequest('POST', urlPost) + ..fields['image'] = _base64String; + + final stream = await req.send(); + final res = await http.Response.fromStream(stream); + + final status = res.statusCode; + print("code status imgbb ${status}"); + if (status != 200) { + showAlertDialog(context, "Erreur image", "Image non posté"); + return; + } + var body = json.decode(utf8.decode(res.bodyBytes)); + imgUrl = body["data"]["url"]; + } + var urlPut = + Uri.parse("${globals.api}/events/${widget.events!.id}"); + var responsePut = await http.put(urlPut, + headers: { + HttpHeaders.cookieHeader: 'access_token=${accessToken}', + HttpHeaders.acceptHeader: + 'application/json, text/plain, */*', + HttpHeaders.contentTypeHeader: 'application/json' + }, + body: jsonEncode({ + 'name': name, + 'place': place, + 'start_date': startDate, + 'end_date': endDate, + 'organizers': organizers, + 'latitude': latitude, + 'longitude': longitude, + 'description': description, + "imgUrl": imgUrl, + "tags": tags + })); + print(responsePut.statusCode); + if ((responsePut.statusCode == 200) || + (responsePut.statusCode == 201)) { + showEventDialog(context, "Evenement ${name} modifie"); + } else { + var text = ""; + switch (responsePut.statusCode) { + case 400: + { + text = "Requête mal construite"; + } + break; + case 406: + { + text = "Mot de passe incorrect"; + } + break; + case 404: + { + text = "Utilisateur inconnu"; + } + break; + case 403: + { + text = "Utilisateur desactive"; + } + break; + case 410: + { + text = "Token invalide"; + } + break; + case 500: + { + text = "Probleme interne du serveur"; + } + break; + default: + { + text = "Probleme d'authentification inconnu"; + } + break; + } + showAlertDialog(context, "Erreur serveur", text); + } + } else { + showAlertDialog( + context, "Erreur serveur", "Aucune donnée geographique"); + } + } else { + showAlertDialog(context, "Erreur serveur", "Mapbox non accessible"); + } + } catch (e) { + showAlertDialog(context, "Erreur serveur", "${e}"); + } + } else { + showAlertDialog(context, "Erreur utilisateur", "Champ vide"); + } + } else { + showAlertDialog(context, "Erreur evenement", "Evenement non futur"); + } + } + + @override + void initState() { + super.initState(); + } + + final _formKey = GlobalKey(); + String? _validateField(String? value) { + return value!.isEmpty ? 'Champ requis' : null; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + title: Text("Add or Update a event"), + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ), + body: Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + children: [ + if (widget.imgPath.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 60.0), + child: Center( + child: Container( + width: 200, + height: 150, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(100.0)), + child: Image.file(File(widget.imgPath))), + ), + ), + if (widget.imgPath.isEmpty) + Padding( + padding: const EdgeInsets.only(top: 60.0), + child: Image.network( + imgUrl, + width: MediaQuery.of(context).size.width * + 0.5, // 50% of screen width + height: MediaQuery.of(context).size.height * 0.5, + loadingBuilder: (BuildContext context, Widget child, + ImageChunkEvent? loadingProgress) { + if (loadingProgress == null) { + return child; // The image has finished loading + } + return Center( + child: CircularProgressIndicator(), + ); + }, + errorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return Center( + child: Icon(Icons.error, + size: MediaQuery.of(context).size.width * 0.1), + ); + }, + )), + Padding( + padding: EdgeInsets.symmetric(horizontal: 15), + child: ElevatedButton.icon( + onPressed: popCamera, + icon: Icon(Icons.edit, size: 16), // Edit icon + label: Text("Edit Image"), // Button text + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, // Button color + foregroundColor: Colors.white, // Text color + padding: + EdgeInsets.symmetric(horizontal: 10, vertical: 5), + ), + ), + ), + Padding( + //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), + padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputName, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Nom', + hintText: 'Modifier le nom de l\'évènement'), + ), + ), + _buildGeographicalZoneSearchField(), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: startDatepicker, + readOnly: true, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Date de debut', + hintText: 'Cliquez ici pour selectionner une date'), + onTap: () => onTapFunctionDatePicker( + context: context, position: "start")), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: startTimepicker, + readOnly: true, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Heure de debut', + hintText: 'Cliquez ici pour selectionner une heure'), + onTap: () => onTapFunctionTimePicker( + context: context, position: "start")), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: endDatepicker, + readOnly: true, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Date de fin', + hintText: 'Cliquez ici pour selectionner une date'), + onTap: () => onTapFunctionDatePicker( + context: context, position: "end")), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: endTimepicker, + readOnly: true, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Heure de fin', + hintText: 'Cliquez ici pour selectionner une heure'), + onTap: () => onTapFunctionTimePicker( + context: context, position: "end")), + ), + TextFieldTags( + textfieldTagsController: _stringTagController, + initialTags: initialTags, + textSeparators: const [' ', ','], + validator: (String tag) { + if (_stringTagController.getTags!.contains(tag)) { + return 'Tu as deja rentre ce tag'; + } + return null; + }, + inputFieldBuilder: (context, inputFieldValues) { + return Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + child: TextField( + controller: inputFieldValues.textEditingController, + focusNode: inputFieldValues.focusNode, + onChanged: inputFieldValues.onTagChanged, + onSubmitted: inputFieldValues.onTagSubmitted, + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Tags', + hintText: inputFieldValues.tags.isNotEmpty + ? '' + : "Enter tag...", + errorText: inputFieldValues.error, + prefixIcon: inputFieldValues.tags.isNotEmpty + ? SingleChildScrollView( + controller: + inputFieldValues.tagScrollController, + scrollDirection: Axis.vertical, + child: Padding( + padding: const EdgeInsets.only( + top: 8, + bottom: 8, + left: 8, + ), + child: Wrap( + runSpacing: 4.0, + spacing: 4.0, + children: inputFieldValues.tags + .map((String tag) { + return Container( + decoration: const BoxDecoration( + borderRadius: BorderRadius.all( + Radius.circular(20.0), + ), + color: Colors.blue, + ), + margin: + const EdgeInsets.symmetric( + horizontal: 5.0), + padding: + const EdgeInsets.symmetric( + horizontal: 10.0, + vertical: 5.0), + child: Row( + mainAxisAlignment: + MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + InkWell( + child: Text( + '$tag', + style: const TextStyle( + color: Colors.white), + ), + onTap: () { + //print("$tag selected"); + }, + ), + const SizedBox(width: 4.0), + InkWell( + child: const Icon( + Icons.cancel, + size: 14.0, + color: Color.fromARGB( + 255, 233, 233, 233), + ), + onTap: () { + inputFieldValues + .onTagRemoved(tag); + }, + ) + ], + ), + ); + }).toList()), + ), + ) + : null, + ), + ), + ); + }), + TextFieldTags( + textfieldTagsController: _stringOrgaController, + initialTags: initialOrga, + textSeparators: const [','], + validator: (String tag) { + if (_stringOrgaController.getTags!.contains(tag)) { + return 'Cet organisateur est déjà rentré'; + } + return null; + }, + inputFieldBuilder: (context, inputFieldValues) { + return Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + child: TextField( + controller: inputFieldValues.textEditingController, + focusNode: inputFieldValues.focusNode, + onChanged: inputFieldValues.onTagChanged, + onSubmitted: inputFieldValues.onTagSubmitted, + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Organisateurs', + hintText: inputFieldValues.tags.isNotEmpty + ? '' + : "Enter un organisateur...", + errorText: inputFieldValues.error, + prefixIcon: inputFieldValues.tags.isNotEmpty + ? SingleChildScrollView( + controller: + inputFieldValues.tagScrollController, + scrollDirection: Axis.vertical, + child: Padding( + padding: const EdgeInsets.only( + top: 8, + bottom: 8, + left: 8, + ), + child: Wrap( + runSpacing: 4.0, + spacing: 4.0, + children: inputFieldValues.tags + .map((String tag) { + return Container( + decoration: const BoxDecoration( + borderRadius: BorderRadius.all( + Radius.circular(20.0), + ), + color: Colors.blue, + ), + margin: + const EdgeInsets.symmetric( + horizontal: 5.0), + padding: + const EdgeInsets.symmetric( + horizontal: 10.0, + vertical: 5.0), + child: Row( + mainAxisAlignment: + MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + InkWell( + child: Text( + '$tag', + style: const TextStyle( + color: Colors.white), + ), + onTap: () { + //print("$tag selected"); + }, + ), + const SizedBox(width: 4.0), + InkWell( + child: const Icon( + Icons.cancel, + size: 14.0, + color: Color.fromARGB( + 255, 233, 233, 233), + ), + onTap: () { + inputFieldValues + .onTagRemoved(tag); + }, + ) + ], + ), + ); + }).toList()), + ), + ) + : null, + ), + ), + ); + }), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextField( + controller: inputDesc, + keyboardType: TextInputType.multiline, + maxLines: 10, + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Description', + hintText: 'Décrire l\'evènement'), + ), + ), + SizedBox( + height: 30, + ), + Container( + height: 50, + width: 250, + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(20)), + child: TextButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + _updateEvent(context); + } + }, + child: Text( + 'Ajouter', + style: TextStyle(color: Colors.white, fontSize: 25), + ), + ), + ) + ], + ), + ), + )); + } +} From 5419da7a982bd8eac3b3ad766536cd901123a2ad Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Fri, 3 Jan 2025 15:06:08 +0100 Subject: [PATCH 07/21] edit profile wip --- covas_mobile/lib/pages/EditProfile.dart | 339 +----------------------- 1 file changed, 2 insertions(+), 337 deletions(-) diff --git a/covas_mobile/lib/pages/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart index 593d1fe..e884d75 100644 --- a/covas_mobile/lib/pages/EditProfile.dart +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -12,10 +12,6 @@ import 'dart:io'; import 'dart:typed_data'; import '../classes/events.dart'; -import 'ItemMenu.dart'; -import 'CameraEdit.dart'; -import 'package:camera/camera.dart'; - import '../classes/alert.dart'; import '../classes/eventAdded.dart'; @@ -54,16 +50,6 @@ class _EditProfileState extends State TextEditingController inputGeo = TextEditingController(); TextEditingController startDatepicker = TextEditingController(); - TextEditingController startTimepicker = TextEditingController(); - TextEditingController endDatepicker = TextEditingController(); - TextEditingController endTimepicker = TextEditingController(); - final _stringTagController = StringTagController(); - - DateTime startDate = DateTime.now(); - DateTime endDate = DateTime.now(); - List> suggestions = []; - String geographicalZone = ""; - String imgUrl = ""; List initialTags = []; @@ -95,37 +81,6 @@ class _EditProfileState extends State } } - onTapFunctionTimePicker( - {required BuildContext context, required String position}) async { - TimeOfDay time; - - if ((startTimepicker.text.isEmpty) || (endTimepicker.text.isEmpty)) { - time = TimeOfDay.now(); - } else { - DateTime date = new DateTime.now(); - date = date.copyWith( - hour: int.parse(startTimepicker.text.split(":")[0]), - minute: int.parse(startTimepicker.text.split(":")[1])); - time = TimeOfDay.fromDateTime(date); - if (position == "end") { - date = date.copyWith( - hour: int.parse(endTimepicker.text.split(":")[0]), - minute: int.parse(endTimepicker.text.split(":")[1])); - time = TimeOfDay.fromDateTime(date); - } - } - - TimeOfDay? pickedDate = - await showTimePicker(context: context, initialTime: time); - if (pickedDate == null) return; - if (position == "start") { - startTimepicker.text = pickedDate.format(context); - } - if (position == "end") { - endTimepicker.text = pickedDate.format(context); - } - } - convertNulltoEmptyString(var check) { if (check == null) { return ""; @@ -150,13 +105,10 @@ class _EditProfileState extends State return "${year}-${month}-${day}"; } - Future _updateEvent(BuildContext context) async { + Future _updateProfile(BuildContext context) async { var name = inputName.text; var place = inputGeo.text; var description = inputDesc.text; - List tags = List.from(_stringTagController.getTags as List); - List organizers = - List.from(_stringOrgaController.getTags as List); var startDateFormat = formatDate(startDatepicker.text); //DateTime startDateCompare = DateTime.parse(startDateFormat); @@ -344,57 +296,6 @@ class _EditProfileState extends State child: SingleChildScrollView( child: Column( children: [ - if (widget.imgPath.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 60.0), - child: Center( - child: Container( - width: 200, - height: 150, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(100.0)), - child: Image.file(File(widget.imgPath))), - ), - ), - if (widget.imgPath.isEmpty) - Padding( - padding: const EdgeInsets.only(top: 60.0), - child: Image.network( - imgUrl, - width: MediaQuery.of(context).size.width * - 0.5, // 50% of screen width - height: MediaQuery.of(context).size.height * 0.5, - loadingBuilder: (BuildContext context, Widget child, - ImageChunkEvent? loadingProgress) { - if (loadingProgress == null) { - return child; // The image has finished loading - } - return Center( - child: CircularProgressIndicator(), - ); - }, - errorBuilder: (BuildContext context, Object error, - StackTrace? stackTrace) { - return Center( - child: Icon(Icons.error, - size: MediaQuery.of(context).size.width * 0.1), - ); - }, - )), - Padding( - padding: EdgeInsets.symmetric(horizontal: 15), - child: ElevatedButton.icon( - onPressed: popCamera, - icon: Icon(Icons.edit, size: 16), // Edit icon - label: Text("Edit Image"), // Button text - style: ElevatedButton.styleFrom( - backgroundColor: Colors.blue, // Button color - foregroundColor: Colors.white, // Text color - padding: - EdgeInsets.symmetric(horizontal: 10, vertical: 5), - ), - ), - ), Padding( //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), padding: EdgeInsets.symmetric(horizontal: 15), @@ -407,7 +308,6 @@ class _EditProfileState extends State hintText: 'Modifier le nom de l\'évènement'), ), ), - _buildGeographicalZoneSearchField(), Padding( padding: const EdgeInsets.only( left: 15.0, right: 15.0, top: 15, bottom: 0), @@ -423,241 +323,6 @@ class _EditProfileState extends State onTap: () => onTapFunctionDatePicker( context: context, position: "start")), ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - //padding: EdgeInsets.symmetric(horizontal: 15), - child: TextFormField( - controller: startTimepicker, - readOnly: true, - validator: (value) => _validateField(value), - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Heure de debut', - hintText: 'Cliquez ici pour selectionner une heure'), - onTap: () => onTapFunctionTimePicker( - context: context, position: "start")), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - //padding: EdgeInsets.symmetric(horizontal: 15), - child: TextFormField( - controller: endDatepicker, - readOnly: true, - validator: (value) => _validateField(value), - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Date de fin', - hintText: 'Cliquez ici pour selectionner une date'), - onTap: () => onTapFunctionDatePicker( - context: context, position: "end")), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - //padding: EdgeInsets.symmetric(horizontal: 15), - child: TextFormField( - controller: endTimepicker, - readOnly: true, - validator: (value) => _validateField(value), - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Heure de fin', - hintText: 'Cliquez ici pour selectionner une heure'), - onTap: () => onTapFunctionTimePicker( - context: context, position: "end")), - ), - TextFieldTags( - textfieldTagsController: _stringTagController, - initialTags: initialTags, - textSeparators: const [' ', ','], - validator: (String tag) { - if (_stringTagController.getTags!.contains(tag)) { - return 'Tu as deja rentre ce tag'; - } - return null; - }, - inputFieldBuilder: (context, inputFieldValues) { - return Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - child: TextField( - controller: inputFieldValues.textEditingController, - focusNode: inputFieldValues.focusNode, - onChanged: inputFieldValues.onTagChanged, - onSubmitted: inputFieldValues.onTagSubmitted, - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Tags', - hintText: inputFieldValues.tags.isNotEmpty - ? '' - : "Enter tag...", - errorText: inputFieldValues.error, - prefixIcon: inputFieldValues.tags.isNotEmpty - ? SingleChildScrollView( - controller: - inputFieldValues.tagScrollController, - scrollDirection: Axis.vertical, - child: Padding( - padding: const EdgeInsets.only( - top: 8, - bottom: 8, - left: 8, - ), - child: Wrap( - runSpacing: 4.0, - spacing: 4.0, - children: inputFieldValues.tags - .map((String tag) { - return Container( - decoration: const BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(20.0), - ), - color: Colors.blue, - ), - margin: - const EdgeInsets.symmetric( - horizontal: 5.0), - padding: - const EdgeInsets.symmetric( - horizontal: 10.0, - vertical: 5.0), - child: Row( - mainAxisAlignment: - MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - InkWell( - child: Text( - '$tag', - style: const TextStyle( - color: Colors.white), - ), - onTap: () { - //print("$tag selected"); - }, - ), - const SizedBox(width: 4.0), - InkWell( - child: const Icon( - Icons.cancel, - size: 14.0, - color: Color.fromARGB( - 255, 233, 233, 233), - ), - onTap: () { - inputFieldValues - .onTagRemoved(tag); - }, - ) - ], - ), - ); - }).toList()), - ), - ) - : null, - ), - ), - ); - }), - TextFieldTags( - textfieldTagsController: _stringOrgaController, - initialTags: initialOrga, - textSeparators: const [','], - validator: (String tag) { - if (_stringOrgaController.getTags!.contains(tag)) { - return 'Cet organisateur est déjà rentré'; - } - return null; - }, - inputFieldBuilder: (context, inputFieldValues) { - return Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - child: TextField( - controller: inputFieldValues.textEditingController, - focusNode: inputFieldValues.focusNode, - onChanged: inputFieldValues.onTagChanged, - onSubmitted: inputFieldValues.onTagSubmitted, - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Organisateurs', - hintText: inputFieldValues.tags.isNotEmpty - ? '' - : "Enter un organisateur...", - errorText: inputFieldValues.error, - prefixIcon: inputFieldValues.tags.isNotEmpty - ? SingleChildScrollView( - controller: - inputFieldValues.tagScrollController, - scrollDirection: Axis.vertical, - child: Padding( - padding: const EdgeInsets.only( - top: 8, - bottom: 8, - left: 8, - ), - child: Wrap( - runSpacing: 4.0, - spacing: 4.0, - children: inputFieldValues.tags - .map((String tag) { - return Container( - decoration: const BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(20.0), - ), - color: Colors.blue, - ), - margin: - const EdgeInsets.symmetric( - horizontal: 5.0), - padding: - const EdgeInsets.symmetric( - horizontal: 10.0, - vertical: 5.0), - child: Row( - mainAxisAlignment: - MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - InkWell( - child: Text( - '$tag', - style: const TextStyle( - color: Colors.white), - ), - onTap: () { - //print("$tag selected"); - }, - ), - const SizedBox(width: 4.0), - InkWell( - child: const Icon( - Icons.cancel, - size: 14.0, - color: Color.fromARGB( - 255, 233, 233, 233), - ), - onTap: () { - inputFieldValues - .onTagRemoved(tag); - }, - ) - ], - ), - ); - }).toList()), - ), - ) - : null, - ), - ), - ); - }), Padding( padding: const EdgeInsets.only( left: 15.0, right: 15.0, top: 15, bottom: 0), @@ -684,7 +349,7 @@ class _EditProfileState extends State child: TextButton( onPressed: () { if (_formKey.currentState!.validate()) { - _updateEvent(context); + _updateProfile(context); } }, child: Text( From 3615c1f476e82d980f738943487b28f550e3e526 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Fri, 3 Jan 2025 17:22:14 +0100 Subject: [PATCH 08/21] fix edit profile wip --- covas_mobile/lib/pages/EditProfile.dart | 99 +++++++++++++------------ 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/covas_mobile/lib/pages/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart index e884d75..17dc4df 100644 --- a/covas_mobile/lib/pages/EditProfile.dart +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -42,43 +42,25 @@ class EditProfile extends StatefulWidget { class _EditProfileState extends State with ShowAlertDialog, ShowEventDialog { + TextEditingController inputUserName = TextEditingController(); + TextEditingController inputName = TextEditingController(); - TextEditingController inputDate = TextEditingController(); - TextEditingController inputDesc = TextEditingController(); + TextEditingController inputFirstName = TextEditingController(); + TextEditingController inputEmail = TextEditingController(); + TextEditingController inputBirth = TextEditingController(); + TextEditingController inputPassword = TextEditingController(); - TextEditingController inputGeo = TextEditingController(); + onTapFunctionDatePicker({required BuildContext context}) async { + DateTime initialDate = DateTime.parse(formatDate(inputBirth.text)); - TextEditingController startDatepicker = TextEditingController(); - - List initialTags = []; - - final _stringOrgaController = StringTagController(); - List initialOrga = []; - - onTapFunctionDatePicker( - {required BuildContext context, required String position}) async { - DateTime date; - if ((startDatepicker.text.isEmpty) || (endDatepicker.text.isEmpty)) { - date = DateTime.now(); - } else { - date = DateTime.parse(formatDate(startDatepicker.text)); - if (position == "end") { - date = DateTime.parse(formatDate(endDatepicker.text)); - } - } DateTime? pickedDate = await showDatePicker( context: context, - firstDate: date, - initialDate: date, + firstDate: DateTime(1900), + initialDate: initialDate, lastDate: DateTime(2104)); if (pickedDate == null) return; - if (position == "start") { - startDatepicker.text = DateFormat("dd/MM/yyyy").format(pickedDate); - } - if (position == "end") { - endDatepicker.text = DateFormat("dd/MM/yyyy").format(pickedDate); - } + inputBirth.text = DateFormat("dd/MM/yyyy").format(pickedDate); } convertNulltoEmptyString(var check) { @@ -296,6 +278,18 @@ class _EditProfileState extends State child: SingleChildScrollView( child: Column( children: [ + Padding( + //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), + padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputUserName, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Pseudo', + hintText: 'Modifier le pseudo'), + ), + ), Padding( //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), padding: EdgeInsets.symmetric(horizontal: 15), @@ -305,7 +299,31 @@ class _EditProfileState extends State decoration: InputDecoration( border: OutlineInputBorder(), labelText: 'Nom', - hintText: 'Modifier le nom de l\'évènement'), + hintText: 'Modifier le nom'), + ), + ), + Padding( + //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), + padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputFirstName, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Prénom', + hintText: 'Modifier le prénom'), + ), + ), + Padding( + //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), + padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputName, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Email', + hintText: 'Modifier l\'adresse mail'), ), ), Padding( @@ -313,29 +331,14 @@ class _EditProfileState extends State left: 15.0, right: 15.0, top: 15, bottom: 0), //padding: EdgeInsets.symmetric(horizontal: 15), child: TextFormField( - controller: startDatepicker, + controller: inputBirth, readOnly: true, validator: (value) => _validateField(value), decoration: InputDecoration( border: OutlineInputBorder(), - labelText: 'Date de debut', + labelText: 'Date de nassance', hintText: 'Cliquez ici pour selectionner une date'), - onTap: () => onTapFunctionDatePicker( - context: context, position: "start")), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - //padding: EdgeInsets.symmetric(horizontal: 15), - child: TextField( - controller: inputDesc, - keyboardType: TextInputType.multiline, - maxLines: 10, - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Description', - hintText: 'Décrire l\'evènement'), - ), + onTap: () => onTapFunctionDatePicker(context: context)), ), SizedBox( height: 30, From f84f513e6717e603480ceb224c5b1664265ab472 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Fri, 3 Jan 2025 18:03:24 +0100 Subject: [PATCH 09/21] update function update --- covas_mobile/lib/pages/EditProfile.dart | 224 +++++++----------------- 1 file changed, 65 insertions(+), 159 deletions(-) diff --git a/covas_mobile/lib/pages/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart index 17dc4df..786acfd 100644 --- a/covas_mobile/lib/pages/EditProfile.dart +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -88,169 +88,75 @@ class _EditProfileState extends State } Future _updateProfile(BuildContext context) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + var accessToken = prefs.getString("access_token") ?? ""; + + var username = inputUserName.text; + var firstName = inputFirstName.text; var name = inputName.text; - var place = inputGeo.text; - var description = inputDesc.text; + var email = inputEmail.text; + var password = inputPassword.text; - var startDateFormat = formatDate(startDatepicker.text); - //DateTime startDateCompare = DateTime.parse(startDateFormat); - DateTime dateNow = DateTime.now(); - var endDateFormat = formatDate(endDatepicker.text); - var startDate = - "${startDateFormat}T${startTimepicker.text.replaceAll('-', ':')}"; - var endDate = "${endDateFormat}T${endTimepicker.text.replaceAll('-', ':')}"; - DateTime startDateCompare = DateTime.parse(startDate); - if (startDateCompare.isAfter(dateNow)) { - SharedPreferences prefs = await SharedPreferences.getInstance(); - var accessToken = prefs.getString("access_token") ?? ""; + var birth = DateTime.parse(formatDate(inputBirth.text)); + var urlPut = Uri.parse("${globals.api}/users/me"); - if (accessToken.isNotEmpty) { - try { - await dotenv.load(); - final ApiTokenGoogle = dotenv.env['PLACE_API_KEY'] ?? ''; - // Searchbox API for geocoding the place (No session token) - final searchboxUrl = Uri.parse( - 'https://maps.googleapis.com/maps/api/place/textsearch/json?query=${place}&key=${ApiTokenGoogle}'); - - // Perform the request - final searchboxResponse = await http.get(searchboxUrl); - - if (searchboxResponse.statusCode == 200) { - final data = json.decode(searchboxResponse.body); - print("data : ${data}"); - - if (data['results'].isNotEmpty) { - place = data['results'][0]['formatted_address']; - final coordinates = data['results'][0]['geometry']['location']; - final longitude = coordinates["lng"]; // Longitude - final latitude = coordinates["lat"]; // Latitude - var urlGet = Uri.parse( - "${globals.api}/events/search?item=${name}&date_event=${startDate}&min_lat=$latitude&max_lat=$latitude" - "&min_lon=$longitude&max_lon=$longitude"); - - var responseGet = await http.get(urlGet, headers: { - HttpHeaders.cookieHeader: 'access_token=${accessToken}' - }); - if (responseGet.statusCode == 200) { - var events = jsonDecode(utf8.decode(responseGet.bodyBytes)); - if (events.length > 0) { - if (events[0]["id"] != widget.events!.id) { - showAlertDialog( - context, "Info evenement", "Evenement deja existant"); - } - - return; - } - } - - if (widget.imgPath.isNotEmpty) { - final params = { - 'expiration': '15552000', - 'key': dotenv.env["IMGBB_API_KEY"], - }; - print("Post Img"); - final urlPost = Uri.parse('https://api.imgbb.com/1/upload') - .replace(queryParameters: params); - File image = File(widget.imgPath); - Uint8List _bytes = await image.readAsBytes(); - String _base64String = base64.encode(_bytes); - - final req = http.MultipartRequest('POST', urlPost) - ..fields['image'] = _base64String; - - final stream = await req.send(); - final res = await http.Response.fromStream(stream); - - final status = res.statusCode; - print("code status imgbb ${status}"); - if (status != 200) { - showAlertDialog(context, "Erreur image", "Image non posté"); - return; - } - var body = json.decode(utf8.decode(res.bodyBytes)); - imgUrl = body["data"]["url"]; - } - var urlPut = - Uri.parse("${globals.api}/events/${widget.events!.id}"); - var responsePut = await http.put(urlPut, - headers: { - HttpHeaders.cookieHeader: 'access_token=${accessToken}', - HttpHeaders.acceptHeader: - 'application/json, text/plain, */*', - HttpHeaders.contentTypeHeader: 'application/json' - }, - body: jsonEncode({ - 'name': name, - 'place': place, - 'start_date': startDate, - 'end_date': endDate, - 'organizers': organizers, - 'latitude': latitude, - 'longitude': longitude, - 'description': description, - "imgUrl": imgUrl, - "tags": tags - })); - print(responsePut.statusCode); - if ((responsePut.statusCode == 200) || - (responsePut.statusCode == 201)) { - showEventDialog(context, "Evenement ${name} modifie"); - } else { - var text = ""; - switch (responsePut.statusCode) { - case 400: - { - text = "Requête mal construite"; - } - break; - case 406: - { - text = "Mot de passe incorrect"; - } - break; - case 404: - { - text = "Utilisateur inconnu"; - } - break; - case 403: - { - text = "Utilisateur desactive"; - } - break; - case 410: - { - text = "Token invalide"; - } - break; - case 500: - { - text = "Probleme interne du serveur"; - } - break; - default: - { - text = "Probleme d'authentification inconnu"; - } - break; - } - showAlertDialog(context, "Erreur serveur", text); - } - } else { - showAlertDialog( - context, "Erreur serveur", "Aucune donnée geographique"); - } - } else { - showAlertDialog(context, "Erreur serveur", "Mapbox non accessible"); - } - } catch (e) { - showAlertDialog(context, "Erreur serveur", "${e}"); - } - } else { - showAlertDialog(context, "Erreur utilisateur", "Champ vide"); - } + var responsePut = await http.put(urlPut, + headers: { + HttpHeaders.cookieHeader: 'access_token=${accessToken}', + HttpHeaders.acceptHeader: 'application/json, text/plain, */*', + HttpHeaders.contentTypeHeader: 'application/json' + }, + body: jsonEncode({ + 'name': name, + 'username': username, + 'firstName': firstName, + 'password': password, + 'email': email, + 'birth': birth + })); + print(responsePut.statusCode); + if (responsePut.statusCode == 200) { + showEventDialog(context, " Votre utiliseteur modifie"); } else { - showAlertDialog(context, "Erreur evenement", "Evenement non futur"); + var text = ""; + switch (responsePut.statusCode) { + case 400: + { + text = "Requête mal construite"; + } + break; + case 406: + { + text = "Mot de passe incorrect"; + } + break; + case 404: + { + text = "Utilisateur inconnu"; + } + break; + case 403: + { + text = "Utilisateur desactive"; + } + break; + case 410: + { + text = "Token invalide"; + } + break; + case 500: + { + text = "Probleme interne du serveur"; + } + break; + default: + { + text = "Probleme d'authentification inconnu"; + } + break; + } + showAlertDialog(context, "Erreur serveur", text); } } From 82c31acf99c52c8b0255026da4080226b76e7028 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Fri, 3 Jan 2025 19:15:35 +0100 Subject: [PATCH 10/21] editprofile complete --- covas_mobile/lib/pages/EditProfile.dart | 103 +++++++++++++----------- 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/covas_mobile/lib/pages/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart index 786acfd..a5bb462 100644 --- a/covas_mobile/lib/pages/EditProfile.dart +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -1,16 +1,14 @@ -import 'package:covas_mobile/pages/CameraEdit.dart'; +import 'package:covas_mobile/classes/MyDrawer.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; import 'package:intl/intl.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:textfield_tags/textfield_tags.dart'; import 'dart:convert'; import 'dart:io'; -import 'dart:typed_data'; import '../classes/events.dart'; +import '../classes/MyDrawer.dart'; import '../classes/alert.dart'; import '../classes/eventAdded.dart'; @@ -50,6 +48,7 @@ class _EditProfileState extends State TextEditingController inputEmail = TextEditingController(); TextEditingController inputBirth = TextEditingController(); TextEditingController inputPassword = TextEditingController(); + TextEditingController inputPasswordConfirmed = TextEditingController(); onTapFunctionDatePicker({required BuildContext context}) async { DateTime initialDate = DateTime.parse(formatDate(inputBirth.text)); @@ -88,18 +87,23 @@ class _EditProfileState extends State } Future _updateProfile(BuildContext context) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - var accessToken = prefs.getString("access_token") ?? ""; - var username = inputUserName.text; var firstName = inputFirstName.text; var name = inputName.text; var email = inputEmail.text; var password = inputPassword.text; - + var confirmedPassword = inputPasswordConfirmed.text; var birth = DateTime.parse(formatDate(inputBirth.text)); + + if (password != confirmedPassword) { + showAlertDialog(context, "Erreur", "Mot de passe different"); + return; + } + var urlPut = Uri.parse("${globals.api}/users/me"); + SharedPreferences prefs = await SharedPreferences.getInstance(); + var accessToken = prefs.getString("access_token") ?? ""; var responsePut = await http.put(urlPut, headers: { HttpHeaders.cookieHeader: 'access_token=${accessToken}', @@ -116,48 +120,22 @@ class _EditProfileState extends State })); print(responsePut.statusCode); if (responsePut.statusCode == 200) { - showEventDialog(context, " Votre utiliseteur modifie"); - } else { - var text = ""; - switch (responsePut.statusCode) { - case 400: - { - text = "Requête mal construite"; - } - break; - case 406: - { - text = "Mot de passe incorrect"; - } - break; - case 404: - { - text = "Utilisateur inconnu"; - } - break; - case 403: - { - text = "Utilisateur desactive"; - } - break; - case 410: - { - text = "Token invalide"; - } - break; - case 500: - { - text = "Probleme interne du serveur"; - } - break; - default: - { - text = "Probleme d'authentification inconnu"; - } - break; - } - showAlertDialog(context, "Erreur serveur", text); + showEventDialog(context, "Votre utilisateur a été modifié"); + return; } + + final errorMessages = { + 400: "Requête mal construite", + 406: "Mot de passe incorrect", + 404: "Utilisateur inconnu", + 403: "Utilisateur désactivé", + 410: "Token invalide", + 500: "Problème interne du serveur", + }; + + final text = errorMessages[responsePut.statusCode] ?? + "Problème d'authentification inconnu"; + showAlertDialog(context, "Erreur serveur", text); } @override @@ -179,6 +157,7 @@ class _EditProfileState extends State backgroundColor: Colors.blue, foregroundColor: Colors.white, ), + drawer: MyDrawer(), body: Form( key: _formKey, child: SingleChildScrollView( @@ -196,6 +175,32 @@ class _EditProfileState extends State hintText: 'Modifier le pseudo'), ), ), + Padding( + //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), + padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputPassword, + obscureText: true, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Mot de passe', + hintText: 'Entrez le mot de passe'), + ), + ), + Padding( + //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), + padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputPasswordConfirmed, + obscureText: true, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Mot de passe', + hintText: 'Confirmez le mot de passe'), + ), + ), Padding( //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), padding: EdgeInsets.symmetric(horizontal: 15), From 39b3efca33ea6fdde25eae1a6be05a54825ed35d Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sat, 4 Jan 2025 14:25:34 +0100 Subject: [PATCH 11/21] redirect to page update profile --- covas_mobile/lib/classes/MyDrawer.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/covas_mobile/lib/classes/MyDrawer.dart b/covas_mobile/lib/classes/MyDrawer.dart index 13e2925..79c18dd 100644 --- a/covas_mobile/lib/classes/MyDrawer.dart +++ b/covas_mobile/lib/classes/MyDrawer.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; import 'dart:io'; - +import '../pages/EditProfile.dart'; import 'alert.dart'; import '../variable/globals.dart' as globals; @@ -108,7 +108,10 @@ class MyDrawer extends StatelessWidget with ShowAlertDialog { leading: Icon(Icons.account_circle), title: Text('Update profile'), onTap: () { - Navigator.pop(context); // Close the drawer + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (_) => EditProfile())); // Close the drawer }, ), ListTile( From da3659e84a6968a20907dd725ccce4e13e2db6d2 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sun, 5 Jan 2025 17:38:31 +0100 Subject: [PATCH 12/21] add edit profile --- covas_mobile/lib/pages/EditProfile.dart | 142 ++++++++++++++++-------- 1 file changed, 98 insertions(+), 44 deletions(-) diff --git a/covas_mobile/lib/pages/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart index a5bb462..79b09d3 100644 --- a/covas_mobile/lib/pages/EditProfile.dart +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -9,6 +9,7 @@ import 'dart:io'; import '../classes/events.dart'; import '../classes/MyDrawer.dart'; +import '../main.dart'; import '../classes/alert.dart'; import '../classes/eventAdded.dart'; @@ -104,43 +105,92 @@ class _EditProfileState extends State SharedPreferences prefs = await SharedPreferences.getInstance(); var accessToken = prefs.getString("access_token") ?? ""; - var responsePut = await http.put(urlPut, - headers: { - HttpHeaders.cookieHeader: 'access_token=${accessToken}', - HttpHeaders.acceptHeader: 'application/json, text/plain, */*', - HttpHeaders.contentTypeHeader: 'application/json' - }, - body: jsonEncode({ - 'name': name, - 'username': username, - 'firstName': firstName, - 'password': password, - 'email': email, - 'birth': birth - })); - print(responsePut.statusCode); - if (responsePut.statusCode == 200) { - showEventDialog(context, "Votre utilisateur a été modifié"); - return; + if (accessToken.isNotEmpty) { + var responsePut = await http.put(urlPut, + headers: { + HttpHeaders.cookieHeader: 'access_token=${accessToken}', + HttpHeaders.acceptHeader: 'application/json, text/plain, */*', + HttpHeaders.contentTypeHeader: 'application/json' + }, + body: jsonEncode({ + 'name': name, + 'username': username, + 'firstName': firstName, + 'password': password, + 'email': email, + 'birth': birth + })); + print(responsePut.statusCode); + if (responsePut.statusCode == 200) { + showEventDialog(context, "Votre utilisateur a été modifié"); + return; + } + + final errorMessages = { + 400: "Requête mal construite", + 406: "Mot de passe incorrect", + 404: "Utilisateur inconnu", + 403: "Utilisateur désactivé", + 410: "Token invalide", + 500: "Problème interne du serveur", + }; + + final text = errorMessages[responsePut.statusCode] ?? + "Problème d'authentification inconnu"; + showAlertDialog(context, "Erreur serveur", text); + } else { + Navigator.pushReplacement( + context, MaterialPageRoute(builder: (_) => LoginDemo())); } + } - final errorMessages = { - 400: "Requête mal construite", - 406: "Mot de passe incorrect", - 404: "Utilisateur inconnu", - 403: "Utilisateur désactivé", - 410: "Token invalide", - 500: "Problème interne du serveur", - }; + Future _getInfoProfile() async { + var urlGet = Uri.parse("${globals.api}/users/me"); - final text = errorMessages[responsePut.statusCode] ?? - "Problème d'authentification inconnu"; - showAlertDialog(context, "Erreur serveur", text); + SharedPreferences prefs = await SharedPreferences.getInstance(); + var accessToken = prefs.getString("access_token") ?? ""; + if (accessToken.isNotEmpty) { + var responseGet = await http.get(urlGet, headers: { + HttpHeaders.cookieHeader: 'access_token=${accessToken}', + HttpHeaders.acceptHeader: 'application/json, text/plain, */*', + HttpHeaders.contentTypeHeader: 'application/json' + }); + print(responseGet.statusCode); + if (responseGet.statusCode == 200) { + var body = json.decode(utf8.decode(responseGet.bodyBytes)); + setState(() { + inputName.text = body["name"]; + inputFirstName.text = body["firstName"]; + inputUserName.text = body["username"]; + inputEmail = body["email"]; + inputBirth.text = + DateFormat("dd/MM/yyyy").format(DateTime.parse(body["birth"])); + }); + return; + } + + final errorMessages = { + 400: "Requête mal construite", + 406: "Mot de passe incorrect", + 404: "Utilisateur inconnu", + 403: "Utilisateur désactivé", + 410: "Token invalide", + 500: "Problème interne du serveur", + }; + + final text = errorMessages[responseGet.statusCode] ?? + "Problème d'authentification inconnu"; + showAlertDialog(context, "Erreur serveur", text); + } else { + Navigator.pushReplacement( + context, MaterialPageRoute(builder: (_) => LoginDemo())); + } } @override void initState() { super.initState(); + _getInfoProfile(); } final _formKey = GlobalKey(); @@ -164,8 +214,9 @@ class _EditProfileState extends State child: Column( children: [ Padding( - //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), - padding: EdgeInsets.symmetric(horizontal: 15), + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), child: TextFormField( controller: inputUserName, validator: (value) => _validateField(value), @@ -176,12 +227,12 @@ class _EditProfileState extends State ), ), Padding( - //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), - padding: EdgeInsets.symmetric(horizontal: 15), + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), child: TextFormField( controller: inputPassword, obscureText: true, - validator: (value) => _validateField(value), decoration: InputDecoration( border: OutlineInputBorder(), labelText: 'Mot de passe', @@ -189,12 +240,12 @@ class _EditProfileState extends State ), ), Padding( - //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), - padding: EdgeInsets.symmetric(horizontal: 15), + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), child: TextFormField( controller: inputPasswordConfirmed, obscureText: true, - validator: (value) => _validateField(value), decoration: InputDecoration( border: OutlineInputBorder(), labelText: 'Mot de passe', @@ -202,8 +253,9 @@ class _EditProfileState extends State ), ), Padding( - //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), - padding: EdgeInsets.symmetric(horizontal: 15), + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), child: TextFormField( controller: inputName, validator: (value) => _validateField(value), @@ -214,8 +266,9 @@ class _EditProfileState extends State ), ), Padding( - //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), - padding: EdgeInsets.symmetric(horizontal: 15), + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), child: TextFormField( controller: inputFirstName, validator: (value) => _validateField(value), @@ -226,8 +279,9 @@ class _EditProfileState extends State ), ), Padding( - //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), - padding: EdgeInsets.symmetric(horizontal: 15), + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), child: TextFormField( controller: inputName, validator: (value) => _validateField(value), @@ -247,7 +301,7 @@ class _EditProfileState extends State validator: (value) => _validateField(value), decoration: InputDecoration( border: OutlineInputBorder(), - labelText: 'Date de nassance', + labelText: 'Date de naissance', hintText: 'Cliquez ici pour selectionner une date'), onTap: () => onTapFunctionDatePicker(context: context)), ), From 83c65be6107f98fa398a59939706fc79de489cd2 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sun, 5 Jan 2025 17:53:14 +0100 Subject: [PATCH 13/21] informations filled --- covas_mobile/lib/pages/EditProfile.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/covas_mobile/lib/pages/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart index 79b09d3..2770ad2 100644 --- a/covas_mobile/lib/pages/EditProfile.dart +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -162,7 +162,7 @@ class _EditProfileState extends State inputName.text = body["name"]; inputFirstName.text = body["firstName"]; inputUserName.text = body["username"]; - inputEmail = body["email"]; + inputEmail.text = body["email"]; inputBirth.text = DateFormat("dd/MM/yyyy").format(DateTime.parse(body["birth"])); }); @@ -248,7 +248,7 @@ class _EditProfileState extends State obscureText: true, decoration: InputDecoration( border: OutlineInputBorder(), - labelText: 'Mot de passe', + labelText: 'Confirmez le mot de passe', hintText: 'Confirmez le mot de passe'), ), ), @@ -283,7 +283,7 @@ class _EditProfileState extends State left: 15.0, right: 15.0, top: 15, bottom: 0), //padding: EdgeInsets.symmetric(horizontal: 15), child: TextFormField( - controller: inputName, + controller: inputEmail, validator: (value) => _validateField(value), decoration: InputDecoration( border: OutlineInputBorder(), From db3cb202551e05b6a54d57aa1fe6bf767dd98b3a Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sun, 5 Jan 2025 21:02:39 +0100 Subject: [PATCH 14/21] add check condition isnotempty --- covas_mobile/lib/pages/EditProfile.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/covas_mobile/lib/pages/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart index 2770ad2..2f72190 100644 --- a/covas_mobile/lib/pages/EditProfile.dart +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -96,9 +96,11 @@ class _EditProfileState extends State var confirmedPassword = inputPasswordConfirmed.text; var birth = DateTime.parse(formatDate(inputBirth.text)); - if (password != confirmedPassword) { - showAlertDialog(context, "Erreur", "Mot de passe different"); - return; + if ((password.isNotEmpty) && (confirmedPassword.isNotEmpty)) { + if (password != confirmedPassword) { + showAlertDialog(context, "Erreur", "Mot de passe different"); + return; + } } var urlPut = Uri.parse("${globals.api}/users/me"); From 30b9be35ef559aa0606d3a11c0bfc1c364d7162e Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Mon, 6 Jan 2025 23:40:17 +0100 Subject: [PATCH 15/21] edit profile ok --- covas_mobile/lib/pages/EditProfile.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/covas_mobile/lib/pages/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart index 2f72190..0754bd7 100644 --- a/covas_mobile/lib/pages/EditProfile.dart +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -120,11 +120,14 @@ class _EditProfileState extends State 'firstName': firstName, 'password': password, 'email': email, - 'birth': birth + 'roles': '', + 'birth': birth.toString() })); print(responsePut.statusCode); if (responsePut.statusCode == 200) { showEventDialog(context, "Votre utilisateur a été modifié"); + Navigator.pushReplacement( + context, MaterialPageRoute(builder: (_) => EditProfile())); return; } @@ -323,7 +326,7 @@ class _EditProfileState extends State } }, child: Text( - 'Ajouter', + 'Modifier le profil', style: TextStyle(color: Colors.white, fontSize: 25), ), ), From 0f40c3e225cc806c9b54b0fd1e71441cd8bfd666 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Thu, 9 Jan 2025 21:35:31 +0100 Subject: [PATCH 16/21] add home link --- covas_mobile/lib/classes/MyDrawer.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/covas_mobile/lib/classes/MyDrawer.dart b/covas_mobile/lib/classes/MyDrawer.dart index 79c18dd..f76fb68 100644 --- a/covas_mobile/lib/classes/MyDrawer.dart +++ b/covas_mobile/lib/classes/MyDrawer.dart @@ -3,6 +3,7 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; import 'dart:io'; import '../pages/EditProfile.dart'; +import '../pages/ListItemMenu.dart'; import 'alert.dart'; import '../variable/globals.dart' as globals; @@ -94,7 +95,10 @@ class MyDrawer extends StatelessWidget with ShowAlertDialog { leading: Icon(Icons.home), title: Text('Home'), onTap: () { - Navigator.pop(context); // Close the drawer + Navigator.pushReplacement( + context, MaterialPageRoute(builder: (_) => ListItemMenu())); + + /// Close the drawer }, ), ListTile( From 3bb85a198a97d9575efb5f1d610a0ef3cbba155c Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Thu, 9 Jan 2025 21:44:43 +0100 Subject: [PATCH 17/21] add edit settings --- covas_mobile/lib/pages/EditSettings.dart | 339 +++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 covas_mobile/lib/pages/EditSettings.dart diff --git a/covas_mobile/lib/pages/EditSettings.dart b/covas_mobile/lib/pages/EditSettings.dart new file mode 100644 index 0000000..7ad8563 --- /dev/null +++ b/covas_mobile/lib/pages/EditSettings.dart @@ -0,0 +1,339 @@ +import 'package:covas_mobile/classes/MyDrawer.dart'; +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:http/http.dart' as http; +import 'package:intl/intl.dart'; + +import 'dart:convert'; +import 'dart:io'; + +import '../classes/events.dart'; +import '../classes/MyDrawer.dart'; +import '../main.dart'; + +import '../classes/alert.dart'; +import '../classes/eventAdded.dart'; + +import '../variable/globals.dart' as globals; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + Events? events; + + @override + Widget build(BuildContext context) { + return MaterialApp( + debugShowCheckedModeBanner: false, + home: EditSettings(), + ); + } +} + +class EditSettings extends StatefulWidget { + const EditSettings({super.key}); + + @override + _EditProfileState createState() => _EditProfileState(); +} + +class _EditProfileState extends State + with ShowAlertDialog, ShowEventDialog { + TextEditingController inputUserName = TextEditingController(); + + TextEditingController inputName = TextEditingController(); + + TextEditingController inputFirstName = TextEditingController(); + TextEditingController inputEmail = TextEditingController(); + TextEditingController inputBirth = TextEditingController(); + TextEditingController inputPassword = TextEditingController(); + TextEditingController inputPasswordConfirmed = TextEditingController(); + + onTapFunctionDatePicker({required BuildContext context}) async { + DateTime initialDate = DateTime.parse(formatDate(inputBirth.text)); + + DateTime? pickedDate = await showDatePicker( + context: context, + firstDate: DateTime(1900), + initialDate: initialDate, + lastDate: DateTime(2104)); + if (pickedDate == null) return; + inputBirth.text = DateFormat("dd/MM/yyyy").format(pickedDate); + } + + convertNulltoEmptyString(var check) { + if (check == null) { + return ""; + } + return check; + } + + convertNulltoArray(List check) { + if (check == null) { + return []; + } + return check; + } + + String formatDate(String date) { + var splitedDate = date.split("/"); + + var day = splitedDate[0]; + var month = splitedDate[1]; + var year = splitedDate[2]; + + return "${year}-${month}-${day}"; + } + + Future _updateProfile(BuildContext context) async { + var username = inputUserName.text; + var firstName = inputFirstName.text; + var name = inputName.text; + var email = inputEmail.text; + var password = inputPassword.text; + var confirmedPassword = inputPasswordConfirmed.text; + var birth = DateTime.parse(formatDate(inputBirth.text)); + + if ((password.isNotEmpty) && (confirmedPassword.isNotEmpty)) { + if (password != confirmedPassword) { + showAlertDialog(context, "Erreur", "Mot de passe different"); + return; + } + } + + var urlPut = Uri.parse("${globals.api}/users/me"); + + SharedPreferences prefs = await SharedPreferences.getInstance(); + var accessToken = prefs.getString("access_token") ?? ""; + if (accessToken.isNotEmpty) { + var responsePut = await http.put(urlPut, + headers: { + HttpHeaders.cookieHeader: 'access_token=${accessToken}', + HttpHeaders.acceptHeader: 'application/json, text/plain, */*', + HttpHeaders.contentTypeHeader: 'application/json' + }, + body: jsonEncode({ + 'name': name, + 'username': username, + 'firstName': firstName, + 'password': password, + 'email': email, + 'roles': '', + 'birth': birth.toString() + })); + print(responsePut.statusCode); + if (responsePut.statusCode == 200) { + showEventDialog(context, "Votre utilisateur a été modifié"); + Navigator.pushReplacement( + context, MaterialPageRoute(builder: (_) => EditSettings())); + return; + } + + final errorMessages = { + 400: "Requête mal construite", + 406: "Mot de passe incorrect", + 404: "Utilisateur inconnu", + 403: "Utilisateur désactivé", + 410: "Token invalide", + 500: "Problème interne du serveur", + }; + + final text = errorMessages[responsePut.statusCode] ?? + "Problème d'authentification inconnu"; + showAlertDialog(context, "Erreur serveur", text); + } else { + Navigator.pushReplacement( + context, MaterialPageRoute(builder: (_) => LoginDemo())); + } + } + + Future _getInfoProfile() async { + var urlGet = Uri.parse("${globals.api}/users/me"); + + SharedPreferences prefs = await SharedPreferences.getInstance(); + var accessToken = prefs.getString("access_token") ?? ""; + if (accessToken.isNotEmpty) { + var responseGet = await http.get(urlGet, headers: { + HttpHeaders.cookieHeader: 'access_token=${accessToken}', + HttpHeaders.acceptHeader: 'application/json, text/plain, */*', + HttpHeaders.contentTypeHeader: 'application/json' + }); + print(responseGet.statusCode); + if (responseGet.statusCode == 200) { + var body = json.decode(utf8.decode(responseGet.bodyBytes)); + setState(() { + inputName.text = body["name"]; + inputFirstName.text = body["firstName"]; + inputUserName.text = body["username"]; + inputEmail.text = body["email"]; + inputBirth.text = + DateFormat("dd/MM/yyyy").format(DateTime.parse(body["birth"])); + }); + return; + } + + final errorMessages = { + 400: "Requête mal construite", + 406: "Mot de passe incorrect", + 404: "Utilisateur inconnu", + 403: "Utilisateur désactivé", + 410: "Token invalide", + 500: "Problème interne du serveur", + }; + + final text = errorMessages[responseGet.statusCode] ?? + "Problème d'authentification inconnu"; + showAlertDialog(context, "Erreur serveur", text); + } else { + Navigator.pushReplacement( + context, MaterialPageRoute(builder: (_) => LoginDemo())); + } + } + + @override + void initState() { + super.initState(); + _getInfoProfile(); + } + + final _formKey = GlobalKey(); + String? _validateField(String? value) { + return value!.isEmpty ? 'Champ requis' : null; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + title: Text("Add or Update a event"), + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ), + drawer: MyDrawer(), + body: Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputUserName, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Pseudo', + hintText: 'Modifier le pseudo'), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputPassword, + obscureText: true, + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Mot de passe', + hintText: 'Entrez le mot de passe'), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputPasswordConfirmed, + obscureText: true, + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Confirmez le mot de passe', + hintText: 'Confirmez le mot de passe'), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputName, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Nom', + hintText: 'Modifier le nom'), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputFirstName, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Prénom', + hintText: 'Modifier le prénom'), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputEmail, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Email', + hintText: 'Modifier l\'adresse mail'), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 15.0, right: 15.0, top: 15, bottom: 0), + //padding: EdgeInsets.symmetric(horizontal: 15), + child: TextFormField( + controller: inputBirth, + readOnly: true, + validator: (value) => _validateField(value), + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Date de naissance', + hintText: 'Cliquez ici pour selectionner une date'), + onTap: () => onTapFunctionDatePicker(context: context)), + ), + SizedBox( + height: 30, + ), + Container( + height: 50, + width: 250, + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(20)), + child: TextButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + _updateProfile(context); + } + }, + child: Text( + 'Modifier le profil', + style: TextStyle(color: Colors.white, fontSize: 25), + ), + ), + ) + ], + ), + ), + )); + } +} From b156cd084b0e7690aea0d3a1205a7a9ebff88838 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Thu, 9 Jan 2025 21:48:24 +0100 Subject: [PATCH 18/21] remove useless input editSettings --- covas_mobile/lib/pages/EditProfile.dart | 2 +- covas_mobile/lib/pages/EditSettings.dart | 251 +---------------------- 2 files changed, 4 insertions(+), 249 deletions(-) diff --git a/covas_mobile/lib/pages/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart index 0754bd7..02a2ded 100644 --- a/covas_mobile/lib/pages/EditProfile.dart +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -208,7 +208,7 @@ class _EditProfileState extends State return Scaffold( backgroundColor: Colors.white, appBar: AppBar( - title: Text("Add or Update a event"), + title: Text("Update profile"), backgroundColor: Colors.blue, foregroundColor: Colors.white, ), diff --git a/covas_mobile/lib/pages/EditSettings.dart b/covas_mobile/lib/pages/EditSettings.dart index 7ad8563..36be328 100644 --- a/covas_mobile/lib/pages/EditSettings.dart +++ b/covas_mobile/lib/pages/EditSettings.dart @@ -1,21 +1,16 @@ import 'package:covas_mobile/classes/MyDrawer.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:http/http.dart' as http; -import 'package:intl/intl.dart'; import 'dart:convert'; import 'dart:io'; import '../classes/events.dart'; import '../classes/MyDrawer.dart'; -import '../main.dart'; import '../classes/alert.dart'; import '../classes/eventAdded.dart'; -import '../variable/globals.dart' as globals; - void main() { runApp(MyApp()); } @@ -43,164 +38,9 @@ class _EditProfileState extends State with ShowAlertDialog, ShowEventDialog { TextEditingController inputUserName = TextEditingController(); - TextEditingController inputName = TextEditingController(); - - TextEditingController inputFirstName = TextEditingController(); - TextEditingController inputEmail = TextEditingController(); - TextEditingController inputBirth = TextEditingController(); - TextEditingController inputPassword = TextEditingController(); - TextEditingController inputPasswordConfirmed = TextEditingController(); - - onTapFunctionDatePicker({required BuildContext context}) async { - DateTime initialDate = DateTime.parse(formatDate(inputBirth.text)); - - DateTime? pickedDate = await showDatePicker( - context: context, - firstDate: DateTime(1900), - initialDate: initialDate, - lastDate: DateTime(2104)); - if (pickedDate == null) return; - inputBirth.text = DateFormat("dd/MM/yyyy").format(pickedDate); - } - - convertNulltoEmptyString(var check) { - if (check == null) { - return ""; - } - return check; - } - - convertNulltoArray(List check) { - if (check == null) { - return []; - } - return check; - } - - String formatDate(String date) { - var splitedDate = date.split("/"); - - var day = splitedDate[0]; - var month = splitedDate[1]; - var year = splitedDate[2]; - - return "${year}-${month}-${day}"; - } - - Future _updateProfile(BuildContext context) async { - var username = inputUserName.text; - var firstName = inputFirstName.text; - var name = inputName.text; - var email = inputEmail.text; - var password = inputPassword.text; - var confirmedPassword = inputPasswordConfirmed.text; - var birth = DateTime.parse(formatDate(inputBirth.text)); - - if ((password.isNotEmpty) && (confirmedPassword.isNotEmpty)) { - if (password != confirmedPassword) { - showAlertDialog(context, "Erreur", "Mot de passe different"); - return; - } - } - - var urlPut = Uri.parse("${globals.api}/users/me"); - - SharedPreferences prefs = await SharedPreferences.getInstance(); - var accessToken = prefs.getString("access_token") ?? ""; - if (accessToken.isNotEmpty) { - var responsePut = await http.put(urlPut, - headers: { - HttpHeaders.cookieHeader: 'access_token=${accessToken}', - HttpHeaders.acceptHeader: 'application/json, text/plain, */*', - HttpHeaders.contentTypeHeader: 'application/json' - }, - body: jsonEncode({ - 'name': name, - 'username': username, - 'firstName': firstName, - 'password': password, - 'email': email, - 'roles': '', - 'birth': birth.toString() - })); - print(responsePut.statusCode); - if (responsePut.statusCode == 200) { - showEventDialog(context, "Votre utilisateur a été modifié"); - Navigator.pushReplacement( - context, MaterialPageRoute(builder: (_) => EditSettings())); - return; - } - - final errorMessages = { - 400: "Requête mal construite", - 406: "Mot de passe incorrect", - 404: "Utilisateur inconnu", - 403: "Utilisateur désactivé", - 410: "Token invalide", - 500: "Problème interne du serveur", - }; - - final text = errorMessages[responsePut.statusCode] ?? - "Problème d'authentification inconnu"; - showAlertDialog(context, "Erreur serveur", text); - } else { - Navigator.pushReplacement( - context, MaterialPageRoute(builder: (_) => LoginDemo())); - } - } - - Future _getInfoProfile() async { - var urlGet = Uri.parse("${globals.api}/users/me"); - - SharedPreferences prefs = await SharedPreferences.getInstance(); - var accessToken = prefs.getString("access_token") ?? ""; - if (accessToken.isNotEmpty) { - var responseGet = await http.get(urlGet, headers: { - HttpHeaders.cookieHeader: 'access_token=${accessToken}', - HttpHeaders.acceptHeader: 'application/json, text/plain, */*', - HttpHeaders.contentTypeHeader: 'application/json' - }); - print(responseGet.statusCode); - if (responseGet.statusCode == 200) { - var body = json.decode(utf8.decode(responseGet.bodyBytes)); - setState(() { - inputName.text = body["name"]; - inputFirstName.text = body["firstName"]; - inputUserName.text = body["username"]; - inputEmail.text = body["email"]; - inputBirth.text = - DateFormat("dd/MM/yyyy").format(DateTime.parse(body["birth"])); - }); - return; - } - - final errorMessages = { - 400: "Requête mal construite", - 406: "Mot de passe incorrect", - 404: "Utilisateur inconnu", - 403: "Utilisateur désactivé", - 410: "Token invalide", - 500: "Problème interne du serveur", - }; - - final text = errorMessages[responseGet.statusCode] ?? - "Problème d'authentification inconnu"; - showAlertDialog(context, "Erreur serveur", text); - } else { - Navigator.pushReplacement( - context, MaterialPageRoute(builder: (_) => LoginDemo())); - } - } - @override void initState() { super.initState(); - _getInfoProfile(); - } - - final _formKey = GlobalKey(); - String? _validateField(String? value) { - return value!.isEmpty ? 'Champ requis' : null; } @override @@ -208,13 +48,12 @@ class _EditProfileState extends State return Scaffold( backgroundColor: Colors.white, appBar: AppBar( - title: Text("Add or Update a event"), + title: Text("Settings"), backgroundColor: Colors.blue, foregroundColor: Colors.white, ), drawer: MyDrawer(), body: Form( - key: _formKey, child: SingleChildScrollView( child: Column( children: [ @@ -224,92 +63,12 @@ class _EditProfileState extends State //padding: EdgeInsets.symmetric(horizontal: 15), child: TextFormField( controller: inputUserName, - validator: (value) => _validateField(value), decoration: InputDecoration( border: OutlineInputBorder(), labelText: 'Pseudo', hintText: 'Modifier le pseudo'), ), ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - //padding: EdgeInsets.symmetric(horizontal: 15), - child: TextFormField( - controller: inputPassword, - obscureText: true, - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Mot de passe', - hintText: 'Entrez le mot de passe'), - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - //padding: EdgeInsets.symmetric(horizontal: 15), - child: TextFormField( - controller: inputPasswordConfirmed, - obscureText: true, - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Confirmez le mot de passe', - hintText: 'Confirmez le mot de passe'), - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - //padding: EdgeInsets.symmetric(horizontal: 15), - child: TextFormField( - controller: inputName, - validator: (value) => _validateField(value), - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Nom', - hintText: 'Modifier le nom'), - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - //padding: EdgeInsets.symmetric(horizontal: 15), - child: TextFormField( - controller: inputFirstName, - validator: (value) => _validateField(value), - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Prénom', - hintText: 'Modifier le prénom'), - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - //padding: EdgeInsets.symmetric(horizontal: 15), - child: TextFormField( - controller: inputEmail, - validator: (value) => _validateField(value), - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Email', - hintText: 'Modifier l\'adresse mail'), - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - //padding: EdgeInsets.symmetric(horizontal: 15), - child: TextFormField( - controller: inputBirth, - readOnly: true, - validator: (value) => _validateField(value), - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Date de naissance', - hintText: 'Cliquez ici pour selectionner une date'), - onTap: () => onTapFunctionDatePicker(context: context)), - ), SizedBox( height: 30, ), @@ -320,13 +79,9 @@ class _EditProfileState extends State color: Colors.blue, borderRadius: BorderRadius.circular(20)), child: TextButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - _updateProfile(context); - } - }, + onPressed: () {}, child: Text( - 'Modifier le profil', + 'Mettre à jour les paramètres', style: TextStyle(color: Colors.white, fontSize: 25), ), ), From 18d5c83181f83a9ff579c587b77e31fe47b16855 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Thu, 9 Jan 2025 22:13:20 +0100 Subject: [PATCH 19/21] add kilometer --- covas_mobile/lib/pages/EditProfile.dart | 3 -- covas_mobile/lib/pages/EditSettings.dart | 57 +++++++++++++++++++----- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/covas_mobile/lib/pages/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart index 02a2ded..805c5b7 100644 --- a/covas_mobile/lib/pages/EditProfile.dart +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -7,7 +7,6 @@ import 'package:intl/intl.dart'; import 'dart:convert'; import 'dart:io'; -import '../classes/events.dart'; import '../classes/MyDrawer.dart'; import '../main.dart'; @@ -21,8 +20,6 @@ void main() { } class MyApp extends StatelessWidget { - Events? events; - @override Widget build(BuildContext context) { return MaterialApp( diff --git a/covas_mobile/lib/pages/EditSettings.dart b/covas_mobile/lib/pages/EditSettings.dart index 36be328..0f91293 100644 --- a/covas_mobile/lib/pages/EditSettings.dart +++ b/covas_mobile/lib/pages/EditSettings.dart @@ -5,7 +5,6 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; import 'dart:io'; -import '../classes/events.dart'; import '../classes/MyDrawer.dart'; import '../classes/alert.dart'; @@ -16,8 +15,6 @@ void main() { } class MyApp extends StatelessWidget { - Events? events; - @override Widget build(BuildContext context) { return MaterialApp( @@ -37,10 +34,20 @@ class EditSettings extends StatefulWidget { class _EditProfileState extends State with ShowAlertDialog, ShowEventDialog { TextEditingController inputUserName = TextEditingController(); + int? kilometer; + + Future getParameter() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + + if (kilometer != null) { + var kilometer = prefs.getInt("kilometer") ?? null; + } + } @override void initState() { super.initState(); + getParameter(); } @override @@ -59,14 +66,44 @@ class _EditProfileState extends State children: [ Padding( padding: const EdgeInsets.only( - left: 15.0, right: 15.0, top: 15, bottom: 0), - //padding: EdgeInsets.symmetric(horizontal: 15), - child: TextFormField( - controller: inputUserName, + left: 15.0, + right: 15.0, + top: 15.0, + bottom: 0.0, + ), + child: DropdownButtonFormField( decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Pseudo', - hintText: 'Modifier le pseudo'), + border: OutlineInputBorder(), + labelText: 'Define kilometer', + ), + value: + kilometer, // Set the initial selected value here, or leave as `null` if unselected. + items: [ + DropdownMenuItem( + value: 5, + child: Text('5km'), + ), + DropdownMenuItem( + value: 25, + child: Text('25km'), + ), + DropdownMenuItem( + value: 50, + child: Text('50km'), + ), + DropdownMenuItem( + value: 75, + child: Text('75km'), + ), + DropdownMenuItem( + value: 100, + child: Text('100km'), + ), + ], + onChanged: (int? newValue) { + // Handle selection + kilometer = newValue; + }, ), ), SizedBox( From 54c95a230bde89f12796de5a4fb7346ba43b35fb Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Thu, 9 Jan 2025 23:27:22 +0100 Subject: [PATCH 20/21] set kilometer in double --- covas_mobile/lib/classes/MyDrawer.dart | 6 +++++- covas_mobile/lib/pages/EditSettings.dart | 9 ++++++++- covas_mobile/lib/pages/ListItemMenu.dart | 6 ++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/covas_mobile/lib/classes/MyDrawer.dart b/covas_mobile/lib/classes/MyDrawer.dart index f76fb68..df4bc42 100644 --- a/covas_mobile/lib/classes/MyDrawer.dart +++ b/covas_mobile/lib/classes/MyDrawer.dart @@ -3,6 +3,7 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; import 'dart:io'; import '../pages/EditProfile.dart'; +import '../pages/EditSettings.dart'; import '../pages/ListItemMenu.dart'; import 'alert.dart'; @@ -105,7 +106,10 @@ class MyDrawer extends StatelessWidget with ShowAlertDialog { leading: Icon(Icons.settings), title: Text('Settings'), onTap: () { - Navigator.pop(context); // Close the drawer + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (_) => EditSettings())); // Close the drawer }, ), ListTile( diff --git a/covas_mobile/lib/pages/EditSettings.dart b/covas_mobile/lib/pages/EditSettings.dart index 0f91293..8ce10e3 100644 --- a/covas_mobile/lib/pages/EditSettings.dart +++ b/covas_mobile/lib/pages/EditSettings.dart @@ -38,9 +38,16 @@ class _EditProfileState extends State Future getParameter() async { SharedPreferences prefs = await SharedPreferences.getInstance(); + setState(() { + var kilometer = prefs.getDouble("kilometer")?.toInt() ?? null; + }); + } + Future setParameter() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); if (kilometer != null) { - var kilometer = prefs.getInt("kilometer") ?? null; + prefs.setDouble("kilometer", kilometer?.toDouble() ?? 50); + showAlertDialog(context, "Update", "Mise à jour des paramètres"); } } diff --git a/covas_mobile/lib/pages/ListItemMenu.dart b/covas_mobile/lib/pages/ListItemMenu.dart index eb99976..46dc868 100644 --- a/covas_mobile/lib/pages/ListItemMenu.dart +++ b/covas_mobile/lib/pages/ListItemMenu.dart @@ -93,9 +93,11 @@ class _MyHomePageState extends State { print('No last known position available.'); } } + SharedPreferences prefs = await SharedPreferences.getInstance(); + if (position != null) { // Calculate the boundaries - double radiusInKm = 50; + double radiusInKm = prefs.getDouble("kilometer") ?? 50; double latDistance = radiusInKm / 111.0; double lonDistance = radiusInKm / (111.0 * cos(position.latitude * pi / 180)); @@ -109,7 +111,7 @@ class _MyHomePageState extends State { "?min_lat=$minLat&max_lat=$maxLat" "&min_lon=$minLon&max_lon=$maxLon¤t_datetime=${currentDatetime.toString()}"); } - SharedPreferences prefs = await SharedPreferences.getInstance(); + var accessToken = prefs.getString("access_token") ?? ""; if (accessToken.isNotEmpty) { From 524427a29f93bfae79f856c892677e68f14a8aa4 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Fri, 10 Jan 2025 21:06:41 +0100 Subject: [PATCH 21/21] add drawer to every page --- covas_mobile/lib/pages/Camera.dart | 3 +++ covas_mobile/lib/pages/CameraEdit.dart | 3 +++ covas_mobile/lib/pages/DisplayPictureScreen.dart | 3 +++ covas_mobile/lib/pages/EditEvent.dart | 3 +++ covas_mobile/lib/pages/ItemMenu.dart | 2 ++ covas_mobile/lib/pages/ListItemByOrganizers.dart | 2 ++ covas_mobile/lib/pages/ListItemByTags.dart | 3 +++ covas_mobile/lib/pages/MapboxPages.dart | 2 ++ covas_mobile/lib/pages/UpdateEventImage.dart | 3 ++- 9 files changed, 23 insertions(+), 1 deletion(-) diff --git a/covas_mobile/lib/pages/Camera.dart b/covas_mobile/lib/pages/Camera.dart index 1187d8f..17fd22f 100644 --- a/covas_mobile/lib/pages/Camera.dart +++ b/covas_mobile/lib/pages/Camera.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'package:image_picker/image_picker.dart'; +import '../classes/MyDrawer.dart'; import 'DisplayPictureScreen.dart'; import 'package:camera/camera.dart'; @@ -93,6 +94,8 @@ class CameraState extends State { // You must wait until the controller is initialized before displaying the // camera preview. Use a FutureBuilder to display a loading spinner until the // controller has finished initializing. + drawer: MyDrawer(), + body: FutureBuilder( future: _initializeControllerFuture, builder: (context, snapshot) { diff --git a/covas_mobile/lib/pages/CameraEdit.dart b/covas_mobile/lib/pages/CameraEdit.dart index b104f3f..ad91db5 100644 --- a/covas_mobile/lib/pages/CameraEdit.dart +++ b/covas_mobile/lib/pages/CameraEdit.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; import '../classes/events.dart'; +import '../classes/MyDrawer.dart'; import 'package:image_picker/image_picker.dart'; import 'EditEvent.dart'; import 'package:camera/camera.dart'; @@ -93,6 +94,8 @@ class CameraEditState extends State { // You must wait until the controller is initialized before displaying the // camera preview. Use a FutureBuilder to display a loading spinner until the // controller has finished initializing. + drawer: MyDrawer(), + body: FutureBuilder( future: _initializeControllerFuture, builder: (context, snapshot) { diff --git a/covas_mobile/lib/pages/DisplayPictureScreen.dart b/covas_mobile/lib/pages/DisplayPictureScreen.dart index 19631a1..41c86fd 100644 --- a/covas_mobile/lib/pages/DisplayPictureScreen.dart +++ b/covas_mobile/lib/pages/DisplayPictureScreen.dart @@ -12,6 +12,7 @@ import 'UpdateEventImage.dart'; import 'dart:convert'; import '../variable/globals.dart' as globals; +import '../classes/MyDrawer.dart'; void main() { runApp(MyApp()); @@ -158,6 +159,8 @@ class DisplayPictureScreenState extends State appBar: AppBar(title: const Text('Display the Picture')), // The image is stored as a file on the device. Use the `Image.file` // constructor with the given path to display the image. + drawer: MyDrawer(), + body: Padding( padding: const EdgeInsets.all(20.0), child: Column( diff --git a/covas_mobile/lib/pages/EditEvent.dart b/covas_mobile/lib/pages/EditEvent.dart index e1b9275..8beb2e5 100644 --- a/covas_mobile/lib/pages/EditEvent.dart +++ b/covas_mobile/lib/pages/EditEvent.dart @@ -11,6 +11,7 @@ import 'dart:io'; import 'dart:typed_data'; import '../classes/events.dart'; +import '../classes/MyDrawer.dart'; import 'ItemMenu.dart'; import 'CameraEdit.dart'; @@ -465,6 +466,8 @@ class _EditEventState extends State Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, + drawer: MyDrawer(), + appBar: AppBar( title: Text("Add or Update a event"), backgroundColor: Colors.blue, diff --git a/covas_mobile/lib/pages/ItemMenu.dart b/covas_mobile/lib/pages/ItemMenu.dart index b1d4995..145353f 100644 --- a/covas_mobile/lib/pages/ItemMenu.dart +++ b/covas_mobile/lib/pages/ItemMenu.dart @@ -14,6 +14,7 @@ import 'package:intl/date_symbol_data_local.dart'; import '../variable/globals.dart' as globals; import '../classes/events.dart'; +IMPORT '../classes/MyDrawer.dart'; import 'ListItemMenu.dart'; import 'MapboxPages.dart'; @@ -215,6 +216,7 @@ class _ItemMenuState extends State with ShowAlertDialog { context, MaterialPageRoute(builder: (_) => ListItemMenu())); }, )), + drawer: MyDrawer(), body: SingleChildScrollView( child: Column( children: [ diff --git a/covas_mobile/lib/pages/ListItemByOrganizers.dart b/covas_mobile/lib/pages/ListItemByOrganizers.dart index 1500a1b..2d8b62d 100644 --- a/covas_mobile/lib/pages/ListItemByOrganizers.dart +++ b/covas_mobile/lib/pages/ListItemByOrganizers.dart @@ -10,6 +10,7 @@ import 'package:intl/intl.dart'; import 'package:intl/date_symbol_data_local.dart'; import '../variable/globals.dart' as globals; +import '../classes/MyDrawer.dart'; // app starting point void main() { @@ -63,6 +64,7 @@ class _MyHomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( + drawer: MyDrawer(), body: Center( // FutureBuilder child: FutureBuilder>( diff --git a/covas_mobile/lib/pages/ListItemByTags.dart b/covas_mobile/lib/pages/ListItemByTags.dart index 59ddcbc..353dea8 100644 --- a/covas_mobile/lib/pages/ListItemByTags.dart +++ b/covas_mobile/lib/pages/ListItemByTags.dart @@ -11,6 +11,8 @@ import 'package:intl/date_symbol_data_local.dart'; import '../variable/globals.dart' as globals; +import '../classes/MyDrawer.dart'; + // app starting point void main() { initializeDateFormatting("fr_FR", null).then((_) => (const MyApp())); @@ -62,6 +64,7 @@ class _MyHomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( + drawer: MyDrawer(), body: Center( // FutureBuilder child: FutureBuilder>( diff --git a/covas_mobile/lib/pages/MapboxPages.dart b/covas_mobile/lib/pages/MapboxPages.dart index 8f26b90..686ddfa 100644 --- a/covas_mobile/lib/pages/MapboxPages.dart +++ b/covas_mobile/lib/pages/MapboxPages.dart @@ -10,6 +10,7 @@ import 'package:geolocator/geolocator.dart'; // For getting the user's location import '../classes/alert.dart'; // Assuming this contains your error dialog code. import '../variable/globals.dart' as globals; +import '../classes/MyDrawer.dart'; void main() async { await dotenv.load(fileName: ".env"); // Load .env file @@ -375,6 +376,7 @@ class _MapboxPagesState extends State with ShowAlertDialog { ) ], ), + drawer: MyDrawer(), body: Stack( children: [ isLoading diff --git a/covas_mobile/lib/pages/UpdateEventImage.dart b/covas_mobile/lib/pages/UpdateEventImage.dart index 46270dc..f95ddb4 100644 --- a/covas_mobile/lib/pages/UpdateEventImage.dart +++ b/covas_mobile/lib/pages/UpdateEventImage.dart @@ -5,7 +5,7 @@ import 'package:uuid/uuid.dart'; import 'package:intl/intl.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:textfield_tags/textfield_tags.dart'; - +import '../classes/MyDrawer.dart'; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; @@ -420,6 +420,7 @@ class _UpdateeventImageState extends State backgroundColor: Colors.blue, foregroundColor: Colors.white, ), + drawer: MyDrawer(), body: Form( key: _formKey, child: SingleChildScrollView(