add latitude and longitude

This commit is contained in:
Valentin CZERYBA 2024-11-07 23:10:03 +01:00
parent b22458021b
commit 44a0691e31
3 changed files with 240 additions and 174 deletions

View File

@ -85,11 +85,14 @@ class DisplayPictureScreenState extends State<DisplayPictureScreen>
} }
Future<void> searchEvents(String json, String imagePath) async { Future<void> searchEvents(String json, String imagePath) async {
print(json); print(json.replaceAll("'''json", '').replaceAll("'''", ""));
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
Map<String, dynamic> jsonData = jsonDecode(json); Map<String, dynamic> jsonData =
jsonDecode(json.replaceAll("```json", '').replaceAll("```", ""));
print("json : ${jsonData}");
var name = jsonData["name"]; var name = jsonData["name"];
print("name : ${name}");
var place = jsonData["place"]; var place = jsonData["place"];
var accessToken = prefs.getString("access_token") ?? ""; var accessToken = prefs.getString("access_token") ?? "";
@ -132,7 +135,7 @@ class DisplayPictureScreenState extends State<DisplayPictureScreen>
gemini gemini
.textAndImage( .textAndImage(
text: text:
"Peux-tu donner le nom, la date avec l'année actuelle ou d'une année future proche et le lieu de l'évènement sous format JSON avec les valeurs suivantes : name, address, city, zip_code, country, description, tags (tableau sans espace), organizers (tableau), start_date et end_date sous le format en YYYY-MM-DD HH:mm:ssZ, et sans la présence du mot json dans la chaîne de caractère", "Peux-tu donner le nom, la date avec l'année actuelle ou d'une année future proche et le lieu de l'évènement sous format JSON (sans le caratère json au début de la chaine de caractère) avec les valeurs suivantes : name, place, description, tags (tableau sans espace), organizers (tableau), start_date et end_date sous le format en YYYY-MM-DD HH:mm:ssZ",
images: [file.readAsBytesSync()], images: [file.readAsBytesSync()],
modelName: "models/gemini-1.5-pro-latest") modelName: "models/gemini-1.5-pro-latest")
.then((value) => searchEvents( .then((value) => searchEvents(

View File

@ -13,6 +13,8 @@ import 'dart:math';
import 'package:geolocator/geolocator.dart'; import 'package:geolocator/geolocator.dart';
import '../variable/globals.dart' as globals; import '../variable/globals.dart' as globals;
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import "Camera.dart";
import 'package:camera/camera.dart';
void main() { void main() {
initializeDateFormatting("fr_FR", null).then((_) => runApp(const MyApp())); initializeDateFormatting("fr_FR", null).then((_) => runApp(const MyApp()));
@ -356,6 +358,11 @@ class _MyHomePageState extends State<ListItemMenu> {
); );
} }
Future<void> popCamera() async {
await availableCameras().then((value) => Navigator.push(context,
MaterialPageRoute(builder: (_) => Camera(camera: value.first))));
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -397,6 +404,12 @@ class _MyHomePageState extends State<ListItemMenu> {
), ),
], ],
), ),
floatingActionButton: FloatingActionButton(
onPressed: popCamera,
backgroundColor: Colors.blue,
tooltip: 'Recherche',
child: const Icon(Icons.photo_camera, color: Colors.white),
),
); );
} }
@ -415,25 +428,26 @@ class _MyHomePageState extends State<ListItemMenu> {
} }
return ListView.separated( return ListView.separated(
itemCount: displayedPosts.length, itemCount: displayedPosts.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final post = displayedPosts[index]; final post = displayedPosts[index];
final startDate = DateTime.parse(post.startDate!); final startDate = DateTime.parse(post.startDate!);
final date = DateFormat.yMd().format(startDate); final date = DateFormat.yMd().format(startDate);
final time = DateFormat.Hm().format(startDate); final time = DateFormat.Hm().format(startDate);
return ListTile( return ListTile(
title: Text('${post.name!}'), title: Text('${post.name!}'),
subtitle: Text('${post.place!}\n${date} ${time}'), subtitle: Text('${post.place!}\n${date} ${time}'),
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (_) => ItemMenu(title: post.id!)), MaterialPageRoute(builder: (_) => ItemMenu(title: post.id!)),
); );
}, },
); );
}, },
separatorBuilder: (context, index) => Divider(), separatorBuilder: (context, index) {
); return Divider();
});
} }
} }

View File

@ -44,20 +44,21 @@ class UpdateeventImage extends StatefulWidget {
class _UpdateeventImageState extends State<UpdateeventImage> class _UpdateeventImageState extends State<UpdateeventImage>
with ShowErrorDialog, ShowEventDialog { with ShowErrorDialog, ShowEventDialog {
TextEditingController inputName = TextEditingController(); TextEditingController inputName = TextEditingController();
TextEditingController inputAddress = TextEditingController();
TextEditingController inputZipCode = TextEditingController();
TextEditingController inputCity = TextEditingController();
TextEditingController inputCountry = TextEditingController();
TextEditingController inputDate = TextEditingController(); TextEditingController inputDate = TextEditingController();
TextEditingController inputDesc = TextEditingController(); TextEditingController inputDesc = TextEditingController();
TextEditingController inputGeo = TextEditingController();
TextEditingController startDatepicker = TextEditingController(); TextEditingController startDatepicker = TextEditingController();
TextEditingController startTimepicker = TextEditingController(); TextEditingController startTimepicker = TextEditingController();
TextEditingController endDatepicker = TextEditingController(); TextEditingController endDatepicker = TextEditingController();
TextEditingController endTimepicker = TextEditingController(); TextEditingController endTimepicker = TextEditingController();
final _stringTagController = StringTagController(); final _stringTagController = StringTagController();
List<Map<String, dynamic>> suggestions = [];
String geographicalZone = "";
List<String> initialTags = []; List<String> initialTags = [];
final _stringOrgaController = StringTagController(); final _stringOrgaController = StringTagController();
@ -128,10 +129,7 @@ class _UpdateeventImageState extends State<UpdateeventImage>
Future<void> _updateEvent(BuildContext context) async { Future<void> _updateEvent(BuildContext context) async {
var url = Uri.parse("${globals.api}/token"); var url = Uri.parse("${globals.api}/token");
var name = inputName.text; var name = inputName.text;
var place = inputAddress.text; var place = inputGeo.text;
var city = inputCity.text;
var country = inputCountry.text;
var zipCode = inputZipCode.text;
var description = inputDesc.text; var description = inputDesc.text;
List<String> tags = List<String>.from(_stringTagController.getTags as List); List<String> tags = List<String>.from(_stringTagController.getTags as List);
List<String> organizers = List<String> organizers =
@ -150,101 +148,118 @@ class _UpdateeventImageState extends State<UpdateeventImage>
if (accessToken.isNotEmpty) { if (accessToken.isNotEmpty) {
try { try {
await dotenv.load(); await dotenv.load();
final params = { final mapboxAccessToken = dotenv.env['MAPBOX_ACCESS_TOKEN'] ?? '';
'expiration': '15552000', final url =
'key': dotenv.env["IMGBB_API_KEY"], 'https://api.mapbox.com/geocoding/v5/mapbox.places/${place}.json?access_token=${mapboxAccessToken}&proximity=ip';
}; final response = await http.get(Uri.parse(url));
print("Post Img");
final urlPost = Uri.parse('https://api.imgbb.com/1/upload')
.replace(queryParameters: params);
File image = File(widget.imagePath);
Uint8List _bytes = await image.readAsBytes();
String _base64String = base64.encode(_bytes);
final req = http.MultipartRequest('POST', urlPost) if (response.statusCode == 200) {
..fields['image'] = _base64String; final data = json.decode(response.body);
final stream = await req.send(); if (data['features'].isNotEmpty) {
final res = await http.Response.fromStream(stream); final coordinates = data['features'][0]['geometry']['coordinates'];
final longitude = coordinates[0]; // Longitude
final latitude = coordinates[1]; // Latitude
final status = res.statusCode; final params = {
print("code status imgbb ${status}"); 'expiration': '15552000',
if (status == 200) { 'key': dotenv.env["IMGBB_API_KEY"],
var body = json.decode(utf8.decode(res.bodyBytes)); };
String imgUrl = body["data"]["url"]; print("Post Img");
final urlPost = Uri.parse('https://api.imgbb.com/1/upload')
.replace(queryParameters: params);
File image = File(widget.imagePath);
Uint8List _bytes = await image.readAsBytes();
String _base64String = base64.encode(_bytes);
//String credentials = "${pseudo}:${password}"; final req = http.MultipartRequest('POST', urlPost)
//Codec<String, String> stringToBase64 = utf8.fuse(base64); ..fields['image'] = _base64String;
//String encoded = stringToBase64.encode(credentials);
var urlPut = Uri.parse("${globals.api}/events"); final stream = await req.send();
var responsePut = await http.put(urlPut, final res = await http.Response.fromStream(stream);
headers: {
HttpHeaders.cookieHeader: 'access_token=${accessToken}', final status = res.statusCode;
HttpHeaders.acceptHeader: 'application/json, text/plain, */*', print("code status imgbb ${status}");
HttpHeaders.contentTypeHeader: 'application/json' if (status == 200) {
}, var body = json.decode(utf8.decode(res.bodyBytes));
body: jsonEncode({ String imgUrl = body["data"]["url"];
'name': name,
'place': place, //String credentials = "${pseudo}:${password}";
'start_date': startDate, //Codec<String, String> stringToBase64 = utf8.fuse(base64);
'end_date': endDate, //String encoded = stringToBase64.encode(credentials);
'zip_code': zipCode, var urlPut = Uri.parse("${globals.api}/events");
'country': country, var responsePut = await http.put(urlPut,
'city': city, headers: {
'organizers': organizers, HttpHeaders.cookieHeader: 'access_token=${accessToken}',
'latitude': '0.0', HttpHeaders.acceptHeader:
'longitude': '0.0', 'application/json, text/plain, */*',
'description': description, HttpHeaders.contentTypeHeader: 'application/json'
"imgUrl": imgUrl, },
"tags": tags body: jsonEncode({
})); 'name': name,
print(responsePut.statusCode); 'place': place,
if ((responsePut.statusCode == 200) || 'start_date': startDate,
(responsePut.statusCode == 201)) { 'end_date': endDate,
showEventDialog(context, "Evenement ${name} ajoute"); 'organizers': organizers,
} else { 'latitude': latitude,
var text = ""; 'longitude': longitude,
switch (responsePut.statusCode) { 'description': description,
case 400: "imgUrl": imgUrl,
{ "tags": tags
text = "Requête mal construite"; }));
print(responsePut.statusCode);
if ((responsePut.statusCode == 200) ||
(responsePut.statusCode == 201)) {
showEventDialog(context, "Evenement ${name} ajoute");
} else {
var text = "";
switch (responsePut.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 = "Utilisateur desactive";
}
break;
case 410:
{
text = "Token invalide";
}
break;
case 500:
{
text = "Probleme interne du serveur";
}
break;
default:
{
text = "Probleme d'authentification inconnu";
}
break;
} }
break; showErrorDialog(context, text);
case 406: }
{ } else {
text = "Mot de passe incorrect"; print("imgbb error : ${status}");
}
break;
case 404:
{
text = "Utilisateur inconnu";
}
break;
case 403:
{
text = "Utilisateur desactive";
}
break;
case 410:
{
text = "Token invalide";
}
break;
case 500:
{
text = "Probleme interne du serveur";
}
break;
default:
{
text = "Probleme d'authentification inconnu";
}
break;
} }
showErrorDialog(context, text); } else {
showErrorDialog(context, "Aucune donnée geographique");
} }
} else { } else {
print("imgbb error : ${status}"); showErrorDialog(context, "Mapbox non accessible");
} }
} catch (e) { } catch (e) {
showErrorDialog(context, "${e}"); showErrorDialog(context, "${e}");
@ -255,11 +270,9 @@ class _UpdateeventImageState extends State<UpdateeventImage>
} }
void start() async { void start() async {
print("events : ${widget.events}");
inputName.text = convertNulltoEmptyString(widget.events["name"]); inputName.text = convertNulltoEmptyString(widget.events["name"]);
inputCity.text = convertNulltoEmptyString(widget.events["city"]); inputGeo.text = convertNulltoEmptyString(widget.events["place"]);
inputAddress.text = convertNulltoEmptyString(widget.events["address"]);
inputZipCode.text = convertNulltoEmptyString(widget.events["zip_code"]);
inputCountry.text = convertNulltoEmptyString(widget.events["country"]);
inputDesc.text = convertNulltoEmptyString(widget.events["description"]); inputDesc.text = convertNulltoEmptyString(widget.events["description"]);
DateTime pickedStartDate = DateTime pickedStartDate =
@ -286,6 +299,93 @@ class _UpdateeventImageState extends State<UpdateeventImage>
return value!.isEmpty ? 'Champ requis' : null; return value!.isEmpty ? 'Champ requis' : null;
} }
Future<void> searchSuggestions(String input) async {
await dotenv.load(fileName: ".env"); // Load .env file
final mapboxAccessToken = dotenv.env['MAPBOX_ACCESS_TOKEN'] ?? '';
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');
}
}
Padding _buildGeographicalZoneSearchField() {
return Padding(
padding:
const EdgeInsets.only(left: 15.0, right: 15.0, top: 15, bottom: 0),
child: Column(
children: [
TextField(
controller: inputGeo,
decoration: InputDecoration(
labelText: 'Lieu',
border: OutlineInputBorder(),
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
setState(() {
inputGeo.clear(); // Clear the text field
geographicalZone = ''; // Reset the geographical zone state
suggestions.clear(); // Optionally clear suggestions
});
},
),
),
onChanged: (value) {
setState(() {
geographicalZone = value;
searchSuggestions(value);
});
},
),
if (suggestions.isNotEmpty)
Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue),
borderRadius: BorderRadius.circular(8),
),
child: ListView.builder(
shrinkWrap: true,
itemCount: suggestions.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(suggestions[index]['place_name']),
onTap: () async {
final latitude =
suggestions[index]['geometry']['coordinates'][1];
final longitude =
suggestions[index]['geometry']['coordinates'][0];
setState(() {
geographicalZone = suggestions[index]['place_name'];
inputGeo.text = geographicalZone;
suggestions.clear();
});
},
);
},
),
),
],
),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -323,58 +423,7 @@ class _UpdateeventImageState extends State<UpdateeventImage>
hintText: 'Modifier le nom de l\'évènement'), hintText: 'Modifier le nom de l\'évènement'),
), ),
), ),
Padding( _buildGeographicalZoneSearchField(),
padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 15, bottom: 0),
//padding: EdgeInsets.symmetric(horizontal: 15),
child: TextFormField(
controller: inputAddress,
validator: (value) => _validateField(value),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Adresse',
hintText: 'Entrer une adresse'),
),
),
Padding(
padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 15, bottom: 0),
//padding: EdgeInsets.symmetric(horizontal: 15),
child: TextFormField(
controller: inputZipCode,
validator: (value) => _validateField(value),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Code postal',
hintText: 'Entrer un code postal'),
),
),
Padding(
padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 15, bottom: 0),
//padding: EdgeInsets.symmetric(horizontal: 15),
child: TextFormField(
controller: inputCity,
validator: (value) => _validateField(value),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Ville',
hintText: 'Entrer une ville'),
),
),
Padding(
padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 15, bottom: 0),
//padding: EdgeInsets.symmetric(horizontal: 15),
child: TextFormField(
controller: inputCountry,
validator: (value) => _validateField(value),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Pays',
hintText: 'Entrer un pays'),
),
),
Padding( Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 15, bottom: 0), left: 15.0, right: 15.0, top: 15, bottom: 0),