3
import 'package:flutter/foundation.dart';
4
import 'package:flutter/material.dart';
5
import 'package:flutter/services.dart';
6
import 'package:fluttertoast/fluttertoast.dart';
7
import 'package:nb_navigation_flutter/nb_navigation_flutter.dart';
8
import 'package:nb_navigation_flutter_example/constants.dart';
10
class LaunchEmbeddedNavigationView extends StatefulWidget {
11
static const String title = "Launch Embedded NavigationView";
13
const LaunchEmbeddedNavigationView({super.key});
16
LaunchEmbeddedNavigationViewState createState() => LaunchEmbeddedNavigationViewState();
19
class LaunchEmbeddedNavigationViewState extends State<LaunchEmbeddedNavigationView> {
20
NextbillionMapController? controller;
21
List<DirectionsRoute> routes = [];
22
late NavNextBillionMap navNextBillionMap;
23
Symbol? mapMarkerSymbol;
25
NavigationViewController? navigationViewController;
26
NavigationProgress? progress;
28
bool startNavigation = false;
30
String locationTrackImage = "assets/location_on.png";
31
UserLocation? currentLocation;
32
List<LatLng> waypoints = [];
34
void _onMapCreated(NextbillionMapController controller) {
35
this.controller = controller;
38
_onStyleLoadedCallback() {
39
if (controller != null) {
40
NavNextBillionMap.create(controller!).then((value) {
41
navNextBillionMap = value;
43
Fluttertoast.showToast(
44
msg: "Long press to select a destination to fetch a route");
45
if (currentLocation != null) {
46
controller?.animateCamera(
47
CameraUpdate.newLatLngZoom(currentLocation!.position, 14),
48
duration: const Duration(milliseconds: 400));
54
_onNavigationViewReady(NavigationViewController controller) {
55
navigationViewController = controller;
58
_onMapLongClick(Point<double> point, LatLng coordinates) {
59
_fetchRoute(coordinates);
62
_onMapClick(Point<double> point, LatLng coordinates) {
63
navNextBillionMap.addRouteSelectedListener(coordinates,
64
(selectedRouteIndex) {
65
if (routes.isNotEmpty && selectedRouteIndex != 0) {
66
var selectedRoute = routes[selectedRouteIndex];
67
routes.removeAt(selectedRouteIndex);
68
routes.insert(0, selectedRoute);
72
navNextBillionMap.drawRoute(routes);
77
_onUserLocationUpdate(UserLocation location) {
78
currentLocation = location;
81
_onCameraTrackingChanged() {
83
locationTrackImage = 'assets/location_off.png';
88
Widget build(BuildContext context) {
91
crossAxisAlignment: CrossAxisAlignment.start,
94
padding: const EdgeInsets.only(top: 60, left: 18, bottom: 5.0),
95
child: Text("distanceRemaining: ${progress?.distanceRemaining}"),
98
padding: const EdgeInsets.only(left: 18, bottom: 5.0),
99
child: Text("durationRemaining: ${progress?.durationRemaining}"),
102
padding: const EdgeInsets.only(left: 18, bottom: 25.0),
103
child: Text("arrivedAtWaypointInfo: ${waypoint?.arrivedWaypointIndex}===${waypoint?.arrivedWaypointLocation}"),
109
_buildNBNavigationView(),
118
Widget _buildNBNavigationView() {
119
return startNavigation
121
onNavigationViewReady: _onNavigationViewReady,
122
navigationOptions: _buildNavigationViewConfig(),
123
onProgressChange: (progress) {
125
this.progress = progress;
128
onNavigationCancelling: () {
130
startNavigation = false;
135
onArriveAtWaypoint: (waypoint) {
137
this.waypoint = waypoint;
140
onRerouteFromLocation: (location) {
145
NavigationLauncherConfig _buildNavigationViewConfig() {
146
NavigationLauncherConfig config = NavigationLauncherConfig(route: routes.first, routes: routes);
147
config.locationLayerRenderMode = LocationLayerRenderMode.gps;
148
config.shouldSimulateRoute = true;
149
config.themeMode = NavigationThemeMode.system;
150
config.useCustomNavigationStyle = false;
154
Widget _buildNBMapView() {
158
onMapCreated: _onMapCreated,
159
onStyleLoadedCallback: _onStyleLoadedCallback,
160
initialCameraPosition: const CameraPosition(
161
target: LatLng(0, 0),
164
trackCameraPosition: true,
165
myLocationEnabled: true,
166
myLocationTrackingMode: MyLocationTrackingMode.Tracking,
167
onMapLongClick: _onMapLongClick,
168
onUserLocationUpdated: _onUserLocationUpdate,
169
onCameraTrackingDismissed: _onCameraTrackingChanged,
170
onMapClick: _onMapClick,
171
styleString: NbNavigationStyles.nbMapDefaultLightStyle,
174
padding: const EdgeInsets.all(8.0),
176
mainAxisAlignment: MainAxisAlignment.end,
177
crossAxisAlignment: CrossAxisAlignment.start,
180
padding: const EdgeInsets.all(8.0),
181
child: GestureDetector(
183
image: AssetImage(locationTrackImage),
188
controller?.updateMyLocationTrackingMode(
189
MyLocationTrackingMode.Tracking);
191
locationTrackImage = 'assets/location_on.png';
195
const Padding(padding: EdgeInsets.only(top: 35)),
197
mainAxisAlignment: MainAxisAlignment.center,
201
backgroundColor: WidgetStateProperty.all(
202
routes.isEmpty ? Colors.grey : Colors.blueAccent),
203
enableFeedback: routes.isNotEmpty),
208
child: const Text("Clear Routes")),
209
const Padding(padding: EdgeInsets.only(left: 8)),
212
backgroundColor: WidgetStateProperty.all(
213
routes.isEmpty ? Colors.grey : Colors.blueAccent),
214
enableFeedback: routes.isNotEmpty),
217
startNavigation = true;
220
child: const Text("Start Navigation")),
223
const Padding(padding: EdgeInsets.only(top: 48)),
225
// padding: const EdgeInsets.only(top: 8.0),
226
// child: Text("route response: ${routeResult}"),
236
void _fetchRoute(LatLng destination) async {
237
if (currentLocation == null) {
240
LatLng origin = currentLocation!.position;
241
waypoints.add(destination);
242
RouteRequestParams requestParams = RouteRequestParams(
244
destination: waypoints.last,
245
// overview: ValidOverview.simplified,
246
// avoid: [SupportedAvoid.toll, SupportedAvoid.ferry],
247
// option: SupportedOption.flexible,
248
// truckSize: [200, 200, 600],
250
// unit: SupportedUnits.imperial,
252
mode: ValidModes.car,
255
if (waypoints.length > 1) {
256
requestParams.waypoints = waypoints.sublist(0, waypoints.length - 1);
259
DirectionsRouteResponse routeResponse =
260
await NBNavigation.fetchRoute(requestParams);
261
if (routeResponse.directionsRoutes.isNotEmpty) {
264
routes = routeResponse.directionsRoutes;
267
fitCameraToBounds(routes);
268
addImageFromAsset(destination);
269
} else if (routeResponse.message != null) {
272
"====error====${routeResponse.message}===${routeResponse.errorCode}");
277
Future<void> drawRoutes(List<DirectionsRoute> routes) async {
278
// navNextBillionMap.toggleDurationSymbolVisibilityWith(false);
279
navNextBillionMap.drawRoute(routes);
282
void fitCameraToBounds(List<DirectionsRoute> routes) {
283
List<LatLng> multiPoints = [];
284
for (var route in routes) {
286
decode(route.geometry ?? '', _getDecodePrecision(route.routeOptions));
287
multiPoints.addAll(routePoints);
289
if (multiPoints.isNotEmpty) {
290
var latLngBounds = LatLngBounds.fromMultiLatLng(multiPoints);
291
controller?.animateCamera(CameraUpdate.newLatLngBounds(latLngBounds,
292
top: 50, left: 50, right: 50, bottom: 50));
296
int _getDecodePrecision(RouteRequestParams? routeOptions) {
297
return routeOptions?.geometry == SupportedGeometry.polyline
302
void clearRouteResult() async {
303
navNextBillionMap.clearRoute();
304
controller?.clearSymbols();
310
Future<void> loadAssetImage() async {
311
final ByteData bytes = await rootBundle.load("assets/map_marker_light.png");
312
final Uint8List list = bytes.buffer.asUint8List();
313
await controller?.addImage("ic_marker_destination", list);
316
Future<void> addImageFromAsset(LatLng coordinates) async {
317
controller?.clearSymbols();
318
var symbolOptions = SymbolOptions(
319
geometry: coordinates,
320
iconImage: "ic_marker_destination",
322
await controller?.addSymbol(symbolOptions);
323
controller?.symbolManager?.setTextAllowOverlap(false);
333
// TODO: implement dispose
338
void didUpdateWidget(LaunchEmbeddedNavigationView oldWidget) {
339
// TODO: implement didUpdateWidget
340
super.didUpdateWidget(oldWidget);
344
void didChangeDependencies() {
345
// TODO: implement didChangeDependencies
346
super.didChangeDependencies();