Erweiterungen

This commit is contained in:
Sven committed 2024-07-29 10:46:55 +02:00
1 parent 41d086e13e
commit 7015d83fd1
20 files changed
+163 -139

No files matched your search

+2 -2
View File
@@ -142,7 +142,7 @@ class _AcceptedJobsPageState extends State<AcceptedJobsPage> {
return jobWidgets; return jobWidgets;
} }
void _clicked(Job job) { void _clicked(Job job) async {
MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: TourListPage(job: job)); await MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: TourListPage(job: job));
} }
} }
+2 -2
View File
@@ -197,7 +197,7 @@ class _ApproachAreaPageState extends State<ApproachAreaPage> {
return columns; return columns;
} }
_sendZip(Rank rank, String zip) { _sendZip(Rank rank, String zip) async {
var position = MyApp.currentPosition; var position = MyApp.currentPosition;
var setPosMessage = ZipSetPos(); var setPosMessage = ZipSetPos();
@@ -212,7 +212,7 @@ class _ApproachAreaPageState extends State<ApproachAreaPage> {
setPosMessage.track!.pos!.acc = position.accuracy.toInt(); setPosMessage.track!.pos!.acc = position.accuracy.toInt();
} }
MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "set_zip", message: setPosMessage.toJson(), qos: MqttQos.exactlyOnce)); await MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "set_zip", message: setPosMessage.toJson(), qos: MqttQos.exactlyOnce));
} }
_initMessages() { _initMessages() {
+2 -2
View File
@@ -200,13 +200,13 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> {
message.track.pos!.long = currentPosition != null ? currentPosition.longitude : 0.0; message.track.pos!.long = currentPosition != null ? currentPosition.longitude : 0.0;
message.track.pos!.acc = currentPosition != null ? currentPosition.accuracy.toInt() : 0; message.track.pos!.acc = currentPosition != null ? currentPosition.accuracy.toInt() : 0;
MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "reaction", message: message.toJson(), qos: MqttQos.exactlyOnce)); await MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "reaction", message: message.toJson(), qos: MqttQos.exactlyOnce));
await MyApp.isarInstance.writeTxn(() async { await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.jobs.delete(job.id); await MyApp.isarInstance.jobs.delete(job.id);
}); });
MessageService().publish<RefreshBadgesMessage>(Constants.messageTopicUpdateBadges, arguments: RefreshBadgesMessage()); await MessageService().publish<RefreshBadgesMessage>(Constants.messageTopicUpdateBadges, arguments: RefreshBadgesMessage());
_entries = await _createListEntries(); _entries = await _createListEntries();
+2 -2
View File
@@ -130,7 +130,7 @@ class _FinishedJobsPageState extends State<FinishedJobsPage> {
return jobWidgets; return jobWidgets;
} }
void _clicked(Job job) { void _clicked(Job job) async {
MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: TourListPage(job: job, readOnly: true,)); await MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: TourListPage(job: job, readOnly: true,));
} }
} }
+12 -13
View File
@@ -143,8 +143,8 @@ class _MainPageState extends State<MainPage> {
child: getDefaultButton( child: getDefaultButton(
'Zugewiesene Aufträge', 'Zugewiesene Aufträge',
image: Image.asset('assets/zugewiesene_auftraege.png', width: 30, height: 30), image: Image.asset('assets/zugewiesene_auftraege.png', width: 30, height: 30),
() => { () async => {
MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: const AssignedJobsPage()) await MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: const AssignedJobsPage())
}), }),
); );
}, },
@@ -176,9 +176,8 @@ class _MainPageState extends State<MainPage> {
child: getDefaultButton( child: getDefaultButton(
'Angenommene Aufträge', 'Angenommene Aufträge',
image: Image.asset('assets/angenommene_auftraege.png', width: 30, height: 30), image: Image.asset('assets/angenommene_auftraege.png', width: 30, height: 30),
() => { () async => {
MessageService() await MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: const AcceptedJobsPage())
.publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: const AcceptedJobsPage())
})); }));
}, },
), ),
@@ -189,7 +188,7 @@ class _MainPageState extends State<MainPage> {
child: getDefaultButton( child: getDefaultButton(
'Erledigte Aufträge', 'Erledigte Aufträge',
image: Image.asset('assets/erledigte_auftraege.png', width: 30, height: 30), image: Image.asset('assets/erledigte_auftraege.png', width: 30, height: 30),
() => {MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: const FinishedJobsPage())}), () async => {await MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: const FinishedJobsPage())}),
), ),
SizedBox(height: _loggedOut == true ? 0 : 20), SizedBox(height: _loggedOut == true ? 0 : 20),
Visibility( Visibility(
@@ -217,8 +216,8 @@ class _MainPageState extends State<MainPage> {
child: getDefaultButton( child: getDefaultButton(
'Nachrichten', 'Nachrichten',
image: Image.asset('assets/nachrichten.png', width: 30, height: 30), image: Image.asset('assets/nachrichten.png', width: 30, height: 30),
() => () async =>
{MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: const MessagesPage())})); {await MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: const MessagesPage())}));
}, },
), ),
), ),
@@ -228,7 +227,7 @@ class _MainPageState extends State<MainPage> {
child: getDefaultButton( child: getDefaultButton(
'Anfahrtsbereich', 'Anfahrtsbereich',
image: Image.asset('assets/anfahrtsbereich.png', width: 30, height: 30), image: Image.asset('assets/anfahrtsbereich.png', width: 30, height: 30),
() => {MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: const ApproachAreaPage())}), () async => {await MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: const ApproachAreaPage())}),
), ),
SizedBox(height: _loggedOut == true ? 0 : 20), SizedBox(height: _loggedOut == true ? 0 : 20),
getDefaultButton( getDefaultButton(
@@ -315,11 +314,11 @@ class _MainPageState extends State<MainPage> {
} }
} }
_logout(context) { _logout(context) async {
if (!_loggedOut) { if (!_loggedOut) {
showLogoutAlertDialog(context); showLogoutAlertDialog(context);
} else { } else {
MessageService().publish<ConnectClientMessage>(Constants.messageTopicConnectClient, arguments: ConnectClientMessage()); await MessageService().publish<ConnectClientMessage>(Constants.messageTopicConnectClient, arguments: ConnectClientMessage());
_loggedOut = false; _loggedOut = false;
@@ -372,7 +371,7 @@ class _MainPageState extends State<MainPage> {
); );
} }
_sendLogoutMessage() { _sendLogoutMessage() async {
var position = MyApp.currentPosition; var position = MyApp.currentPosition;
var logoutMessage = LogoutMessage(); var logoutMessage = LogoutMessage();
@@ -384,6 +383,6 @@ class _MainPageState extends State<MainPage> {
logoutMessage.pos!.acc = position.accuracy.toInt(); logoutMessage.pos!.acc = position.accuracy.toInt();
} }
MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "logout", message: logoutMessage.toJson(), qos: MqttQos.exactlyOnce)); await MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "logout", message: logoutMessage.toJson(), qos: MqttQos.exactlyOnce));
} }
} }
+1 -1
View File
@@ -110,7 +110,7 @@ class _MessagesPageState extends State<MessagesPage> {
await MyApp.isarInstance.messages.put(message); await MyApp.isarInstance.messages.put(message);
}); });
MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "message", message: message.toJson(), qos: MqttQos.exactlyOnce)); await MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "message", message: message.toJson(), qos: MqttQos.exactlyOnce));
_messages.insert(0, types.TextMessage( _messages.insert(0, types.TextMessage(
author: _user, author: _user,
+6 -6
View File
@@ -415,7 +415,7 @@ class _TaskListPageState extends State<TaskListPage> {
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]); SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]);
Future.delayed(const Duration(seconds: 1), () async { Future.delayed(const Duration(seconds: 1), () async {
showSignaturePopup(context, taskInfo, (String? signature) { showSignaturePopup(context, taskInfo, (String? signature) async {
MyApp.suppressAcceptDialog = false; MyApp.suppressAcceptDialog = false;
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
@@ -432,7 +432,7 @@ class _TaskListPageState extends State<TaskListPage> {
_finishTaskProcessing(taskInfo); _finishTaskProcessing(taskInfo);
MessageService().publish<PopContentViewMessage>(Constants.messageTopicPopContentView, arguments: PopContentViewMessage(count: 2)); await MessageService().publish<PopContentViewMessage>(Constants.messageTopicPopContentView, arguments: PopContentViewMessage(count: 2));
} }
}); });
}); });
@@ -467,7 +467,7 @@ class _TaskListPageState extends State<TaskListPage> {
return false; return false;
} }
_sendArrivedMessage(TaskInfo taskInfo) { _sendArrivedMessage(TaskInfo taskInfo) async {
var message = FinTask(); var message = FinTask();
message.trId = widget.tour.id; message.trId = widget.tour.id;
message.task = Task(); message.task = Task();
@@ -483,7 +483,7 @@ class _TaskListPageState extends State<TaskListPage> {
message.task.pos = null; message.task.pos = null;
} }
MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "fin_task", message: message.toJson(), qos: MqttQos.exactlyOnce)); await MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "fin_task", message: message.toJson(), qos: MqttQos.exactlyOnce));
} }
FinTourTask _createAnswerHeader(TaskInfo taskInfo) { FinTourTask _createAnswerHeader(TaskInfo taskInfo) {
@@ -527,7 +527,7 @@ class _TaskListPageState extends State<TaskListPage> {
} }
} }
MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "fin_tour", message: finTourMessage.toJson(), qos: MqttQos.exactlyOnce)); await MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "fin_tour", message: finTourMessage.toJson(), qos: MqttQos.exactlyOnce));
widget.tour.state = Constants.stateFinishedNotConfirmed; widget.tour.state = Constants.stateFinishedNotConfirmed;
@@ -552,7 +552,7 @@ class _TaskListPageState extends State<TaskListPage> {
message.time = DateTime.now().millisecondsSinceEpoch; message.time = DateTime.now().millisecondsSinceEpoch;
message.data = picture.data; message.data = picture.data;
MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "pic", message: message.toJson(), qos: MqttQos.exactlyOnce)); await MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "pic", message: message.toJson(), qos: MqttQos.exactlyOnce));
await MyApp.isarInstance.writeTxn(() async { await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.pictures.delete(picture.id); await MyApp.isarInstance.pictures.delete(picture.id);
+2 -2
View File
@@ -142,9 +142,9 @@ class _TourDetailsPageState extends State<TourDetailsPage> {
), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
getDefaultButton('Weiter', () => getDefaultButton('Weiter', () async =>
{ {
MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: TaskListPage(job: widget.job, tour: widget.tour, readOnly: widget.readOnly)) await MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: TaskListPage(job: widget.job, tour: widget.tour, readOnly: widget.readOnly))
}), }),
], ],
), ),
+2 -2
View File
@@ -208,7 +208,7 @@ class _TourListPageState extends State<TourListPage> {
return readOnly; return readOnly;
} }
void _clicked(JobTour tour, bool readOnly) { Future<void> _clicked(JobTour tour, bool readOnly) async {
MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: TourDetailsPage(job: widget.job, tour: tour, readOnly: readOnly)); await MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: TourDetailsPage(job: widget.job, tour: tour, readOnly: readOnly));
} }
} }
+29 -16
View File
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart'; import 'package:geolocator/geolocator.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:shared_map/shared_map.dart';
import 'package:stadtbote/messages/pop_content_view_message.dart'; import 'package:stadtbote/messages/pop_content_view_message.dart';
import 'package:stadtbote/model/enqueued_message.dart'; import 'package:stadtbote/model/enqueued_message.dart';
import 'package:stadtbote/model/log_entry.dart'; import 'package:stadtbote/model/log_entry.dart';
@@ -17,6 +18,7 @@ import 'package:stadtbote/tools/colored_safe_area.dart';
import 'package:stadtbote/model/session_status.dart'; import 'package:stadtbote/model/session_status.dart';
import 'package:stadtbote/tools/connection_status.dart'; import 'package:stadtbote/tools/connection_status.dart';
import 'package:stadtbote/tools/message_service.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'; import 'package:stadtbote/tools/messages/job_received_message.dart';
import 'package:stadtbote/tools/messages/refresh_badges_message.dart'; import 'package:stadtbote/tools/messages/refresh_badges_message.dart';
import 'package:stadtbote/tools/mqtt_core.dart'; import 'package:stadtbote/tools/mqtt_core.dart';
@@ -29,6 +31,7 @@ import 'tools/constants.dart';
import 'tools/util.dart'; import 'tools/util.dart';
Future<void> main() async { Future<void> main() async {
runZonedGuarded(() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
final dir = await getApplicationDocumentsDirectory(); final dir = await getApplicationDocumentsDirectory();
@@ -46,11 +49,10 @@ Future<void> main() async {
await _clearLog(); await _clearLog();
runZonedGuarded(() {}, (error, stackTrace) { runApp(MyApp());
}, (error, stackTrace) {
_traceUncaughtExceptions(error, stackTrace); _traceUncaughtExceptions(error, stackTrace);
}); });
runApp(MyApp());
} }
Future<void> _clearLog() async { Future<void> _clearLog() async {
@@ -177,8 +179,12 @@ class _MainState extends State<Main> with SingleTickerProviderStateMixin {
late AnimationController _animationController; late AnimationController _animationController;
late Animation<double> _animation; late Animation<double> _animation;
Timer? _checkForNewState0JobsJobsTimer;
bool _dialogOpened = false; bool _dialogOpened = false;
late SharedMap<int, Job>? _jobMap;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -188,8 +194,13 @@ class _MainState extends State<Main> with SingleTickerProviderStateMixin {
_animation = Tween<double>(begin: 0.5, end: 1.0).animate(_animationController); _animation = Tween<double>(begin: 0.5, end: 1.0).animate(_animationController);
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
var store1 = SharedStore('jobs');
_jobMap = await store1.getSharedMap<int, Job>('m1');
_initMessages(); _initMessages();
_startCheckForNewState0JobsJobsTimer();
_currentContent = MainPage(); _currentContent = MainPage();
var headerInfo = await _currentContent.getHeaderInfo(context); var headerInfo = await _currentContent.getHeaderInfo(context);
@@ -366,8 +377,15 @@ class _MainState extends State<Main> with SingleTickerProviderStateMixin {
MessageService().subscribe<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, this, (ConnectionStatus connectionStatus) { MessageService().subscribe<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, this, (ConnectionStatus connectionStatus) {
_connectionStatusChanged(connectionStatus); _connectionStatusChanged(connectionStatus);
}); });
MessageService().subscribe<JobReceivedMessage>(Constants.messageTopicJobReceived, this, (JobReceivedMessage jobReceivedMessage) {
_jobReceived(jobReceivedMessage.job); MessageService().subscribe<JobReceivedMessage>(Constants.messageTopicJobReceived, this, (JobReceivedMessage jobReceivedMessage) async {
if (jobReceivedMessage.job.state == 0) {
await _jobMap!.put(jobReceivedMessage.job.id, jobReceivedMessage.job);
}
});
MessageService().subscribe<JobDeletedMessage>(Constants.messageTopicJobDeleted, this, (JobDeletedMessage jobDeletedMessage) async {
await _jobMap!.remove(jobDeletedMessage.id);
}); });
} }
@@ -457,19 +475,14 @@ class _MainState extends State<Main> with SingleTickerProviderStateMixin {
_connectionLostValueNotifier.value = newConnectionStatus.status == ConnectionStatusEnum.notConnected; _connectionLostValueNotifier.value = newConnectionStatus.status == ConnectionStatusEnum.notConnected;
} }
void _jobReceived(Job job) async { void _startCheckForNewState0JobsJobsTimer() {
if (!MyApp.suppressAcceptDialog) { _checkForNewState0JobsJobsTimer ??= Timer.periodic(const Duration(seconds: 5), (Timer t) async {
if (job.state == 0) { if (await _jobMap!.length() > 0 && !_dialogOpened) {
if (!_dialogOpened) {
_dialogOpened = true; _dialogOpened = true;
await showAcceptJobsPopup(context, _jobMap!.sharedReference(), () async {
await showAcceptJobsPopup(context, await MyApp.isarInstance.jobs.filter().stateEqualTo(0).findAll(), () {
_dialogOpened = false; _dialogOpened = false;
});
MessageService().publish(Constants.messageTopicUpdateBadges, arguments: RefreshBadgesMessage()); }
}); });
} }
} }
}
}
}
-6
View File
@@ -31,12 +31,6 @@ class Job {
@JsonKey(name: 'tours') @JsonKey(name: 'tours')
late List<JobTour> tours; late List<JobTour> tours;
@Ignore()
late DateTime? firstDisplayTime = null;
@Ignore()
late int enableDelay;
Job(); Job();
factory Job.fromJson(Map<String, dynamic> json) => _$JobFromJson(json); factory Job.fromJson(Map<String, dynamic> json) => _$JobFromJson(json);
+1 -5
View File
@@ -1558,10 +1558,7 @@ Job _$JobFromJson(Map<String, dynamic> json) => Job()
..delayOrderTime = json['delayOrderTime'] as int ..delayOrderTime = json['delayOrderTime'] as int
..tours = (json['tours'] as List<dynamic>) ..tours = (json['tours'] as List<dynamic>)
.map((e) => JobTour.fromJson(e as Map<String, dynamic>)) .map((e) => JobTour.fromJson(e as Map<String, dynamic>))
.toList() .toList();
..firstDisplayTime = json['firstDisplayTime'] == null
? null
: DateTime.parse(json['firstDisplayTime'] as String);
Map<String, dynamic> _$JobToJson(Job instance) => <String, dynamic>{ Map<String, dynamic> _$JobToJson(Job instance) => <String, dynamic>{
'id': instance.id, 'id': instance.id,
@@ -1575,5 +1572,4 @@ Map<String, dynamic> _$JobToJson(Job instance) => <String, dynamic>{
'rem': instance.rem, 'rem': instance.rem,
'delayOrderTime': instance.delayOrderTime, 'delayOrderTime': instance.delayOrderTime,
'tours': instance.tours, 'tours': instance.tours,
'firstDisplayTime': instance.firstDisplayTime?.toIso8601String(),
}; };
+49 -52
View File
@@ -1,31 +1,34 @@
import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'package:expandable/expandable.dart'; import 'package:expandable/expandable.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_client.dart';
import 'package:shared_map/shared_map.dart';
import 'package:stadtbote/main.dart'; import 'package:stadtbote/main.dart';
import 'package:stadtbote/protocoll_messages/accept_job_message.dart'; import 'package:stadtbote/protocoll_messages/accept_job_message.dart';
import 'package:stadtbote/model/job.dart'; import 'package:stadtbote/model/job.dart';
import 'package:stadtbote/protocoll_messages/fin_task_message.dart'; import 'package:stadtbote/protocoll_messages/fin_task_message.dart';
import 'package:stadtbote/tools/constants.dart'; import 'package:stadtbote/tools/constants.dart';
import 'package:stadtbote/tools/message_service.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';
import 'package:stadtbote/tools/messages/refresh_badges_message.dart'; import 'package:stadtbote/tools/messages/refresh_badges_message.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
import 'package:badges/badges.dart' as badges; import 'package:badges/badges.dart' as badges;
import '../tools/messages/publish_payload_message.dart'; import '../tools/messages/publish_payload_message.dart';
Future<void> showAcceptJobsPopup(BuildContext context, List<Job> jobs, Function() onFinished) async { Timer? _checkForNewJobsTimer;
Map<int, DateTime> _firstDelayTimeMap = {};
Future<void> showAcceptJobsPopup(BuildContext context, SharedMapReference mapReference, Function() onFinished) async {
await showDialog<void>( await showDialog<void>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
MessageService().unsubscribe(Constants.messageTopicJobDeleted, jobs); _stopTimer();
MessageService().unsubscribe(Constants.messageTopicJobReceived, jobs);
Navigator.of(context).pop(); Navigator.of(context).pop();
@@ -38,34 +41,7 @@ Future<void> showAcceptJobsPopup(BuildContext context, List<Job> jobs, Function(
shadowColor: Colors.transparent, shadowColor: Colors.transparent,
backgroundColor: Colors.white, backgroundColor: Colors.white,
content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
if (jobs.isEmpty) { _startTimer(mapReference, setState);
Navigator.of(context).pop();
onFinished();
}
MessageService().unsubscribe(Constants.messageTopicJobDeleted, jobs);
MessageService().unsubscribe(Constants.messageTopicJobReceived, jobs);
MessageService().subscribe<JobDeletedMessage>(Constants.messageTopicJobDeleted, jobs, (jobDeletedMessage) async {
jobs.removeWhere((value) => value.id == jobDeletedMessage.id);
if (context.mounted) {
setState(() {});
}
});
MessageService().subscribe<JobReceivedMessage>(Constants.messageTopicJobReceived, jobs, (jobMessage) async {
jobs.removeWhere((value) => value.id == jobMessage.job.id);
if (jobMessage.job.state == 0) {
jobs.add(jobMessage.job);
if (context.mounted) {
setState(() {});
}
}
});
return SizedBox( return SizedBox(
key: GlobalKey(), key: GlobalKey(),
@@ -75,7 +51,7 @@ Future<void> showAcceptJobsPopup(BuildContext context, List<Job> jobs, Function(
height: 100, height: 100,
padding: const EdgeInsets.all(5), padding: const EdgeInsets.all(5),
child: FutureBuilder<List<Widget>>( child: FutureBuilder<List<Widget>>(
future: fetchJobWidgets(jobs), future: _fetchJobWidgets(mapReference),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return Util.getWaitWidget(context); return Util.getWaitWidget(context);
@@ -91,19 +67,41 @@ Future<void> showAcceptJobsPopup(BuildContext context, List<Job> jobs, Function(
}); });
} }
Future<List<Widget>> fetchJobWidgets(List<Job> jobs) async { void _startTimer(SharedMapReference mapReference, StateSetter setState) {
_checkForNewJobsTimer ??= Timer.periodic(const Duration(seconds: 5), (Timer t) async {
var jobMap = SharedMap<int, Job>.fromSharedReference(mapReference);
if (await jobMap.length() > 0) {
setState(() { });
}
});
}
void _stopTimer() {
if (_checkForNewJobsTimer != null) {
_checkForNewJobsTimer!.cancel();
_checkForNewJobsTimer = null;
}
}
Future<List<Widget>> _fetchJobWidgets(SharedMapReference mapReference) async {
List<Widget> widgets = []; List<Widget> widgets = [];
for (var job in jobs) { var jobMap = SharedMap<int, Job>.fromSharedReference(mapReference);
int enableDelay = 3; //job.delayOrderTime;
if (job.firstDisplayTime == null) {
await MyApp.isarInstance.writeTxn(() async {
job.firstDisplayTime = DateTime.now();
await MyApp.isarInstance.jobs.put(job); var entries = await jobMap.entries();
}); for (var jobEntry in entries) {
var job = jobEntry.value;
int enableDelay = 3; //job.delayOrderTime;
if (!_firstDelayTimeMap.containsKey(job.id)) {
_firstDelayTimeMap[job.id] = DateTime.now();
} else { } else {
enableDelay = max(0, DateTime.now().difference(job.firstDisplayTime!).inSeconds); DateTime firstDisplayTime = _firstDelayTimeMap[job.id]!;
int diffInSeconds = DateTime.now().difference(firstDisplayTime).inSeconds;
enableDelay = min(0, diffInSeconds);
} }
widgets.add(StatefulBuilder(builder: (BuildContext context, StateSetter setState) { widgets.add(StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
@@ -200,21 +198,21 @@ Future<List<Widget>> fetchJobWidgets(List<Job> jobs) async {
Row(children: [ Row(children: [
Expanded( Expanded(
child: getDefaultButton(!job.global ? 'Ablehnen' : 'Ignorieren', () { child: getDefaultButton(!job.global ? 'Ablehnen' : 'Ignorieren', () {
setState(() {
_sendAnswer(job, !job.global ? 2 : 3); _sendAnswer(job, !job.global ? 2 : 3);
jobs.removeWhere((value) => value.id == job.id); //jobs.removeWhere((value) => value.id == job.id);
});
setState(() {});
}), }),
), ),
const SizedBox(width: 20), const SizedBox(width: 20),
Expanded( Expanded(
child: getDefaultButton('Annehmen', enabledTimerActive: enableDelay > 0, enabledTimerDelay: enableDelay, () { child: getDefaultButton('Annehmen', enabledTimerActive: enableDelay > 0, enabledTimerDelay: enableDelay, () {
setState(() {
_sendAnswer(job, 1); _sendAnswer(job, 1);
jobs.removeWhere((value) => value.id == job.id); //jobs.removeWhere((value) => value.id == job.id);
});
setState(() {});
}), }),
) )
]) ])
@@ -245,12 +243,11 @@ _sendAnswer(Job job, int item) async {
message.track.pos!.long = currentPosition != null ? currentPosition.longitude : 0.0; message.track.pos!.long = currentPosition != null ? currentPosition.longitude : 0.0;
message.track.pos!.acc = currentPosition != null ? currentPosition.accuracy.toInt() : 0; message.track.pos!.acc = currentPosition != null ? currentPosition.accuracy.toInt() : 0;
MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, await MessageService().publish<PublishPayloadMessage>(Constants.messageTopicPublishPayload, arguments: PublishPayloadMessage(topic: "reaction", message: message.toJson(), qos: MqttQos.exactlyOnce));
arguments: PublishPayloadMessage(topic: "reaction", message: message.toJson(), qos: MqttQos.exactlyOnce));
await MyApp.isarInstance.writeTxn(() async { await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.jobs.delete(job.id); await MyApp.isarInstance.jobs.delete(job.id);
}); });
MessageService().publish(Constants.messageTopicUpdateBadges, arguments: RefreshBadgesMessage()); await MessageService().publish(Constants.messageTopicUpdateBadges, arguments: RefreshBadgesMessage());
} }
+1 -2
View File
@@ -14,8 +14,7 @@ void showInfosPopup(BuildContext context, SessionStatus? status) async {
late String connectedString = "Bitte warten..."; late String connectedString = "Bitte warten...";
Future.delayed(const Duration(seconds: 2), () async { Future.delayed(const Duration(seconds: 2), () async {
MessageService() await MessageService().publish<RequestConnectionStatusMessage>(Constants.messageTopicRequestConnectionStatus, arguments: RequestConnectionStatusMessage());
.publish<RequestConnectionStatusMessage>(Constants.messageTopicRequestConnectionStatus, arguments: RequestConnectionStatusMessage());
}); });
void unsubscribeMessages() { void unsubscribeMessages() {
@@ -42,6 +42,7 @@ showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String)
textInputType: TextInputType.text, textInputType: TextInputType.text,
formatter: [FilteringTextInputFormatter.singleLineFormatter], formatter: [FilteringTextInputFormatter.singleLineFormatter],
controller: textEditingController, controller: textEditingController,
maxLength: 50,
autofocus: true), autofocus: true),
const SizedBox(height: 20), const SizedBox(height: 20),
getDefaultButton('Übernehmen', () { getDefaultButton('Übernehmen', () {
+8 -1
View File
@@ -1,3 +1,5 @@
import 'dart:async';
typedef EventHandler<T> = void Function(T args); typedef EventHandler<T> = void Function(T args);
class _MapEntry { class _MapEntry {
@@ -59,13 +61,18 @@ class MessageService {
} }
} }
publish<T>(String topic, {T? arguments}) { publish<T>(String topic, {T? arguments}) async {
Completer<void> completer = Completer();
var entries = _callbackMaps[topic]; var entries = _callbackMaps[topic];
if (entries != null) { if (entries != null) {
for (var entry in entries) { for (var entry in entries) {
entry.handler(arguments); entry.handler(arguments);
} }
completer.complete();
} }
await completer.future;
} }
} }
+32 -25
View File
@@ -4,6 +4,7 @@ import 'dart:math';
import 'package:archive/archive.dart'; import 'package:archive/archive.dart';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_client.dart';
@@ -79,8 +80,8 @@ class MqttCore {
_processBootstrap(); _processBootstrap();
} }
_disconnectMqttClient() { _disconnectMqttClient() async {
MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected)); await MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected));
_disconnectInProgress = true; _disconnectInProgress = true;
@@ -93,7 +94,6 @@ class MqttCore {
} }
connectionState = ConnectionStateEnum.notConnected; connectionState = ConnectionStateEnum.notConnected;
} }
_connectToBroker() async { _connectToBroker() async {
@@ -128,19 +128,23 @@ class MqttCore {
} else { } else {
Util.logInfo('Verbindung zum MQTT-Broker fehlgeschlagen!'); Util.logInfo('Verbindung zum MQTT-Broker fehlgeschlagen!');
MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected)); await MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected));
} }
} catch (ex) { } catch (ex) {
Util.logInfo('Verbindung zum MQTT-Broker fehlgeschlagen!: $ex'); Util.logInfo('Verbindung zum MQTT-Broker fehlgeschlagen!: $ex');
MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected)); await MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected));
} }
} }
bool _publishText(String topic, String text, MqttQos qos, {bool enqueueOnError = true}) { bool _publishText(String topic, String text, MqttQos qos, {bool enqueueOnError = true}) {
try { try {
var buffer = Uint8Buffer(); var buffer = Uint8Buffer();
if (kDebugMode) {
buffer.addAll(const Utf8Encoder().convert(text));
} else {
buffer.addAll(GZipEncoder().encode(const Utf8Encoder().convert(text)) as Iterable<int>); buffer.addAll(GZipEncoder().encode(const Utf8Encoder().convert(text)) as Iterable<int>);
}
var messageTopic = "$_toServerTopic$_clientId/$topic"; var messageTopic = "$_toServerTopic$_clientId/$topic";
@@ -174,8 +178,12 @@ class MqttCore {
Util.logInfo('message received\ntopic: $topic\n'); Util.logInfo('message received\ntopic: $topic\n');
Util.logInfo("size in bytes: ${message.payload.message.length.toString()}"); Util.logInfo("size in bytes: ${message.payload.message.length.toString()}");
var messageBytes = message.payload.message; String payload;
String payload = utf8.decode(GZipDecoder().decodeBytes(messageBytes)); if (kDebugMode) {
payload = utf8.decode(message.payload.message);
} else {
payload = utf8.decode(GZipDecoder().decodeBytes(message.payload.message));
}
Util.logInfo('$topic\nmessage: $payload'); Util.logInfo('$topic\nmessage: $payload');
@@ -244,7 +252,7 @@ class MqttCore {
Util.logInfo('subscribed to topic: $fromServerTopic'); Util.logInfo('subscribed to topic: $fromServerTopic');
MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.connected)); await MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.connected));
} }
void _sessionMessageReceived(payloadData) async { void _sessionMessageReceived(payloadData) async {
@@ -261,8 +269,7 @@ class MqttCore {
await MyApp.isarInstance.sessionStatus.put(sessionStatusMessage); await MyApp.isarInstance.sessionStatus.put(sessionStatusMessage);
}); });
MessageService().publish<SessionStatusInfoUpdate>(Constants.messageTopicSessionStatusInfoUpdate, await MessageService().publish<SessionStatusInfoUpdate>(Constants.messageTopicSessionStatusInfoUpdate, arguments: SessionStatusInfoUpdate(status: sessionStatusMessage));
arguments: SessionStatusInfoUpdate(status: sessionStatusMessage));
_startTrackTimer(); _startTrackTimer();
} }
@@ -275,7 +282,7 @@ class MqttCore {
await MyApp.isarInstance.status.put(statusMessage); await MyApp.isarInstance.status.put(statusMessage);
}); });
MessageService().publish<StatusInfoUpdate>(Constants.messageTopicStatusInfoUpdated, arguments: StatusInfoUpdate(status: statusMessage)); await MessageService().publish<StatusInfoUpdate>(Constants.messageTopicStatusInfoUpdated, arguments: StatusInfoUpdate(status: statusMessage));
} }
void _locationStatusMessageReceived(payloadData) async { void _locationStatusMessageReceived(payloadData) async {
@@ -286,7 +293,7 @@ class MqttCore {
await MyApp.isarInstance.locationStatus.put(locationStatus); await MyApp.isarInstance.locationStatus.put(locationStatus);
}); });
MessageService().publish<LocationStatusUpdate>(Constants.messageTopicLocationStatusUpdated, arguments: LocationStatusUpdate(status: locationStatus)); await MessageService().publish<LocationStatusUpdate>(Constants.messageTopicLocationStatusUpdated, arguments: LocationStatusUpdate(status: locationStatus));
} }
void _rankingMessageReceived(payloadData) async { void _rankingMessageReceived(payloadData) async {
@@ -297,7 +304,7 @@ class MqttCore {
await MyApp.isarInstance.rankings.put(ranking); await MyApp.isarInstance.rankings.put(ranking);
}); });
MessageService().publish<RankingUpdated>(Constants.messageTopicRankingUpdated, arguments: RankingUpdated()); await MessageService().publish<RankingUpdated>(Constants.messageTopicRankingUpdated, arguments: RankingUpdated());
} }
void _jobMessageReceived(payloadData) async { void _jobMessageReceived(payloadData) async {
@@ -318,7 +325,7 @@ class MqttCore {
_acknowlegdeJob(newJob); _acknowlegdeJob(newJob);
try { try {
MessageService().publish<JobReceivedMessage>(Constants.messageTopicJobReceived, arguments: JobReceivedMessage(job: newJob)); await MessageService().publish<JobReceivedMessage>(Constants.messageTopicJobReceived, arguments: JobReceivedMessage(job: newJob));
} catch (ex) { } catch (ex) {
Util.logException("publish messageTopicJobReceived failed!"); Util.logException("publish messageTopicJobReceived failed!");
} }
@@ -333,7 +340,7 @@ class MqttCore {
await MyApp.isarInstance.jobs.delete(jobDelMessage.id); await MyApp.isarInstance.jobs.delete(jobDelMessage.id);
}); });
MessageService().publish<JobDeletedMessage>(Constants.messageTopicJobDeleted, arguments: JobDeletedMessage(id: jobDelMessage.id)); await MessageService().publish<JobDeletedMessage>(Constants.messageTopicJobDeleted, arguments: JobDeletedMessage(id: jobDelMessage.id));
} }
} }
@@ -352,7 +359,7 @@ class MqttCore {
await Util.playMp3('asbeep.mp3'); await Util.playMp3('asbeep.mp3');
MessageService().publish<MessageReceivedMessage>(Constants.messageTopicMessageReceived, arguments: MessageReceivedMessage(message: newMessage)); await MessageService().publish<MessageReceivedMessage>(Constants.messageTopicMessageReceived, arguments: MessageReceivedMessage(message: newMessage));
} }
void _messageUploadDeviceLogReceived(payloadData) async { void _messageUploadDeviceLogReceived(payloadData) async {
@@ -394,24 +401,24 @@ class MqttCore {
} }
} }
void _clientDisconnected() { Future<void> _clientDisconnected() async {
Util.logInfo("_clientDisconnected called"); Util.logInfo("_clientDisconnected called");
connectionState = ConnectionStateEnum.notConnected; connectionState = ConnectionStateEnum.notConnected;
_cancelTrackTimer(); _cancelTrackTimer();
MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected)); await MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected));
} }
void _clientConnected() { Future<void> _clientConnected() async {
Util.logInfo("_clientConnected called"); Util.logInfo("_clientConnected called");
connectionState = ConnectionStateEnum.connected; connectionState = ConnectionStateEnum.connected;
_initSession(); _initSession();
MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.connected)); await MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.connected));
} }
void _processBootstrap() async { void _processBootstrap() async {
@@ -446,8 +453,8 @@ class MqttCore {
var bootstrapResponsePayload = BootstrapResponse.fromJson(jsonDecode(responseText)); var bootstrapResponsePayload = BootstrapResponse.fromJson(jsonDecode(responseText));
var brokerUriAndPortArray = bootstrapResponsePayload.broker.replaceFirst("mqtt://", "").split(":"); var brokerUriAndPortArray = bootstrapResponsePayload.broker.replaceFirst("mqtt://", "").split(":");
_brokerUri = brokerUriAndPortArray[0]; _brokerUri = "192.168.180.27"; //brokerUriAndPortArray[0];
_brokerPort = int.parse(brokerUriAndPortArray[1]); _brokerPort = 1883; //int.parse(brokerUriAndPortArray[1]);
_clientId = bootstrapResponsePayload.id; _clientId = bootstrapResponsePayload.id;
_fromServerTopic = bootstrapResponsePayload.fromServer; _fromServerTopic = bootstrapResponsePayload.fromServer;
_toServerTopic = bootstrapResponsePayload.toServer; _toServerTopic = bootstrapResponsePayload.toServer;
@@ -464,6 +471,7 @@ class MqttCore {
var startSessionMessage = StartSessionMessage(); var startSessionMessage = StartSessionMessage();
var jsonMap = startSessionMessage.toJson(); var jsonMap = startSessionMessage.toJson();
var json = jsonEncode(jsonMap); var json = jsonEncode(jsonMap);
_publishText("session", json, MqttQos.exactlyOnce); _publishText("session", json, MqttQos.exactlyOnce);
} }
@@ -559,7 +567,7 @@ class MqttCore {
}); });
MessageService().subscribe<RequestConnectionStatusMessage>(Constants.messageTopicRequestConnectionStatus, this, MessageService().subscribe<RequestConnectionStatusMessage>(Constants.messageTopicRequestConnectionStatus, this,
(RequestConnectionStatusMessage requestConnectionStatusMessage) { (RequestConnectionStatusMessage requestConnectionStatusMessage) async {
bool connected = false; bool connected = false;
if (_mqttClient != null && _mqttClient!.connectionStatus != null) { if (_mqttClient != null && _mqttClient!.connectionStatus != null) {
if (_mqttClient!.connectionStatus!.state == MqttConnectionState.connected) { if (_mqttClient!.connectionStatus!.state == MqttConnectionState.connected) {
@@ -567,8 +575,7 @@ class MqttCore {
} }
} }
MessageService().publish<CurrentConnectionStatusMessage>(Constants.messageTopicCurrentConnectionStatus, await MessageService().publish<CurrentConnectionStatusMessage>(Constants.messageTopicCurrentConnectionStatus, arguments: CurrentConnectionStatusMessage(state: connected));
arguments: CurrentConnectionStatusMessage(state: connected));
}); });
} }
} }
+2
View File
@@ -152,6 +152,7 @@ class Util {
FocusNode? focusNode, FocusNode? focusNode,
IconButton? iconButton, IconButton? iconButton,
int? maxLines = 1, int? maxLines = 1,
int? maxLength = 100,
TextInputType? textInputType, TextInputType? textInputType,
List<TextInputFormatter>? formatter, List<TextInputFormatter>? formatter,
Function()? onTap, Function()? onTap,
@@ -172,6 +173,7 @@ class Util {
onTap: onTap, onTap: onTap,
keyboardType: textInputType, keyboardType: textInputType,
inputFormatters: formatter, inputFormatters: formatter,
maxLength: maxLength,
autofocus: (autofocus != null) ? autofocus : false, autofocus: (autofocus != null) ? autofocus : false,
decoration: InputDecoration( decoration: InputDecoration(
hintText: hint, hintText: hint,
+8
View File
@@ -1216,6 +1216,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.1" version: "3.0.1"
shared_map:
dependency: "direct main"
description:
name: shared_map
sha256: "42608f6958d490174e172e75e6c655dc6b6cd3ce005801daa3ef5a2597470968"
url: "https://pub.dev"
source: hosted
version: "1.1.9"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
+1
View File
@@ -72,6 +72,7 @@ dependencies:
device_info_plus: ^9.1.2 device_info_plus: ^9.1.2
is_lock_screen: ^2.0.0 is_lock_screen: ^2.0.0
flutter_local_notifications: ^17.1.2 flutter_local_notifications: ^17.1.2
shared_map: ^1.1.9
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: