Merge pull request 'feature/input-date' (#19) from feature/input-date into main
Reviewed-on: #19
This commit is contained in:
commit
6b3bf5004c
@ -1,4 +1,3 @@
|
||||
import 'package:covas_mobile/classes/alert.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart'; // Import dotenv
|
||||
@ -47,6 +46,8 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
String query = '';
|
||||
List<Map<String, dynamic>> suggestions = [];
|
||||
TextEditingController inputGeo = TextEditingController();
|
||||
TextEditingController startDatepicker = TextEditingController();
|
||||
TextEditingController endDatepicker = TextEditingController();
|
||||
|
||||
// Fetching events from API
|
||||
static Future<List<Events>> getPosts() async {
|
||||
@ -112,6 +113,15 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
return body;
|
||||
}
|
||||
|
||||
String formatDate(String date) {
|
||||
var splitedDate = date.split("-");
|
||||
var day = splitedDate[0];
|
||||
var month = splitedDate[1];
|
||||
var year = splitedDate[2];
|
||||
|
||||
return "${year}-${month}-${day}";
|
||||
}
|
||||
|
||||
// Fetching events from API
|
||||
Future<List<Events>> getAllPosts() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
@ -121,6 +131,21 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
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}"
|
||||
@ -146,19 +171,32 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
print("Location permission granted");
|
||||
|
||||
// Get the current position with high accuracy
|
||||
LocationSettings locationSettings = LocationSettings(
|
||||
accuracy: LocationAccuracy.high,
|
||||
distanceFilter:
|
||||
10, // Optional: Minimum distance (in meters) to trigger location update
|
||||
);
|
||||
|
||||
Position position = await Geolocator.getCurrentPosition(
|
||||
locationSettings: locationSettings,
|
||||
);
|
||||
const LocationSettings locationSettings = LocationSettings(
|
||||
accuracy: LocationAccuracy.medium, timeLimit: Duration(seconds: 5));
|
||||
Position? position;
|
||||
try {
|
||||
position = await Geolocator.getCurrentPosition(
|
||||
locationSettings: locationSettings);
|
||||
} on LocationServiceDisabledException {
|
||||
// Handle location services disabled
|
||||
print('Location services are disabled.');
|
||||
position = await Geolocator.getLastKnownPosition();
|
||||
if (position == null) {
|
||||
print('No last known position available.');
|
||||
}
|
||||
} catch (e) {
|
||||
// Handle other errors
|
||||
print('Failed to get location: $e');
|
||||
position = await Geolocator.getLastKnownPosition();
|
||||
if (position == null) {
|
||||
print('No last known position available.');
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse geocode: Get city and country from latitude and longitude using Mapbox Search API
|
||||
final place =
|
||||
await _getCityAndCountry(position.latitude, position.longitude);
|
||||
if (position != null) {
|
||||
_getCityAndCountry(position!.latitude, position!.longitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,7 +227,10 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
String country = _getCountryFromFeatures(features);
|
||||
print("city : ${city} ${country}");
|
||||
if (city.isNotEmpty && country.isNotEmpty) {
|
||||
fetchPostsByLocation(latitude, longitude);
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
prefs.setDouble("city_lat", latitude);
|
||||
prefs.setDouble("city_long", longitude);
|
||||
fetchPostsByLocation();
|
||||
setState(() {
|
||||
inputGeo.text = "${city}, ${country}";
|
||||
});
|
||||
@ -269,11 +310,14 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fetchPostsByLocation(double latitude, double longitude) async {
|
||||
Future<void> fetchPostsByLocation() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
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;
|
||||
|
||||
// Calculate the boundaries
|
||||
double radiusInKm = 50;
|
||||
double latDistance = radiusInKm / 111.0;
|
||||
@ -284,10 +328,35 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
double minLon = longitude - lonDistance;
|
||||
double maxLon = longitude + lonDistance;
|
||||
DateTime currentDate = DateTime.now();
|
||||
print("current_date : ${currentDate}");
|
||||
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) {
|
||||
var date = DateTime.parse(formatDate(startDatepicker.text));
|
||||
url = Uri.parse("${globals.api}/events/search"
|
||||
"?min_lat=$minLat&max_lat=$maxLat"
|
||||
"&min_lon=$minLon&max_lon=$maxLon&date_event=" +
|
||||
date.toString());
|
||||
}
|
||||
if (endDatepicker.text.isNotEmpty) {
|
||||
var date = DateTime.parse(formatDate(endDatepicker.text));
|
||||
url = Uri.parse("${globals.api}/events/search"
|
||||
"?min_lat=$minLat&max_lat=$maxLat"
|
||||
"&min_lon=$minLon&max_lon=$maxLon&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/search"
|
||||
"?min_lat=$minLat&max_lat=$maxLat"
|
||||
"&min_lon=$minLon&max_lon=$maxLon&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"
|
||||
@ -314,6 +383,86 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
}
|
||||
}
|
||||
|
||||
onTapFunctionDatePicker(
|
||||
{required BuildContext context, String position = ""}) async {
|
||||
DateTime dateEvent = DateTime.now();
|
||||
if (startDatepicker.text.isNotEmpty) {
|
||||
dateEvent = DateTime.parse(formatDate(startDatepicker.text));
|
||||
}
|
||||
|
||||
DateTime? pickedDate = await showDatePicker(
|
||||
context: context, firstDate: dateEvent, lastDate: DateTime(2104));
|
||||
if (pickedDate == null) return;
|
||||
if (position == "start") {
|
||||
startDatepicker.text = DateFormat("dd-MM-yyyy").format(pickedDate);
|
||||
} else if (position == "end") {
|
||||
endDatepicker.text = DateFormat("dd-MM-yyyy").format(pickedDate);
|
||||
}
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
if (startDatepicker.text.isNotEmpty) {
|
||||
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) {
|
||||
TextEditingController datePicker = startDatepicker;
|
||||
String hintText = "Date de début";
|
||||
if (position == "end") {
|
||||
datePicker = endDatepicker;
|
||||
hintText = "Date de fin";
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
//padding: EdgeInsets.symmetric(horizontal: 15),
|
||||
child: TextFormField(
|
||||
controller: datePicker,
|
||||
readOnly: true,
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
datePicker.text = '';
|
||||
});
|
||||
SharedPreferences prefs =
|
||||
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),
|
||||
onTap: () =>
|
||||
onTapFunctionDatePicker(context: context, position: position)),
|
||||
);
|
||||
}
|
||||
|
||||
Padding _buildGeographicalZoneSearchField() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
@ -326,7 +475,11 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
border: OutlineInputBorder(),
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: () {
|
||||
onPressed: () async {
|
||||
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
|
||||
@ -367,8 +520,11 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
inputGeo.text = geographicalZone;
|
||||
suggestions.clear();
|
||||
});
|
||||
|
||||
await fetchPostsByLocation(latitude, longitude);
|
||||
SharedPreferences prefs =
|
||||
await SharedPreferences.getInstance();
|
||||
prefs.setDouble("city_lat", latitude);
|
||||
prefs.setDouble("city_long", longitude);
|
||||
await fetchPostsByLocation();
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -397,7 +553,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
onPressed: () {
|
||||
showSearch(
|
||||
context: context,
|
||||
delegate: SearchDelegateExample(geoQuery: inputGeo.text),
|
||||
delegate: SearchDelegateExample(),
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -406,6 +562,8 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
body: Column(
|
||||
children: [
|
||||
_buildGeographicalZoneSearchField(),
|
||||
_buildDateField("start"),
|
||||
_buildDateField("end"),
|
||||
Expanded(
|
||||
child: FutureBuilder<List<Events>>(
|
||||
future: postsFuture,
|
||||
@ -455,7 +613,6 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
final startDate = DateTime.parse(post.startDate!);
|
||||
final date = DateFormat.yMd().format(startDate);
|
||||
final time = DateFormat.Hm().format(startDate);
|
||||
|
||||
return ListTile(
|
||||
title: Text('${post.name!}'),
|
||||
subtitle: Text('${post.place!}\n${date} ${time}'),
|
||||
|
@ -11,11 +11,7 @@ import 'dart:math';
|
||||
import '../variable/globals.dart' as globals;
|
||||
|
||||
class SearchDelegateExample extends SearchDelegate {
|
||||
final String geoQuery;
|
||||
|
||||
SearchDelegateExample({
|
||||
required this.geoQuery,
|
||||
});
|
||||
SearchDelegateExample();
|
||||
|
||||
@override
|
||||
List<Widget> buildActions(BuildContext context) {
|
||||
@ -43,7 +39,7 @@ class SearchDelegateExample extends SearchDelegate {
|
||||
Widget buildResults(BuildContext context) {
|
||||
// Perform the search and return the results
|
||||
return FutureBuilder<List<Events>>(
|
||||
future: searchPosts(query, geoQuery),
|
||||
future: searchPosts(query),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
@ -79,45 +75,51 @@ class SearchDelegateExample extends SearchDelegate {
|
||||
return Container(); // Implement suggestions if needed
|
||||
}
|
||||
|
||||
Future<List<Events>> searchPosts(String query, String geoQuery) async {
|
||||
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) {
|
||||
DateTime currentDate = DateTime.now();
|
||||
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}¤t_dateime=${currentDate.toString()}");
|
||||
if (geoQuery.isNotEmpty) {
|
||||
await dotenv.load(
|
||||
fileName: ".env"); // Load your .env for the Mapbox access token
|
||||
final mapboxAccessToken = dotenv.env['MAPBOX_ACCESS_TOKEN'] ?? '';
|
||||
final geocodeUrl = Uri.parse(
|
||||
'https://api.mapbox.com/geocoding/v5/mapbox.places/$geoQuery.json?access_token=$mapboxAccessToken');
|
||||
final geocodeResponse = await http.get(geocodeUrl);
|
||||
if (geocodeResponse.statusCode == 200) {
|
||||
final geocodeData = json.decode(geocodeResponse.body);
|
||||
if (geocodeData['features'].isNotEmpty) {
|
||||
final coordinates =
|
||||
geocodeData['features'][0]['geometry']['coordinates'];
|
||||
final longitude = coordinates[0]; // Longitude
|
||||
final latitude = coordinates[1]; // Latitude
|
||||
|
||||
// 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}¤t_dateime=${currentDate.toString()}");
|
||||
}
|
||||
}
|
||||
"${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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user