From edd2cd15811dd2e24d68bc6c0adb885c86ae733f Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Thu, 28 Nov 2024 23:44:11 +0100 Subject: [PATCH 1/3] add suggesstion item wip --- covas_mobile/lib/pages/ListItemMenu.dart | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/covas_mobile/lib/pages/ListItemMenu.dart b/covas_mobile/lib/pages/ListItemMenu.dart index 0e17203..6671630 100644 --- a/covas_mobile/lib/pages/ListItemMenu.dart +++ b/covas_mobile/lib/pages/ListItemMenu.dart @@ -44,6 +44,7 @@ class _MyHomePageState extends State { String geographicalZone = ''; String query = ''; List> suggestions = []; + List> suggestionsItem = []; TextEditingController inputGeo = TextEditingController(); TextEditingController startDatepicker = TextEditingController(); TextEditingController endDatepicker = TextEditingController(); @@ -267,6 +268,32 @@ class _MyHomePageState extends State { } } + Future searchSuggestionsByItem(String input) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + var accessToken = prefs.getString("access_token") ?? ""; + + if (accessToken.isNotEmpty) { + final url = + 'https://api.mapbox.com/geocoding/v5/mapbox.places/${input}.json?access_token=${mapboxAccessToken}&proximity=ip'; + final response = await http.get(Uri.parse(url)); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + setState(() { + suggestions = (data['features'] as List) + .map((feature) => { + 'place_name': feature['place_name'], + 'geometry': feature[ + 'geometry'], // Include geometry for latitude/longitude + }) + .toList(); + }); + } else { + throw Exception('Failed to load suggestions'); + } + } + } + Future fetchPostsByLocation() async { SharedPreferences prefs = await SharedPreferences.getInstance(); var accessToken = prefs.getString("access_token") ?? ""; From 559b35c7c21b635477e00881200ec305cf476023 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sat, 30 Nov 2024 00:39:57 +0100 Subject: [PATCH 2/3] add suggestion for search item --- covas_mobile/lib/pages/ListItemMenu.dart | 193 ++++++++++++++--------- 1 file changed, 117 insertions(+), 76 deletions(-) diff --git a/covas_mobile/lib/pages/ListItemMenu.dart b/covas_mobile/lib/pages/ListItemMenu.dart index 6671630..244b6d9 100644 --- a/covas_mobile/lib/pages/ListItemMenu.dart +++ b/covas_mobile/lib/pages/ListItemMenu.dart @@ -42,6 +42,7 @@ class _MyHomePageState extends State { Future> postsFuture = getPosts(); List filteredPosts = []; String geographicalZone = ''; + String itemName = ''; String query = ''; List> suggestions = []; List> suggestionsItem = []; @@ -268,28 +269,80 @@ class _MyHomePageState extends State { } } + Future getUrlForEvents() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + double latitude = prefs.getDouble("city_lat") ?? 0.0; + double longitude = prefs.getDouble("city_long") ?? 0.0; + String stringParameter = ""; + String endpoint = "events"; + if ((latitude != 0.0) && (longitude != 0.0)) { + // Calculate the boundaries + double radiusInKm = 50; + double latDistance = radiusInKm / 111.0; + double lonDistance = radiusInKm / (111.0 * cos(latitude * pi / 180)); + + double minLat = latitude - latDistance; + double maxLat = latitude + latDistance; + double minLon = longitude - lonDistance; + double maxLon = longitude + lonDistance; + endpoint = "events/search"; + + stringParameter = "min_lat=$minLat&max_lat=$maxLat" + "&min_lon=$minLon&max_lon=$maxLon"; + } + DateTime currentDate = DateTime.now(); + String dateParameter = "current_datetime=${currentDate.toString()}"; + if (startDatepicker.text.isNotEmpty) { + var date = DateTime.parse(formatDate(startDatepicker.text)); + dateParameter = "date_event=" + date.toString(); + endpoint = "events/search"; + } + if (endDatepicker.text.isNotEmpty) { + var date = DateTime.parse(formatDate(endDatepicker.text)); + dateParameter = "date_event=" + date.toString(); + 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) { + stringParameter = stringParameter + "&item=${inputItem.text}"; + endpoint = "events/search"; + } + if (stringParameter.isNotEmpty) { + stringParameter = "$stringParameter&$dateParameter"; + } else { + stringParameter = dateParameter; + } + return Uri.parse("${globals.api}/${endpoint}?${stringParameter}"); + } + Future searchSuggestionsByItem(String input) async { SharedPreferences prefs = await SharedPreferences.getInstance(); var accessToken = prefs.getString("access_token") ?? ""; if (accessToken.isNotEmpty) { - final url = - 'https://api.mapbox.com/geocoding/v5/mapbox.places/${input}.json?access_token=${mapboxAccessToken}&proximity=ip'; - final response = await http.get(Uri.parse(url)); + var url = await getUrlForEvents(); + final response = await http.get(url, headers: { + "Content-Type": "application/json", + HttpHeaders.cookieHeader: "access_token=$accessToken" + }); if (response.statusCode == 200) { final data = json.decode(response.body); setState(() { - suggestions = (data['features'] as List) - .map((feature) => { - 'place_name': feature['place_name'], - 'geometry': feature[ - 'geometry'], // Include geometry for latitude/longitude - }) + suggestionsItem = (data as List) + .map((feature) => {'name': feature['name']}) .toList(); }); - } else { - throw Exception('Failed to load suggestions'); + print("status code : ${response.statusCode}"); } } } @@ -299,59 +352,7 @@ class _MyHomePageState extends State { var accessToken = prefs.getString("access_token") ?? ""; if (accessToken.isNotEmpty) { - double latitude = prefs.getDouble("city_lat") ?? 0.0; - double longitude = prefs.getDouble("city_long") ?? 0.0; - String stringParameter = ""; - String endpoint = "events"; - if ((latitude != 0.0) && (longitude != 0.0)) { - // Calculate the boundaries - double radiusInKm = 50; - double latDistance = radiusInKm / 111.0; - double lonDistance = radiusInKm / (111.0 * cos(latitude * pi / 180)); - - double minLat = latitude - latDistance; - double maxLat = latitude + latDistance; - double minLon = longitude - lonDistance; - double maxLon = longitude + lonDistance; - endpoint = "events/search"; - - stringParameter = "min_lat=$minLat&max_lat=$maxLat" - "&min_lon=$minLon&max_lon=$maxLon"; - } - DateTime currentDate = DateTime.now(); - String dateParameter = "current_datetime=${currentDate.toString()}"; - if (startDatepicker.text.isNotEmpty) { - var date = DateTime.parse(formatDate(startDatepicker.text)); - dateParameter = "date_event=" + date.toString(); - endpoint = "events/search"; - } - if (endDatepicker.text.isNotEmpty) { - var date = DateTime.parse(formatDate(endDatepicker.text)); - dateParameter = "date_event=" + date.toString(); - 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) { - stringParameter = stringParameter + "&item=${inputItem.text}"; - endpoint = "events/search"; - } - if (stringParameter.isNotEmpty) { - stringParameter = "$stringParameter&$dateParameter"; - } else { - stringParameter = dateParameter; - } - print("stringParameter : ${stringParameter}"); - var url = Uri.parse("${globals.api}/${endpoint}?${stringParameter}"); + var url = await getUrlForEvents(); final response = await http.get(url, headers: { "Content-Type": "application/json", HttpHeaders.cookieHeader: "access_token=$accessToken" @@ -523,24 +524,64 @@ class _MyHomePageState extends State { child: Column( children: [ TextField( - controller: inputItem, - decoration: InputDecoration( - labelText: 'Search by item', - border: OutlineInputBorder(), - suffixIcon: IconButton( - icon: const Icon(Icons.clear), - onPressed: () { + controller: inputItem, + decoration: InputDecoration( + labelText: 'Search by item', + border: OutlineInputBorder(), + suffixIcon: IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + setState(() { + inputItem.clear(); + itemName = ''; // Reset the geographical zone state + suggestionsItem.clear(); // + }); + fetchPostsByLocation(); + }, + ), + ), + onChanged: (value) { + if (value.isNotEmpty) { setState(() { - inputItem.clear(); + itemName = value; + searchSuggestionsByItem(value); + }); + } else { + setState(() { + inputItem.clear(); // Clear the text field + itemName = ''; // Reset the geographical zone state + suggestionsItem.clear(); // Optionally clear suggestions + + /// 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(); + }); + await fetchPostsByLocation(); + }, + ); }, ), ), - onSubmitted: (value) { - fetchPostsByLocation(); - }, - ), ], ), ); From 0977389695f21a8b0aa4f65ec509f133e65a47a3 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sat, 30 Nov 2024 18:45:41 +0100 Subject: [PATCH 3/3] suggestion search by item --- covas_mobile/lib/pages/ListItemMenu.dart | 25 +++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/covas_mobile/lib/pages/ListItemMenu.dart b/covas_mobile/lib/pages/ListItemMenu.dart index 244b6d9..1391715 100644 --- a/covas_mobile/lib/pages/ListItemMenu.dart +++ b/covas_mobile/lib/pages/ListItemMenu.dart @@ -53,6 +53,7 @@ class _MyHomePageState extends State { bool showDateFields = false; // State to toggle date fields bool showArrow = true; + bool showInputSearch = true; // Fetching events from API static Future> getPosts() async { PermissionStatus status = await Permission.location.status; @@ -262,6 +263,7 @@ class _MyHomePageState extends State { .toList(); if (suggestions.isNotEmpty) { showArrow = false; + showInputSearch = false; } }); } else { @@ -336,11 +338,15 @@ class _MyHomePageState extends State { }); if (response.statusCode == 200) { - final data = json.decode(response.body); + final data = json.decode(utf8.decode(response.bodyBytes)); setState(() { suggestionsItem = (data as List) .map((feature) => {'name': feature['name']}) .toList(); + if (suggestionsItem.isNotEmpty) { + showDateFields = false; + showArrow = false; + } }); print("status code : ${response.statusCode}"); } @@ -449,7 +455,8 @@ class _MyHomePageState extends State { inputGeo.clear(); // Clear the text field geographicalZone = ''; // Reset the geographical zone state suggestions.clear(); - showArrow = true; // Optionally clear suggestions + showArrow = true; + showInputSearch = true; // Optionally clear suggestions /// Clear the filtered posts }); fetchPostsByLocation(); @@ -471,6 +478,7 @@ class _MyHomePageState extends State { geographicalZone = ''; // Reset the geographical zone state suggestions.clear(); // Optionally clear suggestions showArrow = true; + showInputSearch = true; /// Clear the filted posts }); @@ -502,6 +510,7 @@ class _MyHomePageState extends State { inputGeo.text = geographicalZone; suggestions.clear(); showArrow = true; + showInputSearch = true; }); SharedPreferences prefs = await SharedPreferences.getInstance(); @@ -534,7 +543,9 @@ class _MyHomePageState extends State { setState(() { inputItem.clear(); itemName = ''; // Reset the geographical zone state - suggestionsItem.clear(); // + suggestionsItem.clear(); + showDateFields = true; + showArrow = true; }); fetchPostsByLocation(); }, @@ -550,7 +561,9 @@ class _MyHomePageState extends State { setState(() { inputItem.clear(); // Clear the text field itemName = ''; // Reset the geographical zone state - suggestionsItem.clear(); // Optionally clear suggestions + suggestionsItem.clear(); + showDateFields = true; + showArrow = true; // Optionally clear suggestions /// Clear the filted posts }); @@ -575,6 +588,8 @@ class _MyHomePageState extends State { itemName = suggestionsItem[index]['name']; inputItem.text = itemName; suggestionsItem.clear(); + showDateFields = true; + showArrow = true; }); await fetchPostsByLocation(); }, @@ -602,7 +617,7 @@ class _MyHomePageState extends State { ), body: Column( children: [ - if (showArrow) _buildItemZoneSearchField(), + if (showInputSearch) _buildItemZoneSearchField(), if ((showDateFields) && (showArrow)) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween,