How to get our live location in flutter? - flutter

I want to draw the navigation from my live location to destination. So I have used flutter_mapbox_navigation package and its working fine for navigation between two stored points.
RaisedButton(
child: Text("Start"),
onPressed: () async {
var wayPoints = List<WayPoint>();
wayPoints.add(_origin);
wayPoints.add(_stop1);
await _directions.startNavigation(
wayPoints: wayPoints,
options: MapBoxOptions(
mode:
MapBoxNavigationMode.drivingWithTraffic,
simulateRoute: true,
language: "en",
units: VoiceUnits.metric));
},
),
But I want to navigate between my live location and destination. How location package can be used so as to do the following?

A Flutter geolocation plugin that provides easy access to platform-specific location services (FusedLocationProviderClient or if not available the LocationManager on Android and CLLocationManager on iOS).

Related

MapBox-gl Flutter - show my current location on map

I added My Location button + on click event like this:
FloatingActionButton(
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12.0))),
child: const Icon(Icons.gps_fixed_sharp, size: 25),
onPressed: () async {
try {
var position = await _determinePosition();
mapController?.animateCamera(CameraUpdate.newLatLngZoom(LatLng(position.latitude, position.longitude), 17));
} catch (e) {
FToast.toast(context, msg: e.toString());
}
},
)
So, after location determined, camera is animated to my location. It works, but I'm getting problem with blue point showing my current location on map. It's enabled by default with myLocationEnabled: true, in MapboxMap constructor. It's visible only when app is started with location permissions allowed.
After user taps "My Location" button, app displays prompt to allow location permissions, then determines location and moves camera. However, in this case, still MapBox does not show my location point - I need to restart app to get it visible.
How to tell Mapbox that location permissions have been granted to show my location point on map? I can't find any method inside map controller to do so.

How to use Google Maps directions API in Flutter (is it a good practice to keep calling directions API while current location is changing on the map)

In Flutter I use
google_maps_flutter, google_directions_api and flutter_polyline_points packages to have a map with the following functionalities;
Drawing routes between current location and destination points, get distance and durations between them, driver must be notified to take left/right while driving to the destination.
I have done these all, but when current location keeps updating on the map I'm calling direction api which return lots of data like legs and steps this api call is almost every second and google will charge me a lot.
Is anybody faced to same issue, I really appreciate a help.
There is part of my codes I have done so far
void _getCurrentLocation(context) {
showGeneralDialog(
context: context,
barrierDismissible: false,
barrierColor: Colors.black45,
pageBuilder: (BuildContext buildContext, Animation animation,
Animation secondaryAnimation) {
return Center(
child: Container(
width: MediaQuery.of(context).size.width - 10,
height: MediaQuery.of(context).size.height - 80,
padding: EdgeInsets.all(20),
color: Tingsapp.transparent,
child: CurrentLocation(),
),
);
}).then((location) {
if (location != null) {
_addMoverMarker(location, 'mover');
//updateFirebase(location);
_animateCameraToCurrentLocation(location);
}
});
}
destination point are already set.
In the above code I get user current location and add a marker as bellow
void _addMoverMarker(newLocationData, String id) async {
Uint8List imageData = await getMarker();
//LatLng latlng = LatLng(newLocationData.latitude, newLocationData.longitude);
LatLng latlng = LatLng(_moverLatitude!, _moverLongitude!);
MarkerId markerId = MarkerId(id);
Marker marker = Marker(
markerId: markerId,
position: latlng,
zIndex: 2,
icon: BitmapDescriptor.fromBytes(imageData),
infoWindow: InfoWindow(
title: "Mover location",
),
);
markers[markerId] = marker;
circle = Circle(
circleId: CircleId("circle"),
radius: 20,
zIndex: 1,
center: latlng,
strokeColor: Colors.orange.withAlpha(60),
fillColor: Colors.orange.withAlpha(300),
);
_getMoverPolyline(newLocationData);
}
and here I animate the camera
_animateCameraToCurrentLocation(newLocationData) {
if (_locationSubscription != null) {
_locationSubscription!.cancel();
}
_locationSubscription =
_locationTracker.onLocationChanged.listen((newLocationData) {
if (_mapController != null) {
_addMoverMarker(newLocationData, 'mover');
_animateCamera(_moverLatitude, _moverLongitude, 16.0);
//updateFirebase(newLocationData);
}
});
}
when I draw the polyline I call directions api here my problem starts
_getMoverPolyline(LocationData locationData) async {
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
mapKey,
PointLatLng(_originLatitude!, _originLongitude!),
PointLatLng(_moverLatitude!, _moverLongitude!),
//PointLatLng(locationData.latitude!, locationData.longitude!),
travelMode: TravelMode.driving,
);
if (result.points.isNotEmpty) {
moverPolylineCoordinates = [];
result.points.forEach((PointLatLng point) {
moverPolylineCoordinates.add(LatLng(point.latitude, point.longitude));
});
}
_addMoverPolyLine();
_getDirections(_moverLatitude, _moverLongitude, _originLatitude,
_originLongitude).then((data){
_updateData(data);
});
}
_getDirections(_moverLatitude, _moverLongitude, _originLatitude, _originLongitude) async {
Api api = Api();
var res = await api.getDirections(
_moverLatitude, _moverLongitude, _originLatitude, _originLongitude);
var jsonData = jsonDecode(res.body);
print(jsonData['routes'][0]['legs'][0]);
return jsonData['routes'][0]['legs'][0];
}
In the above code _getDirections method gets calling every second.
Isn't possible to call directions api one time?
_updateData method update data like tern right/left or Head south on my map
No I don't think that it's good practice to keep calling the API. And even in the google_directions_api documentation, they say,
Note: This service is not designed to respond in real time to user input.
And to answer your main question..
Don't call the API every time the location changes, instead call it once using the current location. And the response contains everything you need to navigate the user. Check the maneuver key inside each step of a leg.
And you should only use the location subscription to update the current location and animate the camera on the map. Use the getLocation() method to get the current location before starting the trip and use that location to generate the route. Store that route in a variable and use the data inside the route response to display whatever you want.
It´s not a good practice to constantly call directionsAPI, for the good of your pocket and to follow the recommendations of google.
If you are creating a Navigation app you first need to call the Api when the user set a destination, capture de coordinates (overview_polyline) and after that if the user goes off the road you can use maps toolkit to determine when this occurs and after that call again directionsAPI.

Programmatically Select Marker to Navigate To Location Google_Maps_Flutter

I am trying to develop a user experience where the user is provided a list of venues to travel to, and upon selecting one of those locations, I want it to
Add a marker to the map
Show an info window
Provide the option to navigate to the
location.
I was able to use the information from this PR (that has no official documentation it seems) to go from this:
To this:
However, showing the marker info still does not make the given marker "active". When I select the marker, the functionality of the plugin actually displays options for navigating to the given location on the bottom right, like this:
What I would like is for the selection of the venue at the bottom of the list to automatically display all three criteria in the third image with one press. That is, once again:
The marker of the location
The info window
The option to navigate to that location.
Right now, a user has to click the entry from the list at the bottom, and then rather un-intuitively click the marker on the map in order for the navigation options to appear.
How would I go about programatically launching the "on-tap" event that happens when the user "taps" the marker when selecting an item from the list?
Here is my current code for changing the viewport, adding a marker, and showing the info window:
Future<void> goSomewhere(id, name, distance, address, lat, lng) async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(lat, lng), zoom: 14.0)));
setState(() {
_markers.add(Marker(
markerId: MarkerId(id),
position: LatLng(lat, lng),
infoWindow: InfoWindow(
title: name,
snippet: address,
),
onTap: () {
//_pageController.jumpToPage(i);
},
icon: BitmapDescriptor.defaultMarker,
));
print(MarkerId(id));
controller.showMarkerInfoWindow(MarkerId(id));
});
}
Right now, my solution does add the marker and show the info window, but comes up short giving the user options for navigating to the location unless the user clicks the marker. In its current state, I've built something that makes for a very sub-optimal user experience.
I've tried alternative solutions like highlighting the marker, but it does not quite have the functionality I'm looking for. I do not understand what event occurs within the plugin that "selects" the marker on-tap, and all attempts I've found that "programmatically" select the marker do some version of highlighting it. Simply some direction as to where to look to find out what event is being launched when the marker is clicked would be helpful.
I didn't come to a complete answer, but I wanted to share my experience in case anyone else runs into this problem and feels stuck. By going through the Flutter Github / asking around the forums, I was able to get three key take-aways:
As far as I know, there is no way to simulate the "tap" of the marker in Flutter. I tried looking at the Kotlin/Swift APIs for platform channels to write some of this functionality myself, but to be honest it was pretty far out of my wheelhouse and I burned a lot of time on it. This also might result in having to go through the approval process with the nice people at Google for my changes to be accepted, but it's not time that I personally have right now.
I found a package called Maps Launcher that was also mentioned by Craig in the comments section that has the ability to launch the Maps application by two methods - Launch by Query, and Launch by Latitude/Longitude. This functionality is effectively identical to the functionality you get when you tap the marker and then select one of the two maps options on the bottom right.
I discovered that the primary difference between the two
icons that you get when you tap the marker is that one launches
directions by query, and the other by latitude and longitude - just
like the Maps Launcher plugin.
So with these three pieces of information, I redesigned the application to go from this:
To look like this:
Now a user:
Selects a location from the list.
Selecting a new location adds a marker and shows the location's infowindow
Can hit the button on the right to navigate to the given location.
In my opinion, this experience is much more clean - there is no ambiguity between the two maps options you can launch (by query vs by lat/long) when selecting a marker, as a button that launches the maps icon is now on the Listview. This also allows you to navigate to each marker pretty easily just by clicking it in the listview, and then deciding whether or not you want navigation directions by pressing the button on the right.
The code for adding this to your app is pretty simple:
new Flexible(
child: ListView.builder(
itemCount: venues.length,
padding: EdgeInsets.all(4.0),
itemBuilder: (context, index) {
return Card(
color: _selectedIndex != null && _selectedIndex == index
? Colors.greenAccent
: Colors.white,
child: ListTile(
onTap: () {
goSomewhere(
venues[index].venueId,
venues[index].name,
venues[index].distance,
venues[index].formattedAddress,
double.parse(venues[index].latitude),
double.parse(venues[index].longitude)
);
_onSelected(index);
},
title: Text(
venues[index]
.name /*+ ' and ' + venues[index].formattedAddress*/,
style: TextStyle(fontWeight: FontWeight.w500),
),
trailing: Container(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.blue,
),
onPressed: () => MapsLauncher.launchQuery(
venues[index].formattedAddress),
child: Icon(Icons.assistant_navigation),
)),
subtitle: Text(venues[index].formattedAddress),
));
},
))
It's a subtle difference, but I've done some testing and my (small) group of users seem to like this much more as it's much more intuitive. Also, the location they get in their Maps application has a recognizable address regardless of which button they press.
While this is not a "full" answer to the original question, I hope that this might help someone on their Flutter journey to stick to the framework - despite some of these early hurdles.
You beat me to it! I was about to answer this question earlier but when I reloaded the page, I saw you already answered it. Though it appears that you already found the solution to your issue, I thought of posting my answer here still. Please see below:
I couldn't find a way to programmatically display the map toolbar(options for navigating to the given location on the bottom right) as you really need to click a marker to show it. But here's a workaround that I thought would fit your use case:
Disable the map toolbar by setting mapToolbarEnabled: false in GoogleMap() widget. (The map toolbar only works for Android anyway)
Create a custom map toolbar that launches Google Maps and Directions URLs from the app. That toolbar only shows when you select a location from the listview or when you click a marker.
I used the url_launcher package to launch the Google Maps and Directions URLs.
Future<void> _launchUrl(bool isDir, double lat, double lon) async {
String url = 'https://www.google.com/maps/search/?api=1&query=$lat,$lon';
if (isDir) {
url = 'https://www.google.com/maps/dir/?api=1&origin=Googleplex&destination=$lat,$lon';
}
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
Then I used the method above on a custom Map toolbar widget
Widget mapToolBar() {
return Row(
children: [
FloatingActionButton(
child: Icon(Icons.map),
backgroundColor: Colors.blue,
onPressed: () {
_launchUrl(false, {your_lat}, {your_lng})
},
),
FloatingActionButton(
child: Icon(Icons.directions),
backgroundColor: Colors.blue,
onPressed: () {
_launchUrl(true, {your_lat}, {your_lng};
},
),
],
);
}
Then put the custom widget in a Stack widget with the Googlemap() widget
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: <Widget>[
Expanded(
flex: 7,
child: Stack(children: [
GoogleMap(
.
.
.
),
mapToolBar()
]),
),
_pageViewBuilder(context),
]),
);
}

Remove url bar from chromeSafariBrowser in flutter_inappwebview

I am using ChromeSafariBrowser class of flutter_inappwebview to show the webview which contains videos. I am using this class cause it supports pip and also shows media controls on video play which most of dependencies doesnt provide. Now I want to remove the url bar from the top, how can i achieve it?
Any help is appreciated, thanks in advance..
I want to remove the rectangular marked area in this picture
Following is my sample code
RaisedButton(
onPressed: () async {
await widget.browser.open(
url: "https://player.vimeo.com/api/demo",
options: ChromeSafariBrowserClassOptions(
android: AndroidChromeCustomTabsOptions(
addDefaultShareMenuItem: false,
enableUrlBarHiding:true,
toolbarBackgroundColor: "#000000"
),
ios: IOSSafariOptions(
barCollapsingEnabled: true,
preferredBarTintColor: "#000000"
)
),
);
},
child: Text("Open Chrome Safari Browser")
)

How to remove a specific marker from google maps in flutter?

I am Vaibhav Pathak. I am working on a Flutter app in which I add markers in-app based on data change in firestore database and I want to remove the previous marker from the map using its marker id but I don't understand how to do it. I had watched many Youtube videos and blogs but I don't get to know this because of API changes in google maps flutter plugin. For your kind information, I want to tell that I am using the latest version of the google_maps flutter plugin.
My Code for Making Markers :
showLiveLocation(LatLng latLng) {
_markers.add(
Marker(
markerId: MarkerId(latLng.toString()),
position: latLng,
draggable: false,
infoWindow: InfoWindow(
title: "Live Order Location",
snippet: "Dear customer your order is live at this place."),
icon: liveLocation,
visible: true,
),
);
}
Thanks for everyone's help.
github : github#vkpdeveloper
You need to find that specific marker in your _markers list (e.g. by firstWhere()) and then remove it from the list of markers.
Edit:
Marker marker = _markers.firstWhere((marker) => marker.markerId.value == "myId",orElse: () => null);
setState(() {
_markers.remove(marker);
});
This will trigger a rebuild of your map where the marker is no longer included.
Inspired by Thomas, my solution was:
setState(() {
_markers.removeWhere((key, marker) => marker.markerId.value == "myMarkerId");
});