gebeta_gl 0.22.2
gebeta_gl: ^0.22.2 copied to clipboard
A Flutter plugin for integrating MapLibre Maps inside a Flutter application on Android, iOS and web platforms.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show Uint8List, rootBundle;
import 'package:gebeta_gl/gebeta_gl.dart';
import 'dart:async';
// Location model to store pickup/dropoff points
class Location {
final String name;
final LatLng coordinates;
Location(this.name, this.coordinates);
}
// Simulated location stream for demo purposes
class LocationStream {
final _controller = StreamController<LatLng>.broadcast();
Timer? _timer;
bool _isTracking = false;
LatLng _currentLocation;
final List<LatLng> _routePoints;
int _currentPointIndex = 0;
LocationStream(this._currentLocation, this._routePoints);
Stream<LatLng> get stream => _controller.stream;
void startTracking() {
if (_isTracking) return;
_isTracking = true;
_timer = Timer.periodic(Duration(seconds: 2), (timer) {
if (_currentPointIndex < _routePoints.length) {
_currentLocation = _routePoints[_currentPointIndex];
_controller.add(_currentLocation);
_currentPointIndex++;
} else {
stopTracking();
}
});
}
void stopTracking() {
_isTracking = false;
_timer?.cancel();
_currentPointIndex = 0;
}
void dispose() {
_timer?.cancel();
_controller.close();
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Gebeta Maps Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Gebeta maps Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// Your API key
final String apiKey = 'your-api-key';
// Store selected locations
Location? pickupLocation;
Location? dropoffLocation;
GebetaMapController? mapController;
String? styleString;
LocationStream? locationStream;
bool isTracking = false;
LatLng? currentLocation;
// Predefined locations (example points in Addis Ababa)
final List<Location> availableLocations = [
Location('Bole Airport', LatLng(8.9777, 38.7993)),
Location('Meskel Square', LatLng(9.0327, 38.7617)),
Location('Addis Ababa University', LatLng(9.0407, 38.7637)),
Location('Ethiopian National Museum', LatLng(9.0327, 38.7617)),
Location('Unity Park', LatLng(9.0327, 38.7617)),
];
@override
void initState() {
super.initState();
loadMapStyle().then((style) {
setState(() {
styleString = style;
});
});
}
@override
void dispose() {
locationStream?.dispose();
super.dispose();
}
// Function to load the map style
Future<String> loadMapStyle() async {
return await rootBundle.loadString('assets/styles/basic.json');
}
Future<Uint8List> loadMarkerImage() async {
var byteData = await rootBundle.load("assets/marker-black.png");
return byteData.buffer.asUint8List();
}
Future<Uint8List> loadCurrentLocationMarkerImage() async {
var byteData = await rootBundle.load("assets/marker-orange.png");
return byteData.buffer.asUint8List();
}
void onMapCreated(GebetaMapController controller) async {
// grab the controller on map created
mapController = controller;
// add marker image maybe
var markerImage = await loadMarkerImage();
var currentLocationMarkerImage = await loadCurrentLocationMarkerImage();
controller.addImage('marker', markerImage);
controller.addImage('current_location', currentLocationMarkerImage);
}
void updateLocations() {
if (mapController == null) return;
// Clear existing markers and lines
mapController!.clearSymbols();
mapController!.clearLines();
// Add pickup marker if selected
if (pickupLocation != null) {
mapController!.addSymbol(
SymbolOptions(
iconSize: 2,
iconImage: "marker",
iconAnchor: "bottom",
geometry: pickupLocation!.coordinates,
),
);
}
// Add dropoff marker if selected
if (dropoffLocation != null) {
mapController!.addSymbol(
SymbolOptions(
iconSize: 2,
iconImage: "marker",
iconAnchor: "bottom",
geometry: dropoffLocation!.coordinates,
),
);
}
// Add current location marker if tracking
if (currentLocation != null) {
mapController!.addSymbol(
SymbolOptions(
iconSize: 2,
iconImage: "current_location",
iconAnchor: "bottom",
geometry: currentLocation!,
),
);
}
// Draw line between pickup and dropoff if both are selected
if (pickupLocation != null && dropoffLocation != null) {
mapController!.addLine(
LineOptions(
lineColor: '#FF0000',
lineWidth: 2,
geometry: [
pickupLocation!.coordinates,
dropoffLocation!.coordinates,
],
),
);
}
}
void startTracking() {
if (pickupLocation == null || dropoffLocation == null) return;
// Create a simulated route between pickup and dropoff
final routePoints = [
pickupLocation!.coordinates,
LatLng(
(pickupLocation!.coordinates.latitude + dropoffLocation!.coordinates.latitude) / 2,
(pickupLocation!.coordinates.longitude + dropoffLocation!.coordinates.longitude) / 2,
),
dropoffLocation!.coordinates,
];
locationStream?.dispose();
locationStream = LocationStream(pickupLocation!.coordinates, routePoints);
locationStream!.stream.listen((location) {
setState(() {
currentLocation = location;
updateLocations();
});
});
locationStream!.startTracking();
setState(() {
isTracking = true;
});
}
void stopTracking() {
locationStream?.stopTracking();
setState(() {
isTracking = false;
currentLocation = null;
updateLocations();
});
}
// Clear all markers and lines
void clearMap() {
if (mapController == null) return;
stopTracking();
mapController!.clearSymbols();
mapController!.clearLines();
setState(() {
pickupLocation = null;
dropoffLocation = null;
currentLocation = null;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: styleString == null
? Center(child: CircularProgressIndicator())
: Stack(
children: [
GebetaMap(
compassViewPosition: CompassViewPosition.topRight,
styleString: styleString!,
initialCameraPosition: CameraPosition(
target: LatLng(9.0192, 38.7525), // Addis Ababa
zoom: 10.0,
),
onMapCreated: onMapCreated,
apiKey: apiKey,
),
Positioned(
top: 16,
right: 16,
child: Row(
children: [
if (pickupLocation != null && dropoffLocation != null)
ElevatedButton.icon(
onPressed: isTracking ? stopTracking : startTracking,
icon: Icon(isTracking ? Icons.stop : Icons.play_arrow),
label: Text(isTracking ? 'Stop' : 'Start'),
style: ElevatedButton.styleFrom(
backgroundColor: isTracking ? Colors.red : Colors.green,
foregroundColor: Colors.white,
elevation: 2,
),
),
SizedBox(width: 8),
ElevatedButton.icon(
onPressed: clearMap,
icon: Icon(Icons.clear),
label: Text('Clear'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.black87,
elevation: 2,
),
),
],
),
),
Positioned(
bottom: 16,
left: 16,
right: 16,
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
offset: Offset(0, 4),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Select Route',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
SizedBox(height: 16),
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Pickup Location',
style: TextStyle(
fontSize: 14,
color: Colors.black54,
),
),
SizedBox(height: 8),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(8),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<Location>(
value: pickupLocation,
hint: Text('Select pickup'),
isExpanded: true,
padding: EdgeInsets.symmetric(horizontal: 12),
items: availableLocations.map((Location location) {
return DropdownMenuItem<Location>(
value: location,
child: Text(location.name),
);
}).toList(),
onChanged: (Location? newValue) {
setState(() {
pickupLocation = newValue;
updateLocations();
});
},
),
),
),
],
),
),
SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Dropoff Location',
style: TextStyle(
fontSize: 14,
color: Colors.black54,
),
),
SizedBox(height: 8),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(8),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<Location>(
value: dropoffLocation,
hint: Text('Select dropoff'),
isExpanded: true,
padding: EdgeInsets.symmetric(horizontal: 12),
items: availableLocations.map((Location location) {
return DropdownMenuItem<Location>(
value: location,
child: Text(location.name),
);
}).toList(),
onChanged: (Location? newValue) {
setState(() {
dropoffLocation = newValue;
updateLocations();
});
},
),
),
),
],
),
),
],
),
],
),
),
),
],
),
);
}
}