diff --git a/lib/content_views/messages_page.dart b/lib/content_views/messages_page.dart index e911d7c..3aee782 100644 --- a/lib/content_views/messages_page.dart +++ b/lib/content_views/messages_page.dart @@ -53,7 +53,7 @@ class _MessagesPageState extends State with ProducerMixin { var status = await MyApp.isarInstance.sessionStatus.where().findFirst(); _sid = status != null ? status.sid : 'Unbekannt'; - _sendMessagesReceivedMessage(); + _sendMessagesReadMessage(); await _fetchMessages(); @@ -191,7 +191,7 @@ class _MessagesPageState extends State with ProducerMixin { }); } - void _sendMessagesReceivedMessage() async { + void _sendMessagesReadMessage() async { var unreadChatMessages = await MyApp.isarInstance.chatMessages .filter() .readEqualTo(false) @@ -203,13 +203,13 @@ class _MessagesPageState extends State with ProducerMixin { chatMessageIds.add(message.id.toString()); } - var chatMessagesReceived = ChatMessagesReceived(); - chatMessagesReceived.ids = chatMessageIds; - chatMessagesReceived.time = DateTime.now().toUtc().toIso8601String(); + var chatMessagesShowed = ChatMessagesReceived(); + chatMessagesShowed.ids = chatMessageIds; + chatMessagesShowed.time = DateTime.now().toUtc().toIso8601String(); sendMessage( - routingKey: Constants.messageTopicChatMessagesReceived, - payload: chatMessagesReceived, + routingKey: Constants.messageTopicPublishPayload, + payload: PublishPayloadMessage(topic: "mssg_received", message: chatMessagesShowed.toJson(), acknowledgeRequired: false), ); } } diff --git a/lib/content_views/task_list_page.dart b/lib/content_views/task_list_page.dart index 37f0954..42d7cb9 100644 --- a/lib/content_views/task_list_page.dart +++ b/lib/content_views/task_list_page.dart @@ -477,13 +477,10 @@ class _TaskListPageState extends State with ProducerMixin { message.task.pos = null; } - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicPublishPayload, 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)); } FinTourTask _createAnswerHeader(TaskInfo taskInfo) { diff --git a/lib/main.dart b/lib/main.dart index 7bcd0f2..39bb1b1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -347,13 +347,15 @@ class _MainState extends State
with SingleTickerProviderStateMixin, Produc callback: (message) async { var removeJobMessage = message.payload as RemoveJobMessage; + var job = await MyApp.isarInstance.jobs.where().filter().idEqualTo(removeJobMessage.id).findFirst(); + await MyApp.isarInstance.writeTxn(() async { await MyApp.isarInstance.jobs.where().filter().idEqualTo(removeJobMessage.id).deleteAll(); }); sendMessage( routingKey: Constants.messageTopicJobDeleted, - payload: JobDeletedMessage(id: removeJobMessage.id), + payload: JobDeletedMessage(job: job!), ); sendMessage( @@ -377,7 +379,7 @@ class _MainState extends State
with SingleTickerProviderStateMixin, Produc queueId: Constants.messageTopicJobDeleted, callback: (message) async { var jobDeleted = message.payload as JobDeletedMessage; - await _jobMap!.remove(jobDeleted.id); + await _jobMap!.remove(jobDeleted.job.id); }, ); diff --git a/lib/popups/accept_jobs_popup.dart b/lib/popups/accept_jobs_popup.dart index 18174e2..e600c93 100644 --- a/lib/popups/accept_jobs_popup.dart +++ b/lib/popups/accept_jobs_popup.dart @@ -8,7 +8,10 @@ import 'package:stadtbote/main.dart'; import 'package:stadtbote/protocoll_messages/accept_job_message.dart'; import 'package:stadtbote/model/job.dart'; import 'package:stadtbote/protocoll_messages/fin_task_message.dart'; +import 'package:stadtbote/tools/ExtendedStatefulBuilder.dart'; import 'package:stadtbote/tools/constants.dart'; +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/util.dart'; @@ -16,15 +19,98 @@ import 'package:badges/badges.dart' as badges; import '../tools/messages/publish_payload_message.dart'; -late bool _initTimer; -late Timer _checkForNewJobsTimer; late Map _infoExpandedMap; Future showAcceptJobsPopup(SharedMapReference mapReference, Function() onFinished) async { - _initTimer = true; _infoExpandedMap = {}; - await showDialog( + ExtendendStatefulBuilder extendedStatefulBuilder; + + return showDialog( + barrierDismissible: true, + context: MyApp.appNavigatorKey.currentContext!, + builder: (BuildContext context) { + List widgets = []; + StateSetter? extendedStatefulBuilderStateSetter; + + extendedStatefulBuilder = ExtendendStatefulBuilder(builder: (BuildContext context, StateSetter setState) { + extendedStatefulBuilderStateSetter = setState; + + return SizedBox( + key: GlobalKey(), + height: 400, + width: MediaQuery.of(context).size.width * 1.2, + child: Container( + height: 400, + padding: const EdgeInsets.all(5), + child: FutureBuilder>( + future: _fetchJobWidgets(setState, onFinished, mapReference), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Util.getWaitWidget(context); + } else { + return ListView( + children: snapshot.requireData, + ); + } + }, + ), + )); + }); + + extendedStatefulBuilder.subscribe( + queueId: Constants.messageTopicJobReceived, + callback: (message) { + var jobReceivedMessage = message.payload as JobReceivedMessage; + if (jobReceivedMessage.job.state == 0) { + extendedStatefulBuilderStateSetter!(() {}); + } + }, + ); + + extendedStatefulBuilder.subscribe( + queueId: Constants.messageTopicJobDeleted, + callback: (message) { + var jobDeletedMessage = message.payload as JobDeletedMessage; + if (jobDeletedMessage.job.state == 0) { + extendedStatefulBuilderStateSetter!(() {}); + } + extendedStatefulBuilderStateSetter!(() {}); + }, + ); + + widgets.add(extendedStatefulBuilder); + + widgets.add(getDefaultButton("Liste schliessen", () { + extendedStatefulBuilder.unsubscribe(queueId: Constants.messageTopicJobReceived); + extendedStatefulBuilder.unsubscribe(queueId: Constants.messageTopicJobDeleted); + + Navigator.pop(context); + + onFinished(); + })); + + return Material( + color: Colors.transparent, + child: Stack( + children: [ + Align( + alignment: Alignment.bottomCenter, + child: Container( + padding: const EdgeInsets.all(5), + height: 480, + color: Colors.white, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: widgets, + ), + )) + ], + ), + ); + }, + ); + /*await showDialog( context: MyApp.appNavigatorKey.currentContext!, builder: (BuildContext context) { return WillPopScope( @@ -50,7 +136,7 @@ Future showAcceptJobsPopup(SharedMapReference mapReference, Function() onF return SizedBox( key: GlobalKey(), - height: MediaQuery.of(context).size.height * 1, + height: MediaQuery.of(context).size.height * 0.4, width: MediaQuery.of(context).size.width * 1.2, child: Container( height: 100, @@ -69,28 +155,28 @@ Future showAcceptJobsPopup(SharedMapReference mapReference, Function() onF ), )); }))); - }); + });*/ } -void _startTimer(BuildContext context, SharedMapReference mapReference, StateSetter setState, Function() onFinished) { +/*void _startTimer(BuildContext context, SharedMapReference mapReference, StateSetter setState, Function() onFinished) { _checkForNewJobsTimer = Timer.periodic(const Duration(seconds: 5), (Timer t) async { - var jobMap = SharedMap.fromSharedReference(mapReference); + var jobMap = SharedMap.fromSharedReference(mapReference); - if (await jobMap.length() > 0) { - setState(() { }); - } else { - _stopTimer(); + if (await jobMap.length() > 0) { + setState(() {}); + } else { + _stopTimer(); - Navigator.of(MyApp.appNavigatorKey.currentContext!).pop(); + Navigator.of(MyApp.appNavigatorKey.currentContext!).pop(); - onFinished(); - } - }); -} + onFinished(); + } + }); +}*/ -void _stopTimer() { +/*void _stopTimer() { _checkForNewJobsTimer.cancel(); -} +}*/ Future> _fetchJobWidgets(StateSetter dialogState, Function() onFinished, SharedMapReference mapReference) async { List widgets = []; @@ -208,10 +294,6 @@ Future> _fetchJobWidgets(StateSetter dialogState, Function() onFini Expanded( child: getDefaultButton(!job.global ? 'Ablehnen' : 'Ignorieren', () { dialogState(() { - if (jobMap.length() == 1) { - _stopTimer(); - } - _sendAnswer(mapReference, job, !job.global ? 2 : 3); jobMap.remove(job.id); @@ -222,12 +304,6 @@ Future> _fetchJobWidgets(StateSetter dialogState, Function() onFini ); setState(() {}); - - if (jobMap.length() == 0) { - Navigator.of(context).pop(); - - onFinished(); - } }); }), ), @@ -235,10 +311,6 @@ Future> _fetchJobWidgets(StateSetter dialogState, Function() onFini Expanded( child: getDefaultButton('Annehmen', enabledTimerActive: false, () { dialogState(() { - if (jobMap.length() == 1) { - _stopTimer(); - } - _sendAnswer(mapReference, job, 1); jobMap.remove(job.id); @@ -249,12 +321,6 @@ Future> _fetchJobWidgets(StateSetter dialogState, Function() onFini ); setState(() {}); - - if (jobMap.length() == 0) { - Navigator.of(context).pop(); - - onFinished(); - } }); }), ) @@ -286,19 +352,13 @@ _sendAnswer(SharedMapReference mapReference, Job job, int item) async { message.track.pos!.long = currentPosition != null ? currentPosition.longitude : 0.0; message.track.pos!.acc = currentPosition != null ? currentPosition.accuracy.toInt() : 0; - // TODO MESSAGING job.sendMessage( routingKey: Constants.messageTopicPublishPayload, payload: PublishPayloadMessage(topic: "reaction", message: message.toJson(), acknowledgeRequired: true), ); - //await MessageService().publish(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "reaction", message: message.toJson(), qos: MqttQos.exactlyOnce)); - - // TODO MESSAGING job.sendMessage( routingKey: Constants.messageTopicUpdateBadges, payload: RefreshBadgesMessage(), ); - - //await MessageService().publish(Constants.messageTopicUpdateBadges, arguments: RefreshBadgesMessage()); } diff --git a/lib/protocoll_messages/connection_lost_message.dart b/lib/protocoll_messages/connection_lost_message.dart new file mode 100644 index 0000000..187d9d4 --- /dev/null +++ b/lib/protocoll_messages/connection_lost_message.dart @@ -0,0 +1,15 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'connection_lost_message.g.dart'; + +@JsonSerializable() +class ConnectionLostMessage { + @JsonKey(name: "connection_lost") + late bool connectionLost; + + ConnectionLostMessage(); + + factory ConnectionLostMessage.fromJson(Map json) => _$ConnectionLostMessageFromJson(json); + + Map toJson() => _$ConnectionLostMessageToJson(this); +} diff --git a/lib/protocoll_messages/connection_lost_message.g.dart b/lib/protocoll_messages/connection_lost_message.g.dart new file mode 100644 index 0000000..f8988fe --- /dev/null +++ b/lib/protocoll_messages/connection_lost_message.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'connection_lost_message.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ConnectionLostMessage _$ConnectionLostMessageFromJson( + Map json) => + ConnectionLostMessage()..connectionLost = json['connection_lost'] as bool; + +Map _$ConnectionLostMessageToJson( + ConnectionLostMessage instance) => + { + 'connection_lost': instance.connectionLost, + }; diff --git a/lib/tools/ExtendedStatefulBuilder.dart b/lib/tools/ExtendedStatefulBuilder.dart new file mode 100644 index 0000000..9f87bfc --- /dev/null +++ b/lib/tools/ExtendedStatefulBuilder.dart @@ -0,0 +1,6 @@ +import 'package:dart_mq/dart_mq.dart'; +import 'package:flutter/widgets.dart'; + +class ExtendendStatefulBuilder extends StatefulBuilder with ConsumerMixin { + ExtendendStatefulBuilder({super.key, required super.builder}); +} \ No newline at end of file diff --git a/lib/tools/constants.dart b/lib/tools/constants.dart index 3e7ea95..822c3c6 100644 --- a/lib/tools/constants.dart +++ b/lib/tools/constants.dart @@ -24,7 +24,6 @@ class Constants { 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"; diff --git a/lib/tools/messages/job_deleted_message.dart b/lib/tools/messages/job_deleted_message.dart index 2f0408b..4469077 100644 --- a/lib/tools/messages/job_deleted_message.dart +++ b/lib/tools/messages/job_deleted_message.dart @@ -1,6 +1,8 @@ +import 'package:stadtbote/model/job.dart'; + class JobDeletedMessage { - final int id; + final Job job; - JobDeletedMessage({required this.id}); + JobDeletedMessage({required this.job}); } \ No newline at end of file diff --git a/lib/tools/mqtt_core.dart b/lib/tools/mqtt_core.dart index 28573db..0d04259 100644 --- a/lib/tools/mqtt_core.dart +++ b/lib/tools/mqtt_core.dart @@ -19,6 +19,7 @@ import 'package:stadtbote/model/status.dart'; import 'package:stadtbote/protocoll_messages/acknowledge_job.dart'; import 'package:stadtbote/protocoll_messages/bootstrap_request.dart'; import 'package:stadtbote/protocoll_messages/bootstrap_response_payload.dart'; +import 'package:stadtbote/protocoll_messages/connection_lost_message.dart'; 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'; @@ -88,14 +89,11 @@ class MqttCore with ProducerMixin, ConsumerMixin { } _disconnectMqttClient() async { - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicConnectionStatusChanged, payload: ConnectionStatus(status: ConnectionStatusEnum.notConnected), ); - //await MessageService().publish(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected)); - _disconnectInProgress = true; _cancelReconnectTimer(); @@ -134,6 +132,10 @@ class MqttCore with ProducerMixin, ConsumerMixin { willProperties.messageExpiryInterval = 3600; willProperties.willDelayInterval = 0; + var connectionLostMessage = ConnectionLostMessage(); + connectionLostMessage.connectionLost = true; + var connectionLostEncapsulatedMessage = _encapsulateMessage(const Uuid().v4(), false, connectionLostMessage.toJson()); + _mqttClient!.connectionMessage = MqttConnectMessage() .withClientIdentifier(await Util.getAppUuid()) .authenticateAs("app", "apppwd") @@ -142,7 +144,7 @@ class MqttCore with ProducerMixin, ConsumerMixin { .withWillTopic("$_toServerTopic$_clientId/connection_lost") .withWillQos(MqttQos.atMostOnce) .keepAliveFor(60) - .withWillPayload(MqttUtf8Encoding().toUtf8('{"connection_lost": true}')) + .withWillPayload(MqttUtf8Encoding().toUtf8(connectionLostEncapsulatedMessage)) .will(); } @@ -159,13 +161,10 @@ class MqttCore with ProducerMixin, ConsumerMixin { } else { Util.logInfo('Verbindung zum MQTT-Broker fehlgeschlagen!'); - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicConnectionStatusChanged, payload: ConnectionStatus(status: ConnectionStatusEnum.notConnected), ); - - //await MessageService().publish(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected)); } } catch (ex) { Util.logInfo('Verbindung zum MQTT-Broker fehlgeschlagen!: $ex'); @@ -400,32 +399,35 @@ class MqttCore with ProducerMixin, ConsumerMixin { _acknowlegdeJob(newJob); - // TODO MESSAGING sendMessage( routingKey: Constants.messageTopicJobReceived, payload: JobReceivedMessage(job: newJob), ); - - // await MessageService().publish(Constants.messageTopicJobReceived, arguments: JobReceivedMessage(job: newJob)); } void _jobDeleteReceived(payloadData) async { var jobDelMessage = JobDelMessage.fromJson(payloadData); + var job = await MyApp.isarInstance.jobs.where().filter().idEqualTo(jobDelMessage.id).findFirst(); + await MyApp.isarInstance.writeTxn(() async { await MyApp.isarInstance.jobs.where().filter().idEqualTo(jobDelMessage.id).deleteAll(); }); - sendMessage( - routingKey: Constants.messageTopicJobDeleted, - payload: JobDeletedMessage(id: jobDelMessage.id), - ); + if (job != null) { + sendMessage( + routingKey: Constants.messageTopicJobDeleted, + payload: JobDeletedMessage(job: job!), + ); + } } void _syncRequestReceived(payloadData) async { Util.logInfo('_syncRequestReceived'); - _sendSyncMessage(); + await _sendEnqueuedMessages(); + + await _sendSyncMessage(); } void _messageMessageReceived(Map payloadData) async { @@ -701,18 +703,6 @@ class MqttCore with ProducerMixin, ConsumerMixin { ); }, ); - - /*MessageService().subscribe(Constants.messageTopicRequestConnectionStatus, this, - (RequestConnectionStatusMessage requestConnectionStatusMessage) async { - bool connected = false; - if (_mqttClient != null && _mqttClient!.connectionStatus != null) { - if (_mqttClient!.connectionStatus!.state == MqttConnectionState.connected) { - connected = true; - } - } - - await MessageService().publish(Constants.messageTopicCurrentConnectionStatus, arguments: CurrentConnectionStatusMessage(state: connected)); - });*/ } String _encapsulateMessage(String messageId, bool requiresAck, Map message) { diff --git a/pubspec.yaml b/pubspec.yaml index 98d882a..25d5f3d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ 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: 327.0.0+327 +version: 330.0.0+330 environment: sdk: '>=2.19.6 <3.0.0'