Merge pull request 'feature/refactor' (#33) from feature/refactor into main

Reviewed-on: #33
This commit is contained in:
v4l3n71n 2025-01-21 06:57:24 +00:00
commit 280909deb9
2 changed files with 248 additions and 362 deletions

View File

@ -14,7 +14,7 @@ import 'package:intl/date_symbol_data_local.dart';
import '../variable/globals.dart' as globals; import '../variable/globals.dart' as globals;
import '../classes/events.dart'; import '../classes/events.dart';
IMPORT '../classes/MyDrawer.dart'; import '../classes/MyDrawer.dart';
import 'ListItemMenu.dart'; import 'ListItemMenu.dart';
import 'MapboxPages.dart'; import 'MapboxPages.dart';
@ -89,107 +89,61 @@ class _ItemMenuState extends State<ItemMenu> with ShowAlertDialog {
} }
Future<void> _getEventInfos() async { Future<void> _getEventInfos() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
var accessToken = prefs.getString("access_token") ?? ""; final accessToken = prefs.getString("access_token") ?? "";
String formerName = "";
String formerDate = "";
String formerMap = "";
String formerImage = "";
String formerDesc = "";
List<String> formerTags = [];
List<String> formerOrga = [];
if (accessToken.isNotEmpty) { if (accessToken.isEmpty) {
var urlGet = Uri.parse("${globals.api}/events/${widget.title}");
var responseGet = await http.get(urlGet,
headers: {HttpHeaders.cookieHeader: 'access_token=${accessToken}'});
stderr.writeln('Response Get status: ${responseGet.statusCode}');
if (responseGet.statusCode == 200) {
stderr.writeln('Username : ${responseGet.body}');
events =
Events.fromJson(jsonDecode(utf8.decode(responseGet.bodyBytes)));
id = events!.id ?? "";
formerName = events!.name ?? "";
formerMap = "${events!.place}" ?? "";
formerDesc = events!.description ?? "";
formerTags = List<String>.from(events!.tags as List);
formerOrga = List<String>.from(events!.organizers as List);
final startDate =
DateTime.parse(events!.startDate ?? DateTime.now().toString());
final date = DateFormat.yMd().format(startDate);
final time = DateFormat.Hm().format(startDate);
final endDate =
DateTime.parse(events!.endDate ?? DateTime.now().toString());
final dateE = DateFormat.yMd().format(endDate);
final timeE = DateFormat.Hm().format(endDate);
if (events!.imgUrl != null) {
formerImage = events!.imgUrl ?? "";
}
formerDate = "${date} ${time} à ${dateE} ${timeE}";
} else {
var text = "";
switch (responseGet.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 = "Vous n'avez pas l'autorisation de faire cette action";
}
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", "Cache invalide"); showAlertDialog(context, "Erreur serveur", "Cache invalide");
return;
} }
final urlGet = Uri.parse("${globals.api}/events/${widget.title}");
final responseGet = await http.get(
urlGet,
headers: {HttpHeaders.cookieHeader: 'access_token=$accessToken'},
);
stderr.writeln('Response Get status: ${responseGet.statusCode}');
if (responseGet.statusCode == 200) {
final responseBody = utf8.decode(responseGet.bodyBytes);
stderr.writeln('Username : $responseBody');
final event = Events.fromJson(jsonDecode(responseBody));
final startDate =
DateTime.parse(event.startDate ?? DateTime.now().toString());
final endDate =
DateTime.parse(event.endDate ?? DateTime.now().toString());
final formattedStartDate =
"${DateFormat.yMd().format(startDate)} ${DateFormat.Hm().format(startDate)}";
final formattedEndDate =
"${DateFormat.yMd().format(endDate)} ${DateFormat.Hm().format(endDate)}";
setState(() { setState(() {
// This call to setState tells the Flutter framework that something has eventName = event.name ?? "";
// changed in this State, which causes it to rerun the build method below eventStartDate = "$formattedStartDate à $formattedEndDate";
// so that the display can reflect the updated values. If we changed organizers = List<String>.from(event.organizers ?? []);
// _counter without calling setState(), then the build method would not be place = event.place ?? "";
// called again, and so nothing would appear to happen. imgUrl = event.imgUrl ?? "";
eventName = formerName; eventDescription = event.description ?? "";
eventStartDate = formerDate; tags = List<String>.from(event.tags ?? []);
organizers = formerOrga;
place = formerMap;
imgUrl = formerImage;
eventDescription = formerDesc;
tags = formerTags;
}); });
} else {
final errorMessages = {
400: "Requête mal construite",
406: "Mot de passe incorrect",
404: "Utilisateur inconnu",
403: "Vous n'avez pas l'autorisation de faire cette action",
410: "Token invalide",
500: "Problème interne du serveur",
};
final errorMessage = errorMessages[responseGet.statusCode] ??
"Problème d'authentification inconnu";
showAlertDialog(context, "Erreur serveur", errorMessage);
}
} }
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();

View File

@ -281,62 +281,58 @@ class _MyHomePageState extends State<ListItemMenu> {
} }
Future<Uri> getUrlForEvents() async { Future<Uri> getUrlForEvents() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
double latitude = prefs.getDouble("city_lat") ?? 0.0; final latitude = prefs.getDouble("city_lat") ?? 0.0;
double longitude = prefs.getDouble("city_long") ?? 0.0; final longitude = prefs.getDouble("city_long") ?? 0.0;
String stringParameter = "";
final radiusInKm = 50;
String endpoint = "events"; String endpoint = "events";
if ((latitude != 0.0) && (longitude != 0.0)) { String queryParameters = "";
// Calculate the boundaries
double radiusInKm = 50; if (latitude != 0.0 && longitude != 0.0) {
double latDistance = radiusInKm / 111.0; final latDistance = radiusInKm / 111.0;
double lonDistance = radiusInKm / (111.0 * cos(latitude * pi / 180)); final lonDistance = radiusInKm / (111.0 * cos(latitude * pi / 180));
final minLat = latitude - latDistance;
final maxLat = latitude + latDistance;
final minLon = longitude - lonDistance;
final maxLon = longitude + lonDistance;
double minLat = latitude - latDistance;
double maxLat = latitude + latDistance;
double minLon = longitude - lonDistance;
double maxLon = longitude + lonDistance;
endpoint = "events/search"; endpoint = "events/search";
queryParameters =
stringParameter = "min_lat=$minLat&max_lat=$maxLat" "min_lat=$minLat&max_lat=$maxLat&min_lon=$minLon&max_lon=$maxLon";
"&min_lon=$minLon&max_lon=$maxLon";
} }
DateTime currentDate = DateTime.now();
String dateParameter = "current_datetime=${currentDate.toString()}"; final currentDate = DateTime.now();
if (startDatepicker.text.isNotEmpty) { String dateParameter = "current_datetime=${currentDate.toIso8601String()}";
var date = DateTime.parse(formatDate(startDatepicker.text));
dateParameter = "date_event=" + date.toString(); if (startDatepicker.text.isNotEmpty || endDatepicker.text.isNotEmpty) {
endpoint = "events/search"; endpoint = "events/search";
if (startDatepicker.text.isNotEmpty) {
final startDate = DateTime.parse(formatDate(startDatepicker.text));
dateParameter = "start_date=${startDate.toIso8601String()}";
} }
if (endDatepicker.text.isNotEmpty) { if (endDatepicker.text.isNotEmpty) {
var date = DateTime.parse(formatDate(endDatepicker.text)); final endDate = DateTime.parse(formatDate(endDatepicker.text));
dateParameter = "date_event=" + date.toString(); dateParameter += "&end_date=${endDate.toIso8601String()}";
endpoint = "events/search";
} }
if ((startDatepicker.text.isNotEmpty) && (endDatepicker.text.isNotEmpty)) {
var startDate = DateTime.parse(formatDate(startDatepicker.text));
var endDate = DateTime.parse(formatDate(endDatepicker.text));
dateParameter = "&start_date=" +
startDate.toString() +
"&end_date=" +
endDate.toString();
endpoint = "events/search";
} }
if (inputItem.text.isNotEmpty) { if (inputItem.text.isNotEmpty) {
stringParameter = stringParameter + "&item=${inputItem.text}"; queryParameters += "&item=${inputItem.text}";
endpoint = "events/search";
} }
if (inputTags.text.isNotEmpty) { if (inputTags.text.isNotEmpty) {
stringParameter = stringParameter + "&tags=${inputTags.text}"; queryParameters += "&tags=${inputTags.text}";
endpoint = "events/search";
} }
if (stringParameter.isNotEmpty) {
stringParameter = "$stringParameter&$dateParameter"; if (queryParameters.isNotEmpty) {
queryParameters = "$queryParameters&$dateParameter";
} else { } else {
stringParameter = dateParameter; queryParameters = dateParameter;
} }
return Uri.parse("${globals.api}/${endpoint}?${stringParameter}");
return Uri.parse("${globals.api}/$endpoint?$queryParameters");
} }
Future<void> searchSuggestionsByItem(String input) async { Future<void> searchSuggestionsByItem(String input) async {
@ -480,65 +476,33 @@ class _MyHomePageState extends State<ListItemMenu> {
); );
} }
Padding _buildGeographicalZoneSearchField() { Widget _buildSearchField({
required TextEditingController controller,
required String labelText,
required Function(String) onChanged,
required Function() onClear,
required List<Map<String, dynamic>> suggestions,
required Function(Map<String, dynamic>) onSuggestionTap,
}) {
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Column( child: Column(
children: [ children: [
TextField( TextField(
controller: inputGeo, controller: controller,
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Search by geographical zone', labelText: labelText,
border: OutlineInputBorder(), border: OutlineInputBorder(),
suffixIcon: inputGeo.text.isEmpty suffixIcon: controller.text.isEmpty
? null ? null
: IconButton( : IconButton(
icon: const Icon(Icons.clear), icon: const Icon(Icons.clear),
onPressed: () async { onPressed: () => onClear(),
SharedPreferences prefs =
await SharedPreferences.getInstance();
prefs.remove("city_lat");
prefs.remove("city_long");
setState(() {
inputGeo.clear(); // Clear the text field
geographicalZone =
''; // Reset the geographical zone state
suggestionsGeo.clear();
showArrow = true;
showInputSearch =
true; // Optionally clear suggestions
/// Clear the filtered posts
showInputTag = true;
});
fetchPostsByLocation();
},
), ),
), ),
onChanged: (value) async { onChanged: onChanged,
if (value.isNotEmpty) {
setState(() {
geographicalZone = value;
searchSuggestionsGeo(value);
});
} else {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.remove("city_lat");
prefs.remove("city_long");
setState(() {
inputGeo.clear(); // Clear the text field
geographicalZone = ''; // Reset the geographical zone state
suggestionsGeo.clear(); // Optionally clear suggestions
showArrow = true;
showInputSearch = true;
showInputTag = true;
/// Clear the filted posts
});
fetchPostsByLocation();
}
},
), ),
if (suggestionsGeo.isNotEmpty) if (suggestions.isNotEmpty)
Container( Container(
height: 200, height: 200,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -547,181 +511,13 @@ class _MyHomePageState extends State<ListItemMenu> {
), ),
child: ListView.builder( child: ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: suggestionsGeo.length, itemCount: suggestions.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final suggestion = suggestions[index];
return ListTile( return ListTile(
title: Text(suggestionsGeo[index]['place_name']), title: Text(
onTap: () async { suggestion['name'] ?? suggestion['place_name'] ?? ''),
final latitude = onTap: () => onSuggestionTap(suggestion),
suggestionsGeo[index]['geometry']['coordinates'][1];
final longitude =
suggestionsGeo[index]['geometry']['coordinates'][0];
setState(() {
geographicalZone = suggestionsGeo[index]['place_name'];
inputGeo.text = geographicalZone;
suggestionsGeo.clear();
showArrow = true;
showInputSearch = true;
showInputTag = true;
});
SharedPreferences prefs =
await SharedPreferences.getInstance();
prefs.setDouble("city_lat", latitude);
prefs.setDouble("city_long", longitude);
await fetchPostsByLocation();
},
);
},
),
),
],
),
);
}
Padding _buildTagsField() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
TextField(
controller: inputTags,
decoration: InputDecoration(
labelText: 'Search by tags',
border: OutlineInputBorder(),
suffixIcon: inputTags.text.isEmpty
? null
: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
setState(() {
inputTags.clear();
});
fetchPostsByLocation();
},
),
),
onChanged: (value) {
if (value.isNotEmpty) {
setState(() {
itemTags = value;
searchSuggestionsByTag(value);
});
} else {
setState(() {
inputTags.clear();
showArrow = true;
showInputSearch = true;
showInputGeo = true; // Optionally clear suggestions
itemTags = ''; // Clear the text field
/// Clear the filted posts
});
fetchPostsByLocation();
}
}),
if (suggestionsTags.isNotEmpty)
Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue),
borderRadius: BorderRadius.circular(8),
),
child: ListView.builder(
shrinkWrap: true,
itemCount: suggestionsTags.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(suggestionsTags[index]['name']),
onTap: () async {
setState(() {
itemTags = suggestionsTags[index]['name'];
inputTags.text = itemTags;
suggestionsTags.clear();
showArrow = true;
showInputSearch = true;
showInputGeo = true;
});
await fetchPostsByLocation();
},
);
},
),
),
],
),
);
}
Padding _buildItemZoneSearchField() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
TextField(
controller: inputItem,
decoration: InputDecoration(
labelText: 'Search by item',
border: OutlineInputBorder(),
suffixIcon: inputItem.text.isEmpty
? null
: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
setState(() {
inputItem.clear();
itemName = ''; // Reset the geographical zone state
suggestionsItem.clear();
showDateFields = true;
showArrow = true;
});
fetchPostsByLocation();
},
),
),
onChanged: (value) {
if (value.isNotEmpty) {
setState(() {
itemName = value;
searchSuggestionsByItem(value);
});
} else {
setState(() {
showDateFields = true;
showArrow = true; // Optionally clear suggestions
inputItem.clear(); // Clear the text field
itemName = ''; // Reset the geographical zone state
suggestionsItem.clear();
/// Clear the filted posts
});
fetchPostsByLocation();
}
}),
if (suggestionsItem.isNotEmpty)
Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue),
borderRadius: BorderRadius.circular(8),
),
child: ListView.builder(
shrinkWrap: true,
itemCount: suggestionsItem.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(suggestionsItem[index]['name']),
onTap: () async {
setState(() {
itemName = suggestionsItem[index]['name'];
inputItem.text = itemName;
suggestionsItem.clear();
showDateFields = true;
showArrow = true;
});
await fetchPostsByLocation();
},
); );
}, },
), ),
@ -747,8 +543,89 @@ class _MyHomePageState extends State<ListItemMenu> {
drawer: MyDrawer(), drawer: MyDrawer(),
body: Column( body: Column(
children: [ children: [
if (showInputSearch) _buildItemZoneSearchField(), if (showInputSearch)
if ((showDateFields) && (showInputTag)) _buildTagsField(), _buildSearchField(
controller: inputItem,
labelText: 'Search by item',
onChanged: (value) {
if (value.isNotEmpty) {
setState(() {
itemName = value;
searchSuggestionsByItem(value);
});
} else {
setState(() {
inputItem.clear();
itemName = '';
suggestionsItem.clear();
showDateFields = true;
showArrow = true;
});
fetchPostsByLocation();
}
},
onClear: () {
setState(() {
inputItem.clear();
itemName = '';
suggestionsItem.clear();
showDateFields = true;
showArrow = true;
});
fetchPostsByLocation();
},
suggestions: suggestionsItem,
onSuggestionTap: (suggestion) async {
setState(() {
itemName = suggestion['name'];
inputItem.text = itemName;
suggestionsItem.clear();
showDateFields = true;
showArrow = true;
});
await fetchPostsByLocation();
},
),
if ((showDateFields) && (showInputTag))
_buildSearchField(
controller: inputTags,
labelText: 'Search by tags',
onChanged: (value) {
if (value.isNotEmpty) {
setState(() {
itemTags = value;
searchSuggestionsByTag(value);
});
} else {
setState(() {
inputTags.clear();
showArrow = true;
showInputSearch = true;
showInputGeo = true;
itemTags = '';
});
fetchPostsByLocation();
}
},
onClear: () {
setState(() {
inputTags.clear();
});
fetchPostsByLocation();
},
suggestions: suggestionsTags,
onSuggestionTap: (suggestion) async {
setState(() {
itemTags = suggestion['name'];
inputTags.text = itemTags;
suggestionsTags.clear();
showArrow = true;
showInputSearch = true;
showInputGeo = true;
});
await fetchPostsByLocation();
},
),
if ((showDateFields) && (showArrow)) if ((showDateFields) && (showArrow))
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -757,7 +634,62 @@ class _MyHomePageState extends State<ListItemMenu> {
Flexible(child: _buildDateField("end")) Flexible(child: _buildDateField("end"))
]), ]),
if ((showDateFields) && (showInputGeo)) if ((showDateFields) && (showInputGeo))
_buildGeographicalZoneSearchField(), _buildSearchField(
controller: inputGeo,
labelText: 'Search by geographical zone',
onChanged: (value) async {
if (value.isNotEmpty) {
setState(() {
geographicalZone = value;
searchSuggestionsGeo(value);
});
} else {
final prefs = await SharedPreferences.getInstance();
prefs.remove("city_lat");
prefs.remove("city_long");
setState(() {
inputGeo.clear();
geographicalZone = '';
suggestionsGeo.clear();
showArrow = true;
showInputSearch = true;
showInputTag = true;
});
fetchPostsByLocation();
}
},
onClear: () async {
final prefs = await SharedPreferences.getInstance();
prefs.remove("city_lat");
prefs.remove("city_long");
setState(() {
inputGeo.clear();
geographicalZone = '';
suggestionsGeo.clear();
showArrow = true;
showInputSearch = true;
showInputTag = true;
});
fetchPostsByLocation();
},
suggestions: suggestionsGeo,
onSuggestionTap: (suggestion) async {
final latitude = suggestion['geometry']['coordinates'][1];
final longitude = suggestion['geometry']['coordinates'][0];
setState(() {
geographicalZone = suggestion['place_name'];
inputGeo.text = geographicalZone;
suggestionsGeo.clear();
showArrow = true;
showInputSearch = true;
showInputTag = true;
});
final prefs = await SharedPreferences.getInstance();
prefs.setDouble("city_lat", latitude);
prefs.setDouble("city_long", longitude);
await fetchPostsByLocation();
},
),
if (showArrow) if (showArrow)
IconButton( IconButton(
onPressed: () { onPressed: () {