add latitude and longitude
This commit is contained in:
parent
b22458021b
commit
44a0691e31
@ -85,11 +85,14 @@ class DisplayPictureScreenState extends State<DisplayPictureScreen>
|
||||
}
|
||||
|
||||
Future<void> searchEvents(String json, String imagePath) async {
|
||||
print(json);
|
||||
print(json.replaceAll("'''json", '').replaceAll("'''", ""));
|
||||
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"];
|
||||
print("name : ${name}");
|
||||
var place = jsonData["place"];
|
||||
var accessToken = prefs.getString("access_token") ?? "";
|
||||
|
||||
@ -132,7 +135,7 @@ class DisplayPictureScreenState extends State<DisplayPictureScreen>
|
||||
gemini
|
||||
.textAndImage(
|
||||
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()],
|
||||
modelName: "models/gemini-1.5-pro-latest")
|
||||
.then((value) => searchEvents(
|
||||
|
@ -13,6 +13,8 @@ import 'dart:math';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import '../variable/globals.dart' as globals;
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import "Camera.dart";
|
||||
import 'package:camera/camera.dart';
|
||||
|
||||
void main() {
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
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(
|
||||
itemCount: displayedPosts.length,
|
||||
itemBuilder: (context, index) {
|
||||
final post = displayedPosts[index];
|
||||
final startDate = DateTime.parse(post.startDate!);
|
||||
final date = DateFormat.yMd().format(startDate);
|
||||
final time = DateFormat.Hm().format(startDate);
|
||||
itemCount: displayedPosts.length,
|
||||
itemBuilder: (context, index) {
|
||||
final post = displayedPosts[index];
|
||||
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}'),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => ItemMenu(title: post.id!)),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => Divider(),
|
||||
);
|
||||
return ListTile(
|
||||
title: Text('${post.name!}'),
|
||||
subtitle: Text('${post.place!}\n${date} ${time}'),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => ItemMenu(title: post.id!)),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) {
|
||||
return Divider();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -44,20 +44,21 @@ class UpdateeventImage extends StatefulWidget {
|
||||
class _UpdateeventImageState extends State<UpdateeventImage>
|
||||
with ShowErrorDialog, ShowEventDialog {
|
||||
TextEditingController inputName = TextEditingController();
|
||||
TextEditingController inputAddress = TextEditingController();
|
||||
TextEditingController inputZipCode = TextEditingController();
|
||||
|
||||
TextEditingController inputCity = TextEditingController();
|
||||
TextEditingController inputCountry = TextEditingController();
|
||||
|
||||
TextEditingController inputDate = TextEditingController();
|
||||
TextEditingController inputDesc = TextEditingController();
|
||||
|
||||
TextEditingController inputGeo = TextEditingController();
|
||||
|
||||
TextEditingController startDatepicker = TextEditingController();
|
||||
TextEditingController startTimepicker = TextEditingController();
|
||||
TextEditingController endDatepicker = TextEditingController();
|
||||
TextEditingController endTimepicker = TextEditingController();
|
||||
final _stringTagController = StringTagController();
|
||||
|
||||
List<Map<String, dynamic>> suggestions = [];
|
||||
String geographicalZone = "";
|
||||
|
||||
List<String> initialTags = [];
|
||||
|
||||
final _stringOrgaController = StringTagController();
|
||||
@ -128,10 +129,7 @@ class _UpdateeventImageState extends State<UpdateeventImage>
|
||||
Future<void> _updateEvent(BuildContext context) async {
|
||||
var url = Uri.parse("${globals.api}/token");
|
||||
var name = inputName.text;
|
||||
var place = inputAddress.text;
|
||||
var city = inputCity.text;
|
||||
var country = inputCountry.text;
|
||||
var zipCode = inputZipCode.text;
|
||||
var place = inputGeo.text;
|
||||
var description = inputDesc.text;
|
||||
List<String> tags = List<String>.from(_stringTagController.getTags as List);
|
||||
List<String> organizers =
|
||||
@ -150,101 +148,118 @@ class _UpdateeventImageState extends State<UpdateeventImage>
|
||||
if (accessToken.isNotEmpty) {
|
||||
try {
|
||||
await dotenv.load();
|
||||
final params = {
|
||||
'expiration': '15552000',
|
||||
'key': dotenv.env["IMGBB_API_KEY"],
|
||||
};
|
||||
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 mapboxAccessToken = dotenv.env['MAPBOX_ACCESS_TOKEN'] ?? '';
|
||||
final url =
|
||||
'https://api.mapbox.com/geocoding/v5/mapbox.places/${place}.json?access_token=${mapboxAccessToken}&proximity=ip';
|
||||
final response = await http.get(Uri.parse(url));
|
||||
|
||||
final req = http.MultipartRequest('POST', urlPost)
|
||||
..fields['image'] = _base64String;
|
||||
if (response.statusCode == 200) {
|
||||
final data = json.decode(response.body);
|
||||
|
||||
final stream = await req.send();
|
||||
final res = await http.Response.fromStream(stream);
|
||||
if (data['features'].isNotEmpty) {
|
||||
final coordinates = data['features'][0]['geometry']['coordinates'];
|
||||
final longitude = coordinates[0]; // Longitude
|
||||
final latitude = coordinates[1]; // Latitude
|
||||
|
||||
final status = res.statusCode;
|
||||
print("code status imgbb ${status}");
|
||||
if (status == 200) {
|
||||
var body = json.decode(utf8.decode(res.bodyBytes));
|
||||
String imgUrl = body["data"]["url"];
|
||||
final params = {
|
||||
'expiration': '15552000',
|
||||
'key': dotenv.env["IMGBB_API_KEY"],
|
||||
};
|
||||
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}";
|
||||
//Codec<String, String> stringToBase64 = utf8.fuse(base64);
|
||||
//String encoded = stringToBase64.encode(credentials);
|
||||
var urlPut = Uri.parse("${globals.api}/events");
|
||||
var responsePut = await http.put(urlPut,
|
||||
headers: {
|
||||
HttpHeaders.cookieHeader: 'access_token=${accessToken}',
|
||||
HttpHeaders.acceptHeader: 'application/json, text/plain, */*',
|
||||
HttpHeaders.contentTypeHeader: 'application/json'
|
||||
},
|
||||
body: jsonEncode({
|
||||
'name': name,
|
||||
'place': place,
|
||||
'start_date': startDate,
|
||||
'end_date': endDate,
|
||||
'zip_code': zipCode,
|
||||
'country': country,
|
||||
'city': city,
|
||||
'organizers': organizers,
|
||||
'latitude': '0.0',
|
||||
'longitude': '0.0',
|
||||
'description': description,
|
||||
"imgUrl": imgUrl,
|
||||
"tags": tags
|
||||
}));
|
||||
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";
|
||||
final req = http.MultipartRequest('POST', urlPost)
|
||||
..fields['image'] = _base64String;
|
||||
|
||||
final stream = await req.send();
|
||||
final res = await http.Response.fromStream(stream);
|
||||
|
||||
final status = res.statusCode;
|
||||
print("code status imgbb ${status}");
|
||||
if (status == 200) {
|
||||
var body = json.decode(utf8.decode(res.bodyBytes));
|
||||
String imgUrl = body["data"]["url"];
|
||||
|
||||
//String credentials = "${pseudo}:${password}";
|
||||
//Codec<String, String> stringToBase64 = utf8.fuse(base64);
|
||||
//String encoded = stringToBase64.encode(credentials);
|
||||
var urlPut = Uri.parse("${globals.api}/events");
|
||||
var responsePut = await http.put(urlPut,
|
||||
headers: {
|
||||
HttpHeaders.cookieHeader: 'access_token=${accessToken}',
|
||||
HttpHeaders.acceptHeader:
|
||||
'application/json, text/plain, */*',
|
||||
HttpHeaders.contentTypeHeader: 'application/json'
|
||||
},
|
||||
body: jsonEncode({
|
||||
'name': name,
|
||||
'place': place,
|
||||
'start_date': startDate,
|
||||
'end_date': endDate,
|
||||
'organizers': organizers,
|
||||
'latitude': latitude,
|
||||
'longitude': longitude,
|
||||
'description': description,
|
||||
"imgUrl": imgUrl,
|
||||
"tags": tags
|
||||
}));
|
||||
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;
|
||||
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;
|
||||
showErrorDialog(context, text);
|
||||
}
|
||||
} else {
|
||||
print("imgbb error : ${status}");
|
||||
}
|
||||
showErrorDialog(context, text);
|
||||
} else {
|
||||
showErrorDialog(context, "Aucune donnée geographique");
|
||||
}
|
||||
} else {
|
||||
print("imgbb error : ${status}");
|
||||
showErrorDialog(context, "Mapbox non accessible");
|
||||
}
|
||||
} catch (e) {
|
||||
showErrorDialog(context, "${e}");
|
||||
@ -255,11 +270,9 @@ class _UpdateeventImageState extends State<UpdateeventImage>
|
||||
}
|
||||
|
||||
void start() async {
|
||||
print("events : ${widget.events}");
|
||||
inputName.text = convertNulltoEmptyString(widget.events["name"]);
|
||||
inputCity.text = convertNulltoEmptyString(widget.events["city"]);
|
||||
inputAddress.text = convertNulltoEmptyString(widget.events["address"]);
|
||||
inputZipCode.text = convertNulltoEmptyString(widget.events["zip_code"]);
|
||||
inputCountry.text = convertNulltoEmptyString(widget.events["country"]);
|
||||
inputGeo.text = convertNulltoEmptyString(widget.events["place"]);
|
||||
inputDesc.text = convertNulltoEmptyString(widget.events["description"]);
|
||||
|
||||
DateTime pickedStartDate =
|
||||
@ -286,6 +299,93 @@ class _UpdateeventImageState extends State<UpdateeventImage>
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -323,58 +423,7 @@ class _UpdateeventImageState extends State<UpdateeventImage>
|
||||
hintText: 'Modifier le nom de l\'évènement'),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
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'),
|
||||
),
|
||||
),
|
||||
_buildGeographicalZoneSearchField(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 15.0, right: 15.0, top: 15, bottom: 0),
|
||||
|
Loading…
x
Reference in New Issue
Block a user