add searchbar with mapbox and suggesstionbar

This commit is contained in:
Valentin CZERYBA 2024-10-28 23:50:20 +01:00
parent 576d045cd8
commit 3a350e33cc
3 changed files with 150 additions and 37 deletions

View File

@ -1,17 +1,18 @@
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
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 'Camera.dart'; import 'Camera.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.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';
import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/date_symbol_data_local.dart';
import 'package:camera/camera.dart'; import 'package:camera/camera.dart';
import 'package:mapbox_gl/mapbox_gl.dart'; // Add this import
import '../variable/globals.dart' as globals; import '../variable/globals.dart' as globals;
// app starting point
void main() { void main() {
initializeDateFormatting("fr_FR", null).then((_) => runApp(const MyApp())); initializeDateFormatting("fr_FR", null).then((_) => runApp(const MyApp()));
} }
@ -28,7 +29,6 @@ class MyApp extends StatelessWidget {
} }
} }
// homepage class
class ListItemMenu extends StatefulWidget { class ListItemMenu extends StatefulWidget {
const ListItemMenu({super.key}); const ListItemMenu({super.key});
@ -36,14 +36,15 @@ class ListItemMenu extends StatefulWidget {
State<ListItemMenu> createState() => _MyHomePageState(); State<ListItemMenu> createState() => _MyHomePageState();
} }
// homepage state
class _MyHomePageState extends State<ListItemMenu> { class _MyHomePageState extends State<ListItemMenu> {
Future<List<Events>> postsFuture = getPosts(); Future<List<Events>> postsFuture = getPosts();
List<Events> filteredPosts = []; List<Events> filteredPosts = [];
String geographicalZone = ''; String geographicalZone = '';
String query = ''; String query = '';
List<String> suggestions = []; // Store suggestions
TextEditingController inputGeo = TextEditingController();
// function to fetch data from api and return future list of posts // Fetching events from API
static Future<List<Events>> getPosts() async { static Future<List<Events>> getPosts() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
var accessToken = prefs.getString("access_token") ?? ""; var accessToken = prefs.getString("access_token") ?? "";
@ -60,45 +61,77 @@ class _MyHomePageState extends State<ListItemMenu> {
return body; return body;
} }
Future<List<Events>> searchPosts(String query) async { Future<void> searchSuggestions(String input) async {
SharedPreferences prefs = await SharedPreferences.getInstance(); await dotenv.load(fileName: ".env"); // Load .env file
var accessToken = prefs.getString("access_token") ?? "";
final List<Events> body = [];
if (accessToken.isNotEmpty) {
var url = Uri.parse("${globals.api}/events/search?item=$query");
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;
}
Future<void> popCamera() async { final mapboxAccessToken = dotenv.env['MAPBOX_ACCESS_TOKEN'] ?? '';
await availableCameras().then((value) => Navigator.push(context, final url =
MaterialPageRoute(builder: (_) => Camera(camera: value.first)))); 'https://api.mapbox.com/geocoding/v5/mapbox.places/${input}.json?access_token=${mapboxAccessToken}&proximity=ip'; // Replace with your Mapbox token
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) =>
feature['place_name'] as String) // Cast to String explicitly
.toList();
});
} else {
throw Exception('Failed to load suggestions');
}
} }
Padding _buildGeographicalZoneSearchField() { Padding _buildGeographicalZoneSearchField() {
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: TextField( child: Column(
decoration: InputDecoration( children: [
labelText: 'Search by geographical zone', TextField(
border: OutlineInputBorder(), controller: inputGeo,
), decoration: InputDecoration(
onChanged: (value) { labelText: 'Search by geographical zone',
setState(() { border: OutlineInputBorder(),
geographicalZone = value; // Update geographical zone ),
}); onChanged: (value) {
}, setState(() {
geographicalZone = value;
searchSuggestions(value);
});
},
),
if (suggestions.isNotEmpty)
Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue), // Add a border color
borderRadius:
BorderRadius.circular(8), // Optional: rounded corners
),
child: ListView.builder(
shrinkWrap:
true, // Ensure the list takes only the required space
itemCount: suggestions.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(suggestions[index]),
onTap: () {
setState(() {
geographicalZone = suggestions[index];
inputGeo.text = suggestions[index];
suggestions.clear();
});
},
);
},
),
),
],
), ),
); );
} }
// build function
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -120,7 +153,6 @@ class _MyHomePageState extends State<ListItemMenu> {
), ),
body: Column( body: Column(
children: [ children: [
// New Search Bar for Geographical Zone
_buildGeographicalZoneSearchField(), _buildGeographicalZoneSearchField(),
Expanded( Expanded(
child: FutureBuilder<List<Events>>( child: FutureBuilder<List<Events>>(
@ -144,7 +176,7 @@ class _MyHomePageState extends State<ListItemMenu> {
); );
} }
// function to display fetched data on screen // Function to display fetched data on screen
Widget buildPosts(List<Events> posts) { Widget buildPosts(List<Events> posts) {
return ListView.separated( return ListView.separated(
itemCount: posts.length, itemCount: posts.length,

View File

@ -1,6 +1,14 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
archive:
dependency: transitive
description:
name: archive
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
url: "https://pub.dev"
source: hosted
version: "3.6.1"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -89,6 +97,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.4+2" version: "0.3.4+2"
crypto:
dependency: transitive
description:
name: crypto
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev"
source: hosted
version: "3.0.6"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
@ -248,6 +264,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.0.2"
image:
dependency: transitive
description:
name: image
sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6"
url: "https://pub.dev"
source: hosted
version: "3.3.0"
image_picker: image_picker:
dependency: "direct main" dependency: "direct main"
description: description:
@ -320,6 +344,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.19.0" version: "0.19.0"
js:
dependency: transitive
description:
name: js
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
version: "0.6.7"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
@ -360,6 +392,38 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "4.0.0"
mapbox_gl:
dependency: "direct main"
description:
name: mapbox_gl
sha256: d78907338ff232e3cf6c1d6dba45e6a8814069496fd352e49bb1967d498f09af
url: "https://pub.dev"
source: hosted
version: "0.16.0"
mapbox_gl_dart:
dependency: transitive
description:
name: mapbox_gl_dart
sha256: de6d03718e5eb05c9eb1ddaae7f0383b28acb5afa16405e1deed7ff04dd34f3d
url: "https://pub.dev"
source: hosted
version: "0.2.1"
mapbox_gl_platform_interface:
dependency: transitive
description:
name: mapbox_gl_platform_interface
sha256: b7c1490b022e650afd20412bdf8ae45a1897118b7ce6049ef6c42df09193d4b2
url: "https://pub.dev"
source: hosted
version: "0.16.0"
mapbox_gl_web:
dependency: transitive
description:
name: mapbox_gl_web
sha256: e77113bf95a4f321ff44938232517e0f2725aae991f0b283af1afaa7e7a58aca
url: "https://pub.dev"
source: hosted
version: "0.16.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -448,6 +512,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.0"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
url: "https://pub.dev"
source: hosted
version: "6.0.2"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@ -629,6 +701,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
xml:
dependency: transitive
description:
name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
version: "6.5.0"
sdks: sdks:
dart: ">=3.4.0 <4.0.0" dart: ">=3.4.0 <4.0.0"
flutter: ">=3.22.0" flutter: ">=3.22.0"

View File

@ -46,6 +46,7 @@ dependencies:
image_picker: ^1.1.2 image_picker: ^1.1.2
date_format_field: ^0.1.0 date_format_field: ^0.1.0
textfield_tags: ^3.0.1 textfield_tags: ^3.0.1
mapbox_gl: ^0.16.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: