From 81133905de828d61af0a422a0cd97d6712cd2ff5 Mon Sep 17 00:00:00 2001 From: Sven Carstensen Date: Wed, 29 Jan 2025 11:07:37 +0100 Subject: [PATCH] Fehlerkorrekturen und Erweiterungen --- lib/content_views/accepted_jobs_page.dart | 27 +-- lib/content_views/approach_area_page.dart | 3 +- lib/content_views/assigned_jobs_page.dart | 21 +- lib/content_views/main_page.dart | 41 ++-- lib/content_views/messages_page.dart | 32 ++- lib/content_views/set_desired_zip_page.dart | 184 ++++++++++++++ lib/content_views/task_list_page.dart | 10 +- lib/main.dart | 57 ++--- lib/model/chat_message.g.dart | 2 +- lib/model/enqueued_message.dart | 4 + lib/model/enqueued_message.g.dart | 204 +++++++++++++++- lib/model/job.g.dart | 2 +- lib/model/location_status.g.dart | 2 +- lib/model/log_entry.g.dart | 2 +- lib/model/pictures.g.dart | 2 +- lib/model/rank.g.dart | 2 +- lib/model/session_status.g.dart | 2 +- lib/model/status.g.dart | 2 +- lib/model/task_info.g.dart | 2 +- lib/popups/accept_jobs_popup.dart | 5 +- .../tasks_popups/receipt_giver_popup.dart | 32 ++- .../acknowledge_message.dart | 14 ++ .../acknowledge_message.g.dart | 15 ++ lib/protocoll_messages/messages_showed.dart | 16 ++ lib/protocoll_messages/messages_showed.g.dart | 20 ++ .../set_desired_zip_message.dart | 17 ++ .../set_desired_zip_message.g.dart | 228 ++++++++++++++++++ .../start_session_message.dart | 3 + .../start_session_message.g.dart | 6 +- lib/tools/constants.dart | 4 + lib/tools/message_header.dart | 19 ++ lib/tools/message_header.g.dart | 20 ++ .../messages/publish_payload_message.dart | 6 +- .../messages/remove_state_0_job_from_map.dart | 7 + lib/tools/mqtt_core.dart | 162 +++++++------ lib/tools/util.dart | 7 +- pubspec.lock | 18 +- pubspec.yaml | 25 +- 38 files changed, 1003 insertions(+), 222 deletions(-) create mode 100644 lib/content_views/set_desired_zip_page.dart create mode 100644 lib/protocoll_messages/acknowledge_message.dart create mode 100644 lib/protocoll_messages/acknowledge_message.g.dart create mode 100644 lib/protocoll_messages/messages_showed.dart create mode 100644 lib/protocoll_messages/messages_showed.g.dart create mode 100644 lib/protocoll_messages/set_desired_zip_message.dart create mode 100644 lib/protocoll_messages/set_desired_zip_message.g.dart create mode 100644 lib/tools/message_header.dart create mode 100644 lib/tools/message_header.g.dart create mode 100644 lib/tools/messages/remove_state_0_job_from_map.dart diff --git a/lib/content_views/accepted_jobs_page.dart b/lib/content_views/accepted_jobs_page.dart index 52f2b0f..ae7ba96 100644 --- a/lib/content_views/accepted_jobs_page.dart +++ b/lib/content_views/accepted_jobs_page.dart @@ -66,7 +66,12 @@ class _AcceptedJobsPageState extends State with ProducerMixin List jobWidgets = []; for (var job in _jobs) { - String remarkString = ''; + var bottomText = "${job.id}\n${job.tours[0].comp}\n${job.tours[0].street}\n${job.tours[0].city}"; + // BWV + /*if (job.rem.trim().isNotEmpty) { + bottomText += "\n\n${job.rem.trim()}"; + }*/ + jobWidgets.add( ListTile( onTap: () { @@ -85,7 +90,7 @@ class _AcceptedJobsPageState extends State with ProducerMixin children: [ Text( DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime).toLocal()).toString(), - style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.red : Colors.transparent), + style: TextStyle(backgroundColor: isJobTooFarInFuture(job) ? Colors.red : Colors.transparent), textAlign: TextAlign.left, ), Text( @@ -102,23 +107,7 @@ class _AcceptedJobsPageState extends State with ProducerMixin ], ), Text( - remarkString, - textAlign: TextAlign.left, - ), - Text( - job.id.toString(), - textAlign: TextAlign.left, - ), - Text( - job.tours[0].comp, - textAlign: TextAlign.left, - ), - Text( - job.tours[0].street, - textAlign: TextAlign.left, - ), - Text( - job.tours[0].city, + bottomText, textAlign: TextAlign.left, ), ], diff --git a/lib/content_views/approach_area_page.dart b/lib/content_views/approach_area_page.dart index bff8e2b..29b65b5 100644 --- a/lib/content_views/approach_area_page.dart +++ b/lib/content_views/approach_area_page.dart @@ -2,7 +2,6 @@ import 'package:dart_mq/dart_mq.dart'; import 'package:flutter/material.dart'; import 'package:isar/isar.dart'; -import 'package:mqtt5_client/mqtt5_client.dart'; import 'package:stadtbote/content_views/utils/content_view_widget.dart'; import 'package:stadtbote/main.dart'; import 'package:stadtbote/messages/pop_content_view_message.dart'; @@ -196,7 +195,7 @@ class _ApproachAreaPageState extends State with ProducerMixin, // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicPublishPayload, - payload: PublishPayloadMessage(topic: "set_zip", message: setPosMessage.toJson(), qos: MqttQos.exactlyOnce), + payload: PublishPayloadMessage(topic: "set_zip", message: setPosMessage.toJson(), acknowledgeRequired: false), ); //await MessageService().publish(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "set_zip", message: setPosMessage.toJson(), qos: MqttQos.exactlyOnce)); diff --git a/lib/content_views/assigned_jobs_page.dart b/lib/content_views/assigned_jobs_page.dart index 81daa96..3484876 100644 --- a/lib/content_views/assigned_jobs_page.dart +++ b/lib/content_views/assigned_jobs_page.dart @@ -3,7 +3,6 @@ import 'package:dart_mq/dart_mq.dart'; import 'package:expandable/expandable.dart'; import 'package:flutter/material.dart'; import 'package:isar/isar.dart'; -import 'package:mqtt5_client/mqtt5_client.dart'; import 'package:stadtbote/content_views/utils/content_view_widget.dart'; import 'package:intl/intl.dart'; import 'package:badges/badges.dart' as badges; @@ -12,6 +11,7 @@ import 'package:stadtbote/protocoll_messages/accept_job_message.dart'; import 'package:stadtbote/protocoll_messages/fin_task_message.dart'; import 'package:stadtbote/tools/messages/publish_payload_message.dart'; import 'package:stadtbote/tools/messages/refresh_badges_message.dart'; +import 'package:stadtbote/tools/messages/remove_state_0_job_from_map.dart'; import '../main.dart'; import '../model/job.dart'; @@ -112,7 +112,7 @@ class _AssignedJobsPageState extends State with ProducerMixin Text( DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime).toLocal()).toString(), textAlign: TextAlign.left, - style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.red : Colors.white), + style: TextStyle(backgroundColor: isJobTooFarInFuture(job) ? Colors.red : Colors.white), ), Text('Auftragsnummer: ${job.id}'), Text(job.tours[0].comp), @@ -189,26 +189,21 @@ class _AssignedJobsPageState extends State with ProducerMixin message.track.pos!.long = currentPosition != null ? currentPosition.longitude : 0.0; message.track.pos!.acc = currentPosition != null ? currentPosition.accuracy.toInt() : 0; - // TODO MESSAGING sendMessage( - routingKey: Constants.messageTopicPublishPayload, - payload: PublishPayloadMessage(topic: "reaction", message: message.toJson(), qos: MqttQos.exactlyOnce), + routingKey: Constants.messageTopicRemoveState0JobFromMap, + payload: RemoveState0JobFromMapMessage(jobId: job.id), ); - //await MessageService().publish(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "reaction", message: message.toJson(), qos: MqttQos.exactlyOnce)); + sendMessage( + routingKey: Constants.messageTopicPublishPayload, + payload: PublishPayloadMessage(topic: "reaction", message: message.toJson(), acknowledgeRequired: true), + ); - await MyApp.isarInstance.writeTxn(() async { - await MyApp.isarInstance.jobs.delete(job.id); - }); - - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicUpdateBadges, payload: RefreshBadgesMessage(), ); - //await MessageService().publish(Constants.messageTopicUpdateBadges, arguments: RefreshBadgesMessage()); - _entries = await _createListEntries(); setState(() {}); diff --git a/lib/content_views/main_page.dart b/lib/content_views/main_page.dart index e936cdc..d9f8654 100644 --- a/lib/content_views/main_page.dart +++ b/lib/content_views/main_page.dart @@ -1,7 +1,6 @@ import 'package:dart_mq/dart_mq.dart'; import 'package:flutter/material.dart'; import 'package:isar/isar.dart'; -import 'package:mqtt5_client/mqtt5_client.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'; @@ -21,6 +20,7 @@ import 'package:stadtbote/tools/messages/publish_payload_message.dart'; import 'package:stadtbote/tools/messages/connect_client_message.dart'; import 'package:stadtbote/tools/messages/disconnect_client_message.dart'; import 'package:badges/badges.dart' as badges; +import 'package:stadtbote/tools/messages/remove_state_0_job_from_map.dart'; import 'package:stadtbote/tools/util.dart'; class MainPage extends ContentViewWidget { @@ -211,15 +211,30 @@ class _MainPageState extends State with ConsumerMixin, ProducerMixin { child: getDefaultButton( 'Anfahrtsbereich', image: Image.asset('assets/anfahrtsbereich.png', width: 30, height: 30), - () async => { + () async => { // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicPushContentView, payload: const ApproachAreaPage(), ) //await MessageService().publish(Constants.messageTopicPushContentView, arguments: const ApproachAreaPage()) - }), + }), ), + /*SizedBox(height: _loggedOut == true ? 0 : 20), + Visibility( + visible: !_loggedOut, + child: getDefaultButton( + 'Wunschziel für heute', + image: Image.asset('assets/anfahrtsbereich.png', width: 30, height: 30), + () async => { + // TODO MESSAGING + sendMessage( + routingKey: Constants.messageTopicPushContentView, + payload: const SetDesiredZipPage(), + ) + //await MessageService().publish(Constants.messageTopicPushContentView, arguments: const ApproachAreaPage()) + }), + ),*/ SizedBox(height: _loggedOut == true ? 0 : 20), getDefaultButton(_loggedOut ? 'Anmelden' : 'Abmelden', image: Image.asset(_loggedOut ? 'assets/anmelden.png' : 'assets/abmelden.png', width: 30, height: 30), () async { @@ -262,9 +277,6 @@ class _MainPageState extends State with ConsumerMixin, ProducerMixin { _jobReceived((message.payload as JobReceivedMessage).job); }, ); - /*MessageService().subscribe(Constants.messageTopicJobReceived, this, (JobReceivedMessage jobReceivedMessage) { - _jobReceived(jobReceivedMessage.job); - });*/ subscribe( queueId: Constants.messageTopicMessageReceived, @@ -272,9 +284,6 @@ class _MainPageState extends State with ConsumerMixin, ProducerMixin { _refreshBadges(); }, ); - /*MessageService().subscribe(Constants.messageTopicMessageReceived, this, (MessageReceivedMessage mesage) { - _refreshBadges(); - });*/ subscribe( queueId: Constants.messageTopicJobDeleted, @@ -282,9 +291,6 @@ class _MainPageState extends State with ConsumerMixin, ProducerMixin { _refreshBadges(); }, ); - /*MessageService().subscribe(Constants.messageTopicJobDeleted, this, (JobDeletedMessage job) { - _refreshBadges(); - });*/ subscribe( queueId: Constants.messageTopicUpdateBadges, @@ -292,9 +298,6 @@ class _MainPageState extends State with ConsumerMixin, ProducerMixin { _refreshBadges(); }, ); - /*MessageService().subscribe(Constants.messageTopicUpdateBadges, this, (RefreshBadgesMessage message) { - _refreshBadges(); - });*/ } void _refreshBadges() async { @@ -311,14 +314,11 @@ class _MainPageState extends State with ConsumerMixin, ProducerMixin { if (!_loggedOut) { showLogoutAlertDialog(context); } else { - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicConnectClient, payload: ConnectClientMessage(), ); - //await MessageService().publish(Constants.messageTopicConnectClient, arguments: ConnectClientMessage()); - _loggedOut = false; setState(() {}); @@ -338,14 +338,11 @@ class _MainPageState extends State with ConsumerMixin, ProducerMixin { _loggedOut = true; Future.delayed(const Duration(seconds: 2), () async { - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicDisconnectClient, payload: DisconnectClientMessage(), ); - //await MessageService().publish(Constants.messageTopicDisconnectClient, arguments: DisconnectClientMessage()); - Future.delayed(const Duration(seconds: 3), () async { // TODO MESSAGING sendMessage( @@ -404,7 +401,7 @@ class _MainPageState extends State with ConsumerMixin, ProducerMixin { // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicPublishPayload, - payload: PublishPayloadMessage(topic: "logout", message: logoutMessage.toJson(), qos: MqttQos.exactlyOnce), + payload: PublishPayloadMessage(topic: "logout", message: logoutMessage.toJson(), acknowledgeRequired: false), ); //await MessageService().publish(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "logout", message: logoutMessage.toJson(), qos: MqttQos.exactlyOnce)); diff --git a/lib/content_views/messages_page.dart b/lib/content_views/messages_page.dart index b1b98a1..e911d7c 100644 --- a/lib/content_views/messages_page.dart +++ b/lib/content_views/messages_page.dart @@ -4,13 +4,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_chat_ui/flutter_chat_ui.dart'; import 'package:flutter_chat_types/flutter_chat_types.dart' as types; import 'package:isar/isar.dart'; -import 'package:mqtt5_client/mqtt5_client.dart'; import 'package:stadtbote/content_views/utils/content_view_widget.dart'; import 'package:stadtbote/main.dart'; import 'package:stadtbote/messages/pop_content_view_message.dart'; import 'package:stadtbote/model/chat_message.dart' as sbmessage; import 'package:stadtbote/model/chat_message.dart'; import 'package:stadtbote/model/session_status.dart'; +import 'package:stadtbote/protocoll_messages/messages_showed.dart'; import 'package:stadtbote/tools/constants.dart'; import 'package:stadtbote/tools/messages/publish_payload_message.dart'; @@ -53,6 +53,8 @@ class _MessagesPageState extends State with ProducerMixin { var status = await MyApp.isarInstance.sessionStatus.where().findFirst(); _sid = status != null ? status.sid : 'Unbekannt'; + _sendMessagesReceivedMessage(); + await _fetchMessages(); _initCompleted = true; @@ -99,14 +101,11 @@ class _MessagesPageState extends State with ProducerMixin { await MyApp.isarInstance.chatMessages.put(message); }); - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicPublishPayload, - payload: PublishPayloadMessage(topic: "message", message: message.toJson(), qos: MqttQos.exactlyOnce), + payload: PublishPayloadMessage(topic: "message", message: message.toJson(), acknowledgeRequired: true), ); - //await MessageService().publish(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "message", message: message.toJson(), qos: MqttQos.exactlyOnce)); - _messages.insert(0, types.TextMessage( author: _user, createdAt: now.millisecondsSinceEpoch, @@ -191,6 +190,29 @@ class _MessagesPageState extends State with ProducerMixin { ); }); } + + void _sendMessagesReceivedMessage() async { + var unreadChatMessages = await MyApp.isarInstance.chatMessages + .filter() + .readEqualTo(false) + .findAll(); + + if (unreadChatMessages.isNotEmpty) { + List chatMessageIds = []; + for(var message in unreadChatMessages) { + chatMessageIds.add(message.id.toString()); + } + + var chatMessagesReceived = ChatMessagesReceived(); + chatMessagesReceived.ids = chatMessageIds; + chatMessagesReceived.time = DateTime.now().toUtc().toIso8601String(); + + sendMessage( + routingKey: Constants.messageTopicChatMessagesReceived, + payload: chatMessagesReceived, + ); + } + } } class _HeaderWidget extends StatefulWidget { diff --git a/lib/content_views/set_desired_zip_page.dart b/lib/content_views/set_desired_zip_page.dart new file mode 100644 index 0000000..48ce920 --- /dev/null +++ b/lib/content_views/set_desired_zip_page.dart @@ -0,0 +1,184 @@ +import 'package:dart_mq/dart_mq.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:stadtbote/content_views/utils/content_view_widget.dart'; +import 'package:stadtbote/messages/pop_content_view_message.dart'; +import 'package:stadtbote/protocoll_messages/set_desired_zip_message.dart'; +import 'package:stadtbote/tools/messages/publish_payload_message.dart'; + +import '../tools/constants.dart'; +import '../tools/util.dart'; + +class SetDesiredZipPage extends ContentViewWidget { + const SetDesiredZipPage({super.key}); + + @override + State createState() => _SetDesiredZipPageState(); + + @override + Future getHeaderWidget(BuildContext context) async { + await Future.delayed(const Duration(microseconds: 0)); + + return _HeaderWidget(); + } +} + +class _SetDesiredZipPageState extends State with ProducerMixin { + TextEditingController textEditController = TextEditingController(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: + [ + const Text("Bitte geben Sie Ihr Wunschziel für heute ein"), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.center, // Zentriert das Textfeld horizontal + children: [ + SizedBox( + width: 120, // Festlegen der Breite des Textfelds + child: + Util.getDefaultTextField('PLZ', + textInputType: TextInputType.text, + formatter: [FilteringTextInputFormatter.singleLineFormatter], + controller: textEditController, + maxLength: 5, + autofocus: true + ), + ), + ], + ), + const SizedBox(height: 20), + getDefaultButton('Übernehmen', () => + { + Util.preferencesSaveString(Constants.prefsDesiredZip, textEditController.text), + + _sendDesiredZipMessage(textEditController.text), + + sendMessage( + routingKey: Constants.messageTopicPopContentView, + payload: PopContentViewMessage(count: 1), + ) + }) + ] + ), + ); + } + + _sendDesiredZipMessage(String desiredZip) { + var desiredZipMessage = SetDesiredZipMessage(); + desiredZipMessage.desiredZip = desiredZip; + + sendMessage( + routingKey: Constants.messageTopicPublishPayload, + payload: PublishPayloadMessage(topic: "set_desired_zip", message: desiredZipMessage.toJson(),acknowledgeRequired: true), + ); + } +} + +class _HeaderWidget extends StatefulWidget { + @override + State<_HeaderWidget> createState() => _HeaderWidgetState(); +} + +class _HeaderWidgetState extends State<_HeaderWidget> with ProducerMixin { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + var cellWidth = (MediaQuery.of(context).size.width - 60 - 60 - 25) / 2; + + return Padding( + padding: const EdgeInsets.all(8), + child: Stack( + alignment: Alignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Visibility( + visible: true, + child: Container( + width: 60, + height: 60, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.white, + ), + child: FittedBox( + child: GestureDetector( + onTap: () async { + // TODO MESSAGING + sendMessage( + routingKey: Constants.messageTopicPopContentView, + payload: PopContentViewMessage(count: 1), + ); + + //await MessageService().publish(Constants.messageTopicPopContentView, arguments: PopContentViewMessage(count: 1)); + }, + child: const CircleAvatar( + radius: 10, + backgroundColor: Constants.colorPrimary, + child: Padding(padding: EdgeInsets.all(1.0), child: Icon(Icons.arrow_back, size: 20.0, color: Colors.white)), + ), + ), + ), + ), + ), + Visibility( + visible: false, + child: Container( + width: 60, + height: 60, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.red, + ), + child: FittedBox( + child: GestureDetector( + onTap: () async { + // TODO MESSAGING + sendMessage( + routingKey: Constants.messageTopicPopContentView, + payload: PopContentViewMessage(count: 1), + ); + + //await MessageService().publish(Constants.messageTopicPopContentView, arguments: PopContentViewMessage(count: 1)); + }, + child: const CircleAvatar( + backgroundColor: Constants.colorPrimary, + radius: 10, + child: Padding(padding: EdgeInsets.all(1.0), child: Icon(Icons.info_outline, size: 20.0, color: Colors.white))), + ), + ), + ), + ), + ], + ), + SizedBox( + height: 100, + width: cellWidth * 2, + child: const Center( + child: Text( + textAlign: TextAlign.center, + "Wunschziel für heute", + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.white), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/content_views/task_list_page.dart b/lib/content_views/task_list_page.dart index deec029..37f0954 100644 --- a/lib/content_views/task_list_page.dart +++ b/lib/content_views/task_list_page.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; import 'package:isar/isar.dart'; -import 'package:mqtt5_client/mqtt5_client.dart'; import 'package:stadtbote/content_views/utils/content_view_widget.dart'; import 'package:stadtbote/messages/pop_content_view_message.dart'; import 'package:stadtbote/model/job.dart'; @@ -361,8 +360,9 @@ class _TaskListPageState extends State with ProducerMixin { void _processReceiptGiver(TaskInfo taskInfo) { Util.logInfo('Task ${taskInfo.task.sId} called'); - showReceiptGiverPopup(context, taskInfo, (receiptGiver) { + showReceiptGiverPopup(context, taskInfo, (receiptGiver, selectedTourEntry) { var answer = _createAnswerHeader(taskInfo); + answer.code = selectedTourEntry.code; answer.val = receiptGiver; taskInfo.answer = jsonEncode(answer.toJson()); @@ -480,7 +480,7 @@ class _TaskListPageState extends State with ProducerMixin { // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicPublishPayload, - payload: PublishPayloadMessage(topic: "fin_task", message: message.toJson(), qos: MqttQos.exactlyOnce), + payload: PublishPayloadMessage(topic: "fin_task", message: message.toJson(), acknowledgeRequired: true), ); //await MessageService().publish(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "fin_task", message: message.toJson(), qos: MqttQos.exactlyOnce)); @@ -530,7 +530,7 @@ class _TaskListPageState extends State with ProducerMixin { // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicPublishPayload, - payload: PublishPayloadMessage(topic: "fin_tour", message: finTourMessage.toJson(), qos: MqttQos.exactlyOnce), + payload: PublishPayloadMessage(topic: "fin_tour", message: finTourMessage.toJson(), acknowledgeRequired: true), ); //await MessageService().publish(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "fin_tour", message: finTourMessage.toJson(), qos: MqttQos.exactlyOnce)); @@ -561,7 +561,7 @@ class _TaskListPageState extends State with ProducerMixin { // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicPublishPayload, - payload: PublishPayloadMessage(topic: "pic", message: message.toJson(), qos: MqttQos.exactlyOnce), + payload: PublishPayloadMessage(topic: "pic", message: message.toJson(), acknowledgeRequired: true), ); //await MessageService().publish(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "pic", message: message.toJson(), qos: MqttQos.exactlyOnce)); diff --git a/lib/main.dart b/lib/main.dart index 752777a..7bcd0f2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -22,6 +22,7 @@ import 'package:stadtbote/tools/messages/job_deleted_message.dart'; import 'package:stadtbote/tools/messages/job_received_message.dart'; import 'package:stadtbote/tools/messages/refresh_badges_message.dart'; import 'package:stadtbote/tools/messages/remove_job_message.dart'; +import 'package:stadtbote/tools/messages/remove_state_0_job_from_map.dart'; import 'package:stadtbote/tools/mqtt_core.dart'; import 'content_views/main_page.dart'; @@ -53,6 +54,7 @@ Future main() async { MQClient.instance.declareQueue(Constants.messageTopicJobReceived); MQClient.instance.declareQueue(Constants.messageTopicMessageReceived); MQClient.instance.declareQueue(Constants.messageTopicUpdateBadges); + MQClient.instance.declareQueue(Constants.messageTopicRemoveState0JobFromMap); final dir = await getApplicationDocumentsDirectory(); MyApp.isarInstance = await Isar.open([ @@ -190,7 +192,7 @@ class _MainState extends State
with SingleTickerProviderStateMixin, Produc final ValueNotifier _connectionLostValueNotifier = ValueNotifier(true); - late AnimationController _animationController; + late AnimationController? _animationController = null; late Animation _animation; Timer? _checkForNewState0JobsJobsTimer; @@ -199,13 +201,20 @@ class _MainState extends State
with SingleTickerProviderStateMixin, Produc late SharedMap? _jobMap; + @override + void dispose() { + _animationController?.dispose(); + + super.dispose(); + } + @override void initState() { super.initState(); _animationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 1000)); - _animationController.repeat(reverse: true); - _animation = Tween(begin: 0.5, end: 1.0).animate(_animationController); + _animationController!.repeat(reverse: true); + _animation = Tween(begin: 0.5, end: 1.0).animate(_animationController!); WidgetsBinding.instance.addPostFrameCallback((_) async { var store1 = SharedStore('jobs'); @@ -308,9 +317,6 @@ class _MainState extends State
with SingleTickerProviderStateMixin, Produc _pushContentView(widget); }, ); - /*MessageService().subscribe(Constants.messageTopicPushContentView, this, (ContentViewWidget widget) { - _pushContentView(widget); - });*/ subscribe( queueId: Constants.messageTopicPopContentView, @@ -319,9 +325,6 @@ class _MainState extends State
with SingleTickerProviderStateMixin, Produc _popContentView(popContentViewMessage.count); }, ); - /*MessageService().subscribe(Constants.messageTopicPopContentView, this, (PopContentViewMessage message) { - _popContentView(message.count); - });*/ subscribe( queueId: Constants.messageTopicReplaceContentView, @@ -330,9 +333,6 @@ class _MainState extends State
with SingleTickerProviderStateMixin, Produc _replaceContentView(widget); }, ); - /*MessageService().subscribe(Constants.messageTopicReplaceContentView, this, (ContentViewWidget widget) { - _replaceContentView(widget); - });*/ subscribe( queueId: Constants.messageTopicConnectionStatusChanged, @@ -341,9 +341,6 @@ class _MainState extends State
with SingleTickerProviderStateMixin, Produc _connectionStatusChanged(connectionStatus); }, ); - /*MessageService().subscribe(Constants.messageTopicConnectionStatusChanged, this, (ConnectionStatus connectionStatus) { - _connectionStatusChanged(connectionStatus); - });*/ subscribe( queueId: Constants.messageTopicRemoveJob, @@ -354,30 +351,17 @@ class _MainState extends State
with SingleTickerProviderStateMixin, Produc await MyApp.isarInstance.jobs.where().filter().idEqualTo(removeJobMessage.id).deleteAll(); }); - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicJobDeleted, payload: JobDeletedMessage(id: removeJobMessage.id), ); - //await MessageService().publish(Constants.messageTopicJobDeleted, arguments: JobDeletedMessage(id: job.id)); - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicUpdateBadges, payload: RefreshBadgesMessage, ); - //await MessageService().publish(Constants.messageTopicUpdateBadges, arguments: RefreshBadgesMessage()); }, ); - /*MessageService().subscribe(Constants.messageTopicRemoveJob, this, (RemoveJobMessage job) async { - await MyApp.isarInstance.writeTxn(() async { - await MyApp.isarInstance.jobs.where().filter().idEqualTo(job.id).deleteAll(); - }); - - await MessageService().publish(Constants.messageTopicJobDeleted, arguments: JobDeletedMessage(id: job.id)); - - await MessageService().publish(Constants.messageTopicUpdateBadges, arguments: RefreshBadgesMessage()); - });*/ subscribe( queueId: Constants.messageTopicJobReceived, @@ -388,11 +372,6 @@ class _MainState extends State
with SingleTickerProviderStateMixin, Produc } }, ); - /*MessageService().subscribe(Constants.messageTopicJobReceived, this, (JobReceivedMessage jobReceivedMessage) async { - if (jobReceivedMessage.job.state == 0) { - await _jobMap!.put(jobReceivedMessage.job.id, jobReceivedMessage.job); - } - });*/ subscribe( queueId: Constants.messageTopicJobDeleted, @@ -401,9 +380,15 @@ class _MainState extends State
with SingleTickerProviderStateMixin, Produc await _jobMap!.remove(jobDeleted.id); }, ); - /*MessageService().subscribe(Constants.messageTopicJobDeleted, this, (JobDeletedMessage jobDeletedMessage) async { - await _jobMap!.remove(jobDeletedMessage.id); - });*/ + + subscribe( + queueId: Constants.messageTopicRemoveState0JobFromMap, + callback: (message) async { + var removeState0JobFromMap = message.payload as RemoveState0JobFromMapMessage; + await _jobMap!.remove(removeState0JobFromMap.jobId); + }, + ); + } void _replaceContentView(ContentViewWidget widget) async { diff --git a/lib/model/chat_message.g.dart b/lib/model/chat_message.g.dart index 09827db..71ca1a3 100644 --- a/lib/model/chat_message.g.dart +++ b/lib/model/chat_message.g.dart @@ -54,7 +54,7 @@ const ChatMessageSchema = CollectionSchema( getId: _chatMessageGetId, getLinks: _chatMessageGetLinks, attach: _chatMessageAttach, - version: '3.1.0+1', + version: '3.1.8', ); int _chatMessageEstimateSize( diff --git a/lib/model/enqueued_message.dart b/lib/model/enqueued_message.dart index 27d4cce..4a23f4c 100644 --- a/lib/model/enqueued_message.dart +++ b/lib/model/enqueued_message.dart @@ -6,8 +6,12 @@ part 'enqueued_message.g.dart'; class EnqueuedMessage { Id id = DateTime.now().millisecondsSinceEpoch; + late String messageId; + late String topic; late String payload; + + EnqueuedMessage({required this.messageId}); } diff --git a/lib/model/enqueued_message.g.dart b/lib/model/enqueued_message.g.dart index cca2771..f919508 100644 --- a/lib/model/enqueued_message.g.dart +++ b/lib/model/enqueued_message.g.dart @@ -17,13 +17,18 @@ const EnqueuedMessageSchema = CollectionSchema( name: r'EnqueuedMessage', id: 884922652682878785, properties: { - r'payload': PropertySchema( + r'messageId': PropertySchema( id: 0, + name: r'messageId', + type: IsarType.string, + ), + r'payload': PropertySchema( + id: 1, name: r'payload', type: IsarType.string, ), r'topic': PropertySchema( - id: 1, + id: 2, name: r'topic', type: IsarType.string, ) @@ -39,7 +44,7 @@ const EnqueuedMessageSchema = CollectionSchema( getId: _enqueuedMessageGetId, getLinks: _enqueuedMessageGetLinks, attach: _enqueuedMessageAttach, - version: '3.1.0+1', + version: '3.1.8', ); int _enqueuedMessageEstimateSize( @@ -48,6 +53,7 @@ int _enqueuedMessageEstimateSize( Map> allOffsets, ) { var bytesCount = offsets.last; + bytesCount += 3 + object.messageId.length * 3; bytesCount += 3 + object.payload.length * 3; bytesCount += 3 + object.topic.length * 3; return bytesCount; @@ -59,8 +65,9 @@ void _enqueuedMessageSerialize( List offsets, Map> allOffsets, ) { - writer.writeString(offsets[0], object.payload); - writer.writeString(offsets[1], object.topic); + writer.writeString(offsets[0], object.messageId); + writer.writeString(offsets[1], object.payload); + writer.writeString(offsets[2], object.topic); } EnqueuedMessage _enqueuedMessageDeserialize( @@ -69,10 +76,12 @@ EnqueuedMessage _enqueuedMessageDeserialize( List offsets, Map> allOffsets, ) { - final object = EnqueuedMessage(); + final object = EnqueuedMessage( + messageId: reader.readString(offsets[0]), + ); object.id = id; - object.payload = reader.readString(offsets[0]); - object.topic = reader.readString(offsets[1]); + object.payload = reader.readString(offsets[1]); + object.topic = reader.readString(offsets[2]); return object; } @@ -87,6 +96,8 @@ P _enqueuedMessageDeserializeProp

( return (reader.readString(offset)) as P; case 1: return (reader.readString(offset)) as P; + case 2: + return (reader.readString(offset)) as P; default: throw IsarError('Unknown property with id $propertyId'); } @@ -243,6 +254,142 @@ extension EnqueuedMessageQueryFilter }); } + QueryBuilder + messageIdEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'messageId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + messageIdGreaterThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'messageId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + messageIdLessThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'messageId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + messageIdBetween( + String lower, + String upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'messageId', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + messageIdStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'messageId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + messageIdEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'messageId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + messageIdContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'messageId', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + messageIdMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'messageId', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + messageIdIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'messageId', + value: '', + )); + }); + } + + QueryBuilder + messageIdIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'messageId', + value: '', + )); + }); + } + QueryBuilder payloadEqualTo( String value, { @@ -524,6 +671,20 @@ extension EnqueuedMessageQueryLinks extension EnqueuedMessageQuerySortBy on QueryBuilder { + QueryBuilder + sortByMessageId() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'messageId', Sort.asc); + }); + } + + QueryBuilder + sortByMessageIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'messageId', Sort.desc); + }); + } + QueryBuilder sortByPayload() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'payload', Sort.asc); @@ -565,6 +726,20 @@ extension EnqueuedMessageQuerySortThenBy }); } + QueryBuilder + thenByMessageId() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'messageId', Sort.asc); + }); + } + + QueryBuilder + thenByMessageIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'messageId', Sort.desc); + }); + } + QueryBuilder thenByPayload() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'payload', Sort.asc); @@ -594,6 +769,13 @@ extension EnqueuedMessageQuerySortThenBy extension EnqueuedMessageQueryWhereDistinct on QueryBuilder { + QueryBuilder distinctByMessageId( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'messageId', caseSensitive: caseSensitive); + }); + } + QueryBuilder distinctByPayload( {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { @@ -617,6 +799,12 @@ extension EnqueuedMessageQueryProperty }); } + QueryBuilder messageIdProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'messageId'); + }); + } + QueryBuilder payloadProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'payload'); diff --git a/lib/model/job.g.dart b/lib/model/job.g.dart index 983ae61..3dab33a 100644 --- a/lib/model/job.g.dart +++ b/lib/model/job.g.dart @@ -85,7 +85,7 @@ const JobSchema = CollectionSchema( getId: _jobGetId, getLinks: _jobGetLinks, attach: _jobAttach, - version: '3.1.0+1', + version: '3.1.8', ); int _jobEstimateSize( diff --git a/lib/model/location_status.g.dart b/lib/model/location_status.g.dart index 0c1fd82..63b76d6 100644 --- a/lib/model/location_status.g.dart +++ b/lib/model/location_status.g.dart @@ -44,7 +44,7 @@ const LocationStatusSchema = CollectionSchema( getId: _locationStatusGetId, getLinks: _locationStatusGetLinks, attach: _locationStatusAttach, - version: '3.1.0+1', + version: '3.1.8', ); int _locationStatusEstimateSize( diff --git a/lib/model/log_entry.g.dart b/lib/model/log_entry.g.dart index 5c2d1b9..d830226 100644 --- a/lib/model/log_entry.g.dart +++ b/lib/model/log_entry.g.dart @@ -45,7 +45,7 @@ const LogEntrySchema = CollectionSchema( getId: _logEntryGetId, getLinks: _logEntryGetLinks, attach: _logEntryAttach, - version: '3.1.0+1', + version: '3.1.8', ); int _logEntryEstimateSize( diff --git a/lib/model/pictures.g.dart b/lib/model/pictures.g.dart index 0164216..be787a2 100644 --- a/lib/model/pictures.g.dart +++ b/lib/model/pictures.g.dart @@ -44,7 +44,7 @@ const PictureSchema = CollectionSchema( getId: _pictureGetId, getLinks: _pictureGetLinks, attach: _pictureAttach, - version: '3.1.0+1', + version: '3.1.8', ); int _pictureEstimateSize( diff --git a/lib/model/rank.g.dart b/lib/model/rank.g.dart index 9829294..ddce3cd 100644 --- a/lib/model/rank.g.dart +++ b/lib/model/rank.g.dart @@ -35,7 +35,7 @@ const RankingSchema = CollectionSchema( getId: _rankingGetId, getLinks: _rankingGetLinks, attach: _rankingAttach, - version: '3.1.0+1', + version: '3.1.8', ); int _rankingEstimateSize( diff --git a/lib/model/session_status.g.dart b/lib/model/session_status.g.dart index f068ad2..acac984 100644 --- a/lib/model/session_status.g.dart +++ b/lib/model/session_status.g.dart @@ -74,7 +74,7 @@ const SessionStatusSchema = CollectionSchema( getId: _sessionStatusGetId, getLinks: _sessionStatusGetLinks, attach: _sessionStatusAttach, - version: '3.1.0+1', + version: '3.1.8', ); int _sessionStatusEstimateSize( diff --git a/lib/model/status.g.dart b/lib/model/status.g.dart index 29db7f8..2e52bd8 100644 --- a/lib/model/status.g.dart +++ b/lib/model/status.g.dart @@ -35,7 +35,7 @@ const StatusSchema = CollectionSchema( getId: _statusGetId, getLinks: _statusGetLinks, attach: _statusAttach, - version: '3.1.0+1', + version: '3.1.8', ); int _statusEstimateSize( diff --git a/lib/model/task_info.g.dart b/lib/model/task_info.g.dart index e63d588..5a586df 100644 --- a/lib/model/task_info.g.dart +++ b/lib/model/task_info.g.dart @@ -49,7 +49,7 @@ const TaskInfoSchema = CollectionSchema( getId: _taskInfoGetId, getLinks: _taskInfoGetLinks, attach: _taskInfoAttach, - version: '3.1.0+1', + version: '3.1.8', ); int _taskInfoEstimateSize( diff --git a/lib/popups/accept_jobs_popup.dart b/lib/popups/accept_jobs_popup.dart index bc64dce..18174e2 100644 --- a/lib/popups/accept_jobs_popup.dart +++ b/lib/popups/accept_jobs_popup.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:expandable/expandable.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:mqtt5_client/mqtt5_client.dart'; import 'package:shared_map/shared_map.dart'; import 'package:stadtbote/main.dart'; import 'package:stadtbote/protocoll_messages/accept_job_message.dart'; @@ -151,7 +150,7 @@ Future> _fetchJobWidgets(StateSetter dialogState, Function() onFini child: Text( DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime).toLocal()).toString(), textAlign: TextAlign.left, - style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.red : Colors.transparent), + style: TextStyle(backgroundColor: isJobTooFarInFuture(job) ? Colors.red : Colors.transparent), ), ), SizedBox(width: double.infinity, child: Text('Auftragsnummer: ${job.id}', textAlign: TextAlign.left)), @@ -290,7 +289,7 @@ _sendAnswer(SharedMapReference mapReference, Job job, int item) async { // TODO MESSAGING job.sendMessage( routingKey: Constants.messageTopicPublishPayload, - payload: PublishPayloadMessage(topic: "reaction", message: message.toJson(), qos: MqttQos.exactlyOnce), + payload: PublishPayloadMessage(topic: "reaction", message: message.toJson(), acknowledgeRequired: true), ); //await MessageService().publish(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "reaction", message: message.toJson(), qos: MqttQos.exactlyOnce)); diff --git a/lib/popups/tasks_popups/receipt_giver_popup.dart b/lib/popups/tasks_popups/receipt_giver_popup.dart index c71f0e6..58889d5 100644 --- a/lib/popups/tasks_popups/receipt_giver_popup.dart +++ b/lib/popups/tasks_popups/receipt_giver_popup.dart @@ -1,9 +1,19 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:stadtbote/model/task_info.dart'; +import 'package:stadtbote/model/tour_task.dart'; import 'package:stadtbote/tools/util.dart'; -showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String) onFinished) async { +showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String, TourEntry) onFinished) async { + List> entries = []; + for (var entry in taskInfo.task.entries!) { + var dropdownMenuEntry = DropdownMenuEntry(value: entry, label: entry.text); + entries.add(dropdownMenuEntry); + } + + TextEditingController controller = TextEditingController(); + TourEntry? selectedTourEntry; + await showDialog( context: context, builder: (BuildContext context) { @@ -20,7 +30,7 @@ showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String) return SizedBox( key: GlobalKey(), - height: 260, + height: 350, width: MediaQuery.of(context).size.width * 0.8, child: Container( height: 100, @@ -38,6 +48,18 @@ showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String) children: [ Text(taskInfo.task.topic), const SizedBox(height: 20), + DropdownMenu( + expandedInsets: const EdgeInsets.all(0), + controller: controller, + hintText: 'Geschlecht', + onSelected: (TourEntry? value) { + selectedTourEntry = value; + + controller.text = value!.text; + }, + dropdownMenuEntries: entries, + ), + const SizedBox(height: 30), Util.getDefaultTextField(taskInfo.task.topic, textInputType: TextInputType.text, formatter: [FilteringTextInputFormatter.singleLineFormatter], @@ -46,12 +68,12 @@ showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String) autofocus: true), const SizedBox(height: 20), getDefaultButton('Übernehmen', () { - if (textEditingController.text.isNotEmpty) { + if (textEditingController.text.isNotEmpty && selectedTourEntry != null) { Navigator.of(context).pop(); - onFinished(textEditingController.text); + onFinished(textEditingController.text, selectedTourEntry!); } else { - showAlertDialog("Fehler", "Sie müssen einen Text eingeben"); + showAlertDialog("Fehler", "Sie müssen einen Text eingeben und ein Geschlecht auswählen"); } }) ], diff --git a/lib/protocoll_messages/acknowledge_message.dart b/lib/protocoll_messages/acknowledge_message.dart new file mode 100644 index 0000000..97a44ff --- /dev/null +++ b/lib/protocoll_messages/acknowledge_message.dart @@ -0,0 +1,14 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'acknowledge_message.g.dart'; + +@JsonSerializable() +class AcknowledgeMessage { + late String messageId; + + AcknowledgeMessage(); + + factory AcknowledgeMessage.fromJson(Map json) => _$AcknowledgeMessageFromJson(json); + + Map toJson() => _$AcknowledgeMessageToJson(this); +} diff --git a/lib/protocoll_messages/acknowledge_message.g.dart b/lib/protocoll_messages/acknowledge_message.g.dart new file mode 100644 index 0000000..25cd388 --- /dev/null +++ b/lib/protocoll_messages/acknowledge_message.g.dart @@ -0,0 +1,15 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'acknowledge_message.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +AcknowledgeMessage _$AcknowledgeMessageFromJson(Map json) => + AcknowledgeMessage()..messageId = json['messageId'] as String; + +Map _$AcknowledgeMessageToJson(AcknowledgeMessage instance) => + { + 'messageId': instance.messageId, + }; diff --git a/lib/protocoll_messages/messages_showed.dart b/lib/protocoll_messages/messages_showed.dart new file mode 100644 index 0000000..9e07fe2 --- /dev/null +++ b/lib/protocoll_messages/messages_showed.dart @@ -0,0 +1,16 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'messages_showed.g.dart'; + +@JsonSerializable() +class ChatMessagesReceived { + late List ids; + + late String time; + + ChatMessagesReceived(); + + factory ChatMessagesReceived.fromJson(Map json) => _$ChatMessagesReceivedFromJson(json); + + Map toJson() => _$ChatMessagesReceivedToJson(this); +} diff --git a/lib/protocoll_messages/messages_showed.g.dart b/lib/protocoll_messages/messages_showed.g.dart new file mode 100644 index 0000000..144c588 --- /dev/null +++ b/lib/protocoll_messages/messages_showed.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'messages_showed.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ChatMessagesReceived _$ChatMessagesReceivedFromJson( + Map json) => + ChatMessagesReceived() + ..ids = (json['ids'] as List).map((e) => e as String).toList() + ..time = json['time'] as String; + +Map _$ChatMessagesReceivedToJson( + ChatMessagesReceived instance) => + { + 'ids': instance.ids, + 'time': instance.time, + }; diff --git a/lib/protocoll_messages/set_desired_zip_message.dart b/lib/protocoll_messages/set_desired_zip_message.dart new file mode 100644 index 0000000..be9d8c5 --- /dev/null +++ b/lib/protocoll_messages/set_desired_zip_message.dart @@ -0,0 +1,17 @@ +import 'package:isar/isar.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'set_desired_zip_message.g.dart'; + +@embedded +@JsonSerializable() +class SetDesiredZipMessage { + @JsonKey(name: "desired_zip") + late String desiredZip; + + SetDesiredZipMessage(); + + factory SetDesiredZipMessage.fromJson(Map json) => _$SetDesiredZipMessageFromJson(json); + + Map toJson() => _$SetDesiredZipMessageToJson(this); +} diff --git a/lib/protocoll_messages/set_desired_zip_message.g.dart b/lib/protocoll_messages/set_desired_zip_message.g.dart new file mode 100644 index 0000000..d3227a6 --- /dev/null +++ b/lib/protocoll_messages/set_desired_zip_message.g.dart @@ -0,0 +1,228 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'set_desired_zip_message.dart'; + +// ************************************************************************** +// IsarEmbeddedGenerator +// ************************************************************************** + +// coverage:ignore-file +// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types + +const SetDesiredZipMessageSchema = Schema( + name: r'SetDesiredZipMessage', + id: -4167972906487221318, + properties: { + r'desiredZip': PropertySchema( + id: 0, + name: r'desiredZip', + type: IsarType.string, + ) + }, + estimateSize: _setDesiredZipMessageEstimateSize, + serialize: _setDesiredZipMessageSerialize, + deserialize: _setDesiredZipMessageDeserialize, + deserializeProp: _setDesiredZipMessageDeserializeProp, +); + +int _setDesiredZipMessageEstimateSize( + SetDesiredZipMessage object, + List offsets, + Map> allOffsets, +) { + var bytesCount = offsets.last; + bytesCount += 3 + object.desiredZip.length * 3; + return bytesCount; +} + +void _setDesiredZipMessageSerialize( + SetDesiredZipMessage object, + IsarWriter writer, + List offsets, + Map> allOffsets, +) { + writer.writeString(offsets[0], object.desiredZip); +} + +SetDesiredZipMessage _setDesiredZipMessageDeserialize( + Id id, + IsarReader reader, + List offsets, + Map> allOffsets, +) { + final object = SetDesiredZipMessage(); + object.desiredZip = reader.readString(offsets[0]); + return object; +} + +P _setDesiredZipMessageDeserializeProp

( + IsarReader reader, + int propertyId, + int offset, + Map> allOffsets, +) { + switch (propertyId) { + case 0: + return (reader.readString(offset)) as P; + default: + throw IsarError('Unknown property with id $propertyId'); + } +} + +extension SetDesiredZipMessageQueryFilter on QueryBuilder { + QueryBuilder desiredZipEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'desiredZip', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder desiredZipGreaterThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'desiredZip', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder desiredZipLessThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'desiredZip', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder desiredZipBetween( + String lower, + String upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'desiredZip', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder desiredZipStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'desiredZip', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder desiredZipEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'desiredZip', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + desiredZipContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'desiredZip', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + desiredZipMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'desiredZip', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder desiredZipIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'desiredZip', + value: '', + )); + }); + } + + QueryBuilder desiredZipIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'desiredZip', + value: '', + )); + }); + } +} + +extension SetDesiredZipMessageQueryObject on QueryBuilder {} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SetDesiredZipMessage _$SetDesiredZipMessageFromJson( + Map json) => + SetDesiredZipMessage()..desiredZip = json['desired_zip'] as String; + +Map _$SetDesiredZipMessageToJson( + SetDesiredZipMessage instance) => + { + 'desired_zip': instance.desiredZip, + }; diff --git a/lib/protocoll_messages/start_session_message.dart b/lib/protocoll_messages/start_session_message.dart index 8d2f6a9..51d661c 100644 --- a/lib/protocoll_messages/start_session_message.dart +++ b/lib/protocoll_messages/start_session_message.dart @@ -4,6 +4,9 @@ part 'start_session_message.g.dart'; @JsonSerializable() class StartSessionMessage { + @JsonKey(name: "desired_zip") + late String desiredZip; + StartSessionMessage(); factory StartSessionMessage.fromJson(Map json) => _$StartSessionMessageFromJson(json); diff --git a/lib/protocoll_messages/start_session_message.g.dart b/lib/protocoll_messages/start_session_message.g.dart index e99df88..adc7706 100644 --- a/lib/protocoll_messages/start_session_message.g.dart +++ b/lib/protocoll_messages/start_session_message.g.dart @@ -7,8 +7,10 @@ part of 'start_session_message.dart'; // ************************************************************************** StartSessionMessage _$StartSessionMessageFromJson(Map json) => - StartSessionMessage(); + StartSessionMessage()..desiredZip = json['desired_zip'] as String; Map _$StartSessionMessageToJson( StartSessionMessage instance) => - {}; + { + 'desired_zip': instance.desiredZip, + }; diff --git a/lib/tools/constants.dart b/lib/tools/constants.dart index 6e4cca5..3e7ea95 100644 --- a/lib/tools/constants.dart +++ b/lib/tools/constants.dart @@ -19,13 +19,17 @@ class Constants { static const String messageTopicPopContentView = "pop_content_view"; static const String messageTopicReplaceContentView = "replace_content_view"; static const String messageTopicPublishPayload = "publish_payload_message"; + static const String messageTopicRemoveState0JobFromMap = "remove_state_0_job_from_map"; static const String messageTopicConnectClient = "connect_client"; static const String messageTopicDisconnectClient = "disconnect_client"; static const String messageTopicRequestConnectionStatus = "request_connection_status"; static const String messageTopicCurrentConnectionStatus = "current_connection_status"; + static const String messageTopicChatMessagesReceived = "mssg_received"; + static const String messageShowPopup = "show_popup"; static const String prefsPreviousMqttSubscription = "previous_mqtt_subscription"; + static const String prefsDesiredZip = "desired_zip"; static const int stateAssigned = 0; static const int stateAccepted = 1; diff --git a/lib/tools/message_header.dart b/lib/tools/message_header.dart new file mode 100644 index 0000000..55e8f9e --- /dev/null +++ b/lib/tools/message_header.dart @@ -0,0 +1,19 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'message_header.g.dart'; + +@JsonSerializable() +class MessageHeader { + late String messageId; + + late bool requiresAck; + + late Map payload; + + MessageHeader(); + + factory MessageHeader.fromJson(Map json) => _$MessageHeaderFromJson(json); + + Map toJson() => _$MessageHeaderToJson(this); +} + diff --git a/lib/tools/message_header.g.dart b/lib/tools/message_header.g.dart new file mode 100644 index 0000000..2ab10bb --- /dev/null +++ b/lib/tools/message_header.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'message_header.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +MessageHeader _$MessageHeaderFromJson(Map json) => + MessageHeader() + ..messageId = json['messageId'] as String + ..requiresAck = json['requiresAck'] as bool + ..payload = json['payload'] as Map; + +Map _$MessageHeaderToJson(MessageHeader instance) => + { + 'messageId': instance.messageId, + 'requiresAck': instance.requiresAck, + 'payload': instance.payload, + }; diff --git a/lib/tools/messages/publish_payload_message.dart b/lib/tools/messages/publish_payload_message.dart index 9a12425..662bdfe 100644 --- a/lib/tools/messages/publish_payload_message.dart +++ b/lib/tools/messages/publish_payload_message.dart @@ -1,11 +1,9 @@ -import 'package:mqtt5_client/mqtt5_client.dart'; - class PublishPayloadMessage { final String topic; final Map message; - final MqttQos qos; + final bool acknowledgeRequired; - PublishPayloadMessage({required this.topic, required this.message, required this.qos}); + PublishPayloadMessage({required this.topic, required this.message, required this.acknowledgeRequired}); } \ No newline at end of file diff --git a/lib/tools/messages/remove_state_0_job_from_map.dart b/lib/tools/messages/remove_state_0_job_from_map.dart new file mode 100644 index 0000000..82c5189 --- /dev/null +++ b/lib/tools/messages/remove_state_0_job_from_map.dart @@ -0,0 +1,7 @@ +import 'package:stadtbote/model/job.dart'; + +class RemoveState0JobFromMapMessage { + final int jobId; + + RemoveState0JobFromMapMessage({required this.jobId}); +} \ No newline at end of file diff --git a/lib/tools/mqtt_core.dart b/lib/tools/mqtt_core.dart index a7dafa5..28573db 100644 --- a/lib/tools/mqtt_core.dart +++ b/lib/tools/mqtt_core.dart @@ -23,11 +23,13 @@ import 'package:stadtbote/protocoll_messages/device_log_request.dart'; import 'package:stadtbote/protocoll_messages/device_log_response.dart'; import 'package:stadtbote/protocoll_messages/device_object.dart'; import 'package:stadtbote/protocoll_messages/job_del_message.dart'; +import 'package:stadtbote/protocoll_messages/acknowledge_message.dart'; import 'package:stadtbote/protocoll_messages/start_session_message.dart'; import 'package:stadtbote/protocoll_messages/status_info_update.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_header.dart'; import 'package:stadtbote/tools/messages/publish_payload_message.dart'; import 'package:stadtbote/tools/messages/current_connection_status_message.dart'; import 'package:stadtbote/tools/messages/job_deleted_message.dart'; @@ -39,6 +41,7 @@ import 'package:stadtbote/tools/messages/status_info_update.dart'; // ignore: depend_on_referenced_packages import 'package:typed_data/typed_buffers.dart'; + // ignore: unused_import import 'package:uuid/uuid.dart'; @@ -126,7 +129,21 @@ class MqttCore with ProducerMixin, ConsumerMixin { _mqttClient!.onDisconnected = _clientDisconnected; _mqttClient!.onAutoReconnect = _clientDisconnected; _mqttClient!.onAutoReconnected = _clientConnected; - _mqttClient!.connectionMessage = MqttConnectMessage().withClientIdentifier(await Util.getAppUuid()).authenticateAs("app", "apppwd"); + + var willProperties = MqttWillProperties(); + willProperties.messageExpiryInterval = 3600; + willProperties.willDelayInterval = 0; + + _mqttClient!.connectionMessage = MqttConnectMessage() + .withClientIdentifier(await Util.getAppUuid()) + .authenticateAs("app", "apppwd") + .withSessionExpiryInterval(2700) + .withWillProperties(willProperties) + .withWillTopic("$_toServerTopic$_clientId/connection_lost") + .withWillQos(MqttQos.atMostOnce) + .keepAliveFor(60) + .withWillPayload(MqttUtf8Encoding().toUtf8('{"connection_lost": true}')) + .will(); } await _mqttClient!.connect(); @@ -138,7 +155,7 @@ class MqttCore with ProducerMixin, ConsumerMixin { await _setupMqtt(); - _initSession(); + await _initSession(); } else { Util.logInfo('Verbindung zum MQTT-Broker fehlgeschlagen!'); @@ -153,37 +170,37 @@ class MqttCore with ProducerMixin, ConsumerMixin { } catch (ex) { Util.logInfo('Verbindung zum MQTT-Broker fehlgeschlagen!: $ex'); - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicConnectionStatusChanged, payload: ConnectionStatus(status: ConnectionStatusEnum.notConnected), ); - - //await MessageService().publish(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected)); } } - bool _publishText(String topic, String text, MqttQos qos, {bool enqueueOnError = true}) { + bool _publishMessage(String topic, Map message, bool acknowledgeRequired, {bool enqueueOnError = true}) { try { + String messageId = const Uuid().v4(); + String messageText = jsonEncode(message); + + if (acknowledgeRequired) { + _enqueueMessage(messageId, topic, messageText); + } + + var encapsulatedMessageText = _encapsulateMessage(messageId, acknowledgeRequired, message); + var buffer = Uint8Buffer(); - buffer.addAll(GZipEncoder().encode(const Utf8Encoder().convert(text)) as Iterable); + buffer.addAll(GZipEncoder().encode(const Utf8Encoder().convert(encapsulatedMessageText)) as Iterable); var messageTopic = "$_toServerTopic$_clientId/$topic"; - _mqttClient!.publishMessage(messageTopic, qos, buffer); + _mqttClient!.publishMessage(messageTopic, MqttQos.atMostOnce, buffer); - Util.logInfo("message\n$text\nsend to $messageTopic"); + Util.logInfo("message\n$encapsulatedMessageText\nsend to $messageTopic"); Util.logInfo("size in bytes: ${buffer.length}"); return true; } catch (ex) { Util.logInfo("send failed!"); - - if (enqueueOnError) { - _enqueueMessage(topic, text); - - Util.logInfo("message enqueued"); - } } return false; @@ -199,50 +216,58 @@ class MqttCore with ProducerMixin, ConsumerMixin { var topicArray = message.variableHeader?.topicName; var topicArraySplited = topicArray!.split("/"); - var topic = topicArraySplited[6]; + var topic = topicArraySplited[7]; Util.logInfo('message received\ntopic: $topic\n'); Util.logInfo("size in bytes: ${message.payload.message!.length.toString()}"); - var payload = utf8.decode(GZipDecoder().decodeBytes(message.payload.message!)); + var decompressedPayload = utf8.decode(GZipDecoder().decodeBytes(message.payload.message!)); - Util.logInfo('$topic\nmessage: $payload'); + var headerMessage = MessageHeader.fromJson(jsonDecode(decompressedPayload)); + Util.logInfo('$topic\nmessageId: ${headerMessage.messageId}'); + + var payloadString = jsonEncode(headerMessage.payload); + Util.logInfo('$topic\nplayloadString: $payloadString'); switch (topic) { case 'session': - _sessionMessageReceived(jsonDecode(payload)); + _sessionMessageReceived(jsonDecode(payloadString)); break; case 'status': - _statusMessageReceived(jsonDecode(payload)); + _statusMessageReceived(jsonDecode(payloadString)); break; case 'ranking': - _rankingMessageReceived(jsonDecode(payload)); + _rankingMessageReceived(jsonDecode(payloadString)); break; case 'job': - _jobMessageReceived(jsonDecode(payload)); + _jobMessageReceived(jsonDecode(payloadString)); break; case 'job_del': - _jobDeleteReceived(jsonDecode(payload)); + _jobDeleteReceived(jsonDecode(payloadString)); break; case 'sync_request': - _syncRequestReceived(jsonDecode(payload)); + _syncRequestReceived(jsonDecode(payloadString)); break; case 'location_status': - _locationStatusMessageReceived(jsonDecode(payload)); + _locationStatusMessageReceived(jsonDecode(payloadString)); break; case "mssg": - _messageMessageReceived(jsonDecode(payload)); + _messageMessageReceived(jsonDecode(payloadString)); break; case "upload_device_log": - _messageUploadDeviceLogReceived(jsonDecode(payload)); + _messageUploadDeviceLogReceived(jsonDecode(payloadString)); + break; + + case "acknowledge": + _messageAcknowledgeReceived(jsonDecode(payloadString)); break; default: @@ -391,13 +416,10 @@ class MqttCore with ProducerMixin, ConsumerMixin { await MyApp.isarInstance.jobs.where().filter().idEqualTo(jobDelMessage.id).deleteAll(); }); - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicJobDeleted, payload: JobDeletedMessage(id: jobDelMessage.id), ); - - //await MessageService().publish(Constants.messageTopicJobDeleted, arguments: JobDeletedMessage(id: jobDelMessage.id)); } void _syncRequestReceived(payloadData) async { @@ -415,13 +437,10 @@ class MqttCore with ProducerMixin, ConsumerMixin { await Util.playMp3('asbeep.mp3'); - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicMessageReceived, payload: MessageReceivedMessage(message: newMessage), ); - - //await MessageService().publish(Constants.messageTopicMessageReceived, arguments: MessageReceivedMessage(message: newMessage)); } void _messageUploadDeviceLogReceived(payloadData) async { @@ -436,12 +455,22 @@ class MqttCore with ProducerMixin, ConsumerMixin { var deviceLog = DeviceLogResponse(); deviceLog.entries = logEintries; - var json = jsonEncode(deviceLog.toJson()); - - _publishText("device_log", json, MqttQos.atMostOnce); + _publishMessage("device_log", deviceLog.toJson(), false); } - void _startBootstrapReconnectTimer() { + void _messageAcknowledgeReceived(payloadData) async { + var acknowledgeMessage = AcknowledgeMessage.fromJson(payloadData); + + await MyApp.isarInstance.writeTxn(() async { + await MyApp.isarInstance.enqueuedMessages + .filter() + .messageIdEqualTo(acknowledgeMessage.messageId) + .deleteAll(); + }); + } + + + void _startReconnectTimer() { connectionState = ConnectionStateEnum.notConnected; if (!_disconnectInProgress) { @@ -470,13 +499,10 @@ class MqttCore with ProducerMixin, ConsumerMixin { _cancelTrackTimer(); - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicConnectionStatusChanged, payload: ConnectionStatus(status: ConnectionStatusEnum.notConnected), ); - - //await MessageService().publish(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected)); } Future _clientConnected() async { @@ -486,13 +512,10 @@ class MqttCore with ProducerMixin, ConsumerMixin { _initSession(); - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicConnectionStatusChanged, payload: ConnectionStatus(status: ConnectionStatusEnum.connected), ); - - //await MessageService().publish(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.connected)); } void _processBootstrap() async { @@ -546,16 +569,17 @@ class MqttCore with ProducerMixin, ConsumerMixin { } catch (ex) { Util.logException("bootstrap failed: {$ex}"); - _startBootstrapReconnectTimer(); + _startReconnectTimer(); } } - _initSession() { + _initSession() async { var startSessionMessage = StartSessionMessage(); - var jsonMap = startSessionMessage.toJson(); - var json = jsonEncode(jsonMap); + startSessionMessage.desiredZip = (await Util.preferencesGetString(Constants.prefsDesiredZip, ""))!; - _publishText("session", json, MqttQos.exactlyOnce); + var jsonMap = startSessionMessage.toJson(); + + _publishMessage("session", jsonMap, false); } _sendSyncMessage() async { @@ -573,7 +597,7 @@ class MqttCore with ProducerMixin, ConsumerMixin { answer.sync.jobs.add(syncJob); } - _publishText("sync", jsonEncode(answer.toJson()), MqttQos.exactlyOnce); + _publishMessage("sync", answer.toJson(), false); } void _startTrackTimer() { @@ -586,7 +610,7 @@ class MqttCore with ProducerMixin, ConsumerMixin { trackMessage.long = position.longitude; trackMessage.acc = position.accuracy.toInt(); - _publishText("track", jsonEncode(trackMessage.toJson()), MqttQos.atMostOnce); + _publishMessage("track", trackMessage.toJson(), false); } }); } @@ -598,8 +622,8 @@ class MqttCore with ProducerMixin, ConsumerMixin { } } - void _enqueueMessage(String receiver, String payload) async { - var enqueuedMessage = EnqueuedMessage(); + void _enqueueMessage(String uuid, String receiver, String payload) async { + var enqueuedMessage = EnqueuedMessage(messageId: uuid); enqueuedMessage.topic = receiver; enqueuedMessage.payload = payload; @@ -613,7 +637,9 @@ class MqttCore with ProducerMixin, ConsumerMixin { if (enqueuedMessages.isNotEmpty) { for (var enqueuedMessage in enqueuedMessages) { try { - if (_publishText(enqueuedMessage.topic, enqueuedMessage.payload, MqttQos.exactlyOnce, enqueueOnError: false)) { + var json = jsonDecode(enqueuedMessage.payload); + + if (_publishMessage(enqueuedMessage.topic, json, false, enqueueOnError: false)) { await MyApp.isarInstance.writeTxn(() async { await MyApp.isarInstance.enqueuedMessages.delete(enqueuedMessage.id); }); @@ -632,21 +658,18 @@ class MqttCore with ProducerMixin, ConsumerMixin { message.ver = job.ver; message.utc = DateTime.now().millisecondsSinceEpoch; - _publishText('job_received', jsonEncode(message.toJson()), MqttQos.exactlyOnce); + _publishMessage('job_received', message.toJson(), false); } void initMessages() { subscribe( queueId: Constants.messageTopicPublishPayload, callback: (message) { - var publisPayloadMessage = message.payload as PublishPayloadMessage; + var publishPayloadMessage = message.payload as PublishPayloadMessage; - _publishText(publisPayloadMessage.topic, jsonEncode(publisPayloadMessage.message), publisPayloadMessage.qos); + _publishMessage(publishPayloadMessage.topic, publishPayloadMessage.message, publishPayloadMessage.acknowledgeRequired); }, ); - /*MessageService().subscribe(Constants.messageTopicPublishPayload, this, (PublishPayloadMessage payloadMessage) { - _publishText(payloadMessage.topic, jsonEncode(payloadMessage.message), payloadMessage.qos); - });*/ subscribe( queueId: Constants.messageTopicDisconnectClient, @@ -654,10 +677,6 @@ class MqttCore with ProducerMixin, ConsumerMixin { _disconnectMqttClient(); }, ); - /*MessageService().subscribe(Constants.messageTopicDisconnectClient, this, - (DisconnectClientMessage disconnectClientMessage) { - _disconnectMqttClient(); - });*/ subscribe( queueId: Constants.messageTopicConnectClient, @@ -665,9 +684,6 @@ class MqttCore with ProducerMixin, ConsumerMixin { _connectToBroker(); }, ); - /*MessageService().subscribe(Constants.messageTopicConnectClient, this, (ConnectClientMessage connectClientMessage) { - _connectToBroker(); - });*/ subscribe( queueId: Constants.messageTopicRequestConnectionStatus, @@ -679,13 +695,10 @@ class MqttCore with ProducerMixin, ConsumerMixin { } } - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicCurrentConnectionStatus, payload: CurrentConnectionStatusMessage(state: connected), ); - - //await MessageService().publish(Constants.messageTopicCurrentConnectionStatus, arguments: CurrentConnectionStatusMessage(state: connected)); }, ); @@ -701,4 +714,15 @@ class MqttCore with ProducerMixin, ConsumerMixin { await MessageService().publish(Constants.messageTopicCurrentConnectionStatus, arguments: CurrentConnectionStatusMessage(state: connected)); });*/ } + + String _encapsulateMessage(String messageId, bool requiresAck, Map message) { + var messageHeader = MessageHeader(); + messageHeader.messageId = messageId; + messageHeader.requiresAck = requiresAck; + messageHeader.payload = message; + + var encapsulatedMessageText = jsonEncode(messageHeader.toJson()); + + return encapsulatedMessageText; + } } diff --git a/lib/tools/util.dart b/lib/tools/util.dart index 05d2c2e..c853000 100644 --- a/lib/tools/util.dart +++ b/lib/tools/util.dart @@ -452,8 +452,11 @@ class DecimalTextInputFormatter extends TextInputFormatter { } } -bool isJobInFuture(Job job) { - return DateTime.parse(job.ordertime).add(Duration(minutes: job.offsWarn)).toUtc().millisecondsSinceEpoch > DateTime.now().toUtc().millisecondsSinceEpoch; +bool isJobTooFarInFuture(Job job) { + var ordertime = DateTime.parse(job.ordertime).toUtc().millisecondsSinceEpoch; + var dateTimeThreshold = DateTime.now().add(Duration(minutes: job.offsWarn)).toUtc().millisecondsSinceEpoch; + + return ordertime > dateTimeThreshold; } Future taskDialogSecurityException(BuildContext context) async { diff --git a/pubspec.lock b/pubspec.lock index adb2030..fe064ff 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -836,26 +836,26 @@ packages: dependency: "direct main" description: name: isar - sha256: "99165dadb2cf2329d3140198363a7e7bff9bbd441871898a87e26914d25cf1ea" - url: "https://pub.dev" + sha256: e17a9555bc7f22ff26568b8c64d019b4ffa2dc6bd4cb1c8d9b269aefd32e53ad + url: "https://pub.isar-community.dev" source: hosted - version: "3.1.0+1" + version: "3.1.8" isar_flutter_libs: dependency: "direct main" description: name: isar_flutter_libs - sha256: bc6768cc4b9c61aabff77152e7f33b4b17d2fc93134f7af1c3dd51500fe8d5e8 - url: "https://pub.dev" + sha256: "78710781e658ce4bff59b3f38c5b2735e899e627f4e926e1221934e77b95231a" + url: "https://pub.isar-community.dev" source: hosted - version: "3.1.0+1" + version: "3.1.8" isar_generator: dependency: "direct dev" description: name: isar_generator - sha256: "76c121e1295a30423604f2f819bc255bc79f852f3bc8743a24017df6068ad133" - url: "https://pub.dev" + sha256: "484e73d3b7e81dbd816852fe0b9497333118a9aeb646fd2d349a62cc8980ffe1" + url: "https://pub.isar-community.dev" source: hosted - version: "3.1.0+1" + version: "3.1.8" js: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 512cb0e..98d882a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,11 +16,13 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 323.0.0+323 +version: 327.0.0+327 environment: sdk: '>=2.19.6 <3.0.0' +isar_version: &isar_version 3.1.8 # define the version to be used + # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, @@ -31,9 +33,13 @@ dependencies: flutter: sdk: flutter + isar: + version: *isar_version + hosted: https://pub.isar-community.dev/ + isar_flutter_libs: # contains Isar Core + version: *isar_version + hosted: https://pub.isar-community.dev/ - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 uuid: ^3.0.7 file_picker: ^5.2.7 @@ -41,13 +47,11 @@ dependencies: image_picker: ^0.8.7+1 mime: ^1.0.4 open_filex: ^4.3.2 - path_provider: ^2.0.14 + path_provider: ^2.1.2 split_view: ^3.2.1 mqtt5_client: ^4.4.0 - isar_flutter_libs: ^3.1.0+1 - isar: ^3.1.0+1 json_serializable: ^6.6.2 - json_annotation: ^4.8.1 + json_annotation: ^4.9.0 shared_preferences: ^2.1.1 badges: ^3.1.1 intl: ^0.18.0 @@ -82,9 +86,12 @@ dev_dependencies: flutter_test: sdk: flutter source_gen: ^1.3.1 - build_runner: ^2.3.3 + build_runner: any analyzer: ^5.12.0 - isar_generator: ^3.1.0+1 + + isar_generator: + version: *isar_version + hosted: https://pub.isar-community.dev/ # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is