diff --git a/lib/content_views/approach_area_page.dart b/lib/content_views/approach_area_page.dart index e2ac4a1..6afc6e4 100644 --- a/lib/content_views/approach_area_page.dart +++ b/lib/content_views/approach_area_page.dart @@ -1,13 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:isar/isar.dart'; -import 'package:stadtbote/content_views/tour_list_page.dart'; import 'package:stadtbote/content_views/utils/content_view_widget.dart'; import 'package:stadtbote/content_views/utils/header_info.dart'; -import 'package:stadtbote/tools/message_service.dart'; -import '../main.dart'; -import '../model/job.dart'; -import '../tools/constants.dart'; import '../tools/util.dart'; class ApproachAreaPage extends ContentViewWidget { @@ -36,14 +30,14 @@ class ApproachAreaPage extends ContentViewWidget { } class _ApproachAreaPageState extends State { - late List _jobs; + //late List _jobs; late bool _initCompleted = false; @override void initState() { Future.delayed(const Duration(seconds: 0), () async { - _jobs = await MyApp.isarInstance.jobs.filter().stateEqualTo(1).findAll(); + //_jobs = await MyApp.isarInstance.jobs.filter().stateEqualTo(1).findAll(); _initCompleted = true; @@ -59,25 +53,25 @@ class _ApproachAreaPageState extends State { return Util.getWaitWidget(context); } - return SingleChildScrollView( + return const SingleChildScrollView( scrollDirection: Axis.vertical, child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ - Container(width: 80, child: Text('Row 1')), - Container(width: 80, child: Text('Row 2')), - Container(width: 80, child: Text('Row 3')), - Container(width: 80, child: Text('Row 4')), - Container(width: 80, child: Text('Row 5')), - Container(width: 80, child: Text('Row 6')), + SizedBox(width: 80, child: Text('Row 1')), + SizedBox(width: 80, child: Text('Row 2')), + SizedBox(width: 80, child: Text('Row 3')), + SizedBox(width: 80, child: Text('Row 4')), + SizedBox(width: 80, child: Text('Row 5')), + SizedBox(width: 80, child: Text('Row 6')), ], ), ), ); } - void _clicked(Job job) { + /*void _clicked(Job job) { MessageService().publish(Constants.messageTopicPushContentView, arguments: TourListPage(job: job)); - } + }*/ } diff --git a/lib/content_views/main_page.dart b/lib/content_views/main_page.dart index 8e33fbe..97580d5 100644 --- a/lib/content_views/main_page.dart +++ b/lib/content_views/main_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:isar/isar.dart'; -import 'package:mqtt_client/mqtt_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'; @@ -12,8 +11,8 @@ import 'package:stadtbote/model/job.dart'; import 'package:stadtbote/model/message.dart'; import 'package:stadtbote/model/session_status.dart'; import 'package:stadtbote/model/status.dart'; -import 'package:stadtbote/popups/accept_jobs_popup.dart'; import 'package:stadtbote/popups/infos_popup.dart'; +import 'package:stadtbote/protocoll_messages/logout_message.dart'; import 'package:stadtbote/tools/message_service.dart'; import 'package:stadtbote/tools/messages/job_deleted_message.dart'; import 'package:stadtbote/tools/messages/job_received_message.dart'; @@ -21,6 +20,7 @@ import 'package:stadtbote/tools/messages/message_message.dart'; import 'package:stadtbote/tools/messages/session_info_update.dart'; import 'package:badges/badges.dart' as badges; import 'package:stadtbote/tools/messages/status_info_update.dart'; +import 'package:stadtbote/tools/mqtt_core.dart'; import '../main.dart'; import '../tools/constants.dart'; @@ -83,6 +83,8 @@ class _MainPageState extends State { final ValueNotifier _acceptedJobsValueNotifier = ValueNotifier(0); final ValueNotifier _messagesValueNotifier = ValueNotifier(0); + late bool _loggedOut = false; + @override void initState() { super.initState(); @@ -112,40 +114,12 @@ class _MainPageState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - ValueListenableBuilder( - valueListenable: _assignedJobsValueNotifier, - builder: (context, value, child) { - return badges.Badge( - showBadge: value > 0, - position: badges.BadgePosition.topEnd(top: -12, end: -5), - badgeContent: Text( - value.toString(), - style: const TextStyle( - color: Colors.white, - fontSize: 13.0, - ), - ), - badgeStyle: badges.BadgeStyle( - badgeColor: Colors.red, - padding: const EdgeInsets.all(10), - borderRadius: BorderRadius.circular(4), - borderSide: const BorderSide(color: Colors.white, width: 0), - elevation: 0, - ), - child: getDefaultButton( - 'Zugewiesene Aufträge', - image: Image.asset('assets/zugewiesene_auftraege.png', width: 30, height: 30), - () => { - MessageService().publish(Constants.messageTopicPushContentView, arguments: const AssignedJobsPage()) - }), - ); - }, - ), - const SizedBox(height: 20), - ValueListenableBuilder( - valueListenable: _acceptedJobsValueNotifier, - builder: (context, value, child) { - return badges.Badge( + Visibility( + visible: !_loggedOut, + child: ValueListenableBuilder( + valueListenable: _assignedJobsValueNotifier, + builder: (context, value, child) { + return badges.Badge( showBadge: value > 0, position: badges.BadgePosition.topEnd(top: -12, end: -5), badgeContent: Text( @@ -163,57 +137,100 @@ class _MainPageState extends State { elevation: 0, ), child: getDefaultButton( - 'Angenommene Aufträge', - image: Image.asset('assets/angenommene_auftraege.png', width: 30, height: 30), + 'Zugewiesene Aufträge', + image: Image.asset('assets/zugewiesene_auftraege.png', width: 30, height: 30), () => { - MessageService() - .publish(Constants.messageTopicPushContentView, arguments: const AcceptedJobsPage()) - })); - }, + MessageService().publish(Constants.messageTopicPushContentView, arguments: const AssignedJobsPage()) + }), + ); + }, + ), ), - const SizedBox(height: 20), - getDefaultButton( - 'Erledigte Aufträge', - image: Image.asset('assets/erledigte_auftraege.png', width: 30, height: 30), - () => {MessageService().publish(Constants.messageTopicPushContentView, arguments: const FinishedJobsPage())}), - const SizedBox(height: 20), - ValueListenableBuilder( - valueListenable: _messagesValueNotifier, - builder: (context, value, child) { - return badges.Badge( - showBadge: value > 0, - position: badges.BadgePosition.topEnd(top: -12, end: -5), - badgeContent: Text( - value.toString(), - style: const TextStyle( - color: Colors.white, - fontSize: 13.0, + SizedBox(height: _loggedOut == true ? 0 : 20), + Visibility( + visible: !_loggedOut, + child: ValueListenableBuilder( + valueListenable: _acceptedJobsValueNotifier, + builder: (context, value, child) { + return badges.Badge( + showBadge: value > 0, + position: badges.BadgePosition.topEnd(top: -12, end: -5), + badgeContent: Text( + value.toString(), + style: const TextStyle( + color: Colors.white, + fontSize: 13.0, + ), ), - ), - badgeStyle: badges.BadgeStyle( - badgeColor: Colors.red, - padding: const EdgeInsets.all(10), - borderRadius: BorderRadius.circular(4), - borderSide: const BorderSide(color: Colors.white, width: 0), - elevation: 0, - ), - child: getDefaultButton( - 'Nachrichten', - image: Image.asset('assets/nachrichten.png', width: 30, height: 30), - () => - {MessageService().publish(Constants.messageTopicPushContentView, arguments: const MessagesPage())})); - }, + badgeStyle: badges.BadgeStyle( + badgeColor: Colors.red, + padding: const EdgeInsets.all(10), + borderRadius: BorderRadius.circular(4), + borderSide: const BorderSide(color: Colors.white, width: 0), + elevation: 0, + ), + child: getDefaultButton( + 'Angenommene Aufträge', + image: Image.asset('assets/angenommene_auftraege.png', width: 30, height: 30), + () => { + MessageService() + .publish(Constants.messageTopicPushContentView, arguments: const AcceptedJobsPage()) + })); + }, + ), ), - const SizedBox(height: 20), + SizedBox(height: _loggedOut == true ? 0 : 20), + Visibility( + visible: !_loggedOut, + child: getDefaultButton( + 'Erledigte Aufträge', + image: Image.asset('assets/erledigte_auftraege.png', width: 30, height: 30), + () => {MessageService().publish(Constants.messageTopicPushContentView, arguments: const FinishedJobsPage())}), + ), + SizedBox(height: _loggedOut == true ? 0 : 20), + Visibility( + visible: !_loggedOut, + child: ValueListenableBuilder( + valueListenable: _messagesValueNotifier, + builder: (context, value, child) { + return badges.Badge( + showBadge: value > 0, + position: badges.BadgePosition.topEnd(top: -12, end: -5), + badgeContent: Text( + value.toString(), + style: const TextStyle( + color: Colors.white, + fontSize: 13.0, + ), + ), + badgeStyle: badges.BadgeStyle( + badgeColor: Colors.red, + padding: const EdgeInsets.all(10), + borderRadius: BorderRadius.circular(4), + borderSide: const BorderSide(color: Colors.white, width: 0), + elevation: 0, + ), + child: getDefaultButton( + 'Nachrichten', + image: Image.asset('assets/nachrichten.png', width: 30, height: 30), + () => + {MessageService().publish(Constants.messageTopicPushContentView, arguments: const MessagesPage())})); + }, + ), + ), + SizedBox(height: _loggedOut == true ? 0 : 20), + Visibility( + visible: !_loggedOut, + child: getDefaultButton( + 'Anfahrtsbereich', + image: Image.asset('assets/anfahrtsbereich.png', width: 30, height: 30), + () => {MessageService().publish(Constants.messageTopicPushContentView, arguments: const ApproachAreaPage())}), + ), + SizedBox(height: _loggedOut == true ? 0 : 20), getDefaultButton( - 'Anfahrtsbereich', - image: Image.asset('assets/anfahrtsbereich.png', width: 30, height: 30), - () => {MessageService().publish(Constants.messageTopicPushContentView, arguments: const ApproachAreaPage())}), - const SizedBox(height: 20), - getDefaultButton( - 'Abmelden', - image: Image.asset('assets/abmelden.png', width: 30, height: 30), - () async => {showAcceptJobsPopup(context, await MyApp.isarInstance.jobs.filter().stateEqualTo(0).findAll())}), + _loggedOut ? 'Anmelden' : 'Abmelden', + image: Image.asset(_loggedOut ? 'assets/anmelden.png' : 'assets/abmelden.png', width: 30, height: 30), + () async => {_logout()}), Expanded( child: Container( decoration: BoxDecoration( @@ -287,4 +304,36 @@ class _MainPageState extends State { widget._zipValueNotifier.value = "---"; } } + + _logout() { + if (!_loggedOut) { + _sendLogoutMessage(); + + Future.delayed(const Duration(seconds: 1), () async { + MqttCore.instance.diconnect(); + }); + } else { + MqttCore.setup(); + } + + _loggedOut = !_loggedOut; + + setState(() {}); + } + + _sendLogoutMessage() { + var position = MyApp.currentPosition; + + var logoutMessage = LogoutMessage(); + logoutMessage.logout = LogoutContainer(); + if (position != null) { + logoutMessage.logout.pos = LogoutMessagePosition(); + logoutMessage.logout.pos!.time = position.timestamp.toIso8601String(); + logoutMessage.logout.pos!.lat = position.latitude; + logoutMessage.logout.pos!.long = position.longitude; + logoutMessage.logout.pos!.acc = position.accuracy.toInt(); + } + + MqttCore.instance.publishPayloadMessage('session', logoutMessage.toJson()); + } } diff --git a/lib/content_views/messages_page.dart b/lib/content_views/messages_page.dart index 1b9b1e7..0412971 100644 --- a/lib/content_views/messages_page.dart +++ b/lib/content_views/messages_page.dart @@ -1,16 +1,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:intl/intl.dart'; import 'package:isar/isar.dart'; import 'package:stadtbote/content_views/utils/content_view_widget.dart'; import 'package:stadtbote/content_views/utils/header_info.dart'; import 'package:stadtbote/main.dart'; import 'package:stadtbote/model/message.dart' as sbmessage; import 'package:stadtbote/model/session_status.dart'; -import 'package:stadtbote/popups/infos_popup.dart'; import 'package:stadtbote/tools/mqtt_core.dart'; -import 'package:uuid/uuid.dart'; import '../tools/util.dart'; diff --git a/lib/content_views/task_list_page.dart b/lib/content_views/task_list_page.dart index b6be096..b299892 100644 --- a/lib/content_views/task_list_page.dart +++ b/lib/content_views/task_list_page.dart @@ -18,7 +18,6 @@ import 'package:stadtbote/popups/tasks_popups/take_photos_popup.dart'; import 'package:stadtbote/protocoll_messages/accept_job_message.dart'; import 'package:stadtbote/protocoll_messages/fin_task_message.dart'; import 'package:stadtbote/protocoll_messages/fin_tour_message.dart'; -import 'package:stadtbote/protocoll_messages/track_station_message.dart'; import 'package:stadtbote/tools/constants.dart'; import 'package:stadtbote/tools/mqtt_core.dart'; @@ -388,7 +387,7 @@ class _TaskListPageState extends State { MqttCore.instance.publishPayloadMessage("job", finTaskMessage.toJson()); } - _sendTrackStationMessage(TaskInfo taskInfo) + /*_sendTrackStationMessage(TaskInfo taskInfo) { var trackStationMessage = TrackStationMessage(); trackStationMessage.sid = taskInfo.task.sId; @@ -402,7 +401,7 @@ class _TaskListPageState extends State { } MqttCore.instance.publishPayloadMessage("", trackStationMessage.toJson()); - } + }*/ _sendFinTourMessage() async { var finTourMessage = FinTourMessage(); diff --git a/lib/popups/tasks_popups/pickup_delivery_status_popup.dart b/lib/popups/tasks_popups/pickup_delivery_status_popup.dart index 86b4734..86be005 100644 --- a/lib/popups/tasks_popups/pickup_delivery_status_popup.dart +++ b/lib/popups/tasks_popups/pickup_delivery_status_popup.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +// ignore: unused_import import 'package:kumi_popup_window/kumi_popup_window.dart'; import 'package:stadtbote/model/task_info.dart'; import 'package:stadtbote/model/tour_task.dart'; diff --git a/lib/protocoll_messages/logout_message.dart b/lib/protocoll_messages/logout_message.dart new file mode 100644 index 0000000..bc92ec8 --- /dev/null +++ b/lib/protocoll_messages/logout_message.dart @@ -0,0 +1,43 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'logout_message.g.dart'; + +@JsonSerializable() +class LogoutMessage { + late LogoutContainer logout; + + LogoutMessage(); + + factory LogoutMessage.fromJson(Map json) => _$LogoutMessageFromJson(json); + + Map toJson() => _$LogoutMessageToJson(this); +} + +@JsonSerializable() +class LogoutContainer { + late LogoutMessagePosition? pos; + + LogoutContainer(); + + factory LogoutContainer.fromJson(Map json) => _$LogoutContainerFromJson(json); + + Map toJson() => _$LogoutContainerToJson(this); +} + +@JsonSerializable() +class LogoutMessagePosition { + late String time; + + late double lat; + + late double long; + + late int acc; + + LogoutMessagePosition(); + + factory LogoutMessagePosition.fromJson(Map json) => _$LogoutMessagePositionFromJson(json); + + Map toJson() => _$LogoutMessagePositionToJson(this); +} + diff --git a/lib/protocoll_messages/logout_message.g.dart b/lib/protocoll_messages/logout_message.g.dart new file mode 100644 index 0000000..a107ce8 --- /dev/null +++ b/lib/protocoll_messages/logout_message.g.dart @@ -0,0 +1,45 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'logout_message.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LogoutMessage _$LogoutMessageFromJson(Map json) => + LogoutMessage() + ..logout = + LogoutContainer.fromJson(json['logout'] as Map); + +Map _$LogoutMessageToJson(LogoutMessage instance) => + { + 'logout': instance.logout, + }; + +LogoutContainer _$LogoutContainerFromJson(Map json) => + LogoutContainer() + ..pos = json['pos'] == null + ? null + : LogoutMessagePosition.fromJson(json['pos'] as Map); + +Map _$LogoutContainerToJson(LogoutContainer instance) => + { + 'pos': instance.pos, + }; + +LogoutMessagePosition _$LogoutMessagePositionFromJson( + Map json) => + LogoutMessagePosition() + ..time = json['time'] as String + ..lat = (json['lat'] as num).toDouble() + ..long = (json['long'] as num).toDouble() + ..acc = json['acc'] as int; + +Map _$LogoutMessagePositionToJson( + LogoutMessagePosition instance) => + { + 'time': instance.time, + 'lat': instance.lat, + 'long': instance.long, + 'acc': instance.acc, + }; diff --git a/lib/protocoll_messages/track_message.dart b/lib/protocoll_messages/track_message.dart index fba20d6..07f1885 100644 --- a/lib/protocoll_messages/track_message.dart +++ b/lib/protocoll_messages/track_message.dart @@ -1,5 +1,4 @@ import 'package:json_annotation/json_annotation.dart'; -import 'package:stadtbote/protocoll_messages/fin_task_message.dart'; part 'track_message.g.dart'; diff --git a/lib/tools/mqtt_core.dart b/lib/tools/mqtt_core.dart index 18a6410..91bdfb4 100644 --- a/lib/tools/mqtt_core.dart +++ b/lib/tools/mqtt_core.dart @@ -5,14 +5,12 @@ import 'dart:math'; import 'package:isar/isar.dart'; import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_server_client.dart'; -import 'package:stadtbote/model/job_tour.dart'; import 'package:stadtbote/model/status.dart'; import 'package:stadtbote/protocoll_messages/bootstrap_request.dart'; import 'package:stadtbote/protocoll_messages/bootstrap_response_payload.dart'; import 'package:stadtbote/protocoll_messages/device_object.dart'; import 'package:stadtbote/model/job.dart'; import 'package:stadtbote/model/message.dart'; -import 'package:stadtbote/protocoll_messages/fin_task_message.dart'; import 'package:stadtbote/protocoll_messages/job_del_message.dart'; import 'package:stadtbote/protocoll_messages/payload_container.dart'; import 'package:stadtbote/protocoll_messages/start_session_message.dart'; @@ -45,6 +43,8 @@ class MqttCore { late ConnectionStateEnum connectionState = ConnectionStateEnum.notConnected; + late bool _disconnectInProgress = false; + late String _brokerUri; late int _brokerPort; late String _fromServerTopic; @@ -54,9 +54,13 @@ class MqttCore { late int _reconnectDelay = 0; - late Timer? _trackTimer; + late Timer? _reconnectTimer = null; + + late Timer? _trackTimer = null; MqttCore() { + _disconnectInProgress = false; + _processBootstrap(); } @@ -64,6 +68,18 @@ class MqttCore { instance = MqttCore(); } + diconnect() { + _disconnectInProgress = true; + + _cancelReconnectTimer(); + + _cancelTrackTimer(); + + _mqttClient.disconnect(); + + connectionState = ConnectionStateEnum.notConnected; + } + _connectToBroker() async { try { String clientId = await Util.getAppUuid(); @@ -303,13 +319,21 @@ class MqttCore { void _startReconnectTimer() { connectionState = ConnectionStateEnum.notConnected; - Util.logInfo("_startReconnectTimer called"); + if (!_disconnectInProgress) { + Util.logInfo("_startReconnectTimer called"); - _reconnectDelay = min(_reconnectDelay + 1, 30); + _reconnectDelay = min(_reconnectDelay + 1, 30); - Timer(Duration(seconds: _reconnectDelay), () { - _processBootstrap(); - }); + _reconnectTimer = Timer(Duration(seconds: _reconnectDelay), () { + _processBootstrap(); + }); + } + } + + void _cancelReconnectTimer() { + if (_reconnectTimer != null && _reconnectTimer!.isActive) { + _reconnectTimer!.cancel(); + } } void _clientDisconnected() { @@ -321,7 +345,9 @@ class MqttCore { MessageService().publish(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected)); - _startReconnectTimer(); + if (!_disconnectInProgress) { + _startReconnectTimer(); + } } void _processBootstrap() async { diff --git a/lib/tools/util.dart b/lib/tools/util.dart index 181532b..d7bf9ab 100644 --- a/lib/tools/util.dart +++ b/lib/tools/util.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:audioplayers/audioplayers.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:image_picker/image_picker.dart';