summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/RoutingExample.dart148
-rw-r--r--lib/events/NextStopLoadedEvent.dart1
-rw-r--r--lib/events/StopCompletedEvent.dart1
-rw-r--r--lib/pages/navigation_page.dart180
4 files changed, 275 insertions, 55 deletions
diff --git a/lib/RoutingExample.dart b/lib/RoutingExample.dart
index 0ec3e7e..02c097a 100644
--- a/lib/RoutingExample.dart
+++ b/lib/RoutingExample.dart
@@ -17,6 +17,8 @@ import 'package:here_sdk/routing.dart';
import 'package:image/image.dart' as image;
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/pages/navigation_page.dart';
import 'route.dart' as DHLRoute;
@@ -25,12 +27,45 @@ import 'main.dart';
// A callback to notify the hosting widget.
typedef ShowDialogFunction = void Function(String title, String message);
+class DestinationPin {
+ final String text;
+ final GeoCoordinates? coords;
+ WidgetPin? pin;
+
+ DestinationPin({this.text = '', this.coords});
+}
+
+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;
double currentZoom = 20;
HereMapController hereMapController;
+ StreamSubscription? stopCompletedEvent;
+
List<MapPolyline> _routeSections = [];
+ List<MapPolyline> _pathSections = [];
+ List<DestinationPin> _parcelNumberPins = [];
+ List<GeoCoordinates> _destinationCoords = [];
+ List<ActiveTask> allTasks = [];
+ late ActiveTask activeTask;
+
int routeSectionCursor = 0;
late DHLRoute.Route _route;
@@ -40,6 +75,8 @@ class RoutingExample {
RoutingExample(HereMapController _hereMapController)
: hereMapController = _hereMapController {
+ activeTask = ActiveTask(0, "", 0, "", false, false);
+
try {
_routingEngine = RoutingEngine();
} on InstantiationException {
@@ -65,6 +102,21 @@ class RoutingExample {
isLookingAround = true;
eventBus.fire(MapPanningEvent(true));
});
+
+ stopCompletedEvent = eventBus.on<StopCompletedEvent>().listen((e) {
+ routeSectionCursor += 1;
+ if (routeSectionCursor >= allTasks.length) {
+ routeSectionCursor = allTasks.length - 1;
+ }
+ activeTask = allTasks[routeSectionCursor];
+ updateHighlightedRouteSections();
+ eventBus.fire(NextStopLoadedEvent());
+ });
+ }
+
+ void destroy() {
+ stopCompletedEvent?.cancel();
+ timer?.cancel();
}
void _updateLocation(Position value) {
@@ -129,9 +181,20 @@ class RoutingExample {
}
void showAnchoredMapViewPin(GeoCoordinates coords, String text) {
- var widgetPin = hereMapController.pinWidget(
- _createWidget(text, Color.fromARGB(200, 0, 144, 138)), coords);
- widgetPin?.anchor = Anchor2D.withHorizontalAndVertical(0.5, 0.5);
+ _parcelNumberPins.add(DestinationPin(text: text, coords: coords));
+ }
+
+ 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;
}
Future<void> addRoute(DHLRoute.Route route) async {
@@ -145,23 +208,54 @@ class RoutingExample {
List<Waypoint> waypoints = [Waypoint.withDefaults(routeStartCoords)];
- GeoCoordinates previousCoords = routeStartCoords;
+ bool isFirst = true;
for (final item in route.tasks!) {
var destinationGeoCoordinates = GeoCoordinates(
double.parse(item.addressLatitude!),
double.parse(item.addressLongitude!));
- if (item.groupFirst == 'false') continue;
+ 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;
+ }
+ }
waypoints.add(Waypoint.withDefaults(destinationGeoCoordinates));
- showAnchoredMapViewPin(
- destinationGeoCoordinates, item.deliverySequenceNumber.toString());
- previousCoords = destinationGeoCoordinates;
+ _parcelNumberPins.add(DestinationPin(
+ text: item.deliverySequenceNumber.toString(),
+ coords: destinationGeoCoordinates));
+ _destinationCoords.add(destinationGeoCoordinates);
+ debugPrint(item.deliverySequenceNumber);
+
+ int sequenceNumber = int.parse(item.deliverySequenceNumber!);
+ int groupLastSequenceNumber = int.parse(item.deliverySequenceNumber!);
+ if (item.groupSize != null) {
+ groupLastSequenceNumber += int.parse(item.groupSize!) - 1;
+ }
+ var groupedTask = ActiveTask(
+ sequenceNumber,
+ item.timeframe!,
+ groupLastSequenceNumber,
+ item.fullAddressForNavigation!,
+ item.indicationSignatureRequired == true,
+ item.indicationNotAtNeighbours == true);
+
+ if (isFirst) {
+ activeTask = groupedTask;
+ isFirst = false;
+ }
+ allTasks.add(groupedTask);
}
PedestrianOptions f = PedestrianOptions.withDefaults();
f.routeOptions.alternatives = 0;
+ f.routeOptions.enableTrafficOptimization = false;
f.routeOptions.optimizationMode = OptimizationMode.fastest;
_routingEngine.calculatePedestrianRoute(waypoints, f,
@@ -181,6 +275,8 @@ class RoutingExample {
var error = routingError.toString();
}
});
+
+ eventBus.fire(NextStopLoadedEvent());
}
_showLineToHouse(Section section, GeoCoordinates houseCoords) {
@@ -192,7 +288,7 @@ class RoutingExample {
MapPolyline(walkLine, 8, Color.fromARGB(160, 255, 20, 20));
hereMapController.mapScene.addMapPolyline(walkPathPolyline);
- //_routeSections.add(walkPathPolyline);
+ _pathSections.add(walkPathPolyline);
}
_showRouteOnMap(here.Route route) {
@@ -211,13 +307,43 @@ class RoutingExample {
}
void updateHighlightedRouteSections() {
+ // Show the next 20 parcel pins, to let the delivery driver decide on possible detours.
+ int maxPins = 20;
+ for (int i = 0; i < _parcelNumberPins.length; i++) {
+ DestinationPin pin = _parcelNumberPins.elementAt(i);
+
+ if (i > routeSectionCursor && i < routeSectionCursor + maxPins) {
+ if (pin.pin != null) continue;
+ var widgetPin = hereMapController.pinWidget(
+ _createWidget(pin.text, Color.fromARGB(200, 0, 144, 138)),
+ _destinationCoords[i]);
+ widgetPin?.anchor = Anchor2D.withHorizontalAndVertical(0.5, 0.5);
+ pin.pin = widgetPin;
+ } else {
+ pin.pin?.unpin();
+ pin.pin = null;
+ }
+
+ // Highlight current destination.
+ if (i == routeSectionCursor) {
+ var widgetPin = hereMapController.pinWidget(
+ _createWidget(pin.text, ui.Color.fromARGB(199, 143, 8, 31)),
+ _destinationCoords[i]);
+ widgetPin?.anchor = Anchor2D.withHorizontalAndVertical(0.5, 0.5);
+ pin.pin = widgetPin;
+ }
+ }
+
+ // Show the next 5 sections as to not clutter the screen.
+ int maxSections = 5;
for (int i = 0; i < _routeSections.length; i++) {
MapPolyline section = _routeSections.elementAt(i);
- int maxSections = 5;
+ 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 &&
@@ -228,8 +354,10 @@ class RoutingExample {
0,
144,
138);
+ path.lineColor = Color.fromARGB(160, 255, 0, 0);
} else {
section.lineColor = Color.fromARGB(0, 255, 255, 255);
+ path.lineColor = Color.fromARGB(0, 255, 255, 255);
}
}
}
diff --git a/lib/events/NextStopLoadedEvent.dart b/lib/events/NextStopLoadedEvent.dart
new file mode 100644
index 0000000..c4fd59d
--- /dev/null
+++ b/lib/events/NextStopLoadedEvent.dart
@@ -0,0 +1 @@
+class NextStopLoadedEvent {}
diff --git a/lib/events/StopCompletedEvent.dart b/lib/events/StopCompletedEvent.dart
new file mode 100644
index 0000000..8aa283b
--- /dev/null
+++ b/lib/events/StopCompletedEvent.dart
@@ -0,0 +1 @@
+class StopCompletedEvent {}
diff --git a/lib/pages/navigation_page.dart b/lib/pages/navigation_page.dart
index 531395e..d1c15b9 100644
--- a/lib/pages/navigation_page.dart
+++ b/lib/pages/navigation_page.dart
@@ -8,6 +8,8 @@ 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';
+import 'package:training_planner/events/NextStopLoadedEvent.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';
@@ -28,8 +30,9 @@ class NavigationPage extends StatefulWidget {
class _NavigationPageState extends State<NavigationPage> {
RoutingExample? _routingExample;
-
StreamSubscription? panGestureEvent;
+ StreamSubscription? taskLoadedEvent;
+ ActiveTask? activeTask;
Future<bool> _handleLocationPermission() async {
bool serviceEnabled;
@@ -69,6 +72,10 @@ class _NavigationPageState extends State<NavigationPage> {
panGestureEvent = eventBus.on<MapPanningEvent>().listen((event) {
changeIsLookingAround(event.isPanning);
});
+
+ taskLoadedEvent = eventBus.on<NextStopLoadedEvent>().listen((event) {
+ setState(() {});
+ });
}
void changeIsLookingAround(bool val) {
@@ -86,52 +93,135 @@ class _NavigationPageState extends State<NavigationPage> {
}
void _mockStopComplete() {
- _routingExample?.routeSectionCursor++;
- _routingExample?.updateHighlightedRouteSections();
+ eventBus.fire(StopCompletedEvent());
}
@override
Widget build(BuildContext context) {
return Scaffold(
- floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
- floatingActionButton: Padding(
- padding: const EdgeInsets.all(8.0),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: <Widget>[
- FloatingActionButton(
- onPressed: () => _mockStopComplete(),
- child: Icon(Icons.check_circle),
- ),
- Visibility(
- visible: _routingExample == null
- ? false
- : _routingExample!.isLookingAround,
- child: FloatingActionButton(
- backgroundColor: Colors.green,
- child: const Icon(Icons.center_focus_strong),
- onPressed: () => {
- changeIsLookingAround(false),
- _routingExample?.flyTo(_routingExample!.lastPosition)
- },
+ floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
+ floatingActionButton: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: <Widget>[
+ FloatingActionButton(
+ onPressed: () => _mockStopComplete(),
+ child: Icon(Icons.check_circle),
),
+ Visibility(
+ visible: _routingExample == null
+ ? false
+ : _routingExample!.isLookingAround,
+ child: FloatingActionButton(
+ backgroundColor: Colors.green,
+ child: const Icon(Icons.center_focus_strong),
+ onPressed: () => {
+ changeIsLookingAround(false),
+ _routingExample?.flyTo(_routingExample!.lastPosition)
+ },
+ ),
+ ),
+ Padding(padding: EdgeInsets.all(5)),
+ FloatingActionButton(
+ onPressed: () => _zoomOut(),
+ child: Icon(Icons.zoom_out),
+ ),
+ Padding(padding: EdgeInsets.all(2)),
+ FloatingActionButton(
+ onPressed: () => _zoomIn(),
+ child: Icon(Icons.zoom_in),
+ )
+ ],
+ ),
+ ),
+ body: Column(
+ children: [
+ _createNextDropInfoWidget(),
+ Container(
+ decoration: BoxDecoration(color: Colors.black),
+ height: 2,
),
- Padding(padding: EdgeInsets.all(5)),
- FloatingActionButton(
- onPressed: () => _zoomOut(),
- child: Icon(Icons.zoom_out),
- ),
- Padding(padding: EdgeInsets.all(2)),
- FloatingActionButton(
- onPressed: () => _zoomIn(),
- child: Icon(Icons.zoom_in),
- )
+ Expanded(child: HereMap(onMapCreated: _onMapCreated)),
],
- ),
- ),
- body: Stack(
+ ));
+ }
+
+ Widget _createNextDropInfoWidget() {
+ if (_routingExample == null) return Padding(padding: EdgeInsets.all(0));
+
+ return Container(
+ decoration: BoxDecoration(color: Colors.white),
+ height: 80,
+ child: Column(
children: [
- HereMap(onMapCreated: _onMapCreated),
+ SizedBox(
+ height: 10,
+ ),
+ Container(
+ height: 50,
+ padding: EdgeInsets.only(left: 10, right: 10),
+ child: Row(
+ children: [
+ RichText(
+ text: TextSpan(
+ style: DefaultTextStyle.of(context).style,
+ children: <TextSpan>[
+ TextSpan(
+ text: '[' +
+ _routingExample!.activeTask.firstParcelNumber
+ .toString() +
+ ' - ' +
+ _routingExample!.activeTask.lastParcelNumber
+ .toString() +
+ '',
+ style: TextStyle(
+ color: Color.fromARGB(255, 0, 0, 0),
+ fontSize: 25,
+ ),
+ ),
+ TextSpan(
+ text: ' ' +
+ (_routingExample!.activeTask.lastParcelNumber -
+ _routingExample!
+ .activeTask.firstParcelNumber +
+ 1)
+ .toString(),
+ style: TextStyle(
+ color: Color.fromARGB(150, 0, 0, 0),
+ fontSize: 12,
+ ),
+ ),
+ TextSpan(
+ text: ']',
+ style: TextStyle(
+ color: Color.fromARGB(255, 0, 0, 0),
+ fontSize: 25,
+ ),
+ ),
+ ],
+ ),
+ ),
+ Padding(padding: EdgeInsets.all(5)),
+ Expanded(
+ child: Text(
+ _routingExample!.activeTask.fullAddress,
+ style: TextStyle(
+ color: Color.fromARGB(255, 0, 0, 0),
+ fontSize: 18,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ Container(
+ height: 20,
+ padding: EdgeInsets.only(left: 10, right: 10),
+ child: Row(children: [
+ Text(_routingExample!.activeTask.deliveryTimeBlock)
+ ]),
+ ),
],
),
);
@@ -142,9 +232,9 @@ class _NavigationPageState extends State<NavigationPage> {
(MapError? error) {
if (error == null) {
_routingExample = RoutingExample(hereMapController);
- routeProvider
- .getRoute(0)
- .then((value) => _routingExample?.addRoute(value));
+ routeProvider.getRoute(0).then((value) {
+ _routingExample?.addRoute(value);
+ });
} else {
print("Map scene not loaded. MapError: " + error.toString());
}
@@ -154,11 +244,11 @@ class _NavigationPageState extends State<NavigationPage> {
@override
void dispose() {
// Free HERE SDK resources before the application shuts down.
- SDKNativeEngine.sharedInstance?.dispose();
- SdkContext.release();
+ //SDKNativeEngine.sharedInstance?.dispose();
+ //SdkContext.release();
panGestureEvent?.cancel();
-
- _routingExample?.timer?.cancel();
+ taskLoadedEvent?.cancel();
+ _routingExample?.destroy();
super.dispose();
}
}