diff --git a/covas_mobile/lib/classes/MyDrawer.dart b/covas_mobile/lib/classes/MyDrawer.dart new file mode 100644 index 0000000..df4bc42 --- /dev/null +++ b/covas_mobile/lib/classes/MyDrawer.dart @@ -0,0 +1,145 @@ +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 '../pages/EditSettings.dart'; +import '../pages/ListItemMenu.dart'; +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( + 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.pushReplacement( + context, MaterialPageRoute(builder: (_) => ListItemMenu())); + + /// Close the drawer + }, + ), + ListTile( + leading: Icon(Icons.settings), + title: Text('Settings'), + onTap: () { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (_) => EditSettings())); // Close the drawer + }, + ), + ListTile( + leading: Icon(Icons.account_circle), + title: Text('Update profile'), + onTap: () { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (_) => EditProfile())); // Close the drawer + }, + ), + ListTile( + leading: Icon(Icons.info), + title: Text('About'), + onTap: () { + 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/classes/alert.dart b/covas_mobile/lib/classes/alert.dart index 7ca853a..ed83093 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 { + 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/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 b50aaa2..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()); @@ -54,7 +55,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 +81,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 +120,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); @@ -157,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 3f95af3..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'; @@ -52,7 +53,7 @@ class EditEvent extends StatefulWidget { } class _EditEventState extends State - with ShowErrorDialog, ShowEventDialog { + with ShowAlertDialog, ShowEventDialog { TextEditingController inputName = TextEditingController(); TextEditingController inputDate = TextEditingController(); @@ -208,7 +209,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 +238,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 +308,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"); } } @@ -463,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/EditProfile.dart b/covas_mobile/lib/pages/EditProfile.dart new file mode 100644 index 0000000..805c5b7 --- /dev/null +++ b/covas_mobile/lib/pages/EditProfile.dart @@ -0,0 +1,336 @@ +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/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 { + @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 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: (_) => EditProfile())); + 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("Update profile"), + 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), + ), + ), + ) + ], + ), + ), + )); + } +} diff --git a/covas_mobile/lib/pages/EditSettings.dart b/covas_mobile/lib/pages/EditSettings.dart new file mode 100644 index 0000000..8ce10e3 --- /dev/null +++ b/covas_mobile/lib/pages/EditSettings.dart @@ -0,0 +1,138 @@ +import 'package:covas_mobile/classes/MyDrawer.dart'; +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'dart:convert'; +import 'dart:io'; + +import '../classes/MyDrawer.dart'; + +import '../classes/alert.dart'; +import '../classes/eventAdded.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + @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(); + int? kilometer; + + 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) { + prefs.setDouble("kilometer", kilometer?.toDouble() ?? 50); + showAlertDialog(context, "Update", "Mise à jour des paramètres"); + } + } + + @override + void initState() { + super.initState(); + getParameter(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + title: Text("Settings"), + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ), + drawer: MyDrawer(), + body: Form( + child: SingleChildScrollView( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only( + left: 15.0, + right: 15.0, + top: 15.0, + bottom: 0.0, + ), + child: DropdownButtonFormField( + decoration: InputDecoration( + 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( + height: 30, + ), + Container( + height: 50, + width: 250, + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(20)), + child: TextButton( + onPressed: () {}, + child: Text( + 'Mettre à jour les paramètres', + style: TextStyle(color: Colors.white, fontSize: 25), + ), + ), + ) + ], + ), + ), + )); + } +} diff --git a/covas_mobile/lib/pages/ItemMenu.dart b/covas_mobile/lib/pages/ItemMenu.dart index daafdc8..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'; @@ -67,7 +68,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 +170,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(() { @@ -215,6 +216,7 @@ class _ItemMenuState extends State with ShowErrorDialog { 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/ListItemMenu.dart b/covas_mobile/lib/pages/ListItemMenu.dart index da85d5c..46dc868 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'; @@ -14,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())); @@ -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) { @@ -742,6 +744,7 @@ class _MyHomePageState extends State { backgroundColor: Colors.blue, foregroundColor: Colors.white, ), + drawer: MyDrawer(), body: Column( children: [ if (showInputSearch) _buildItemZoneSearchField(), diff --git a/covas_mobile/lib/pages/MapboxPages.dart b/covas_mobile/lib/pages/MapboxPages.dart index cd9f7a7..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 @@ -42,7 +43,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 +64,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 +90,7 @@ class _MapboxPagesState extends State with ShowErrorDialog { _handleErrorResponse(responseGet.statusCode); } } else { - showErrorDialog(context, "Invalid cache."); + showAlertDialog(context, "Erreur serveur", "Invalid cache."); } } @@ -116,14 +118,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 +134,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 +175,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 +195,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 +248,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 +288,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."); } } @@ -371,6 +376,7 @@ class _MapboxPagesState extends State with ShowErrorDialog { ) ], ), + drawer: MyDrawer(), body: Stack( children: [ isLoading diff --git a/covas_mobile/lib/pages/UpdateEventImage.dart b/covas_mobile/lib/pages/UpdateEventImage.dart index 83a1c85..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'; @@ -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 { @@ -417,6 +420,7 @@ class _UpdateeventImageState extends State backgroundColor: Colors.blue, foregroundColor: Colors.white, ), + drawer: MyDrawer(), body: Form( key: _formKey, child: SingleChildScrollView(