From 3c2e9ceecb2bae5a84c6d92721ed789b26a0e6c1 Mon Sep 17 00:00:00 2001 From: Sven Carstensen Date: Tue, 6 Feb 2024 11:49:50 +0100 Subject: [PATCH] Erweiterungen --- lib/content_views/approach_area_page.dart | 69 +++++++++++++++++++ lib/content_views/main_page.dart | 17 +++-- lib/content_views/messages_page.dart | 2 +- lib/content_views/task_list_page.dart | 12 ++-- lib/content_views/tour_list_page.dart | 8 +-- lib/popups/accept_jobs_popup.dart | 2 +- lib/protocoll_messages/fin_task_message.dart | 2 +- .../fin_task_message.g.dart | 2 +- lib/protocoll_messages/track_message.dart | 32 +++++++++ lib/protocoll_messages/track_message.g.dart | 15 ++++ lib/tools/mqtt_core.dart | 32 ++++++++- lib/tools/util.dart | 7 ++ pubspec.lock | 6 +- pubspec.yaml | 1 + 14 files changed, 180 insertions(+), 27 deletions(-) create mode 100644 lib/content_views/approach_area_page.dart create mode 100644 lib/protocoll_messages/track_message.dart create mode 100644 lib/protocoll_messages/track_message.g.dart diff --git a/lib/content_views/approach_area_page.dart b/lib/content_views/approach_area_page.dart new file mode 100644 index 0000000..16d55f1 --- /dev/null +++ b/lib/content_views/approach_area_page.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:isar/isar.dart'; +import 'package:stadtbote/content_views/tour_list_page.dart'; +import 'package:stadtbote/content_views/utils/content_view_widget.dart'; +import 'package:stadtbote/content_views/utils/header_info.dart'; +import 'package:intl/intl.dart'; +import 'package:stadtbote/tools/message_service.dart'; + +import '../main.dart'; +import '../model/job.dart'; +import '../tools/constants.dart'; +import '../tools/util.dart'; + +class ApproachAreaPage extends ContentViewWidget { + const ApproachAreaPage({super.key}); + + @override + State createState() => _ApproachAreaPageState(); + + @override + Future getHeaderInfo(BuildContext context) async { + return HeaderInfo( + titleWidget: const Text( + 'Angenommene Aufträge', + style: TextStyle( + color: Colors.white, + fontSize: 24.0, + ), + ), + rightButtonEnabled: true, + rightButtonVisible: true, + rightButtonImage: Util.fetchFutureIcon(const Icon(Icons.info_outline, size: 20.0, color: Colors.white)), + rightButtonOnPressed: () async { + await Util.startBrowser('https://app.assecutor.de/help/sb/app/context/001/index.html'); + }); + } +} + +class _ApproachAreaPageState extends State { + late List _jobs; + + late bool _initCompleted = false; + + @override + void initState() { + Future.delayed(const Duration(seconds: 0), () async { + _jobs = await MyApp.isarInstance.jobs.filter().stateEqualTo(1).findAll(); + + _initCompleted = true; + + setState(() {}); + }); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + if (!_initCompleted) { + return Util.getWaitWidget(context); + } + + return const Text("Hello World!"); + } + + void _clicked(Job job) { + MessageService().publish(Constants.messageTopicPushContentView, arguments: TourListPage(job: job)); + } +} diff --git a/lib/content_views/main_page.dart b/lib/content_views/main_page.dart index 21b80ba..fe37387 100644 --- a/lib/content_views/main_page.dart +++ b/lib/content_views/main_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:isar/isar.dart'; import 'package:stadtbote/content_views/accepted_jobs_page.dart'; +import 'package:stadtbote/content_views/approach_area_page.dart'; import 'package:stadtbote/content_views/assigned_jobs_page.dart'; import 'package:stadtbote/content_views/finished_jobs_page.dart'; import 'package:stadtbote/content_views/messages_page.dart'; @@ -132,8 +133,9 @@ class _MainPageState extends State { child: getDefaultButton( 'Zugewiesene Aufträge', image: Image.asset('assets/zugewiesene_auftraege.png', width: 30, height: 30), - () => {MessageService() - .publish(Constants.messageTopicPushContentView, arguments: const AssignedJobsPage())}), + () => { + MessageService().publish(Constants.messageTopicPushContentView, arguments: const AssignedJobsPage()) + }), ); }, ), @@ -162,7 +164,7 @@ class _MainPageState extends State { 'Angenommene Aufträge', image: Image.asset('assets/angenommene_auftraege.png', width: 30, height: 30), () => { - MessageService() + MessageService() .publish(Constants.messageTopicPushContentView, arguments: const AcceptedJobsPage()) })); }, @@ -196,18 +198,15 @@ class _MainPageState extends State { child: getDefaultButton( 'Nachrichten', image: Image.asset('assets/nachrichten.png', width: 30, height: 30), - () => { - MessageService().publish(Constants.messageTopicPushContentView, arguments: const MessagesPage()) - })); + () => + {MessageService().publish(Constants.messageTopicPushContentView, arguments: const MessagesPage())})); }, ), const SizedBox(height: 20), getDefaultButton( 'Anfahrtsbereich', image: Image.asset('assets/anfahrtsbereich.png', width: 30, height: 30), - () => { - //BroadcastReceiver().publish(Constants.messageTopicPushContentView, arguments: const FinishedJobsPage()) - }), + () => {MessageService().publish(Constants.messageTopicPushContentView, arguments: const ApproachAreaPage())}), const SizedBox(height: 20), getDefaultButton( 'Abmelden', diff --git a/lib/content_views/messages_page.dart b/lib/content_views/messages_page.dart index 318bf00..b8a46bc 100644 --- a/lib/content_views/messages_page.dart +++ b/lib/content_views/messages_page.dart @@ -33,7 +33,7 @@ class MessagesPage extends ContentViewWidget { rightButtonVisible: true, rightButtonImage: Util.fetchFutureIcon(const Icon(Icons.info_outline, size: 20.0, color: Colors.white)), rightButtonOnPressed: () async { - showInfosPopup(context, await MyApp.isarInstance.status.where().findFirst()); + await Util.startBrowser('https://app.assecutor.de/help/sb/app/context/003/index.html'); }); } } diff --git a/lib/content_views/task_list_page.dart b/lib/content_views/task_list_page.dart index 1cbb65d..de3974d 100644 --- a/lib/content_views/task_list_page.dart +++ b/lib/content_views/task_list_page.dart @@ -1,4 +1,4 @@ - +import 'dart:convert' show utf8; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; @@ -46,11 +46,11 @@ class TaskListPage extends ContentViewWidget { fontSize: 24.0, ), ), - rightButtonEnabled: false, - rightButtonVisible: false, - rightButtonImage: null, + rightButtonEnabled: true, + rightButtonVisible: true, + rightButtonImage: Util.fetchFutureIcon(const Icon(Icons.info_outline, size: 20.0, color: Colors.white)), rightButtonOnPressed: () async { - //BroadcastReceiver().publish(Constants.messageTopicPushContentView, arguments: EmployeeEditProfileWidget()); + await Util.startBrowser('https://app.assecutor.de/help/sb/app/context/002/index.html'); }); } } @@ -148,7 +148,7 @@ class _TaskListPageState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Text( - taskInfo.task.topic, + utf8.decode(taskInfo.task.topic.codeUnits), textAlign: TextAlign.left, style: TextStyle( color: textColor, diff --git a/lib/content_views/tour_list_page.dart b/lib/content_views/tour_list_page.dart index ab954dc..b67a55f 100644 --- a/lib/content_views/tour_list_page.dart +++ b/lib/content_views/tour_list_page.dart @@ -30,11 +30,11 @@ class TourListPage extends ContentViewWidget { fontSize: 24.0, ), ), - rightButtonEnabled: false, - rightButtonVisible: false, - rightButtonImage: null, + rightButtonEnabled: true, + rightButtonVisible: true, + rightButtonImage: Util.fetchFutureIcon(const Icon(Icons.info_outline, size: 20.0, color: Colors.white)), rightButtonOnPressed: () async { - //BroadcastReceiver().publish(Constants.messageTopicPushContentView, arguments: EmployeeEditProfileWidget()); + await Util.startBrowser('https://app.assecutor.de/help/sb/app/context/004/index.html'); }); } } diff --git a/lib/popups/accept_jobs_popup.dart b/lib/popups/accept_jobs_popup.dart index 124cf28..bfd63df 100644 --- a/lib/popups/accept_jobs_popup.dart +++ b/lib/popups/accept_jobs_popup.dart @@ -148,7 +148,7 @@ _sendAnswer(Job job, int item) { message.reaction.track.pos = FinTaskPos(); message.reaction.track.pos.lat = currentPosition != null ? currentPosition.latitude : 0.0; message.reaction.track.pos.long = currentPosition != null ? currentPosition.longitude : 0.0; - message.reaction.track.pos.acc = currentPosition != null ? currentPosition.accuracy : 0.0; + message.reaction.track.pos.acc = currentPosition != null ? currentPosition.accuracy.toInt() : 0; MqttCore.instance.publishPayloadMessage("job", message.toJson()); diff --git a/lib/protocoll_messages/fin_task_message.dart b/lib/protocoll_messages/fin_task_message.dart index 3b09444..ad17639 100644 --- a/lib/protocoll_messages/fin_task_message.dart +++ b/lib/protocoll_messages/fin_task_message.dart @@ -49,7 +49,7 @@ class FinTaskPos { late double long; - late double acc; + late int acc; FinTaskPos(); diff --git a/lib/protocoll_messages/fin_task_message.g.dart b/lib/protocoll_messages/fin_task_message.g.dart index a939979..6561d02 100644 --- a/lib/protocoll_messages/fin_task_message.g.dart +++ b/lib/protocoll_messages/fin_task_message.g.dart @@ -40,7 +40,7 @@ Map _$TaskToJson(Task instance) => { FinTaskPos _$FinTaskPosFromJson(Map json) => FinTaskPos() ..lat = (json['lat'] as num).toDouble() ..long = (json['long'] as num).toDouble() - ..acc = (json['acc'] as num).toDouble(); + ..acc = json['acc'] as int; Map _$FinTaskPosToJson(FinTaskPos instance) => { diff --git a/lib/protocoll_messages/track_message.dart b/lib/protocoll_messages/track_message.dart new file mode 100644 index 0000000..30c958b --- /dev/null +++ b/lib/protocoll_messages/track_message.dart @@ -0,0 +1,32 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:stadtbote/protocoll_messages/fin_task_message.dart'; + +part 'track_message.g.dart'; + +/* +var payloadObject = new JObject(); + + var posObject = new JObject(); + payloadObject.Add(new JProperty("pos", posObject)); + posObject.Add(new JProperty("time", DateTime.Now.ToString("o"))); + posObject.Add(new JProperty("lat", location.Latitude)); + posObject.Add(new JProperty("long", location.Longitude)); + if (location.Accuracy != null) + { + posObject.Add(new JProperty("acc", (int)location.Accuracy)); + } + + SendJsonMessageAsync("track", payloadObject); + */ + +@JsonSerializable() +class TrackMessage { + late FinTaskPos pos; + + TrackMessage(); + + factory TrackMessage.fromJson(Map json) => _$TrackMessageFromJson(json); + + Map toJson() => _$TrackMessageToJson(this); +} + diff --git a/lib/protocoll_messages/track_message.g.dart b/lib/protocoll_messages/track_message.g.dart new file mode 100644 index 0000000..231c185 --- /dev/null +++ b/lib/protocoll_messages/track_message.g.dart @@ -0,0 +1,15 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'track_message.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +TrackMessage _$TrackMessageFromJson(Map json) => TrackMessage() + ..pos = FinTaskPos.fromJson(json['pos'] as Map); + +Map _$TrackMessageToJson(TrackMessage instance) => + { + 'pos': instance.pos, + }; diff --git a/lib/tools/mqtt_core.dart b/lib/tools/mqtt_core.dart index 9c3cea3..d52138a 100644 --- a/lib/tools/mqtt_core.dart +++ b/lib/tools/mqtt_core.dart @@ -5,15 +5,18 @@ import 'dart:math'; import 'package:isar/isar.dart'; import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_server_client.dart'; +import 'package:stadtbote/model/job_tour.dart'; import 'package:stadtbote/protocoll_messages/bootstrap_request.dart'; import 'package:stadtbote/protocoll_messages/bootstrap_response_payload.dart'; import 'package:stadtbote/protocoll_messages/device_object.dart'; import 'package:stadtbote/model/job.dart'; import 'package:stadtbote/model/message.dart'; +import 'package:stadtbote/protocoll_messages/fin_task_message.dart'; import 'package:stadtbote/protocoll_messages/job_del_message.dart'; import 'package:stadtbote/protocoll_messages/payload_container.dart'; import 'package:stadtbote/protocoll_messages/start_session_message.dart'; import 'package:stadtbote/protocoll_messages/sync_jobs_message.dart'; +import 'package:stadtbote/protocoll_messages/track_message.dart'; import 'package:stadtbote/tools/connection_status.dart'; import 'package:stadtbote/tools/message_service.dart'; import 'package:stadtbote/tools/messages/job_deleted_message.dart'; @@ -49,6 +52,8 @@ class MqttCore { late int _reconnectDelay = 0; + late Timer? _trackTimer; + MqttCore() { _processBootstrap(); } @@ -168,7 +173,7 @@ class MqttCore { break; case 'job_del': - //_jobDeleteReceived(payloadData); + _jobDeleteReceived(payloadData); break; case 'sync_request': @@ -209,6 +214,8 @@ class MqttCore { }); MessageService().publish(Constants.messageTopicStatusInfoUpdate, arguments: StatusInfoUpdate(status: statusMessage)); + + _startTrackTimer(); } void _rankingMessageReceived(payloadData) async { @@ -288,6 +295,8 @@ class MqttCore { void _clientDisconnected() { connectionState = ConnectionStateEnum.notConnected; + _cancelTrackTimer(); + Util.logInfo("_clientDisconnected called"); MessageService().publish(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected)); @@ -374,4 +383,25 @@ class MqttCore { MqttCore.instance.publishPayloadMessage("server", answer.toJson()); } + + void _startTrackTimer() { + _trackTimer = Timer(const Duration(seconds: 60), () { + var position = MyApp.currentPosition; + if (position != null) { + var trackMessage = TrackMessage(); + trackMessage.pos = FinTaskPos(); + trackMessage.pos.lat = position.latitude; + trackMessage.pos.long = position.longitude; + trackMessage.pos.acc = position.accuracy.toInt(); + + publishPayloadMessage("track", trackMessage.toJson()); + } + }); + } + + void _cancelTrackTimer() { + if (_trackTimer != null) { + _trackTimer!.cancel(); + } + } } diff --git a/lib/tools/util.dart b/lib/tools/util.dart index 9a584fc..9853855 100644 --- a/lib/tools/util.dart +++ b/lib/tools/util.dart @@ -6,6 +6,7 @@ import 'package:flutter/services.dart'; import 'package:image_picker/image_picker.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:stadtbote/tools/constants.dart'; +import 'package:url_launcher/url_launcher.dart'; import 'package:uuid/uuid.dart'; import '../Tools/colored_safe_area.dart'; @@ -174,6 +175,12 @@ class Util { return null; } + + static Future startBrowser(String websiteUrl) async { + if (!await launchUrl(Uri.parse(websiteUrl))) { + throw Exception('Could not launch $websiteUrl'); + } + } } Widget getDefaultButton(String text, Function() onPressed, {Image? image, double? buttonHeight}) { diff --git a/pubspec.lock b/pubspec.lock index 593d335..0a3e057 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1254,13 +1254,13 @@ packages: source: hosted version: "0.3.1" url_launcher: - dependency: transitive + dependency: "direct main" description: name: url_launcher - sha256: b1c9e98774adf8820c96fbc7ae3601231d324a7d5ebd8babe27b6dfac91357ba + sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "6.2.4" url_launcher_android: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 18e1b32..8921e09 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -66,6 +66,7 @@ dependencies: flutter_chat_ui: ^1.6.10 geolocator: ^10.1.0 expandable: ^5.0.1 + url_launcher: ^6.2.4 dev_dependencies: flutter_test: