Merge pull request 'add pint bar search by item' (#21) from feature/model-input into main
Reviewed-on: #21
This commit is contained in:
commit
4b75abe6b6
@ -4,7 +4,6 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; // Import dotenv
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'ItemMenu.dart';
|
import 'ItemMenu.dart';
|
||||||
import 'SearchDelegate.dart';
|
|
||||||
import '../classes/events.dart';
|
import '../classes/events.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
@ -48,6 +47,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
TextEditingController inputGeo = TextEditingController();
|
TextEditingController inputGeo = TextEditingController();
|
||||||
TextEditingController startDatepicker = TextEditingController();
|
TextEditingController startDatepicker = TextEditingController();
|
||||||
TextEditingController endDatepicker = TextEditingController();
|
TextEditingController endDatepicker = TextEditingController();
|
||||||
|
TextEditingController inputItem = TextEditingController();
|
||||||
|
|
||||||
bool showDateFields = false; // State to toggle date fields
|
bool showDateFields = false; // State to toggle date fields
|
||||||
|
|
||||||
@ -124,40 +124,6 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
return "${year}-${month}-${day}";
|
return "${year}-${month}-${day}";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetching events from API
|
|
||||||
Future<List<Events>> getAllPosts() async {
|
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
var accessToken = prefs.getString("access_token") ?? "";
|
|
||||||
final List<Events> body = [];
|
|
||||||
if (accessToken.isNotEmpty) {
|
|
||||||
DateTime currentDateTime = DateTime.now();
|
|
||||||
var url = Uri.parse(
|
|
||||||
"${globals.api}/events?current_datetime=${currentDateTime.toString()}");
|
|
||||||
if (startDatepicker.text.isNotEmpty) {
|
|
||||||
var date = DateTime.parse(formatDate(startDatepicker.text));
|
|
||||||
url = Uri.parse("${globals.api}/events?date_event=${date.toString()}");
|
|
||||||
}
|
|
||||||
if (endDatepicker.text.isNotEmpty) {
|
|
||||||
var date = DateTime.parse(formatDate(endDatepicker.text));
|
|
||||||
url = Uri.parse("${globals.api}/events?date_event=${date.toString()}");
|
|
||||||
}
|
|
||||||
if ((startDatepicker.text.isNotEmpty) &&
|
|
||||||
(endDatepicker.text.isNotEmpty)) {
|
|
||||||
var start_date = DateTime.parse(formatDate(startDatepicker.text));
|
|
||||||
var end_date = DateTime.parse(formatDate(endDatepicker.text));
|
|
||||||
url = Uri.parse(
|
|
||||||
"${globals.api}/events?start_date=${start_date.toString()}&end_date=${end_date.toString()}");
|
|
||||||
}
|
|
||||||
final response = await http.get(url, headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
HttpHeaders.cookieHeader: "access_token=${accessToken}"
|
|
||||||
});
|
|
||||||
final List body = json.decode(utf8.decode(response.bodyBytes));
|
|
||||||
return body.map((e) => Events.fromJson(e)).toList();
|
|
||||||
}
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -237,17 +203,17 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
inputGeo.text = "${city}, ${country}";
|
inputGeo.text = "${city}, ${country}";
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
_fetchInitialData();
|
fetchPostsByLocation();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_fetchInitialData();
|
fetchPostsByLocation();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_fetchInitialData();
|
fetchPostsByLocation();
|
||||||
throw Exception('Failed to load location data');
|
throw Exception('Failed to load location data');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_fetchInitialData();
|
fetchPostsByLocation();
|
||||||
print("Error getting city and country: $e");
|
print("Error getting city and country: $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,20 +240,6 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch initial data from API or any other necessary initialization
|
|
||||||
Future<void> _fetchInitialData() async {
|
|
||||||
try {
|
|
||||||
// Optionally, you can fetch posts initially if needed.
|
|
||||||
List<Events> initialPosts = await getAllPosts();
|
|
||||||
setState(() {
|
|
||||||
// Assign to the postsFuture and update the filtered posts if needed
|
|
||||||
filteredPosts = initialPosts;
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
print('Error fetching initial data: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> searchSuggestions(String input) async {
|
Future<void> searchSuggestions(String input) async {
|
||||||
await dotenv.load(fileName: ".env"); // Load .env file
|
await dotenv.load(fileName: ".env"); // Load .env file
|
||||||
|
|
||||||
@ -319,46 +271,47 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
if (accessToken.isNotEmpty) {
|
if (accessToken.isNotEmpty) {
|
||||||
double latitude = prefs.getDouble("city_lat") ?? 0.0;
|
double latitude = prefs.getDouble("city_lat") ?? 0.0;
|
||||||
double longitude = prefs.getDouble("city_long") ?? 0.0;
|
double longitude = prefs.getDouble("city_long") ?? 0.0;
|
||||||
|
String stringParameter = "";
|
||||||
|
String dateParameter = "current_datetime";
|
||||||
|
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));
|
||||||
|
|
||||||
// Calculate the boundaries
|
double minLat = latitude - latDistance;
|
||||||
double radiusInKm = 50;
|
double maxLat = latitude + latDistance;
|
||||||
double latDistance = radiusInKm / 111.0;
|
double minLon = longitude - lonDistance;
|
||||||
double lonDistance = radiusInKm / (111.0 * cos(latitude * pi / 180));
|
double maxLon = longitude + lonDistance;
|
||||||
|
|
||||||
double minLat = latitude - latDistance;
|
stringParameter = "min_lat=$minLat&max_lat=$maxLat"
|
||||||
double maxLat = latitude + latDistance;
|
"&min_lon=$minLon&max_lon=$maxLon";
|
||||||
double minLon = longitude - lonDistance;
|
}
|
||||||
double maxLon = longitude + lonDistance;
|
|
||||||
DateTime currentDate = DateTime.now();
|
DateTime currentDate = DateTime.now();
|
||||||
print("current_date : ${currentDate}");
|
dateParameter = "¤t_datetime=${currentDate.toString()}";
|
||||||
var url = Uri.parse("${globals.api}/events/search"
|
|
||||||
"?min_lat=$minLat&max_lat=$maxLat"
|
|
||||||
"&min_lon=$minLon&max_lon=$maxLon¤t_datetime=${currentDate.toString()}");
|
|
||||||
if (startDatepicker.text.isNotEmpty) {
|
if (startDatepicker.text.isNotEmpty) {
|
||||||
var date = DateTime.parse(formatDate(startDatepicker.text));
|
var date = DateTime.parse(formatDate(startDatepicker.text));
|
||||||
url = Uri.parse("${globals.api}/events/search"
|
dateParameter = "&date_event=" + date.toString();
|
||||||
"?min_lat=$minLat&max_lat=$maxLat"
|
|
||||||
"&min_lon=$minLon&max_lon=$maxLon&date_event=" +
|
|
||||||
date.toString());
|
|
||||||
}
|
}
|
||||||
if (endDatepicker.text.isNotEmpty) {
|
if (endDatepicker.text.isNotEmpty) {
|
||||||
var date = DateTime.parse(formatDate(endDatepicker.text));
|
var date = DateTime.parse(formatDate(endDatepicker.text));
|
||||||
url = Uri.parse("${globals.api}/events/search"
|
dateParameter = "&date_event=" + date.toString();
|
||||||
"?min_lat=$minLat&max_lat=$maxLat"
|
|
||||||
"&min_lon=$minLon&max_lon=$maxLon&date_event=" +
|
|
||||||
date.toString());
|
|
||||||
}
|
}
|
||||||
if ((startDatepicker.text.isNotEmpty) &&
|
if ((startDatepicker.text.isNotEmpty) &&
|
||||||
(endDatepicker.text.isNotEmpty)) {
|
(endDatepicker.text.isNotEmpty)) {
|
||||||
var start_date = DateTime.parse(formatDate(startDatepicker.text));
|
var startDate = DateTime.parse(formatDate(startDatepicker.text));
|
||||||
var end_date = DateTime.parse(formatDate(endDatepicker.text));
|
var endDate = DateTime.parse(formatDate(endDatepicker.text));
|
||||||
url = Uri.parse("${globals.api}/events/search"
|
dateParameter = "&start_date=" +
|
||||||
"?min_lat=$minLat&max_lat=$maxLat"
|
startDate.toString() +
|
||||||
"&min_lon=$minLon&max_lon=$maxLon&start_date=" +
|
|
||||||
start_date.toString() +
|
|
||||||
"&end_date=" +
|
"&end_date=" +
|
||||||
end_date.toString());
|
endDate.toString();
|
||||||
}
|
}
|
||||||
|
stringParameter = stringParameter + dateParameter;
|
||||||
|
if (inputItem.text.isNotEmpty) {
|
||||||
|
stringParameter = stringParameter + "&item=${inputItem.text}";
|
||||||
|
}
|
||||||
|
print("stringParameter : ${stringParameter}");
|
||||||
|
var url = Uri.parse("${globals.api}/events/search?${stringParameter}");
|
||||||
final response = await http.get(url, headers: {
|
final response = await http.get(url, headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
HttpHeaders.cookieHeader: "access_token=$accessToken"
|
HttpHeaders.cookieHeader: "access_token=$accessToken"
|
||||||
@ -400,23 +353,8 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
} else if (position == "end") {
|
} else if (position == "end") {
|
||||||
endDatepicker.text = DateFormat("dd-MM-yyyy").format(pickedDate);
|
endDatepicker.text = DateFormat("dd-MM-yyyy").format(pickedDate);
|
||||||
}
|
}
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
if (startDatepicker.text.isNotEmpty) {
|
fetchPostsByLocation();
|
||||||
prefs.setString("date_event", startDatepicker.text);
|
|
||||||
prefs.setString("start_date", startDatepicker.text);
|
|
||||||
}
|
|
||||||
if (endDatepicker.text.isNotEmpty) {
|
|
||||||
prefs.setString("date_event", endDatepicker.text);
|
|
||||||
prefs.setString("end_date", endDatepicker.text);
|
|
||||||
}
|
|
||||||
if ((startDatepicker.text.isNotEmpty) && (endDatepicker.text.isNotEmpty)) {
|
|
||||||
prefs.remove("date_event");
|
|
||||||
}
|
|
||||||
if (inputGeo.text.isEmpty) {
|
|
||||||
_fetchInitialData();
|
|
||||||
} else {
|
|
||||||
fetchPostsByLocation();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Padding _buildDateField(String position) {
|
Padding _buildDateField(String position) {
|
||||||
@ -440,23 +378,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
datePicker.text = '';
|
datePicker.text = '';
|
||||||
});
|
});
|
||||||
SharedPreferences prefs =
|
fetchPostsByLocation();
|
||||||
await SharedPreferences.getInstance();
|
|
||||||
if (position == "start") {
|
|
||||||
prefs.remove("start_date");
|
|
||||||
}
|
|
||||||
if (position == "end") {
|
|
||||||
prefs.remove("end_date");
|
|
||||||
}
|
|
||||||
if ((startDatepicker.text.isEmpty) &&
|
|
||||||
(endDatepicker.text.isEmpty)) {
|
|
||||||
prefs.remove("date_event");
|
|
||||||
}
|
|
||||||
if (inputGeo.text.isNotEmpty) {
|
|
||||||
fetchPostsByLocation();
|
|
||||||
} else {
|
|
||||||
_fetchInitialData();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
hintText: hintText),
|
hintText: hintText),
|
||||||
@ -486,7 +408,9 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
inputGeo.clear(); // Clear the text field
|
inputGeo.clear(); // Clear the text field
|
||||||
geographicalZone = ''; // Reset the geographical zone state
|
geographicalZone = ''; // Reset the geographical zone state
|
||||||
suggestions.clear(); // Optionally clear suggestions
|
suggestions.clear(); // Optionally clear suggestions
|
||||||
_fetchInitialData(); // Clear the filtered posts
|
fetchPostsByLocation();
|
||||||
|
|
||||||
|
/// Clear the filtered posts
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -537,6 +461,35 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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: IconButton(
|
||||||
|
icon: const Icon(Icons.clear),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
inputItem.clear();
|
||||||
|
});
|
||||||
|
fetchPostsByLocation();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onSubmitted: (value) {
|
||||||
|
fetchPostsByLocation();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> popCamera() async {
|
Future<void> popCamera() async {
|
||||||
await availableCameras().then((value) => Navigator.push(context,
|
await availableCameras().then((value) => Navigator.push(context,
|
||||||
MaterialPageRoute(builder: (_) => Camera(camera: value.first))));
|
MaterialPageRoute(builder: (_) => Camera(camera: value.first))));
|
||||||
@ -549,21 +502,11 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
title: const Text("Item list menu"),
|
title: const Text("Item list menu"),
|
||||||
backgroundColor: Colors.blue,
|
backgroundColor: Colors.blue,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
actions: [
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.search),
|
|
||||||
onPressed: () {
|
|
||||||
showSearch(
|
|
||||||
context: context,
|
|
||||||
delegate: SearchDelegateExample(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
_buildGeographicalZoneSearchField(),
|
_buildItemZoneSearchField(),
|
||||||
|
if (showDateFields) _buildGeographicalZoneSearchField(),
|
||||||
if (showDateFields) _buildDateField("start"),
|
if (showDateFields) _buildDateField("start"),
|
||||||
if (showDateFields) _buildDateField("end"),
|
if (showDateFields) _buildDateField("end"),
|
||||||
IconButton(
|
IconButton(
|
||||||
|
@ -1,133 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
|
||||||
import 'ItemMenu.dart';
|
|
||||||
import '../classes/events.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart'; // Import dotenv
|
|
||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import '../variable/globals.dart' as globals;
|
|
||||||
|
|
||||||
class SearchDelegateExample extends SearchDelegate {
|
|
||||||
SearchDelegateExample();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Widget> buildActions(BuildContext context) {
|
|
||||||
return [
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.clear),
|
|
||||||
onPressed: () {
|
|
||||||
query = '';
|
|
||||||
},
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget buildLeading(BuildContext context) {
|
|
||||||
return IconButton(
|
|
||||||
icon: const Icon(Icons.arrow_back),
|
|
||||||
onPressed: () {
|
|
||||||
close(context, null);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget buildResults(BuildContext context) {
|
|
||||||
// Perform the search and return the results
|
|
||||||
return FutureBuilder<List<Events>>(
|
|
||||||
future: searchPosts(query),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
||||||
return const Center(child: CircularProgressIndicator());
|
|
||||||
} else if (snapshot.hasData) {
|
|
||||||
final posts = snapshot.data!;
|
|
||||||
return ListView.builder(
|
|
||||||
itemCount: posts.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final post = posts[index];
|
|
||||||
return ListTile(
|
|
||||||
title: Text(post.name!),
|
|
||||||
subtitle: Text(post.place!),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (_) => ItemMenu(title: post.id!),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return const Center(child: Text("No results found"));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget buildSuggestions(BuildContext context) {
|
|
||||||
return Container(); // Implement suggestions if needed
|
|
||||||
}
|
|
||||||
|
|
||||||
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<List<Events>> searchPosts(String query) async {
|
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
var accessToken = prefs.getString("access_token") ?? "";
|
|
||||||
var latitude = prefs.getDouble("city_lat") ?? 0.0;
|
|
||||||
var longitude = prefs.getDouble("city_long") ?? 0.0;
|
|
||||||
final List<Events> body = [];
|
|
||||||
if (accessToken.isNotEmpty) {
|
|
||||||
String parameter = "current_datetime";
|
|
||||||
String currentDate = DateTime.now().toString();
|
|
||||||
String date = prefs.getString("date_event") ?? "";
|
|
||||||
String startDate = prefs.getString("start_date") ?? "";
|
|
||||||
String endDate = prefs.getString("end_date") ?? "";
|
|
||||||
if (date.isNotEmpty) {
|
|
||||||
currentDate = DateTime.parse(formatDate(date)).toString();
|
|
||||||
parameter = "date_event";
|
|
||||||
}
|
|
||||||
String parameterString = "${parameter}=${currentDate}";
|
|
||||||
if ((startDate.isNotEmpty) && (endDate.isNotEmpty)) {
|
|
||||||
startDate = DateTime.parse(formatDate(startDate)).toString();
|
|
||||||
endDate = DateTime.parse(formatDate(endDate)).toString();
|
|
||||||
parameterString = "start_date=${startDate}&end_date=${endDate}";
|
|
||||||
}
|
|
||||||
var url = Uri.parse(
|
|
||||||
"${globals.api}/events/search?item=${query}&${parameterString}");
|
|
||||||
if ((latitude != 0.0) && (longitude != 0.0)) {
|
|
||||||
// Now use the latitude and longitude to get events within a 50km radius
|
|
||||||
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;
|
|
||||||
// Construct the search URL with the item query and latitude/longitude bounds
|
|
||||||
url = Uri.parse(
|
|
||||||
"${globals.api}/events/search?item=${query}&min_lat=${minLat}&max_lat=${maxLat}&min_lon=${minLon}&max_lon=${maxLon}&${parameterString}");
|
|
||||||
}
|
|
||||||
final response = await http.get(url, headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
HttpHeaders.cookieHeader: "access_token=${accessToken}"
|
|
||||||
});
|
|
||||||
final List body = json.decode(utf8.decode(response.bodyBytes));
|
|
||||||
return body.map((e) => Events.fromJson(e)).toList();
|
|
||||||
}
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user