Map
Map
import 'dart:math';
import 'package:chapsante/utils/constants.dart';
import 'package:figma_squircle/figma_squircle.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:gap/gap.dart';
import 'package:geolocator/geolocator.dart';
import 'package:flutter_map/plugin_api.dart';
import 'package:latlong2/latlong.dart';
import 'package:http/http.dart' as http;
@override
State<MapWidget> createState() => _MapWidgetState();
}
Position? _currentPosition;
LatLng? _deliveryPosition;
LatLng? _clientPosition;
LatLng? _midPoint;
List<LatLng> _pharmacies = [];
List<LatLng> _closestPharmacies = [];
List<LatLng> _otherPharmacies = [];
List<LatLng> _route = [];
@override
void initState() {
super.initState();
_determinePosition();
}
@override
void dispose() {
super.dispose();
}
if (permission == LocationPermission.deniedForever) {
return Future.error(
'Les permissions de localisation sont refusées de façon permanente.');
}
print("\n================ around:$radius,${midPoint.latitude},$
{midPoint.longitude} ================\n");
final url =
'https://overpass-api.de/api/interpreter?
data=[out:json];node[amenity=pharmacy](around:$radius,${midPoint.latitude},$
{midPoint.longitude});out;';
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final List<LatLng> pharmacies = [];
for (var element in data['elements']) {
pharmacies.add(
LatLng(element['lat'], element['lon']),
);
}
if (mounted) {
if (pharmacies.isNotEmpty) {
_processPharmacies(pharmacies);
}
}
} else {
throw Exception('Failed to load pharmacies');
}
}
nearbyPharmacies.sort((a, b) {
final distA = Geolocator.distanceBetween(
_deliveryPosition!.latitude,
_deliveryPosition!.longitude,
a.latitude,
a.longitude,
) +
Geolocator.distanceBetween(
_clientPosition!.latitude,
_clientPosition!.longitude,
a.latitude,
a.longitude,
);
return distA.compareTo(distB);
});
setState(() {
_midPoint = midPoint;
_pharmacies = pharmacies;
_closestPharmacies = closestPharmacies;
_otherPharmacies = otherPharmacies;
if (closestPharmacies.isNotEmpty) {
_fetchRoute(closestPharmacies[0]);
}
});
}
print("route1Response.statusCode: ${route1Response.statusCode}");
print("route2Response.statusCode: ${route2Response.statusCode}");
print("route1Data: $route1Data");
print("route2Data: $route2Data");
setState(() {
_route = routeToPharmacy + routeToClient;
_moveMarker();
});
} else {
throw Exception('Failed to fetch route');
}
}
setState(() {
_deliveryPosition = LatLng(lat, lng);
});
mapController.move(_deliveryPosition!, mapController.zoom);
}
}
}
final url =
'https://api.openrouteservice.org/v2/directions/driving-car?
api_key=$apiKey&start=${_deliveryPosition!.longitude},$
{_deliveryPosition!.latitude}&end=${_clientPosition!.longitude},$
{_clientPosition!.latitude}';
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final List<LatLng> route = [];
return route;
} else {
throw Exception('Failed to fetch new route');
}
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Center(
child: Stack(
children: [
_buildMap(),
_buildZoomButtons(),
_buildPharmaButton(),
_buildTrackPositionButton(),
Positioned(
top: 10,
left: 10,
child: Container(
padding: const EdgeInsets.all(8),
color: Colors.white.withOpacity(0.8),
child: Text(
_calculateDistanceAndTime(),
style: TextStyle(fontSize: 16, color: Colors.black),
),
),
),
],
),
),
);
}
Widget _buildMap() {
return FlutterMap(
mapController: mapController,
options: MapOptions(
center: _currentPosition != null
? LatLng(_currentPosition!.latitude, _currentPosition!.longitude)
: LatLng(6.1319, 1.2228),
zoom: 14.0,
minZoom: 12.0,
maxZoom: 18.0,
),
children: [
TileLayer(
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c'],
),
MarkerLayer(
markers: _buildMarkers(),
),
PolylineLayer(
polylines: [
Polyline(
points: _route,
color: Colors.blue,
strokeWidth: 4.0,
),
Polyline(
points: _newRoute,
color: Colors.cyanAccent,
strokeWidth: 4.0,
isDotted: true,
),
],
),
],
);
}
List<Marker> _buildMarkers() {
final List<Marker> markers = [];
if (_currentPosition != null) {
markers.add(
Marker(
point:
LatLng(_currentPosition!.latitude, _currentPosition!.longitude),
builder: (ctx) => Icon(Icons.person_pin_circle,
color: Colors.blue, size: defaultIconSize),
),
);
}
if (_deliveryPosition != null) {
markers.add(
Marker(
point: _deliveryPosition!,
builder: (ctx) => Icon(Icons.delivery_dining,
color: Colors.red, size: defaultIconSize),
),
);
}
return markers;
}
String _calculateDistanceAndTime() {
if (_deliveryPosition == null || _clientPosition == null) return '';
Widget _buildZoomButtons() {
return Positioned(
bottom: 10,
right: 5,
child: Column(
children: [
_buildIconButton(
icon: Icons.add,
onPressed: () {
mapController.move(mapController.center, mapController.zoom + 1);
},
),
const Gap(defaultSpacing),
_buildIconButton(
icon: Icons.remove,
onPressed: () {
mapController.move(mapController.center, mapController.zoom - 1);
},
),
],
),
);
}
Widget _buildPharmaButton() {
return Positioned(
bottom: 10,
left: 5,
child: _buildIconButton(
icon: Icons.home_work_outlined,
onPressed: () {
mapController.move(
_currentPosition != null
? LatLng(
_currentPosition!.latitude, _currentPosition!.longitude)
: LatLng(6.1319, 1.2228),
16.0,
);
},
),
);
}
Widget _buildTrackPositionButton() {
return Positioned(
top: 10,
right: 5,
child: _buildIconButton(
icon: Icons.my_location,
onPressed: () async {
Position position = await Geolocator.getCurrentPosition();
mapController.move(
LatLng(position.latitude, position.longitude),
16.0,
);
},
),
);
}
Widget _buildIconButton({
required IconData icon,
required VoidCallback onPressed,
}) {
return Container(
decoration: ShapeDecoration(
color: Colors.white.withOpacity(0.8),
shape: SmoothRectangleBorder(
side: const BorderSide(
color: accentColor,
width: 2,
),
borderRadius: SmoothBorderRadius(
cornerRadius: defaultRadius,
cornerSmoothing: 1,
),
),
),
child: IconButton(
color: accentColor,
onPressed: onPressed,
icon: Icon(icon),
),
);
}
}