flutter_polyline_points 3.1.0 copy "flutter_polyline_points: ^3.1.0" to clipboard
flutter_polyline_points: ^3.1.0 copied to clipboard

A flutter package to get polyline points by either passing the coordinates or google encoded polyline string

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

import 'package:flutter_polyline_points/flutter_polyline_points.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Polyline Points Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      home: const MainScreen(),
    );
  }
}

class MainScreen extends StatefulWidget {
  const MainScreen({super.key});

  @override
  MainScreenState createState() {
    return MainScreenState();
  }
}

class MainScreenState extends State<MainScreen> with TickerProviderStateMixin {
  late TabController _tabController;
  String googleApiKey =
      "YOUR_GOOGLE_API_KEY_HERE"; // Replace with your actual API key

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 4, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Polyline Points'),
        bottom: TabBar(
          controller: _tabController,
          tabs: const [
            Tab(text: 'Legacy API', icon: Icon(Icons.route)),
            Tab(text: 'Routes API', icon: Icon(Icons.alt_route)),
            Tab(text: 'Two-Wheeler', icon: Icon(Icons.motorcycle)),
            Tab(text: 'Headers', icon: Icon(Icons.security)),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          LegacyMapScreen(apiKey: googleApiKey),
          RoutesApiMapScreen(apiKey: googleApiKey),
          TwoWheelerMapScreen(apiKey: googleApiKey),
          CustomHeadersMapScreen(apiKey: googleApiKey),
        ],
      ),
    );
  }
}

// Legacy API Example (Backward Compatibility)
class LegacyMapScreen extends StatefulWidget {
  final String apiKey;

  const LegacyMapScreen({super.key, required this.apiKey});

  @override
  LegacyMapScreenState createState() => LegacyMapScreenState();
}

class LegacyMapScreenState extends State<LegacyMapScreen> {
  late GoogleMapController mapController;
  final double _originLatitude = 6.5212402, _originLongitude = 3.3679965;
  final double _destLatitude = 6.849660, _destLongitude = 3.648190;
  Map<MarkerId, Marker> markers = {};
  Map<PolylineId, Polyline> polylines = {};
  List<LatLng> polylineCoordinates = [];
  late PolylinePoints polylinePoints;
  bool isLoading = false;
  String? errorMessage;

  @override
  void initState() {
    super.initState();
    polylinePoints = PolylinePoints(apiKey: widget.apiKey);

    _addMarker(LatLng(_originLatitude, _originLongitude), "origin",
        BitmapDescriptor.defaultMarker);
    _addMarker(LatLng(_destLatitude, _destLongitude), "destination",
        BitmapDescriptor.defaultMarkerWithHue(90));

    _getPolyline();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          GoogleMap(
            initialCameraPosition: CameraPosition(
                target: LatLng(_originLatitude, _originLongitude), zoom: 12),
            myLocationEnabled: true,
            tiltGesturesEnabled: true,
            compassEnabled: true,
            scrollGesturesEnabled: true,
            zoomGesturesEnabled: true,
            onMapCreated: _onMapCreated,
            markers: Set<Marker>.of(markers.values),
            polylines: Set<Polyline>.of(polylines.values),
          ),
          if (isLoading)
            Container(
              color: Colors.black26,
              child: const Center(
                child: CircularProgressIndicator(),
              ),
            ),
          if (errorMessage != null)
            Positioned(
              top: 16,
              left: 16,
              right: 16,
              child: Card(
                color: Colors.red[100],
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Text(
                    'Error: $errorMessage',
                    style: TextStyle(color: Colors.red[800]),
                  ),
                ),
              ),
            ),
          Positioned(
            bottom: 16,
            left: 16,
            right: 16,
            child: Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Text(
                      'Legacy Directions API',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 8),
                    Text(
                      'Using the original Google Directions API with basic routing features.',
                      style: Theme.of(context).textTheme.bodySmall,
                      textAlign: TextAlign.center,
                    ),
                    const SizedBox(height: 8),
                    ElevatedButton(
                      onPressed: _getPolyline,
                      child: const Text('Refresh Route'),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  void _onMapCreated(GoogleMapController controller) async {
    mapController = controller;
  }

  _addMarker(LatLng position, String id, BitmapDescriptor descriptor) {
    MarkerId markerId = MarkerId(id);
    Marker marker =
        Marker(markerId: markerId, icon: descriptor, position: position);
    markers[markerId] = marker;
  }

  _addPolyLine() {
    PolylineId id = const PolylineId("poly");
    Polyline polyline = Polyline(
        polylineId: id,
        color: Colors.blue,
        points: polylineCoordinates,
        width: 5);
    polylines[id] = polyline;
    setState(() {});
  }

  _getPolyline() async {
    setState(() {
      isLoading = true;
      errorMessage = null;
      polylineCoordinates.clear();
      polylines.clear();
    });

    try {
      final result = await polylinePoints.getRouteBetweenCoordinatesV2(
        request: RoutesApiRequest(
          origin: PointLatLng(_originLatitude, _originLongitude),
          destination: PointLatLng(_destLatitude, _destLongitude),
        ),
      );

      if (result.primaryRoute?.polylinePoints case List<PointLatLng> points) {
        for (var point in points) {
          polylineCoordinates.add(LatLng(point.latitude, point.longitude));
        }
        _addPolyLine();
      } else {
        setState(() {
          errorMessage = result.errorMessage ?? 'No route found';
        });
      }
    } catch (e) {
      setState(() {
        errorMessage = e.toString();
      });
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }
}

// Custom Headers Example (Android-restricted API keys)
class CustomHeadersMapScreen extends StatefulWidget {
  final String apiKey;

  const CustomHeadersMapScreen({super.key, required this.apiKey});

  @override
  CustomHeadersMapScreenState createState() => CustomHeadersMapScreenState();
}

class CustomHeadersMapScreenState extends State<CustomHeadersMapScreen> {
  late GoogleMapController mapController;
  final double _originLatitude = 6.5212402, _originLongitude = 3.3679965;
  final double _destLatitude = 6.849660, _destLongitude = 3.648190;
  Map<MarkerId, Marker> markers = {};
  Map<PolylineId, Polyline> polylines = {};
  late PolylinePoints polylinePoints;
  bool isLoading = false;
  String? errorMessage;
  RoutesApiResponse? currentResponse;

  // Custom headers for Android-restricted API keys
  final TextEditingController _packageNameController = TextEditingController();
  final TextEditingController _certFingerprintController =
      TextEditingController();
  bool _useCustomHeaders = false;

  @override
  void initState() {
    super.initState();
    polylinePoints = PolylinePoints.enhanced(widget.apiKey);
    _addMarker(LatLng(_originLatitude, _originLongitude), "origin",
        BitmapDescriptor.defaultMarker);
    _addMarker(LatLng(_destLatitude, _destLongitude), "destination",
        BitmapDescriptor.defaultMarkerWithHue(90));

    // Set default values for demonstration
    _packageNameController.text = 'com.example.myapp';
    _certFingerprintController.text = 'YOUR_SHA1_FINGERPRINT';
  }

  @override
  void dispose() {
    _packageNameController.dispose();
    _certFingerprintController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          GoogleMap(
            initialCameraPosition: CameraPosition(
                target: LatLng(_originLatitude, _originLongitude), zoom: 12),
            myLocationEnabled: true,
            tiltGesturesEnabled: true,
            compassEnabled: true,
            scrollGesturesEnabled: true,
            zoomGesturesEnabled: true,
            onMapCreated: _onMapCreated,
            markers: Set<Marker>.of(markers.values),
            polylines: Set<Polyline>.of(polylines.values),
          ),
          if (isLoading)
            Container(
              color: Colors.black26,
              child: const Center(
                child: CircularProgressIndicator(),
              ),
            ),
          if (errorMessage != null)
            Positioned(
              top: 16,
              left: 16,
              right: 16,
              child: Card(
                color: Colors.red[100],
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Text(
                    'Error: $errorMessage',
                    style: TextStyle(color: Colors.red[800]),
                  ),
                ),
              ),
            ),
          Positioned(
            bottom: 16,
            left: 16,
            right: 16,
            child: Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Row(
                      children: [
                        const Icon(Icons.security, color: Colors.purple),
                        const SizedBox(width: 8),
                        Text(
                          'Custom Headers Demo',
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                      ],
                    ),
                    const SizedBox(height: 8),
                    Text(
                      'Demonstrates using custom headers for Android-restricted API keys.',
                      style: Theme.of(context).textTheme.bodySmall,
                      textAlign: TextAlign.center,
                    ),
                    const SizedBox(height: 8),
                    CheckboxListTile(
                      title: const Text('Use Custom Headers',
                          style: TextStyle(fontSize: 14)),
                      subtitle: const Text('For Android-restricted API keys',
                          style: TextStyle(fontSize: 12)),
                      value: _useCustomHeaders,
                      onChanged: (value) {
                        setState(() {
                          _useCustomHeaders = value ?? false;
                        });
                      },
                      dense: true,
                    ),
                    if (_useCustomHeaders) ..._buildHeaderInputs(),
                    const SizedBox(height: 8),
                    ElevatedButton.icon(
                      onPressed: _getRouteWithHeaders,
                      icon: const Icon(Icons.security),
                      label: const Text('Get Route with Headers'),
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.purple,
                        foregroundColor: Colors.white,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  List<Widget> _buildHeaderInputs() {
    return [
      const SizedBox(height: 8),
      TextField(
        controller: _packageNameController,
        decoration: const InputDecoration(
          labelText: 'Package Name',
          hintText: 'com.example.myapp',
          border: OutlineInputBorder(),
        ),
        style: const TextStyle(fontSize: 12),
      ),
      const SizedBox(height: 8),
      TextField(
        controller: _certFingerprintController,
        decoration: const InputDecoration(
          labelText: 'SHA1 Fingerprint',
          hintText: 'YOUR_SHA1_FINGERPRINT',
          border: OutlineInputBorder(),
        ),
        style: const TextStyle(fontSize: 12),
      ),
    ];
  }

  void _onMapCreated(GoogleMapController controller) async {
    mapController = controller;
  }

  _addMarker(LatLng position, String id, BitmapDescriptor descriptor) {
    MarkerId markerId = MarkerId(id);
    Marker marker =
        Marker(markerId: markerId, icon: descriptor, position: position);
    markers[markerId] = marker;
  }

  _addPolyLine(List<LatLng> coordinates) {
    PolylineId id = const PolylineId("poly");
    Polyline polyline = Polyline(
        polylineId: id, color: Colors.purple, points: coordinates, width: 5);
    polylines[id] = polyline;
    setState(() {});
  }

  _getRouteWithHeaders() async {
    setState(() {
      isLoading = true;
      errorMessage = null;
      polylines.clear();
      currentResponse = null;
    });

    try {
      // Prepare custom headers if enabled
      Map<String, String>? customHeaders;
      if (_useCustomHeaders) {
        customHeaders = {
          'X-Android-Package': _packageNameController.text.trim(),
          'X-Android-Cert': _certFingerprintController.text.trim(),
        };
      }

      RoutesApiResponse response =
          await polylinePoints.getRouteBetweenCoordinatesV2(
        request: RoutesApiRequest(
          origin: PointLatLng(_originLatitude, _originLongitude),
          destination: PointLatLng(_destLatitude, _destLongitude),
          travelMode: TravelMode.driving,
          headers: customHeaders, // Pass custom headers
        ),
      );

      setState(() {
        currentResponse = response;
      });

      if (response.routes.isNotEmpty) {
        final route = response.routes.first;
        if (route.polylinePoints != null) {
          final points = polylinePoints.convertToLegacyResult(response).points;
          final coordinates = points
              .map((point) => LatLng(point.latitude, point.longitude))
              .toList();
          _addPolyLine(coordinates);
        }
      } else {
        setState(() {
          errorMessage = response.errorMessage ?? 'No route found';
        });
      }
    } catch (e) {
      setState(() {
        errorMessage = e.toString();
      });
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }
}

// Routes API Example (Enhanced Features)
class RoutesApiMapScreen extends StatefulWidget {
  final String apiKey;

  const RoutesApiMapScreen({super.key, required this.apiKey});

  @override
  RoutesApiMapScreenState createState() => RoutesApiMapScreenState();
}

class RoutesApiMapScreenState extends State<RoutesApiMapScreen> {
  late GoogleMapController mapController;
  final double _originLatitude = 6.5212402, _originLongitude = 3.3679965;
  final double _destLatitude = 6.849660, _destLongitude = 3.648190;
  Map<MarkerId, Marker> markers = {};
  Map<PolylineId, Polyline> polylines = {};
  List<LatLng> polylineCoordinates = [];
  late PolylinePoints polylinePoints;
  bool isLoading = false;
  String? errorMessage;
  RoutesApiResponse? currentResponse;

  @override
  void initState() {
    super.initState();
    polylinePoints = PolylinePoints.enhanced(widget.apiKey);
    _addMarker(LatLng(_originLatitude, _originLongitude), "origin",
        BitmapDescriptor.defaultMarker);
    _addMarker(LatLng(_destLatitude, _destLongitude), "destination",
        BitmapDescriptor.defaultMarkerWithHue(90));
    _getEnhancedRoute();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          GoogleMap(
            initialCameraPosition: CameraPosition(
                target: LatLng(_originLatitude, _originLongitude), zoom: 12),
            myLocationEnabled: true,
            tiltGesturesEnabled: true,
            compassEnabled: true,
            scrollGesturesEnabled: true,
            zoomGesturesEnabled: true,
            onMapCreated: _onMapCreated,
            markers: Set<Marker>.of(markers.values),
            polylines: Set<Polyline>.of(polylines.values),
          ),
          if (isLoading)
            Container(
              color: Colors.black26,
              child: const Center(
                child: CircularProgressIndicator(),
              ),
            ),
          if (errorMessage != null)
            Positioned(
              top: 16,
              left: 16,
              right: 16,
              child: Card(
                color: Colors.red[100],
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Text(
                    'Error: $errorMessage',
                    style: TextStyle(color: Colors.red[800]),
                  ),
                ),
              ),
            ),
          Positioned(
            bottom: 16,
            left: 16,
            right: 16,
            child: Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Text(
                      'Enhanced Routes API',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 8),
                    Text(
                      'Using the new Google Routes API with traffic-aware routing, toll information, and enhanced features.',
                      style: Theme.of(context).textTheme.bodySmall,
                      textAlign: TextAlign.center,
                    ),
                    if (currentResponse != null &&
                        currentResponse!.routes.isNotEmpty)
                      ..._buildRouteInfo(),
                    const SizedBox(height: 8),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        ElevatedButton(
                          onPressed: _getEnhancedRoute,
                          child: const Text('Enhanced Route'),
                        ),
                        ElevatedButton(
                          onPressed: _getAlternativeRoutes,
                          child: const Text('Alternatives'),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  List<Widget> _buildRouteInfo() {
    final route = currentResponse!.routes.first;
    return [
      const SizedBox(height: 8),
      Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          Column(
            children: [
              const Text('Duration',
                  style: TextStyle(fontWeight: FontWeight.bold)),
              Text(route.duration?.toString() ?? 'N/A'),
            ],
          ),
          Column(
            children: [
              const Text('Distance',
                  style: TextStyle(fontWeight: FontWeight.bold)),
              Text(route.distanceMeters != null
                  ? '${(route.distanceMeters! / 1000).toStringAsFixed(1)} km'
                  : 'N/A'),
            ],
          ),
        ],
      ),
    ];
  }

  void _onMapCreated(GoogleMapController controller) async {
    mapController = controller;
  }

  _addMarker(LatLng position, String id, BitmapDescriptor descriptor) {
    MarkerId markerId = MarkerId(id);
    Marker marker =
        Marker(markerId: markerId, icon: descriptor, position: position);
    markers[markerId] = marker;
  }

  _addPolyLine(List<LatLng> coordinates,
      {Color color = Colors.green, String id = "poly"}) {
    PolylineId polylineId = PolylineId(id);
    Polyline polyline = Polyline(
        polylineId: polylineId, color: color, points: coordinates, width: 5);
    polylines[polylineId] = polyline;
    setState(() {});
  }

  _getEnhancedRoute() async {
    setState(() {
      isLoading = true;
      errorMessage = null;
      polylineCoordinates.clear();
      polylines.clear();
      currentResponse = null;
    });

    try {
      RoutesApiResponse response =
          await polylinePoints.getRouteBetweenCoordinatesV2(
              request: RequestConverter.createEnhancedRequest(
        origin: PointLatLng(_originLatitude, _originLongitude),
        destination: PointLatLng(_destLatitude, _destLongitude),
      ));

      setState(() {
        currentResponse = response;
      });

      if (response.routes.isNotEmpty) {
        final route = response.routes.first;
        if (route.polylinePoints != null) {
          final points = polylinePoints.convertToLegacyResult(response).points;
          final coordinates = points
              .map((point) => LatLng(point.latitude, point.longitude))
              .toList();
          _addPolyLine(coordinates, color: Colors.green);
        }
      } else {
        setState(() {
          errorMessage = response.errorMessage ?? 'No route found';
        });
      }
    } catch (e) {
      setState(() {
        errorMessage = e.toString();
      });
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }

  _getAlternativeRoutes() async {
    setState(() {
      isLoading = true;
      errorMessage = null;
      polylines.clear();
      currentResponse = null;
    });

    try {
      RoutesApiResponse response =
          await polylinePoints.getRouteBetweenCoordinatesV2(
              request: RequestConverter.createEnhancedRequest(
        origin: PointLatLng(_originLatitude, _originLongitude),
        destination: PointLatLng(_destLatitude, _destLongitude),
        waypoints: [PolylineWayPoint(location: "Sabo, Yaba Lagos Nigeria")],
        alternatives: true,
        extraComputations: [ExtraComputation.fuelConsumption],
      ));

      setState(() {
        currentResponse = response;
      });

      if (response.routes.isNotEmpty) {
        final colors = [Colors.green, Colors.blue, Colors.orange];
        for (int i = 0; i < response.routes.length && i < colors.length; i++) {
          final route = response.routes[i];
          if (route.polylinePoints != null) {
            final coordinates = route.polylinePoints!
                .map((point) => LatLng(point.latitude, point.longitude))
                .toList();
            _addPolyLine(coordinates, color: colors[i], id: "poly_$i");
          }
        }
      } else {
        setState(() {
          errorMessage = response.errorMessage ?? 'No routes found';
        });
      }
    } catch (e) {
      setState(() {
        errorMessage = e.toString();
      });
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }
}

// Two-Wheeler Example (Routes API Exclusive Feature)
class TwoWheelerMapScreen extends StatefulWidget {
  final String apiKey;

  const TwoWheelerMapScreen({super.key, required this.apiKey});

  @override
  TwoWheelerMapScreenState createState() => TwoWheelerMapScreenState();
}

class TwoWheelerMapScreenState extends State<TwoWheelerMapScreen> {
  late GoogleMapController mapController;
  final double _originLatitude = 6.5212402, _originLongitude = 3.3679965;
  final double _destLatitude = 6.849660, _destLongitude = 3.648190;
  Map<MarkerId, Marker> markers = {};
  Map<PolylineId, Polyline> polylines = {};
  late PolylinePoints polylinePointsV2;
  bool isLoading = false;
  String? errorMessage;
  RoutesApiResponse? currentResponse;
  bool avoidHighways = false;
  bool avoidTolls = false;

  @override
  void initState() {
    super.initState();
    polylinePointsV2 = PolylinePoints.enhanced(widget.apiKey);
    _addMarker(LatLng(_originLatitude, _originLongitude), "origin",
        BitmapDescriptor.defaultMarker);
    _addMarker(LatLng(_destLatitude, _destLongitude), "destination",
        BitmapDescriptor.defaultMarkerWithHue(90));
    _getTwoWheelerRoute();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          GoogleMap(
            initialCameraPosition: CameraPosition(
                target: LatLng(_originLatitude, _originLongitude), zoom: 12),
            myLocationEnabled: true,
            tiltGesturesEnabled: true,
            compassEnabled: true,
            scrollGesturesEnabled: true,
            zoomGesturesEnabled: true,
            onMapCreated: _onMapCreated,
            markers: Set<Marker>.of(markers.values),
            polylines: Set<Polyline>.of(polylines.values),
          ),
          if (isLoading)
            Container(
              color: Colors.black26,
              child: const Center(
                child: CircularProgressIndicator(),
              ),
            ),
          if (errorMessage != null)
            Positioned(
              top: 16,
              left: 16,
              right: 16,
              child: Card(
                color: Colors.red[100],
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Text(
                    'Error: $errorMessage',
                    style: TextStyle(color: Colors.red[800]),
                  ),
                ),
              ),
            ),
          Positioned(
            bottom: 16,
            left: 16,
            right: 16,
            child: Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Row(
                      children: [
                        const Icon(Icons.motorcycle, color: Colors.orange),
                        const SizedBox(width: 8),
                        Text(
                          'Two-Wheeler Routing',
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                      ],
                    ),
                    const SizedBox(height: 8),
                    Text(
                      'Optimized routing for motorcycles and scooters. This feature is exclusive to the Routes API.',
                      style: Theme.of(context).textTheme.bodySmall,
                      textAlign: TextAlign.center,
                    ),
                    const SizedBox(height: 8),
                    Row(
                      children: [
                        Expanded(
                          child: CheckboxListTile(
                            title: const Text('Avoid Highways',
                                style: TextStyle(fontSize: 12)),
                            value: avoidHighways,
                            onChanged: (value) {
                              setState(() {
                                avoidHighways = value ?? false;
                              });
                              _getTwoWheelerRoute();
                            },
                            dense: true,
                          ),
                        ),
                        Expanded(
                          child: CheckboxListTile(
                            title: const Text('Avoid Tolls',
                                style: TextStyle(fontSize: 12)),
                            value: avoidTolls,
                            onChanged: (value) {
                              setState(() {
                                avoidTolls = value ?? false;
                              });
                              _getTwoWheelerRoute();
                            },
                            dense: true,
                          ),
                        ),
                      ],
                    ),
                    if (currentResponse != null &&
                        currentResponse!.routes.isNotEmpty)
                      ..._buildRouteInfo(),
                    const SizedBox(height: 8),
                    ElevatedButton.icon(
                      onPressed: _getTwoWheelerRoute,
                      icon: const Icon(Icons.motorcycle),
                      label: const Text('Get Two-Wheeler Route'),
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.orange,
                        foregroundColor: Colors.white,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  List<Widget> _buildRouteInfo() {
    final route = currentResponse!.routes.first;
    return [
      const SizedBox(height: 8),
      Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          Column(
            children: [
              const Text('Duration',
                  style: TextStyle(fontWeight: FontWeight.bold)),
              Text(route.duration?.toString() ?? 'N/A'),
            ],
          ),
          Column(
            children: [
              const Text('Distance',
                  style: TextStyle(fontWeight: FontWeight.bold)),
              Text(route.distanceMeters != null
                  ? '${(route.distanceMeters! / 1000).toStringAsFixed(1)} km'
                  : 'N/A'),
            ],
          ),
        ],
      ),
    ];
  }

  void _onMapCreated(GoogleMapController controller) async {
    mapController = controller;
  }

  _addMarker(LatLng position, String id, BitmapDescriptor descriptor) {
    MarkerId markerId = MarkerId(id);
    Marker marker =
        Marker(markerId: markerId, icon: descriptor, position: position);
    markers[markerId] = marker;
  }

  _addPolyLine(List<LatLng> coordinates) {
    PolylineId id = const PolylineId("poly");
    Polyline polyline = Polyline(
        polylineId: id, color: Colors.orange, points: coordinates, width: 5);
    polylines[id] = polyline;
    setState(() {});
  }

  _getTwoWheelerRoute() async {
    setState(() {
      isLoading = true;
      errorMessage = null;
      polylines.clear();
      currentResponse = null;
    });

    try {
      RoutesApiResponse response =
          await polylinePointsV2.getRouteBetweenCoordinatesV2(
              request: RequestConverter.createEnhancedRequest(
        origin: PointLatLng(_originLatitude, _originLongitude),
        destination: PointLatLng(_destLatitude, _destLongitude),
        travelMode: TravelMode.twoWheeler,
      ));

      setState(() {
        currentResponse = response;
      });

      if (response.routes.isNotEmpty) {
        final route = response.routes.first;
        if (route.polylinePoints != null) {
          final points =
              polylinePointsV2.convertToLegacyResult(response).points;
          final coordinates = points
              .map((point) => LatLng(point.latitude, point.longitude))
              .toList();
          _addPolyLine(coordinates);
        }
      } else {
        setState(() {
          errorMessage = response.errorMessage ?? 'No route found';
        });
      }
    } catch (e) {
      setState(() {
        errorMessage = e.toString();
      });
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }
}
637
likes
150
points
59.5k
downloads

Publisher

verified publishercraftme.dev

Weekly Downloads

A flutter package to get polyline points by either passing the coordinates or google encoded polyline string

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, http

More

Packages that depend on flutter_polyline_points