236 lines
7.5 KiB
Dart
236 lines
7.5 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart' as mapbox;
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:geolocator/geolocator.dart' as geo;
|
|
|
|
import '../classes/alert.dart';
|
|
import '../variable/globals.dart' as globals;
|
|
import '../classes/MyDrawer.dart';
|
|
import '../classes/auth_service.dart';
|
|
|
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
|
import 'package:covas_mobile/gen_l10n/app_localizations.dart';
|
|
import 'package:provider/provider.dart';
|
|
import '../locale_provider.dart';
|
|
|
|
void main() async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
await dotenv.load(fileName: ".env");
|
|
|
|
// Set the access token globally
|
|
mapbox.MapboxOptions.setAccessToken(dotenv.env['MAPBOX_ACCESS_TOKEN'] ?? '');
|
|
|
|
runApp(const MyApp());
|
|
}
|
|
|
|
class MyApp extends StatelessWidget {
|
|
const MyApp({Key? key}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
title: 'Flutter Directions Example',
|
|
theme: ThemeData(primarySwatch: Colors.blue),
|
|
home: const MapboxPages(title: 'Event Location', place: "Flutter"),
|
|
);
|
|
}
|
|
}
|
|
|
|
class MapboxPages extends StatefulWidget {
|
|
const MapboxPages({Key? key, required this.title, required this.place})
|
|
: super(key: key);
|
|
|
|
final String title;
|
|
final String place;
|
|
|
|
@override
|
|
State<MapboxPages> createState() => _MapboxPagesState();
|
|
}
|
|
|
|
class _MapboxPagesState extends State<MapboxPages> with ShowAlertDialog {
|
|
final AuthService _authService = AuthService();
|
|
|
|
mapbox.MapboxMap? mapboxMap;
|
|
mapbox.PointAnnotationManager? pointAnnotationManager;
|
|
mapbox.PolylineAnnotationManager? polylineAnnotationManager;
|
|
|
|
double longitude = 0.0;
|
|
double latitude = 0.0;
|
|
bool isLoading = true;
|
|
mapbox.Point? userPosition;
|
|
bool isUserPositionInitialized = false;
|
|
|
|
String selectedMode = 'driving';
|
|
List<List<double>> routeCoordinates = [];
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_authService.checkTokenStatus(context);
|
|
_getUserLocation();
|
|
}
|
|
|
|
Future<void> _getEventInfo() async {
|
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
var accessToken = prefs.getString("access_token") ?? "";
|
|
|
|
if (accessToken.isNotEmpty) {
|
|
var urlGet = Uri.parse("${globals.api}/events/${widget.title}");
|
|
|
|
var responseGet = await http.get(urlGet,
|
|
headers: {HttpHeaders.cookieHeader: 'access_token=${accessToken}'});
|
|
if (responseGet.statusCode == 200) {
|
|
var events = jsonDecode(utf8.decode(responseGet.bodyBytes));
|
|
latitude = events["latitude"];
|
|
longitude = events["longitude"];
|
|
|
|
setState(() => isLoading = false);
|
|
} else {
|
|
_handleErrorResponse(responseGet.statusCode);
|
|
}
|
|
} else {
|
|
showAlertDialog(context, "Error", "Invalid cache.");
|
|
}
|
|
}
|
|
|
|
void _handleErrorResponse(int statusCode) {
|
|
final errorMessage = "Error $statusCode fetching event";
|
|
showAlertDialog(context, "Error", errorMessage);
|
|
}
|
|
|
|
Future<void> _getUserLocation() async {
|
|
await dotenv.load(fileName: ".env");
|
|
|
|
// Set the access token globally
|
|
mapbox.MapboxOptions.setAccessToken(
|
|
dotenv.env['MAPBOX_ACCESS_TOKEN'] ?? '');
|
|
try {
|
|
bool serviceEnabled = await geo.Geolocator.isLocationServiceEnabled();
|
|
if (!serviceEnabled) return;
|
|
|
|
geo.LocationPermission permission =
|
|
await geo.Geolocator.checkPermission();
|
|
if (permission == geo.LocationPermission.denied) {
|
|
permission = await geo.Geolocator.requestPermission();
|
|
}
|
|
|
|
if (permission == geo.LocationPermission.deniedForever) return;
|
|
|
|
geo.Position position = await geo.Geolocator.getCurrentPosition();
|
|
setState(() {
|
|
userPosition = mapbox.Point(
|
|
coordinates:
|
|
mapbox.Position(position.latitude, position.longitude));
|
|
isUserPositionInitialized = true;
|
|
});
|
|
|
|
_getEventInfo();
|
|
} catch (e) {
|
|
showAlertDialog(context, "Error", "Failed to get location");
|
|
}
|
|
}
|
|
|
|
Future<void> _fetchRoute(
|
|
mapbox.Point origin, mapbox.Point destination, String mode) async {
|
|
final url = Uri.parse(
|
|
'https://api.mapbox.com/directions/v5/mapbox/$mode/${origin.coordinates.lng},${origin.coordinates.lat};${destination.coordinates.lng},${destination.coordinates.lat}?geometries=geojson&access_token=${dotenv.env['MAPBOX_ACCESS_TOKEN']}',
|
|
);
|
|
|
|
final response = await http.get(url);
|
|
if (response.statusCode == 200) {
|
|
final data = jsonDecode(response.body);
|
|
final geometry = data['routes'][0]['geometry']['coordinates'];
|
|
setState(() {
|
|
routeCoordinates = (geometry as List)
|
|
.map<List<double>>((coord) => [coord[0], coord[1]])
|
|
.toList();
|
|
});
|
|
}
|
|
}
|
|
|
|
Future<void> _drawRouteAndMarkers() async {
|
|
if (mapboxMap == null || !isUserPositionInitialized) return;
|
|
|
|
// Managers
|
|
pointAnnotationManager ??=
|
|
await mapboxMap!.annotations.createPointAnnotationManager();
|
|
polylineAnnotationManager ??=
|
|
await mapboxMap!.annotations.createPolylineAnnotationManager();
|
|
|
|
// Clear old annotations
|
|
await pointAnnotationManager!.deleteAll();
|
|
await polylineAnnotationManager!.deleteAll();
|
|
|
|
final destination =
|
|
mapbox.Point(coordinates: mapbox.Position(longitude, latitude));
|
|
|
|
// Add user marker
|
|
final userIcon = await _loadMarkerImage('images/marker.png');
|
|
await pointAnnotationManager!.create(mapbox.PointAnnotationOptions(
|
|
geometry: mapbox.Point(
|
|
coordinates: mapbox.Position(
|
|
userPosition!.coordinates.lng, userPosition!.coordinates.lat)),
|
|
image: userIcon,
|
|
iconSize: 0.4,
|
|
));
|
|
|
|
// Add event marker
|
|
final eventIcon = await _loadMarkerImage('images/marker-red.png');
|
|
await pointAnnotationManager!.create(mapbox.PointAnnotationOptions(
|
|
geometry: mapbox.Point(
|
|
coordinates: mapbox.Position(
|
|
destination.coordinates.lng, destination.coordinates.lat)),
|
|
image: eventIcon,
|
|
iconSize: 0.4,
|
|
));
|
|
|
|
// Fetch and draw route
|
|
await _fetchRoute(userPosition!, destination, selectedMode);
|
|
if (routeCoordinates.isNotEmpty) {
|
|
await polylineAnnotationManager!.create(mapbox.PolylineAnnotationOptions(
|
|
geometry: mapbox.LineString(
|
|
coordinates:
|
|
routeCoordinates.map((c) => mapbox.Position(c[0], c[1])).toList(),
|
|
),
|
|
lineColor: Colors.blue.value,
|
|
lineWidth: 4.0,
|
|
));
|
|
}
|
|
}
|
|
|
|
Future<Uint8List> _loadMarkerImage(String assetPath) async {
|
|
final ByteData data = await rootBundle.load(assetPath);
|
|
return data.buffer.asUint8List();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(title: Text(widget.place)),
|
|
drawer: MyDrawer(),
|
|
body: isLoading
|
|
? const Center(child: CircularProgressIndicator())
|
|
: mapbox.MapWidget(
|
|
onMapCreated: (controller) {
|
|
mapboxMap = controller;
|
|
},
|
|
cameraOptions: mapbox.CameraOptions(
|
|
center: mapbox.Point(
|
|
coordinates: mapbox.Position(longitude, latitude)),
|
|
zoom: 14.0,
|
|
),
|
|
),
|
|
floatingActionButton: FloatingActionButton(
|
|
onPressed: _drawRouteAndMarkers,
|
|
child: const Icon(Icons.directions),
|
|
),
|
|
);
|
|
}
|
|
}
|