add searchbar with mapbox and suggesstionbar

This commit is contained in:
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:io';
import 'ItemMenu.dart';
import 'Camera.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import '../classes/events.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:intl/intl.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:camera/camera.dart';
import 'package:mapbox_gl/mapbox_gl.dart'; // Add this import
import '../variable/globals.dart' as globals;
// app starting point
void main() {
initializeDateFormatting("fr_FR", null).then((_) => runApp(const MyApp()));
}
@@ -28,7 +29,6 @@ class MyApp extends StatelessWidget {
}
}
// homepage class
class ListItemMenu extends StatefulWidget {
const ListItemMenu({super.key});
@@ -36,14 +36,15 @@ class ListItemMenu extends StatefulWidget {
State<ListItemMenu> createState() => _MyHomePageState();
}
// homepage state
class _MyHomePageState extends State<ListItemMenu> {
Future<List<Events>> postsFuture = getPosts();
List<Events> filteredPosts = [];
String geographicalZone = '';
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 {
SharedPreferences prefs = await SharedPreferences.getInstance();
var accessToken = prefs.getString("access_token") ?? "";
@@ -60,45 +61,77 @@ class _MyHomePageState extends State<ListItemMenu> {
return body;
}
Future<List<Events>> searchPosts(String query) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
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> searchSuggestions(String input) async {
await dotenv.load(fileName: ".env"); // Load .env file
Future<void> popCamera() async {
await availableCameras().then((value) => Navigator.push(context,
MaterialPageRoute(builder: (_) => Camera(camera: value.first))));
final mapboxAccessToken = dotenv.env['MAPBOX_ACCESS_TOKEN'] ?? '';
final url =
'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() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(
labelText: 'Search by geographical zone',
border: OutlineInputBorder(),
),
onChanged: (value) {
setState(() {
geographicalZone = value; // Update geographical zone
});
},
child: Column(
children: [
TextField(
controller: inputGeo,
decoration: InputDecoration(
labelText: 'Search by geographical zone',
border: OutlineInputBorder(),
),
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
Widget build(BuildContext context) {
return Scaffold(
@@ -120,7 +153,6 @@ class _MyHomePageState extends State<ListItemMenu> {
),
body: Column(
children: [
// New Search Bar for Geographical Zone
_buildGeographicalZoneSearchField(),
Expanded(
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) {
return ListView.separated(
itemCount: posts.length,