From d35e4014e16bfdf2e2fc2bde397c385fc53e498c Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Mon, 10 Apr 2023 21:11:29 +0200 Subject: refactor --- lib/RoutingExample.dart | 78 +++------ lib/events/NextStopLoadedEvent.dart | 2 +- lib/events/StopCompletedEvent.dart | 12 ++ lib/navigation/HERENavigation.dart | 324 ++++++++++++++++++++++++++++++++++++ lib/navigation/baseNavigation.dart | 290 ++++++++++++++++++++++++++++++++ lib/pages/navigation_page.dart | 53 ++---- 6 files changed, 668 insertions(+), 91 deletions(-) create mode 100644 lib/navigation/HERENavigation.dart create mode 100644 lib/navigation/baseNavigation.dart 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 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 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 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 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 _routeSections = []; + List _pathSections = []; + + late RoutingEngine _routingEngine; + late SearchOptions _searchOptions; + late MapMarker mapMarker; + + Future _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 _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().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().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 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 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? 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 allTasks = []; + List blacklist = []; + List parcelNumberPins = []; + List destinationCoords = []; + final DHLRoute.Route route; + + BaseNavigation({Key? key, required this.route}) : super(key: key); +} + +abstract class BaseNavigationState extends State { + int routeSectionCursor = 0; + + StreamSubscription? changeZoomEvent; + StreamSubscription? flyToEvent; + + BaseNavigationState() { + changeZoomEvent = eventBus.on().listen((event) { + changeZoom(event.zoom); + }); + + flyToEvent = eventBus.on().listen((event) { + flyTo(event.coords); + }); + } + + void flyTo(DHLCoordinates coords); + void changeZoom(double newVal); + Future 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 groupPids) { + List 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 groupPids) { + List 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 { - 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 { 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 { @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 { ), ), 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 { ), Expanded( child: Stack( - children: [HereMap(onMapCreated: _onMapCreated)], + children: [navigation!], ), ), ], @@ -179,7 +176,7 @@ class _NavigationPageState extends State { } 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 { ); } - 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( -- cgit v1.2.3-70-g09d2