summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAldrik Ramaekers <aldrik@amftech.nl>2023-04-10 21:11:29 +0200
committerAldrik Ramaekers <aldrik@amftech.nl>2023-04-10 21:11:29 +0200
commitd35e4014e16bfdf2e2fc2bde397c385fc53e498c (patch)
tree8880a668547b36821ac1d809f61c4dc89e873b99
parentc9dfd2e261c938c42bfa9527fa2786e8d3cdeb79 (diff)
refactor
-rw-r--r--lib/RoutingExample.dart78
-rw-r--r--lib/events/NextStopLoadedEvent.dart2
-rw-r--r--lib/events/StopCompletedEvent.dart12
-rw-r--r--lib/navigation/HERENavigation.dart324
-rw-r--r--lib/navigation/baseNavigation.dart290
-rw-r--r--lib/pages/navigation_page.dart53
6 files changed, 668 insertions, 91 deletions
diff --git a/lib/RoutingExample.dart b/lib/RoutingExample.dart
index 7f4444f..ade893d 100644
--- a/lib/RoutingExample.dart
+++ b/lib/RoutingExample.dart
@@ -20,6 +20,7 @@ import 'package:here_sdk/routing.dart' as here;
import 'package:training_planner/events/MapPanningEvent.dart';
import 'package:training_planner/events/NextStopLoadedEvent.dart';
import 'package:training_planner/events/StopCompletedEvent.dart';
+import 'package:training_planner/navigation/baseNavigation.dart';
import 'package:training_planner/pages/navigation_page.dart';
import 'package:training_planner/services/iblacklist_provider_service.dart';
import 'route.dart' as DHLRoute;
@@ -29,43 +30,6 @@ import 'main.dart';
// A callback to notify the hosting widget.
typedef ShowDialogFunction = void Function(String title, String message);
-class DestinationPin {
- final String text;
- final int sequenceNumber;
- final GeoCoordinates? coords;
- final String? postalcodeNumeric;
- final String? postalcodeAlpha;
- final String? houseNumberWithExtra;
- WidgetPin? pin;
- bool isDoublePlannedAddress;
-
- DestinationPin(
- {this.text = '',
- this.coords,
- required this.sequenceNumber,
- required this.isDoublePlannedAddress,
- required this.postalcodeNumeric,
- required this.postalcodeAlpha,
- required this.houseNumberWithExtra});
-}
-
-class ActiveTask {
- final int firstParcelNumber;
- final String deliveryTimeBlock;
- final int lastParcelNumber;
- final String fullAddress;
- final bool needsSignature;
- final bool notAtNeighbors;
-
- ActiveTask(
- this.firstParcelNumber,
- this.deliveryTimeBlock,
- this.lastParcelNumber,
- this.fullAddress,
- this.needsSignature,
- this.notAtNeighbors);
-}
-
class RoutingExample {
Timer? timer;
bool isLookingAround = false;
@@ -267,7 +231,7 @@ class RoutingExample {
if (item == taskToCheck) {
return true; // first one of the double planned addresses is visible.
}
- if (item.coords == taskToCheck.coords) {
+ if (item.coords.compare(taskToCheck.coords)) {
return false;
}
}
@@ -278,23 +242,13 @@ class RoutingExample {
bool isAddressDoublePlanned(DestinationPin taskToCheck) {
for (final item in _parcelNumberPins) {
if (item == taskToCheck) continue;
- if (item.coords == taskToCheck.coords) return true;
+ if (item.coords.compare(taskToCheck.coords)) return true;
}
return false;
}
- Future<void> addRoute(DHLRoute.Route route) async {
- if (route.tasks == null) return;
- _route = route;
-
- Position currentPosition = await Geolocator.getCurrentPosition(
- desiredAccuracy: LocationAccuracy.high);
- GeoCoordinates routeStartCoords =
- GeoCoordinates(currentPosition.latitude, currentPosition.longitude);
-
- List<Waypoint> waypoints = [Waypoint.withDefaults(routeStartCoords)];
-
+ void groupTasksIntoGroups(DHLRoute.Route route) {
bool isFirst = true;
for (final item in route.tasks!) {
//debugPrint(item.deliverySequenceNumber.toString());
@@ -320,8 +274,6 @@ class RoutingExample {
}
}
- waypoints.add(Waypoint.withDefaults(destinationGeoCoordinates));
-
_parcelNumberPins.add(
DestinationPin(
sequenceNumber: int.parse(item.deliverySequenceNumber!),
@@ -331,7 +283,8 @@ class RoutingExample {
(item.houseNumberAddition != null
? item.houseNumberAddition!
: ''),
- coords: destinationGeoCoordinates,
+ coords: DHLCoordinates(destinationGeoCoordinates.latitude,
+ destinationGeoCoordinates.longitude),
isDoublePlannedAddress: false,
postalcodeNumeric: item.postalCodeNumeric,
postalcodeAlpha: item.postalCodeAlpha,
@@ -365,6 +318,25 @@ class RoutingExample {
}
allTasks.add(groupedTask);
}
+ }
+
+ Future<void> addRoute(DHLRoute.Route route) async {
+ if (route.tasks == null) return;
+ _route = route;
+
+ Position currentPosition = await Geolocator.getCurrentPosition(
+ desiredAccuracy: LocationAccuracy.high);
+ GeoCoordinates routeStartCoords =
+ GeoCoordinates(currentPosition.latitude, currentPosition.longitude);
+
+ List<Waypoint> waypoints = [Waypoint.withDefaults(routeStartCoords)];
+
+ groupTasksIntoGroups(route);
+
+ for (var item in _parcelNumberPins) {
+ waypoints.add(Waypoint.withDefaults(GeoCoordinates(
+ item.coords?.lattitude ?? 0, item.coords?.longitude ?? 0)));
+ }
for (var item in _parcelNumberPins) {
item.isDoublePlannedAddress = isAddressDoublePlanned(item);
diff --git a/lib/events/NextStopLoadedEvent.dart b/lib/events/NextStopLoadedEvent.dart
index a95e29c..8cc8897 100644
--- a/lib/events/NextStopLoadedEvent.dart
+++ b/lib/events/NextStopLoadedEvent.dart
@@ -1,4 +1,4 @@
-import 'package:training_planner/RoutingExample.dart';
+import 'package:training_planner/navigation/baseNavigation.dart';
class NextStopLoadedEvent {
ActiveTask task;
diff --git a/lib/events/StopCompletedEvent.dart b/lib/events/StopCompletedEvent.dart
index 1729307..fc70bf4 100644
--- a/lib/events/StopCompletedEvent.dart
+++ b/lib/events/StopCompletedEvent.dart
@@ -1,3 +1,15 @@
+import 'package:training_planner/navigation/baseNavigation.dart';
+
class StopCompletedEvent {}
class StopIncompletedEvent {}
+
+class ChangeZoomEvent {
+ double zoom;
+ ChangeZoomEvent(this.zoom);
+}
+
+class FlyToEvent {
+ DHLCoordinates coords;
+ FlyToEvent(this.coords);
+}
diff --git a/lib/navigation/HERENavigation.dart b/lib/navigation/HERENavigation.dart
new file mode 100644
index 0000000..0504061
--- /dev/null
+++ b/lib/navigation/HERENavigation.dart
@@ -0,0 +1,324 @@
+import 'dart:async';
+import 'package:here_sdk/routing.dart' as here;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:geolocator/geolocator.dart';
+import 'package:here_sdk/core.dart';
+import 'package:here_sdk/core.errors.dart';
+import 'package:here_sdk/gestures.dart';
+import 'package:here_sdk/mapview.dart';
+import 'package:here_sdk/routing.dart';
+import 'package:here_sdk/search.dart';
+import 'package:training_planner/events/MapPanningEvent.dart';
+import 'package:training_planner/events/NextStopLoadedEvent.dart';
+import 'package:training_planner/events/RouteLoadedEvent.dart';
+import 'package:training_planner/events/StopCompletedEvent.dart';
+import 'package:training_planner/main.dart';
+import 'package:training_planner/navigation/baseNavigation.dart';
+import 'package:training_planner/pages/navigation_page.dart';
+import 'package:training_planner/route.dart';
+import '../route.dart' as DHLRoute;
+
+class HERENavigation extends BaseNavigation {
+ HERENavigation({Key? key, required route}) : super(key: key, route: route);
+
+ @override
+ _HERENavigationState createState() => _HERENavigationState();
+}
+
+class _HERENavigationState extends BaseNavigationState {
+ late HereMapController hereMapController;
+
+ List<MapPolyline> _routeSections = [];
+ List<MapPolyline> _pathSections = [];
+
+ late RoutingEngine _routingEngine;
+ late SearchOptions _searchOptions;
+ late MapMarker mapMarker;
+
+ Future<Uint8List> _loadFileAsUint8List(String assetPathToFile) async {
+ // The path refers to the assets directory as specified in pubspec.yaml.
+ ByteData fileData = await rootBundle.load(assetPathToFile);
+ return Uint8List.view(fileData.buffer);
+ }
+
+ Future<void> _addCircle(GeoCoordinates geoCoordinates) async {
+ Uint8List imagePixelData = await _loadFileAsUint8List('assets/package.png');
+ MapImage circleMapImage =
+ MapImage.withPixelDataAndImageFormat(imagePixelData, ImageFormat.png);
+ mapMarker = MapMarker(geoCoordinates, circleMapImage);
+ hereMapController.mapScene.addMapMarker(mapMarker);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return HereMap(onMapCreated: _onMapCreated);
+ }
+
+ void _updateLocation(Position value) {
+ widget.lastPosition = DHLCoordinates(value.latitude, value.longitude);
+ mapMarker.coordinates = GeoCoordinates(value.latitude, value.longitude);
+ flyTo(DHLCoordinates(value.latitude, value.longitude));
+ }
+
+ void _setLocationOnMap() {
+ if (!widget.isLookingAround) {
+ Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
+ .then(
+ (value) => {if (!widget.isLookingAround) _updateLocation(value)});
+ }
+ }
+
+ void initialize() {
+ try {
+ _routingEngine = RoutingEngine();
+ } on InstantiationException {
+ throw ("Initialization of RoutingEngine failed.");
+ }
+
+ _searchOptions = SearchOptions.withDefaults();
+ _searchOptions.languageCode = LanguageCode.enUs;
+ _searchOptions.maxItems = 5;
+
+ hereMapController.camera.lookAtPoint(GeoCoordinates(50.8434572, 5.7381166));
+ hereMapController.camera.zoomTo(widget.currentZoom);
+
+ _addCircle(GeoCoordinates(50.8434572, 5.7381166));
+
+ widget.timer =
+ Timer.periodic(Duration(seconds: 1), (Timer t) => _setLocationOnMap());
+
+ hereMapController.gestures.panListener = PanListener(
+ (GestureState state, Point2D touchPoint, Point2D p2, double d) {
+ widget.isLookingAround = true;
+ eventBus.fire(MapPanningEvent(true));
+ });
+
+ widget.stopCompletedEvent = eventBus.on<StopCompletedEvent>().listen((e) {
+ routeSectionCursor += 1;
+ if (routeSectionCursor >= widget.allTasks.length) {
+ routeSectionCursor = widget.allTasks.length - 1;
+ }
+ updateHighlightedRouteSections();
+ eventBus.fire(NextStopLoadedEvent(widget.allTasks[routeSectionCursor]));
+ });
+
+ widget.stopIncompletedEvent =
+ eventBus.on<StopIncompletedEvent>().listen((e) {
+ routeSectionCursor -= 1;
+ if (routeSectionCursor < 0) routeSectionCursor = 0;
+ updateHighlightedRouteSections(force: true);
+ eventBus.fire(NextStopLoadedEvent(widget.allTasks[routeSectionCursor]));
+ });
+
+ blacklistProvider
+ .getBlacklist()
+ .then((value) => {widget.blacklist = value});
+ }
+
+ void _onMapCreated(HereMapController hereMapController) async {
+ this.hereMapController = hereMapController;
+ hereMapController.mapScene.loadSceneForMapScheme(MapScheme.normalDay,
+ (MapError? error) {
+ if (error == null) {
+ initialize();
+ addRoute(widget.route).then((value) {
+ widget.doneLoading = true;
+ });
+ } else {
+ print("Map scene not loaded. MapError: " + error.toString());
+ }
+ });
+ }
+
+ @override
+ Future<void> addRoute(DHLRoute.Route route) async {
+ if (route.tasks == null) return;
+
+ Position currentPosition = await Geolocator.getCurrentPosition(
+ desiredAccuracy: LocationAccuracy.high);
+ GeoCoordinates routeStartCoords =
+ GeoCoordinates(currentPosition.latitude, currentPosition.longitude);
+
+ List<Waypoint> waypoints = [Waypoint.withDefaults(routeStartCoords)];
+
+ groupTasksIntoGroups(route);
+
+ for (var item in widget.parcelNumberPins) {
+ waypoints.add(Waypoint.withDefaults(
+ GeoCoordinates(item.coords.lattitude, item.coords.longitude)));
+ }
+
+ for (var item in widget.parcelNumberPins) {
+ item.isDoublePlannedAddress = isAddressDoublePlanned(item);
+ }
+
+ PedestrianOptions f = PedestrianOptions.withDefaults();
+ f.routeOptions.alternatives = 0;
+ f.routeOptions.enableTrafficOptimization = false;
+ f.routeOptions.optimizationMode = OptimizationMode.fastest;
+
+ _routingEngine.calculatePedestrianRoute(waypoints, f,
+ (RoutingError? routingError, List<here.Route>? routeList) async {
+ if (routingError == null) {
+ here.Route route = routeList!.first;
+
+ _showRouteOnMap(route);
+
+ for (int i = 0; i < route.sections.length; i++) {
+ _showLineToHouse(route.sections.elementAt(i),
+ waypoints.elementAt(i + 1).coordinates);
+ }
+
+ updateHighlightedRouteSections();
+ } else {
+ var error = routingError.toString();
+ }
+ });
+ }
+
+ _showLineToHouse(Section section, GeoCoordinates houseCoords) {
+ GeoPolyline routeGeoPolyline = section.geometry;
+
+ GeoPolyline walkLine =
+ GeoPolyline([routeGeoPolyline.vertices.last, houseCoords]);
+ MapPolyline walkPathPolyline =
+ MapPolyline(walkLine, 8, Color.fromARGB(160, 255, 20, 20));
+ hereMapController.mapScene.addMapPolyline(walkPathPolyline);
+
+ _pathSections.add(walkPathPolyline);
+ }
+
+ _showRouteOnMap(here.Route route) {
+ double widthInPixels = 15;
+
+ for (int i = 0; i < route.sections.length; i++) {
+ Section section = route.sections.elementAt(i);
+ GeoPolyline routeGeoPolyline = section.geometry;
+
+ MapPolyline routeMapPolyline = MapPolyline(
+ routeGeoPolyline, widthInPixels, Color.fromARGB(160, 0, 144, 138));
+ hereMapController.mapScene.addMapPolyline(routeMapPolyline);
+
+ _routeSections.add(routeMapPolyline);
+ }
+ }
+
+ @override
+ void changeZoom(double newVal) {
+ if (newVal > 20) newVal = 20;
+ if (newVal < 13) newVal = 13;
+ widget.currentZoom = newVal;
+ print('hallo' + newVal.toString());
+ hereMapController.camera.zoomTo(widget.currentZoom);
+ }
+
+ @override
+ void flyTo(DHLCoordinates coords) {
+ double bearingInDegress = 0;
+ double tiltInDegress = 0;
+ GeoOrientationUpdate orientation =
+ GeoOrientationUpdate(bearingInDegress, tiltInDegress);
+
+ hereMapController.camera.lookAtPointWithGeoOrientationAndMeasure(
+ GeoCoordinates(coords.lattitude, coords.longitude),
+ orientation,
+ MapMeasure(MapMeasureKind.zoomLevel, widget.currentZoom));
+ }
+
+ @override
+ dynamic createPinWidget(
+ DestinationPin pin, Color color, DHLCoordinates coords) {
+ var pp = hereMapController.pinWidget(
+ createPin(pin, color,
+ isDoublePlannedAddress: pin.isDoublePlannedAddress),
+ GeoCoordinates(coords.lattitude, coords.longitude));
+ pp?.anchor = Anchor2D.withHorizontalAndVertical(0.5, 0.5);
+ return pp;
+ }
+
+ @override
+ void dispose() {
+ destroyNavigation();
+ super.dispose();
+ }
+
+ @override
+ void updateHighlightedRouteSections({bool force = false}) {
+ int maxPins = 300;
+
+ for (int i = widget.parcelNumberPins.length - 1; i >= 0; i--) {
+ DestinationPin pin = widget.parcelNumberPins.elementAt(i);
+
+ Color color = Color.fromARGB(200, 0, 144, 138);
+ if (i == routeSectionCursor) color = Color.fromARGB(199, 143, 8, 31);
+ if (i == routeSectionCursor + 1) color = Color.fromARGB(197, 13, 36, 241);
+ if (destinationPinIsInBlacklist(widget.parcelNumberPins[i])) {
+ color = Color.fromRGBO(143, 8, 31, 0.78);
+ }
+
+ bool forceUpdateThisPin =
+ force && (i > routeSectionCursor - 3 && i < routeSectionCursor + 3);
+
+ if (!shouldDoublePlannedAddressBeVisible(pin)) {
+ pin.pin?.unpin();
+ pin.pin = null;
+ continue;
+ }
+
+ if (i > routeSectionCursor + 1 && i < routeSectionCursor + maxPins) {
+ if (forceUpdateThisPin) {
+ pin.pin?.unpin();
+ pin.pin = null;
+ } else if (pin.pin != null) {
+ continue;
+ }
+ var widgetPin =
+ createPinWidget(pin, color, widget.destinationCoords[i]);
+ pin.pin = widgetPin;
+ } else {
+ pin.pin?.unpin();
+ pin.pin = null;
+ }
+
+ if (i == routeSectionCursor || i == routeSectionCursor + 1) {
+ var widgetPin =
+ createPinWidget(pin, color, widget.destinationCoords[i]);
+ pin.pin = widgetPin;
+ }
+ }
+
+ // Show the next 5 sections as to not clutter the screen.
+ int maxSections = 5;
+ int maxWalkPaths = 300;
+ for (int i = _routeSections.length - 1; i >= 0; i--) {
+ MapPolyline section = _routeSections.elementAt(i);
+ MapPolyline path = _pathSections.elementAt(i);
+
+ // previous section
+ if (i == routeSectionCursor - 1) {
+ section.lineColor = Color.fromARGB(160, 168, 113, 108);
+ path.lineColor = Color.fromARGB(0, 255, 255, 255);
+ }
+ // current and next 5 sections
+ else if (i >= routeSectionCursor &&
+ i < routeSectionCursor + maxSections) {
+ section.lineColor = Color.fromARGB(
+ (255 - ((255 / (maxSections + 1)) * (i - routeSectionCursor)))
+ .toInt(),
+ 0,
+ 144,
+ 138);
+ } else {
+ section.lineColor = Color.fromARGB(0, 255, 255, 255);
+ }
+
+ if (i >= routeSectionCursor && i < routeSectionCursor + maxWalkPaths) {
+ path.lineColor = Color.fromARGB(160, 255, 0, 0);
+ } else {
+ path.lineColor = Color.fromARGB(0, 255, 255, 255);
+ }
+ }
+ }
+}
diff --git a/lib/navigation/baseNavigation.dart b/lib/navigation/baseNavigation.dart
new file mode 100644
index 0000000..e8f5379
--- /dev/null
+++ b/lib/navigation/baseNavigation.dart
@@ -0,0 +1,290 @@
+import 'dart:async';
+import 'package:flutter/material.dart';
+import 'package:training_planner/events/NextStopLoadedEvent.dart';
+import 'package:training_planner/events/StopCompletedEvent.dart';
+import 'package:training_planner/main.dart';
+
+import '../route.dart' as DHLRoute;
+import 'package:training_planner/services/iblacklist_provider_service.dart';
+
+class DestinationPin {
+ final String text;
+ final int sequenceNumber;
+ final DHLCoordinates coords;
+ final String? postalcodeNumeric;
+ final String? postalcodeAlpha;
+ final String? houseNumberWithExtra;
+ dynamic pin; // however the map source defines a pin.
+ bool isDoublePlannedAddress;
+
+ DestinationPin(
+ {this.text = '',
+ required this.coords,
+ required this.sequenceNumber,
+ required this.isDoublePlannedAddress,
+ required this.postalcodeNumeric,
+ required this.postalcodeAlpha,
+ required this.houseNumberWithExtra});
+}
+
+class DHLCoordinates {
+ double lattitude;
+ double longitude;
+
+ DHLCoordinates(this.lattitude, this.longitude);
+
+ bool compare(DHLCoordinates other) {
+ return other.lattitude == lattitude && other.longitude == longitude;
+ }
+}
+
+class ActiveTask {
+ final int firstParcelNumber;
+ final String deliveryTimeBlock;
+ final int lastParcelNumber;
+ final String fullAddress;
+ final bool needsSignature;
+ final bool notAtNeighbors;
+
+ ActiveTask(
+ this.firstParcelNumber,
+ this.deliveryTimeBlock,
+ this.lastParcelNumber,
+ this.fullAddress,
+ this.needsSignature,
+ this.notAtNeighbors);
+}
+
+abstract class BaseNavigation extends StatefulWidget {
+ bool doneLoading = false;
+ Timer? timer;
+ bool isLookingAround = false;
+ double currentZoom = 20;
+ DHLCoordinates lastPosition = DHLCoordinates(0, 0);
+
+ StreamSubscription? stopCompletedEvent;
+ StreamSubscription? stopIncompletedEvent;
+
+ List<ActiveTask> allTasks = [];
+ List<BlacklistEntry> blacklist = [];
+ List<DestinationPin> parcelNumberPins = [];
+ List<DHLCoordinates> destinationCoords = [];
+ final DHLRoute.Route route;
+
+ BaseNavigation({Key? key, required this.route}) : super(key: key);
+}
+
+abstract class BaseNavigationState extends State<BaseNavigation> {
+ int routeSectionCursor = 0;
+
+ StreamSubscription? changeZoomEvent;
+ StreamSubscription? flyToEvent;
+
+ BaseNavigationState() {
+ changeZoomEvent = eventBus.on<ChangeZoomEvent>().listen((event) {
+ changeZoom(event.zoom);
+ });
+
+ flyToEvent = eventBus.on<FlyToEvent>().listen((event) {
+ flyTo(event.coords);
+ });
+ }
+
+ void flyTo(DHLCoordinates coords);
+ void changeZoom(double newVal);
+ Future<void> addRoute(DHLRoute.Route route);
+ void updateHighlightedRouteSections({bool force = false});
+ dynamic createPinWidget(
+ DestinationPin pin, Color color, DHLCoordinates coords);
+
+ Widget createPin(DestinationPin pin, Color backgroundColor,
+ {bool isDoublePlannedAddress = false}) {
+ return Container(
+ decoration: BoxDecoration(
+ color: backgroundColor,
+ borderRadius: BorderRadius.circular(10),
+ shape: BoxShape.rectangle,
+ border: Border.all(
+ color: isDoublePlannedAddress
+ ? Color.fromARGB(255, 255, 0, 0)
+ : Color.fromARGB(0, 0, 0, 0),
+ width: 2),
+ ),
+ child: GestureDetector(
+ child: Row(
+ children: [
+ Container(
+ padding: EdgeInsets.all(3),
+ decoration: BoxDecoration(
+ color: Color.fromARGB(255, 0, 0, 0),
+ borderRadius: BorderRadius.circular(10),
+ shape: BoxShape.rectangle,
+ ),
+ child: Text(
+ pin.sequenceNumber.toString(),
+ style: TextStyle(
+ fontSize: 20.0, color: Color.fromARGB(255, 255, 255, 255)),
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.all(3),
+ child: Text(
+ pin.houseNumberWithExtra ?? 'Zie pakket',
+ style: TextStyle(fontSize: 20.0),
+ ),
+ ),
+ ],
+ )),
+ );
+ }
+
+ bool isAddressDoublePlanned(DestinationPin taskToCheck) {
+ for (final item in widget.parcelNumberPins) {
+ if (item == taskToCheck) continue;
+ if (item.coords.compare(taskToCheck.coords)) return true;
+ }
+
+ return false;
+ }
+
+ // if address is double planned and there is a stop before this one.
+ bool shouldDoublePlannedAddressBeVisible(DestinationPin taskToCheck) {
+ if (!taskToCheck.isDoublePlannedAddress) return true;
+ for (int i = routeSectionCursor; i < widget.parcelNumberPins.length; i++) {
+ var item = widget.parcelNumberPins[i];
+
+ if (item == taskToCheck) {
+ return true; // first one of the double planned addresses is visible.
+ }
+ if (item.coords.compare(taskToCheck.coords)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ DHLRoute.Task findTaskWithLowestSequenceNumberInGroup(
+ DHLRoute.Route route, List<String> groupPids) {
+ List<DHLRoute.Task> tasksFound = [];
+
+ for (final item in route.tasks!) {
+ if (groupPids.contains(item.pid)) tasksFound.add(item);
+ }
+
+ tasksFound.sort((e1, e2) => int.parse(e1.deliverySequenceNumber!)
+ .compareTo(int.parse(e2.deliverySequenceNumber!)));
+ return tasksFound.first;
+ }
+
+ bool destinationPinIsInBlacklist(DestinationPin pin) {
+ try {
+ for (int i = 0; i < widget.blacklist.length; i++) {
+ if (pin.postalcodeNumeric == widget.blacklist[i].postalcodeNumeric &&
+ pin.postalcodeAlpha!.toLowerCase() ==
+ widget.blacklist[i].postalcodeAplha &&
+ pin.houseNumberWithExtra!.toLowerCase() ==
+ (widget.blacklist[i].houseNumber.toString() +
+ widget.blacklist[i].houseNumberExtra.toLowerCase())) {
+ return true;
+ }
+ }
+ return false;
+ } catch (e) {
+ return false;
+ }
+ }
+
+ void destroyNavigation() {
+ widget.stopCompletedEvent?.cancel();
+ widget.stopIncompletedEvent?.cancel();
+ changeZoomEvent?.cancel();
+ flyToEvent?.cancel();
+ widget.timer?.cancel();
+ }
+
+ DHLRoute.Task _findTaskWithLowestSequenceNumberInGroup(
+ DHLRoute.Route route, List<String> groupPids) {
+ List<DHLRoute.Task> tasksFound = [];
+
+ for (final item in route.tasks!) {
+ if (groupPids.contains(item.pid)) tasksFound.add(item);
+ }
+
+ tasksFound.sort((e1, e2) => int.parse(e1.deliverySequenceNumber!)
+ .compareTo(int.parse(e2.deliverySequenceNumber!)));
+ return tasksFound.first;
+ }
+
+ void groupTasksIntoGroups(DHLRoute.Route route) {
+ bool isFirst = true;
+ for (final item in route.tasks!) {
+ //debugPrint(item.deliverySequenceNumber.toString());
+
+ if (item.addressLatitude == null || item.addressLongitude == null) {
+ // Skip adressen die fout zijn ingegeven.
+ // Hier moeten we nog iets voor vinden om bestuurder te laten weten
+ continue;
+ }
+
+ var destinationGeoCoordinates = DHLCoordinates(
+ double.parse(item.addressLatitude!),
+ double.parse(item.addressLongitude!));
+
+ if (item.isIntervention != 'true' &&
+ item.groupSize != null &&
+ item.groupPids != null &&
+ int.parse(item.groupSize!) > 1) {
+ var firstTaskInGroup =
+ _findTaskWithLowestSequenceNumberInGroup(route, item.groupPids!);
+ if (firstTaskInGroup != item) {
+ continue;
+ }
+ }
+
+ widget.parcelNumberPins.add(
+ DestinationPin(
+ sequenceNumber: int.parse(item.deliverySequenceNumber!),
+ text: item.deliverySequenceNumber.toString() +
+ ' = ' +
+ item.houseNumber! +
+ (item.houseNumberAddition != null
+ ? item.houseNumberAddition!
+ : ''),
+ coords: DHLCoordinates(destinationGeoCoordinates.lattitude,
+ destinationGeoCoordinates.longitude),
+ isDoublePlannedAddress: false,
+ postalcodeNumeric: item.postalCodeNumeric,
+ postalcodeAlpha: item.postalCodeAlpha,
+ houseNumberWithExtra:
+ item.houseNumber! + (item.houseNumberAddition ?? '')),
+ );
+ widget.destinationCoords.add(destinationGeoCoordinates);
+
+ int sequenceNumber = int.parse(item.deliverySequenceNumber!);
+ int groupLastSequenceNumber = int.parse(item.deliverySequenceNumber!);
+ if (item.groupSize != null) {
+ groupLastSequenceNumber += int.parse(item.groupSize!) - 1;
+ }
+
+ String addrToDisplay = (item.street ?? "").toUpperCase() +
+ " " +
+ (item.houseNumber ?? "") +
+ (item.houseNumberAddition ?? "");
+
+ var groupedTask = ActiveTask(
+ sequenceNumber,
+ item.timeframe!,
+ groupLastSequenceNumber,
+ addrToDisplay,
+ item.indicationSignatureRequired == true,
+ item.indicationNotAtNeighbours == true);
+
+ if (isFirst) {
+ eventBus.fire(NextStopLoadedEvent(groupedTask));
+ isFirst = false;
+ }
+ widget.allTasks.add(groupedTask);
+ }
+ }
+}
diff --git a/lib/pages/navigation_page.dart b/lib/pages/navigation_page.dart
index 59b5451..96a5ef2 100644
--- a/lib/pages/navigation_page.dart
+++ b/lib/pages/navigation_page.dart
@@ -1,12 +1,13 @@
import 'dart:async';
import 'package:auto_orientation/auto_orientation.dart';
import 'package:flutter/services.dart';
+import 'package:training_planner/navigation/HERENavigation.dart';
+import 'package:training_planner/navigation/baseNavigation.dart';
import 'package:training_planner/route.dart' as DHLRoute;
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:here_sdk/mapview.dart';
-import 'package:in_date_utils/in_date_utils.dart' as DateUtilities;
import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:training_planner/RoutingExample.dart';
import 'package:training_planner/events/MapPanningEvent.dart';
@@ -14,15 +15,7 @@ import 'package:training_planner/events/NextStopLoadedEvent.dart';
import 'package:training_planner/events/RouteLoadedEvent.dart';
import 'package:training_planner/events/StopCompletedEvent.dart';
import 'package:training_planner/main.dart';
-import 'package:training_planner/shift.dart';
import 'package:training_planner/style/style.dart';
-import 'package:training_planner/utils/date.dart';
-import 'package:training_planner/widgets/agenda_week.dart';
-import 'package:flutter_local_notifications/flutter_local_notifications.dart';
-import 'package:here_sdk/core.dart';
-import 'package:here_sdk/core.engine.dart';
-import 'package:here_sdk/core.errors.dart';
-import 'package:here_sdk/mapview.dart';
import 'package:wakelock/wakelock.dart';
class NavigationPage extends StatefulWidget {
@@ -34,7 +27,8 @@ class NavigationPage extends StatefulWidget {
}
class _NavigationPageState extends State<NavigationPage> {
- RoutingExample? _routingExample;
+ //RoutingExample? _routingExample;
+ BaseNavigation? navigation;
StreamSubscription? panGestureEvent;
StreamSubscription? taskLoadedEvent;
ActiveTask? activeTask = ActiveTask(1, "", 1, "", false, false);
@@ -91,16 +85,16 @@ class _NavigationPageState extends State<NavigationPage> {
void changeIsLookingAround(bool val) {
setState(() {
- _routingExample?.isLookingAround = val;
+ navigation?.isLookingAround = val;
});
}
void _zoomIn() {
- _routingExample?.changeZoom(_routingExample!.currentZoom + 1);
+ eventBus.fire(ChangeZoomEvent(navigation!.currentZoom + 1));
}
void _zoomOut() {
- _routingExample?.changeZoom(_routingExample!.currentZoom - 1);
+ eventBus.fire(ChangeZoomEvent(navigation!.currentZoom - 1));
}
void _mockStopComplete() {
@@ -113,6 +107,10 @@ class _NavigationPageState extends State<NavigationPage> {
@override
Widget build(BuildContext context) {
+ if (navigation == null) {
+ navigation = HERENavigation(route: widget.route);
+ }
+
return Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: Padding(
@@ -129,15 +127,14 @@ class _NavigationPageState extends State<NavigationPage> {
),
),
Visibility(
- visible: _routingExample == null
- ? false
- : _routingExample!.isLookingAround,
+ visible:
+ navigation == null ? false : navigation!.isLookingAround,
child: FloatingActionButton(
backgroundColor: Colors.green,
child: const Icon(Icons.center_focus_strong),
onPressed: () => {
changeIsLookingAround(false),
- _routingExample?.flyTo(_routingExample!.lastPosition)
+ eventBus.fire(FlyToEvent(navigation!.lastPosition))
},
),
),
@@ -163,7 +160,7 @@ class _NavigationPageState extends State<NavigationPage> {
),
Expanded(
child: Stack(
- children: [HereMap(onMapCreated: _onMapCreated)],
+ children: [navigation!],
),
),
],
@@ -179,7 +176,7 @@ class _NavigationPageState extends State<NavigationPage> {
}
Widget _createNextDropInfoWidget() {
- if (_routingExample == null) return Padding(padding: EdgeInsets.all(0));
+ if (navigation == null) return Padding(padding: EdgeInsets.all(0));
return Container(
decoration: BoxDecoration(color: Colors.white),
@@ -253,28 +250,10 @@ class _NavigationPageState extends State<NavigationPage> {
);
}
- void _onMapCreated(HereMapController hereMapController) async {
- hereMapController.mapScene.loadSceneForMapScheme(MapScheme.normalDay,
- (MapError? error) {
- if (error == null) {
- _routingExample = RoutingExample(hereMapController);
- _routingExample?.addRoute(widget.route).then((value) {
- eventBus.fire(RouteLoadedEvent(page: widget));
- });
- } else {
- print("Map scene not loaded. MapError: " + error.toString());
- }
- });
- }
-
@override
void dispose() {
- // Free HERE SDK resources before the application shuts down.
- //SDKNativeEngine.sharedInstance?.dispose();
- //SdkContext.release();
panGestureEvent?.cancel();
taskLoadedEvent?.cancel();
- _routingExample?.destroy();
Wakelock.disable();
AutoOrientation.portraitUpMode();
SystemChrome.setEnabledSystemUIOverlays(