eopeter / flutter_mapbox_navigation

Turn By Turn Navigation for Your Flutter Application
Apache License 2.0
217 stars 186 forks source link

Navigation Mode for Buses #343

Closed Kashif-Asghar60 closed 9 months ago

Kashif-Asghar60 commented 9 months ago

Is MapBoxNavigationMode.drivingWithTraffic suitable for buses? I need to navigate routes that are bus-friendly, but it seems the plugin currently lacks support for this.

Kashif-Asghar60 commented 9 months ago

Solved

To use Mapbox Navigation for bus and custom routes, :

Directions API Playground: Explore and test different outputs using the Directions API Playground

https://docs.mapbox.com/playground/directions/?profile=driving-traffic&maxHeight=9.3&maxWidth=9&maxWeight=13.5&exclude=motorway&alternatives=false

Request URL for Customized Data:

Adjust parameters to customize your request and obtain route data from the following URL: '$apiUrl/$origin;$destination?approaches=curb;curb&exclude=motorway,toll&steps=true&access_token=$apiKey';

Fetch Method from API

 Future<void> initialize() async {
  // Set up MapBoxOptions
  _navigationOption = MapBoxOptions(
    initialLatitude: widget.userLAT,
    initialLongitude: widget.userLNG,
    zoom: 10.0,
    tilt: 0.0,
    bearing: 0.0,
    enableRefresh: true,
    alternatives: true,
    voiceInstructionsEnabled: true,
    bannerInstructionsEnabled: true,
    mode: MapBoxNavigationMode.driving, // Change mode if needed
    simulateRoute: true,
    language: 'en',
  );

  // Register route event listener
  MapBoxNavigation.instance.registerRouteEventListener(_onEmbeddedRouteEvent);
  // Set default options
  MapBoxNavigation.instance.setDefaultOptions(_navigationOption);

  // Construct request URL for directions API
  final apiKey = "YOUR_MAPBOX_API_KEY";
  final apiUrl = 'https://api.mapbox.com/directions/v5/mapbox/driving';
  final origin = '${widget.userLNG},${widget.userLAT}';
  final destination = '${widget.destinationLNG},${widget.destinationLAT}';
  final requestUrl =
      '$apiUrl/$origin;$destination?approaches=curb;curb&exclude=motorway,toll&steps=true&access_token=$apiKey';

  try {
    final response = await http.get(Uri.parse(requestUrl));

    if (response.statusCode == 200) {
      // Parse response and extract routes
      final data = json.decode(response.body);
      final List<dynamic> routes = data['routes'];

      if (routes.isNotEmpty) {
        // Extract legs and waypoints from route
        final route = routes[0];
        final List<dynamic>? legs = route['legs'];

        if (legs != null && legs.isNotEmpty) {
          final List<WayPoint> wayPoints = [];

          // Iterate through legs to create waypoints
          for (var leg in legs) {
            final WayPoint start = WayPoint(
              name: "Start",
              latitude: leg['steps'][0]['maneuver']['location'][1],
              longitude: leg['steps'][0]['maneuver']['location'][0],
            );

            final WayPoint end = WayPoint(
              name: "End",
              latitude: leg['steps'][leg['steps'].length - 1]['maneuver']['location'][1],
              longitude: leg['steps'][leg['steps'].length - 1]['maneuver']['location'][0],
            );

            wayPoints.add(start);
            wayPoints.add(end);
          }

          // Start navigation with generated waypoints
          MapBoxNavigation.instance.registerRouteEventListener(_onEmbeddedRouteEvent);
          getwayPoints = wayPoints;
          startNavigation();
        } else {
          print('No legs found in the route');
        }
      } else {
        print('No routes found');
      }
    } else {
      print('Failed to get route: ${response.statusCode}');
    }
  } catch (e) {
    print('Error initializing navigation: $e');
  }
}

Complete CODE :


class SampleNavigationApp extends StatefulWidget {
  double userLAT, userLNG, destinationLAT, destinationLNG;
  final VoidCallback? onNavigationCompleted;

  SampleNavigationApp(
      {super.key,
      required this.userLAT,
      required this.userLNG,
      required this.destinationLAT,
      this.onNavigationCompleted,
      required this.destinationLNG});

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

class _SampleNavigationAppState extends State<SampleNavigationApp> {
  String? _platformVersion;
  String? _instruction;

  var _home;
  var _store;

  bool _isMultipleStop = false;
  double? _distanceRemaining, _durationRemaining;
  MapBoxNavigationViewController? _controller;
  bool _routeBuilt = false;
  bool _isNavigating = false;
  late MapBoxOptions _navigationOption;
  var getwayPoints;
  @override
  void initState() {
    _home = WayPoint(
      name: "Home",
      latitude: widget.userLAT,
      longitude: widget.userLNG,
      //  latitude: 38.813349,
      // longitude: -77.070666
    );
    _store = WayPoint(
      name: "Store",
      latitude: widget.destinationLAT,
      longitude: widget.destinationLNG,
    );
    super.initState();
    initialize();

    // Call navigation function directly
  }

  Future<void> startNavigation() async {
    /* var wayPoints = <WayPoint>[];
    wayPoints.add(_home);
    wayPoints.add(_store);
 */
    print("seegeting  $getwayPoints");
    await MapBoxNavigation.instance.startNavigation(wayPoints: getwayPoints);
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initialize() async {
    if (!mounted) return;

    _navigationOption = MapBoxOptions(
      initialLatitude: widget.userLAT,
      initialLongitude: widget.userLNG,
      zoom: 10.0,
      tilt: 0.0,
      bearing: 0.0,
      enableRefresh: true,
      alternatives: true,
      voiceInstructionsEnabled: true,
      bannerInstructionsEnabled: true,
      mode: MapBoxNavigationMode.driving,
      simulateRoute: true,
      language: 'en',
    );

    //_navigationOption.initialLatitude = 36.1175275;
    //_navigationOption.initialLongitude = -115.1839524;
    MapBoxNavigation.instance.registerRouteEventListener(_onEmbeddedRouteEvent);
    MapBoxNavigation.instance.setDefaultOptions(_navigationOption);
    /*   String? platformVersion;
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      platformVersion = await MapBoxNavigation.instance.getPlatformVersion();
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    setState(() {
      _platformVersion = platformVersion;
    }); */

    final apiKey =
        "API KEY HERE";
    final apiUrl = 'https://api.mapbox.com/directions/v5/mapbox/driving';
    final origin = '${widget.userLNG},${widget.userLAT}';
    final destination = '${widget.destinationLNG},${widget.destinationLAT}';
    final requestUrl =
        '$apiUrl/$origin;$destination?approaches=curb;curb&exclude=motorway,toll&steps=true&access_token=$apiKey';

    try {
      final response = await http.get(Uri.parse(requestUrl));

      if (response.statusCode == 200) {
        final data = json.decode(response.body);
        final List<dynamic> routes = data['routes'];
        print("objecrouts /// $routes ");

        if (routes.isNotEmpty) {
          final route = routes[0];
          final List<dynamic>? legs = route['legs'];
          print("oblegs   ;; $legs");

          if (legs != null && legs.isNotEmpty) {
            final List<WayPoint> wayPoints = [];
            print("above loop  ");

            for (var leg in legs) {
              print(" probhere ? objecleg $legs");

              print("leg: $leg");
              print("leg['steps']: ${leg['steps']}");
              print("leg['steps'][0]: ${leg['steps'][0]}");
              final WayPoint start = WayPoint(
                name: "Start",
                latitude: leg['steps'][0]['maneuver']['location'][1],
                longitude: leg['steps'][0]['maneuver']['location'][0],
              );

              final WayPoint end = WayPoint(
                name: "End",
                latitude: leg['steps'][leg['steps'].length - 1]['maneuver']
                    ['location'][1],
                longitude: leg['steps'][leg['steps'].length - 1]['maneuver']
                    ['location'][0],
              );

              wayPoints.add(start);
              wayPoints.add(end);
            }

            /*    final options = MapBoxOptions(
              initialLatitude: wayPoints.first.latitude,
              initialLongitude: wayPoints.first.longitude,
              zoom: 10.0,
              tilt: 0.0,
              bearing: 0.0,
              enableRefresh: true,
              alternatives: true,
              voiceInstructionsEnabled: true,
              bannerInstructionsEnabled: true,
              mode: MapBoxNavigationMode.driving,
              simulateRoute: true,
              language: 'en',
            ); */

            MapBoxNavigation.instance
                .registerRouteEventListener(_onEmbeddedRouteEvent);
            getwayPoints = wayPoints;
            //  final bool? isNavigationStarted =
            /*   await MapBoxNavigation.instance.startNavigation(
              wayPoints: wayPoints,

            ); */
            startNavigation();
          } else {
            print('No legs found in the route');
          }
        } else {
          print('No routes found');
        }
      } else {
        print('Failed to get route: ${response.statusCode}');
      }
    } catch (e) {
      print('Error initializing navigation: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox.shrink();
  }

  Future<void> _onEmbeddedRouteEvent(e) async {
    _distanceRemaining = await MapBoxNavigation.instance.getDistanceRemaining();
    _durationRemaining = await MapBoxNavigation.instance.getDurationRemaining();

    switch (e.eventType) {
      case MapBoxEvent.progress_change:
        var progressEvent = e.data as RouteProgressEvent;
        if (progressEvent.currentStepInstruction != null) {
          _instruction = progressEvent.currentStepInstruction;
        }
        break;
      case MapBoxEvent.route_building:
      case MapBoxEvent.route_built:
        setState(() {
          _routeBuilt = true;
        });
        break;
      case MapBoxEvent.route_build_failed:
        setState(() {
          _routeBuilt = false;
        });
        break;
      case MapBoxEvent.navigation_running:
        setState(() {
          _isNavigating = true;
        });
        break;
      case MapBoxEvent.on_arrival:
        if (!_isMultipleStop) {
          await Future.delayed(const Duration(seconds: 3));
          await _controller?.finishNavigation();
        } else {}
        break;
      case MapBoxEvent.navigation_finished:
      case MapBoxEvent.navigation_cancelled:
        setState(() {
          _routeBuilt = false;
          _isNavigating = false;
        });
        widget.onNavigationCompleted?.call(); // Invoke the callback function

        break;
      default:
        break;
    }
    setState(() {});
  }
}