Merge branch 'main' into new_appserver

# Conflicts:
#	lib/content_views/approach_area_page.dart
#	lib/content_views/assigned_jobs_page.dart
#	lib/content_views/main_page.dart
#	lib/content_views/task_list_page.dart
#	lib/main.dart
#	lib/popups/accept_jobs_popup.dart
#	lib/protocoll_messages/logout_message.dart
#	lib/protocoll_messages/logout_message.g.dart
#	lib/tools/constants.dart
#	lib/tools/mqtt_core.dart
#	pubspec.lock
#	pubspec.yaml
This commit is contained in:
Sven committed 2024-03-26 12:56:04 +01:00
commit 880cdd65ff
74 files changed
+2463 -441

No files matched your search

-3
View File
@@ -49,10 +49,7 @@ android {
} }
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "de.assecutor.stadtbote" applicationId "de.assecutor.stadtbote"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
+2 -2
View File
@@ -1,9 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.assecutor.stadtbote"> package="de.assecutor.stadtbote">
<application <application
android:label="stadtbote" android:label="Stadtbote"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/launcher_icon">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

+8 -2
View File
@@ -45,6 +45,12 @@ class _AcceptedJobsPageState extends State<AcceptedJobsPage> {
void initState() { void initState() {
Future.delayed(const Duration(seconds: 0), () async { Future.delayed(const Duration(seconds: 0), () async {
_jobs = await MyApp.isarInstance.jobs.filter().stateEqualTo(Constants.stateAccepted).findAll(); _jobs = await MyApp.isarInstance.jobs.filter().stateEqualTo(Constants.stateAccepted).findAll();
_jobs.sort((job1, job2) {
var date1 = DateTime.parse(job1.ordertime).millisecondsSinceEpoch;
var date2 = DateTime.parse(job2.ordertime).millisecondsSinceEpoch;
return date1 - date2;
});
_initCompleted = true; _initCompleted = true;
@@ -88,8 +94,8 @@ class _AcceptedJobsPageState extends State<AcceptedJobsPage> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Text( Text(
DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime)).toString(), DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime).toLocal()).toString(),
style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.yellow : Colors.white), style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.yellow : Colors.transparent),
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
Text( Text(
+43 -54
View File
@@ -1,12 +1,13 @@
import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stadtbote/content_views/utils/content_view_widget.dart'; import 'package:stadtbote/content_views/utils/content_view_widget.dart';
import 'package:stadtbote/content_views/utils/header_info.dart'; import 'package:stadtbote/content_views/utils/header_info.dart';
import 'package:stadtbote/model/rank.dart'; import 'package:stadtbote/model/ranking.dart';
import 'package:stadtbote/popups/tasks_popups/zip_popup.dart'; import 'package:stadtbote/popups/tasks_popups/zip_popup.dart';
import 'package:stadtbote/protocoll_messages/zip_message.dart'; import 'package:stadtbote/protocoll_messages/zip_message.dart';
import 'package:stadtbote/tools/constants.dart';
import 'package:stadtbote/tools/message_service.dart';
import 'package:stadtbote/tools/messages/ranking_updated.dart';
import 'package:stadtbote/tools/mqtt_core.dart'; import 'package:stadtbote/tools/mqtt_core.dart';
import '../main.dart'; import '../main.dart';
@@ -43,21 +44,30 @@ class ApproachAreaPage extends ContentViewWidget {
} }
class _ApproachAreaPageState extends State<ApproachAreaPage> { class _ApproachAreaPageState extends State<ApproachAreaPage> {
late List<Rank>? _rankings; late Ranking? _ranking;
late bool _initCompleted = false; late bool _initCompleted = false;
@override @override
void initState() { void initState() {
super.initState();
Future.delayed(const Duration(seconds: 0), () async { Future.delayed(const Duration(seconds: 0), () async {
_rankings = await MyApp.isarInstance.ranks.where().findAll(); _ranking = await MyApp.isarInstance.rankings.where().findFirst();
_initCompleted = true; _initCompleted = true;
setState(() {}); setState(() {});
}); });
super.initState(); _initMessages();
}
@override
void deactivate() {
super.deactivate();
MessageService().unsubscribe(Constants.messageTopicRankingUpdated, this);
} }
@override @override
@@ -84,18 +94,16 @@ class _ApproachAreaPageState extends State<ApproachAreaPage> {
List<Widget> _fillColumns() { List<Widget> _fillColumns() {
List<Widget> columns = []; List<Widget> columns = [];
if (_rankings != null) { if (_ranking != null) {
for (int i = 0; i < _rankings!.length; i++) { for (int i = 0; i < _ranking!.ranks.length; i++) {
var rank = _rankings![i]; var rank = _ranking!.ranks[i];
List<Widget> entries = []; List<Widget> entries = [];
entries.add( entries.add(
GestureDetector( GestureDetector(
onTap: ()=> { onTap: () => {
if (i == 0) { if (i == 0) {
showZipPopup(context, 'ACHTUNG: Wenn Sie Ihre PLZ ändern, verlieren Sie Ihr Ranking!\n', 'Freimelden', (zip) => {_sendZip(rank, zip, ModeEnum.set)}), showZipPopup(context, 'ACHTUNG: Wenn Sie Ihre PLZ ändern, verlieren Sie Ihr Ranking!\n', 'Freimelden', (zip) => {_sendZip(rank, zip, ModeEnum.set)}),
} else {
showZipPopup(context, 'ACHTUNG: Wenn Sie Ihre PLZ ändern, verlieren Sie Ihr Ranking!\n', 'OK', (zip) => {_sendZip(rank, zip, ModeEnum.request)}),
} }
}, },
child: Container( child: Container(
@@ -103,7 +111,7 @@ class _ApproachAreaPageState extends State<ApproachAreaPage> {
margin: const EdgeInsets.all(2), margin: const EdgeInsets.all(2),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
color: i == 0 ? Colors.lightGreen : Colors.white, color: i == 0 ? Constants.colorPrimary : Colors.white,
border: Border.all( border: Border.all(
color: Colors.grey, color: Colors.grey,
width: 0.5, width: 0.5,
@@ -114,10 +122,11 @@ class _ApproachAreaPageState extends State<ApproachAreaPage> {
child: Column(children: [ child: Column(children: [
Text( Text(
rank.zip, rank.zip,
style: const TextStyle(fontSize: 20), style: TextStyle(fontSize: 20, color: (i == 0 ? Colors.white : Colors.black)),
), ),
Text( Text(
rank.area, rank.area,
style: TextStyle(fontSize: 13, color: (i == 0 ? Colors.white : Colors.black)),
) )
] ]
) )
@@ -168,56 +177,36 @@ class _ApproachAreaPageState extends State<ApproachAreaPage> {
} }
_sendZip(Rank rank, String zip, ModeEnum mode) { _sendZip(Rank rank, String zip, ModeEnum mode) {
var message = ZipMessage(); var zipMessage = ZipMessage();
if (mode == ModeEnum.set) { if (mode == ModeEnum.set) {
var position = MyApp.currentPosition; var position = MyApp.currentPosition;
message.setPos = ZipSetPos(); zipMessage.setPos = ZipSetPos();
message.setPos!.zip = zip; zipMessage.setPos!.zip = zip;
if (position != null) { if (position != null) {
message.setPos!.track = ZipTrack(); zipMessage.setPos!.track = ZipTrack();
message.setPos!.track.time = DateTime.now().toIso8601String(); zipMessage.setPos!.track!.time = DateTime.now().toIso8601String();
message.setPos!.track.pos = ZipTrackPos(); zipMessage.setPos!.track!.pos = ZipTrackPos();
message.setPos!.track.pos!.lat = position.latitude; zipMessage.setPos!.track!.pos!.lat = position.latitude;
message.setPos!.track.pos!.long = position.longitude; zipMessage.setPos!.track!.pos!.long = position.longitude;
message.setPos!.track.pos!.acc = position.accuracy.toInt(); zipMessage.setPos!.track!.pos!.acc = position.accuracy.toInt();
} }
} else { } else {
message.reqZip = ZipReqZip(); zipMessage.reqZip = ZipReqZip();
message.reqZip!.id = rank.id; zipMessage.reqZip!.id = rank.id;
message.reqZip!.zip = zip; zipMessage.reqZip!.zip = zip;
} }
MqttCore.instance.publishText("set_location", jsonEncode(message.toJson())); MqttCore.instance.publishPayloadMessage("rank", zipMessage.toJson());
} }
}
/* _initMessages() {
private void SendMessage(int columnNumber, string zipNumber) MessageService().subscribe<RankingUpdated>(Constants.messageTopicRankingUpdated, this, (rankingUpdateMessage) async {
{ _ranking = await MyApp.isarInstance.rankings.where().findFirst();
var payloadObject = new JObject();
if (columnNumber == 0) setState(() {});
{ });
var setPosObject = new JObject(); }
payloadObject.Add(new JProperty("set_pos", setPosObject)); }
setPosObject.Add(new JProperty("zip", zipNumber));
setPosObject.Add(new JProperty("track", CreateTrackObject()));
}
else
{
var regZipObject = new JObject();
payloadObject.Add(new JProperty("reg_zip", regZipObject));
regZipObject.Add(new JProperty("id", columnNumber));
regZipObject.Add(new JProperty("zip", zipNumber));
}
var json = payloadObject.ToString();
App.Core.SendJsonMessageAsync("rank", payloadObject);
}
*/
+11 -5
View File
@@ -1,5 +1,3 @@
import 'dart:convert';
import 'package:expandable/expandable.dart'; import 'package:expandable/expandable.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
@@ -10,7 +8,7 @@ import 'package:badges/badges.dart' as badges;
import 'package:stadtbote/protocoll_messages/accept_job_message.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_task_message.dart';
import 'package:stadtbote/tools/message_service.dart'; import 'package:stadtbote/tools/message_service.dart';
import 'package:stadtbote/tools/messages/refresh_badges_message.dart'; import 'package:stadtbote/tools/messages/job_deleted_message.dart';
import 'package:stadtbote/tools/mqtt_core.dart'; import 'package:stadtbote/tools/mqtt_core.dart';
import '../main.dart'; import '../main.dart';
@@ -53,6 +51,8 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> {
Future.delayed(const Duration(seconds: 0), () async { Future.delayed(const Duration(seconds: 0), () async {
_entries = await _createListEntries(); _entries = await _createListEntries();
_initMessages();
_initCompleted = true; _initCompleted = true;
setState(() {}); setState(() {});
@@ -86,6 +86,12 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> {
var jobs = await MyApp.isarInstance.jobs.filter().stateEqualTo(Constants.stateAssigned).findAll(); var jobs = await MyApp.isarInstance.jobs.filter().stateEqualTo(Constants.stateAssigned).findAll();
for (var job in jobs) { for (var job in jobs) {
String remarkString = '';
for (var remark in job.rem) {
remarkString += '$remark\n';
}
remarkString = remarkString.trim();
entries.add(ExpandableNotifier( entries.add(ExpandableNotifier(
child: ListTile( child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
@@ -119,7 +125,7 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> {
child: Column( child: Column(
children: [ children: [
Text( Text(
DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime)).toString(), DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime).toLocal()).toString(),
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.yellow : Colors.white), style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.yellow : Colors.white),
), ),
@@ -144,7 +150,7 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> {
)), )),
collapsed: const SizedBox(), collapsed: const SizedBox(),
expanded: Column( expanded: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
Container( Container(
height: 200, height: 200,
+1 -1
View File
@@ -88,7 +88,7 @@ class _FinishedJobsPageState extends State<FinishedJobsPage> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Text( Text(
DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime)).toString(), DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime).toLocal()).toString(),
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
Text( Text(
+60 -13
View File
@@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stadtbote/content_views/accepted_jobs_page.dart'; import 'package:stadtbote/content_views/accepted_jobs_page.dart';
@@ -10,19 +11,21 @@ import 'package:stadtbote/content_views/messages_page.dart';
import 'package:stadtbote/content_views/utils/content_view_widget.dart'; import 'package:stadtbote/content_views/utils/content_view_widget.dart';
import 'package:stadtbote/content_views/utils/header_info.dart'; import 'package:stadtbote/content_views/utils/header_info.dart';
import 'package:stadtbote/model/job.dart'; import 'package:stadtbote/model/job.dart';
import 'package:stadtbote/model/log_entry.dart';
import 'package:stadtbote/model/message.dart'; import 'package:stadtbote/model/message.dart';
import 'package:stadtbote/model/session_status.dart'; import 'package:stadtbote/model/session_status.dart';
import 'package:stadtbote/model/status.dart'; import 'package:stadtbote/model/status.dart';
import 'package:stadtbote/popups/infos_popup.dart'; import 'package:stadtbote/popups/infos_popup.dart';
import 'package:stadtbote/protocoll_messages/device_log_response.dart';
import 'package:stadtbote/protocoll_messages/logout_message.dart'; import 'package:stadtbote/protocoll_messages/logout_message.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_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/message_message.dart'; import 'package:stadtbote/tools/messages/message_message.dart';
import 'package:stadtbote/tools/messages/refresh_badges_message.dart';
import 'package:stadtbote/tools/messages/session_info_update.dart'; import 'package:stadtbote/tools/messages/session_info_update.dart';
import 'package:badges/badges.dart' as badges; import 'package:badges/badges.dart' as badges;
import 'package:stadtbote/tools/messages/status_info_update.dart'; import 'package:stadtbote/tools/messages/status_info_update.dart';
import 'package:stadtbote/tools/messages/update_badges_message.dart';
import 'package:stadtbote/tools/mqtt_core.dart'; import 'package:stadtbote/tools/mqtt_core.dart';
import '../main.dart'; import '../main.dart';
@@ -30,8 +33,8 @@ import '../tools/constants.dart';
import '../tools/util.dart'; import '../tools/util.dart';
class MainPage extends ContentViewWidget { class MainPage extends ContentViewWidget {
final ValueNotifier<String> _zipValueNotifier = ValueNotifier("----"); final ValueNotifier<String> _zipValueNotifier = ValueNotifier("-----");
final ValueNotifier<String> sidValueNotifier = ValueNotifier("----"); final ValueNotifier<String> sidValueNotifier = ValueNotifier("-----");
MainPage({super.key}); MainPage({super.key});
@@ -233,7 +236,13 @@ class _MainPageState extends State<MainPage> {
getDefaultButton( getDefaultButton(
_loggedOut ? 'Anmelden' : 'Abmelden', _loggedOut ? 'Anmelden' : 'Abmelden',
image: Image.asset(_loggedOut ? 'assets/anmelden.png' : 'assets/abmelden.png', width: 30, height: 30), image: Image.asset(_loggedOut ? 'assets/anmelden.png' : 'assets/abmelden.png', width: 30, height: 30),
() async => {_logout()}), () async {
if (!kDebugMode) {
_logout(context);
} else {
_test();
}
}),
Expanded( Expanded(
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -278,7 +287,7 @@ class _MainPageState extends State<MainPage> {
_refreshBadges(); _refreshBadges();
}); });
MessageService().subscribe<RefreshBadgesMessage>(Constants.messageTopicRefreshBadges, this, (RefreshBadgesMessage refreshMessage) { MessageService().subscribe<UpdateBadgesMessage>(Constants.messageTopicUpdateBadges, this, (UpdateBadgesMessage message) {
_refreshBadges(); _refreshBadges();
}); });
} }
@@ -312,20 +321,58 @@ class _MainPageState extends State<MainPage> {
} }
} }
_logout() { _logout(context) {
if (!_loggedOut) { if (!_loggedOut) {
_sendLogoutMessage(); showLogoutAlertDialog(context);
Future.delayed(const Duration(seconds: 1), () async {
MqttCore.instance.diconnect();
});
} else { } else {
MqttCore.setup(); MqttCore.setup();
_loggedOut = false;
setState(() {});
} }
}
_loggedOut = !_loggedOut; showLogoutAlertDialog(BuildContext context) {
Widget yesButton = TextButton(
child: const Text("Ja"),
onPressed: () {
Navigator.of(context).pop();
_sendLogoutMessage();
setState(() {}); Future.delayed(const Duration(seconds: 1), () async {
MqttCore.instance.diconnect();
});
_loggedOut = true;
setState(() {});
},
);
Widget noButton = TextButton(
child: const Text("Nein"),
onPressed: () {
Navigator.of(context).pop();
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: const Text("Warnung"),
content: const Text("Wollen Sie sich wirklich abmelden?"),
actions: [
yesButton, noButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
} }
_sendLogoutMessage() { _sendLogoutMessage() {
+20 -18
View File
@@ -8,6 +8,7 @@ import 'package:stadtbote/content_views/utils/content_view_widget.dart';
import 'package:stadtbote/content_views/utils/header_info.dart'; import 'package:stadtbote/content_views/utils/header_info.dart';
import 'package:stadtbote/main.dart'; import 'package:stadtbote/main.dart';
import 'package:stadtbote/model/message.dart' as sbmessage; import 'package:stadtbote/model/message.dart' as sbmessage;
import 'package:stadtbote/model/message.dart';
import 'package:stadtbote/model/session_status.dart'; import 'package:stadtbote/model/session_status.dart';
import 'package:stadtbote/tools/mqtt_core.dart'; import 'package:stadtbote/tools/mqtt_core.dart';
@@ -95,16 +96,17 @@ class _MessagesPageState extends State<MessagesPage> {
void _handleSendPressed(types.PartialText text) async { void _handleSendPressed(types.PartialText text) async {
var now = DateTime.now(); var now = DateTime.now();
var message = sbmessage.Message(); var message = MessageMessage();
message.text = [text.text]; message.mssg = sbmessage.Message();
message.from = _sid; message.mssg.text = [text.text];
message.subj = ''; message.mssg.from = _sid;
message.time = now.toIso8601String(); message.mssg.subj = '';
message.read = true; message.mssg.time = now.toUtc().toIso8601String();
message.id = await sbmessage.Message.getNextId(); message.mssg.read = true;
message.mssg.id = await sbmessage.Message.getNextId();
MyApp.isarInstance.writeTxnSync(() { await MyApp.isarInstance.writeTxn(() async {
MyApp.isarInstance.messages.putSync(message); await MyApp.isarInstance.messages.put(message.mssg);
}); });
var json = jsonEncode(message.toJson()); var json = jsonEncode(message.toJson());
@@ -114,7 +116,7 @@ class _MessagesPageState extends State<MessagesPage> {
_messages.insert(0, types.TextMessage( _messages.insert(0, types.TextMessage(
author: _user, author: _user,
createdAt: now.millisecondsSinceEpoch, createdAt: now.millisecondsSinceEpoch,
id: message.id.toString(), id: message.mssg.id.toString(),
text: text.text, text: text.text,
)); ));
@@ -132,18 +134,18 @@ class _MessagesPageState extends State<MessagesPage> {
} }
text = text.trim(); text = text.trim();
_messages.insert(0, types.TextMessage( _messages.add(types.TextMessage(
author: message.from == _sid ? _user : _central, author: message.from == _sid ? _user : _central,
createdAt: DateTime createdAt: DateTime.parse(message.time).toLocal().millisecondsSinceEpoch,
.parse(message.time)
.millisecondsSinceEpoch,
id: message.id.toString(), id: message.id.toString(),
text: text, text: text,
)); ));
_messages.sort((a, b) => b.createdAt! > a.createdAt! ? 1 : 0);
message.read = true; message.read = true;
MyApp.isarInstance.writeTxnSync(() { await MyApp.isarInstance.writeTxn(() async {
MyApp.isarInstance.messages.putSync(message); await MyApp.isarInstance.messages.put(message);
}); });
} }
@@ -181,8 +183,8 @@ class _MessagesPageState extends State<MessagesPage> {
), ),
const SizedBox(width: 20), const SizedBox(width: 20),
Expanded( Expanded(
child: getDefaultButton('Ja', () => { child: getDefaultButton('Ja', () async => {
MyApp.isarInstance.writeTxnSync(() => {MyApp.isarInstance.messages.deleteSync(int.parse(message.id))}), await MyApp.isarInstance.writeTxnSync(() async => { await MyApp.isarInstance.messages.delete(int.parse(message.id))}),
_fetchMessages(), _fetchMessages(),
+63 -25
View File
@@ -20,6 +20,7 @@ import 'package:stadtbote/popups/tasks_popups/take_photos_popup.dart';
import 'package:stadtbote/protocoll_messages/accept_job_message.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_task_message.dart';
import 'package:stadtbote/protocoll_messages/fin_tour_message.dart'; import 'package:stadtbote/protocoll_messages/fin_tour_message.dart';
import 'package:stadtbote/protocoll_messages/pic_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/mqtt_core.dart'; import 'package:stadtbote/tools/mqtt_core.dart';
@@ -64,11 +65,17 @@ class _TaskListPageState extends State<TaskListPage> {
late List<TaskInfo> _taskList; late List<TaskInfo> _taskList;
List<Uint8List> _photos = [];
late String _commisionNumber;
@override @override
void initState() { void initState() {
Future.delayed(const Duration(seconds: 0), () async { Future.delayed(const Duration(seconds: 0), () async {
_taskList = await _fetchTaskList(); _taskList = await _fetchTaskList();
_commisionNumber = widget.tour.com ?? "";
_initCompleted = true; _initCompleted = true;
setState(() {}); setState(() {});
@@ -93,8 +100,21 @@ class _TaskListPageState extends State<TaskListPage> {
child: AbsorbPointer( child: AbsorbPointer(
absorbing: widget.readOnly, absorbing: widget.readOnly,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: steps, Visibility(
visible: _commisionNumber.length > 0,
child: Row(
children: [
Text('Komm-#: $_commisionNumber', style: const TextStyle(fontSize: 20), textAlign: TextAlign.left),
],
),
),
const SizedBox(height: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: steps,
),
],
), ),
), ),
), ),
@@ -125,7 +145,7 @@ class _TaskListPageState extends State<TaskListPage> {
left: 16.5, left: 16.5,
top: i == 0 ? 40 : 40, top: i == 0 ? 40 : 40,
child: Container( child: Container(
height: i == widget.tour.tasks!.length - 1 ? 0 : 20, height: i == widget.tour.tasks.length - 1 ? 0 : 20,
width: 6, width: 6,
color: isTaskActive(i) ? Constants.colorPrimary : Constants.colorPrimaryOpaque, color: isTaskActive(i) ? Constants.colorPrimary : Constants.colorPrimaryOpaque,
), ),
@@ -159,12 +179,16 @@ class _TaskListPageState extends State<TaskListPage> {
), ),
), ),
const SizedBox(height: 5), const SizedBox(height: 5),
Text( SizedBox(
taskInfo.additionalText ?? '', width: MediaQuery.of(context).size.width * 0.7,
textAlign: TextAlign.left, child: Text(
style: TextStyle( taskInfo.additionalText ?? '',
color: textColor, textAlign: TextAlign.left,
fontSize: 12.0, overflow: TextOverflow.ellipsis,
style: TextStyle(
color: textColor,
fontSize: 12.0,
),
), ),
), ),
], ],
@@ -187,7 +211,7 @@ class _TaskListPageState extends State<TaskListPage> {
Future<List<TaskInfo>> _fetchTaskList() async { Future<List<TaskInfo>> _fetchTaskList() async {
List<TaskInfo> taskList = []; List<TaskInfo> taskList = [];
for(var task in widget.tour.tasks!) { for(var task in widget.tour.tasks) {
var taskInfo = await MyApp.isarInstance.taskInfos.filter().sIdEqualTo(task.sId).findFirst(); var taskInfo = await MyApp.isarInstance.taskInfos.filter().sIdEqualTo(task.sId).findFirst();
if (taskInfo == null) { if (taskInfo == null) {
taskInfo = TaskInfo(); taskInfo = TaskInfo();
@@ -268,6 +292,8 @@ class _TaskListPageState extends State<TaskListPage> {
taskInfo.additionalText = comissionNumber; taskInfo.additionalText = comissionNumber;
taskInfo.completed = true; taskInfo.completed = true;
_commisionNumber = comissionNumber;
setState(() {}); setState(() {});
_finishTaskProcessing(taskInfo); _finishTaskProcessing(taskInfo);
@@ -282,6 +308,7 @@ class _TaskListPageState extends State<TaskListPage> {
answer.codes!.add(barcode); answer.codes!.add(barcode);
} }
taskInfo.answer = jsonEncode(answer.toJson());
taskInfo.additionalText = "Barcodes gescannt"; taskInfo.additionalText = "Barcodes gescannt";
taskInfo.completed = true; taskInfo.completed = true;
@@ -292,13 +319,17 @@ class _TaskListPageState extends State<TaskListPage> {
} }
_processTakePhotos(TaskInfo taskInfo) { _processTakePhotos(TaskInfo taskInfo) {
showTakePhotosPopup(context, taskInfo, () { showTakePhotosPopup(context, taskInfo, (List<Uint8List>? photos) {
taskInfo.additionalText = "Fotos aufgenommen"; if (photos != null) {
taskInfo.completed = true; _photos = photos;
setState(() {}); taskInfo.additionalText = "Fotos aufgenommen";
taskInfo.completed = true;
_finishTaskProcessing(taskInfo); setState(() {});
_finishTaskProcessing(taskInfo);
}
}); });
} }
@@ -308,6 +339,7 @@ class _TaskListPageState extends State<TaskListPage> {
answer.val = notice; answer.val = notice;
taskInfo.answer = jsonEncode(answer.toJson()); taskInfo.answer = jsonEncode(answer.toJson());
taskInfo.additionalText = notice;
taskInfo.completed = true; taskInfo.completed = true;
_finishTaskProcessing(taskInfo); _finishTaskProcessing(taskInfo);
@@ -349,23 +381,29 @@ class _TaskListPageState extends State<TaskListPage> {
} }
void _processSignature(TaskInfo taskInfo) { void _processSignature(TaskInfo taskInfo) {
MyApp.suppressAcceptDialog = true;
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, () { showSignaturePopup(context, taskInfo, (String? signature) {
var answer = _createAnswerHeader(taskInfo); MyApp.suppressAcceptDialog = false;
answer.sign = 'A110';
taskInfo.answer = jsonEncode(answer.toJson());
taskInfo.completed = true;
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
_sendFinTourMessage(); if (signature != null) {
var answer = _createAnswerHeader(taskInfo);
answer.sign = signature;
_finishTaskProcessing(taskInfo); taskInfo.answer = jsonEncode(answer.toJson());
taskInfo.completed = true;
MessageService().publish<PopContentViewMessage>(Constants.messageTopicPopContentView, arguments: PopContentViewMessage(count: 2)); _sendFinTourMessage();
_finishTaskProcessing(taskInfo);
MessageService().publish<PopContentViewMessage>(Constants.messageTopicPopContentView, arguments: PopContentViewMessage(count: 2));
}
}); });
}); });
} }
@@ -407,7 +445,7 @@ class _TaskListPageState extends State<TaskListPage> {
message.task.pos!.long = position.longitude; message.task.pos!.long = position.longitude;
} }
MqttCore.instance.publishText("fin_task", jsonEncode(message.toJson())); MqttCore.instance.publishPayloadMessage("job", finTaskMessage.toJson());
} }
FinTourTask _createAnswerHeader(TaskInfo taskInfo) { FinTourTask _createAnswerHeader(TaskInfo taskInfo) {
+27 -10
View File
@@ -63,7 +63,7 @@ class _TourListPageState extends State<TourListPage> {
return Util.getWaitWidget(context); return Util.getWaitWidget(context);
} }
late List<Widget> jobWidgets = _createjobWidgets(); late List<Widget> jobWidgets = _createTourWidgets();
return Padding( return Padding(
padding: const EdgeInsets.all(18.0), padding: const EdgeInsets.all(18.0),
@@ -124,14 +124,26 @@ class _TourListPageState extends State<TourListPage> {
); );
} }
List<Widget> _createjobWidgets() { List<Widget> _createTourWidgets() {
List<Widget> jobWidgets = []; List<Widget> tourWidgets = [];
JobTour? lastTour;
for (var tour in _tours) { for (var tour in _tours) {
bool tourActive = false;
if (lastTour == null) {
tourActive = true;
} else {
if (lastTour.state != 0) {
tourActive = true;
}
}
Color color = Colors.transparent; Color color = Colors.transparent;
switch (tour.state) { switch (tour.state) {
case 0: case 0:
color = Colors.white; color = tourActive ? Colors.white : Colors.grey;
break; break;
case 1: case 1:
@@ -143,11 +155,17 @@ class _TourListPageState extends State<TourListPage> {
break; break;
} }
jobWidgets.add( lastTour = tour;
tourWidgets.add(
ListTile( ListTile(
contentPadding: const EdgeInsets.all(0), contentPadding: const EdgeInsets.all(0),
onTap: () { onTap: () {
_clicked(tour); if (tourActive) {
_clicked(tour, false);
} else {
_clicked(tour, true);
}
}, },
title: Container( title: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -179,11 +197,10 @@ class _TourListPageState extends State<TourListPage> {
); );
} }
return jobWidgets; return tourWidgets;
} }
void _clicked(JobTour tour) { void _clicked(JobTour tour, bool readOnly) {
MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: TourDetailsPage(job: widget.job, tour: tour, readOnly: readOnly));
arguments: TourDetailsPage(job: widget.job, tour: tour, readOnly: tour.state != 0));
} }
} }
+24 -5
View File
@@ -5,8 +5,10 @@ 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: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/log_entry.dart';
import 'package:stadtbote/model/message.dart'; import 'package:stadtbote/model/message.dart';
import 'package:stadtbote/model/rank.dart'; import 'package:stadtbote/model/ranking.dart';
import 'package:stadtbote/model/status.dart'; import 'package:stadtbote/model/status.dart';
import 'package:stadtbote/model/task_info.dart'; import 'package:stadtbote/model/task_info.dart';
import 'package:stadtbote/popups/accept_jobs_popup.dart'; import 'package:stadtbote/popups/accept_jobs_popup.dart';
@@ -15,8 +17,9 @@ 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_received_message.dart'; import 'package:stadtbote/tools/messages/job_received_message.dart';
import 'package:stadtbote/tools/messages/update_badges_message.dart';
import 'package:stadtbote/tools/mqtt_core.dart';
import 'tools/mqtt_core.dart';
import 'content_views/main_page.dart'; import 'content_views/main_page.dart';
import 'content_views/utils/content_view_widget.dart'; import 'content_views/utils/content_view_widget.dart';
import 'content_views/utils/widget_stack.dart'; import 'content_views/utils/widget_stack.dart';
@@ -34,7 +37,9 @@ Future<void> main() async {
JobSchema, JobSchema,
TaskInfoSchema, TaskInfoSchema,
MessageSchema, MessageSchema,
RankSchema RankingSchema,
EnqueuedMessageSchema,
LogEntrySchema
], directory: dir.path); ], directory: dir.path);
runZonedGuarded(() {}, (error, stackTrace) { runZonedGuarded(() {}, (error, stackTrace) {
@@ -60,6 +65,8 @@ class MyApp extends StatelessWidget {
static Position? currentPosition; static Position? currentPosition;
static bool suppressAcceptDialog = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
@@ -149,6 +156,8 @@ class _MainState extends State<Main> with SingleTickerProviderStateMixin {
late AnimationController _animationController; late AnimationController _animationController;
late Animation<double> _animation; late Animation<double> _animation;
bool _dialogOpened = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -417,8 +426,18 @@ class _MainState extends State<Main> with SingleTickerProviderStateMixin {
} }
void _jobReceived(Job job) async { void _jobReceived(Job job) async {
if (job.state == 0) { if (!MyApp.suppressAcceptDialog) {
await showAcceptJobsPopup(context, await MyApp.isarInstance.jobs.filter().stateEqualTo(0).findAll()); if (job.state == 0) {
if (!_dialogOpened) {
_dialogOpened = true;
await showAcceptJobsPopup(context, await MyApp.isarInstance.jobs.filter().stateEqualTo(0).findAll(), () {
_dialogOpened = false;
MessageService().publish(Constants.messageTopicUpdateBadges, arguments: UpdateBadgesMessage());
});
}
}
} }
} }
} }
+13
View File
@@ -0,0 +1,13 @@
import 'package:isar/isar.dart';
part 'enqueued_message.g.dart';
@collection
class EnqueuedMessage {
Id id = DateTime.now().millisecondsSinceEpoch;
late String topic;
late String payload;
}
+631
View File
@@ -0,0 +1,631 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'enqueued_message.dart';
// **************************************************************************
// IsarCollectionGenerator
// **************************************************************************
// 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
extension GetEnqueuedMessageCollection on Isar {
IsarCollection<EnqueuedMessage> get enqueuedMessages => this.collection();
}
const EnqueuedMessageSchema = CollectionSchema(
name: r'EnqueuedMessage',
id: 884922652682878785,
properties: {
r'payload': PropertySchema(
id: 0,
name: r'payload',
type: IsarType.string,
),
r'topic': PropertySchema(
id: 1,
name: r'topic',
type: IsarType.string,
)
},
estimateSize: _enqueuedMessageEstimateSize,
serialize: _enqueuedMessageSerialize,
deserialize: _enqueuedMessageDeserialize,
deserializeProp: _enqueuedMessageDeserializeProp,
idName: r'id',
indexes: {},
links: {},
embeddedSchemas: {},
getId: _enqueuedMessageGetId,
getLinks: _enqueuedMessageGetLinks,
attach: _enqueuedMessageAttach,
version: '3.1.0+1',
);
int _enqueuedMessageEstimateSize(
EnqueuedMessage object,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
var bytesCount = offsets.last;
bytesCount += 3 + object.payload.length * 3;
bytesCount += 3 + object.topic.length * 3;
return bytesCount;
}
void _enqueuedMessageSerialize(
EnqueuedMessage object,
IsarWriter writer,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
writer.writeString(offsets[0], object.payload);
writer.writeString(offsets[1], object.topic);
}
EnqueuedMessage _enqueuedMessageDeserialize(
Id id,
IsarReader reader,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
final object = EnqueuedMessage();
object.id = id;
object.payload = reader.readString(offsets[0]);
object.topic = reader.readString(offsets[1]);
return object;
}
P _enqueuedMessageDeserializeProp<P>(
IsarReader reader,
int propertyId,
int offset,
Map<Type, List<int>> allOffsets,
) {
switch (propertyId) {
case 0:
return (reader.readString(offset)) as P;
case 1:
return (reader.readString(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
}
}
Id _enqueuedMessageGetId(EnqueuedMessage object) {
return object.id;
}
List<IsarLinkBase<dynamic>> _enqueuedMessageGetLinks(EnqueuedMessage object) {
return [];
}
void _enqueuedMessageAttach(
IsarCollection<dynamic> col, Id id, EnqueuedMessage object) {
object.id = id;
}
extension EnqueuedMessageQueryWhereSort
on QueryBuilder<EnqueuedMessage, EnqueuedMessage, QWhere> {
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterWhere> anyId() {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(const IdWhereClause.any());
});
}
}
extension EnqueuedMessageQueryWhere
on QueryBuilder<EnqueuedMessage, EnqueuedMessage, QWhereClause> {
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterWhereClause> idEqualTo(
Id id) {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(IdWhereClause.between(
lower: id,
upper: id,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterWhereClause>
idNotEqualTo(Id id) {
return QueryBuilder.apply(this, (query) {
if (query.whereSort == Sort.asc) {
return query
.addWhereClause(
IdWhereClause.lessThan(upper: id, includeUpper: false),
)
.addWhereClause(
IdWhereClause.greaterThan(lower: id, includeLower: false),
);
} else {
return query
.addWhereClause(
IdWhereClause.greaterThan(lower: id, includeLower: false),
)
.addWhereClause(
IdWhereClause.lessThan(upper: id, includeUpper: false),
);
}
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterWhereClause>
idGreaterThan(Id id, {bool include = false}) {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(
IdWhereClause.greaterThan(lower: id, includeLower: include),
);
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterWhereClause> idLessThan(
Id id,
{bool include = false}) {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(
IdWhereClause.lessThan(upper: id, includeUpper: include),
);
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterWhereClause> idBetween(
Id lowerId,
Id upperId, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(IdWhereClause.between(
lower: lowerId,
includeLower: includeLower,
upper: upperId,
includeUpper: includeUpper,
));
});
}
}
extension EnqueuedMessageQueryFilter
on QueryBuilder<EnqueuedMessage, EnqueuedMessage, QFilterCondition> {
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
idEqualTo(Id value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'id',
value: value,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
idGreaterThan(
Id value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'id',
value: value,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
idLessThan(
Id value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'id',
value: value,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
idBetween(
Id lower,
Id upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'id',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
payloadEqualTo(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'payload',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
payloadGreaterThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'payload',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
payloadLessThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'payload',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
payloadBetween(
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'payload',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
payloadStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'payload',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
payloadEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'payload',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
payloadContains(String value, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'payload',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
payloadMatches(String pattern, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'payload',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
payloadIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'payload',
value: '',
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
payloadIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'payload',
value: '',
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
topicEqualTo(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'topic',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
topicGreaterThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'topic',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
topicLessThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'topic',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
topicBetween(
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'topic',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
topicStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'topic',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
topicEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'topic',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
topicContains(String value, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'topic',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
topicMatches(String pattern, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'topic',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
topicIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'topic',
value: '',
));
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterFilterCondition>
topicIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'topic',
value: '',
));
});
}
}
extension EnqueuedMessageQueryObject
on QueryBuilder<EnqueuedMessage, EnqueuedMessage, QFilterCondition> {}
extension EnqueuedMessageQueryLinks
on QueryBuilder<EnqueuedMessage, EnqueuedMessage, QFilterCondition> {}
extension EnqueuedMessageQuerySortBy
on QueryBuilder<EnqueuedMessage, EnqueuedMessage, QSortBy> {
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterSortBy> sortByPayload() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'payload', Sort.asc);
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterSortBy>
sortByPayloadDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'payload', Sort.desc);
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterSortBy> sortByTopic() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'topic', Sort.asc);
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterSortBy>
sortByTopicDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'topic', Sort.desc);
});
}
}
extension EnqueuedMessageQuerySortThenBy
on QueryBuilder<EnqueuedMessage, EnqueuedMessage, QSortThenBy> {
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterSortBy> thenById() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'id', Sort.asc);
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterSortBy> thenByIdDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'id', Sort.desc);
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterSortBy> thenByPayload() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'payload', Sort.asc);
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterSortBy>
thenByPayloadDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'payload', Sort.desc);
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterSortBy> thenByTopic() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'topic', Sort.asc);
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QAfterSortBy>
thenByTopicDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'topic', Sort.desc);
});
}
}
extension EnqueuedMessageQueryWhereDistinct
on QueryBuilder<EnqueuedMessage, EnqueuedMessage, QDistinct> {
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QDistinct> distinctByPayload(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'payload', caseSensitive: caseSensitive);
});
}
QueryBuilder<EnqueuedMessage, EnqueuedMessage, QDistinct> distinctByTopic(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'topic', caseSensitive: caseSensitive);
});
}
}
extension EnqueuedMessageQueryProperty
on QueryBuilder<EnqueuedMessage, EnqueuedMessage, QQueryProperty> {
QueryBuilder<EnqueuedMessage, int, QQueryOperations> idProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'id');
});
}
QueryBuilder<EnqueuedMessage, String, QQueryOperations> payloadProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'payload');
});
}
QueryBuilder<EnqueuedMessage, String, QQueryOperations> topicProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'topic');
});
}
}
+2 -2
View File
@@ -14,10 +14,10 @@ class JobTour {
late String mode; late String mode;
late String comp; late String comp;
late String person; late String person;
late String phone; late String? phone;
late String street; late String street;
late String city; late String city;
late String com; late String? com;
late TourPosition? pos; late TourPosition? pos;
late String rem; late String rem;
late List<TourTask>? tasks; late List<TourTask>? tasks;
+60 -18
View File
@@ -94,11 +94,21 @@ int _jobTourEstimateSize(
) { ) {
var bytesCount = offsets.last; var bytesCount = offsets.last;
bytesCount += 3 + object.city.length * 3; bytesCount += 3 + object.city.length * 3;
bytesCount += 3 + object.com.length * 3; {
final value = object.com;
if (value != null) {
bytesCount += 3 + value.length * 3;
}
}
bytesCount += 3 + object.comp.length * 3; bytesCount += 3 + object.comp.length * 3;
bytesCount += 3 + object.mode.length * 3; bytesCount += 3 + object.mode.length * 3;
bytesCount += 3 + object.person.length * 3; bytesCount += 3 + object.person.length * 3;
bytesCount += 3 + object.phone.length * 3; {
final value = object.phone;
if (value != null) {
bytesCount += 3 + value.length * 3;
}
}
{ {
final value = object.pos; final value = object.pos;
if (value != null) { if (value != null) {
@@ -164,12 +174,12 @@ JobTour _jobTourDeserialize(
) { ) {
final object = JobTour(); final object = JobTour();
object.city = reader.readString(offsets[0]); object.city = reader.readString(offsets[0]);
object.com = reader.readString(offsets[1]); object.com = reader.readStringOrNull(offsets[1]);
object.comp = reader.readString(offsets[2]); object.comp = reader.readString(offsets[2]);
object.id = reader.readLong(offsets[3]); object.id = reader.readLong(offsets[3]);
object.mode = reader.readString(offsets[4]); object.mode = reader.readString(offsets[4]);
object.person = reader.readString(offsets[5]); object.person = reader.readString(offsets[5]);
object.phone = reader.readString(offsets[6]); object.phone = reader.readStringOrNull(offsets[6]);
object.pos = reader.readObjectOrNull<TourPosition>( object.pos = reader.readObjectOrNull<TourPosition>(
offsets[7], offsets[7],
TourPositionSchema.deserialize, TourPositionSchema.deserialize,
@@ -198,7 +208,7 @@ P _jobTourDeserializeProp<P>(
case 0: case 0:
return (reader.readString(offset)) as P; return (reader.readString(offset)) as P;
case 1: case 1:
return (reader.readString(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 2: case 2:
return (reader.readString(offset)) as P; return (reader.readString(offset)) as P;
case 3: case 3:
@@ -208,7 +218,7 @@ P _jobTourDeserializeProp<P>(
case 5: case 5:
return (reader.readString(offset)) as P; return (reader.readString(offset)) as P;
case 6: case 6:
return (reader.readString(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 7: case 7:
return (reader.readObjectOrNull<TourPosition>( return (reader.readObjectOrNull<TourPosition>(
offset, offset,
@@ -367,8 +377,24 @@ extension JobTourQueryFilter
}); });
} }
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'com',
));
});
}
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'com',
));
});
}
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comEqualTo( QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comEqualTo(
String value, { String? value, {
bool caseSensitive = true, bool caseSensitive = true,
}) { }) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@@ -381,7 +407,7 @@ extension JobTourQueryFilter
} }
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comGreaterThan( QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comGreaterThan(
String value, { String? value, {
bool include = false, bool include = false,
bool caseSensitive = true, bool caseSensitive = true,
}) { }) {
@@ -396,7 +422,7 @@ extension JobTourQueryFilter
} }
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comLessThan( QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comLessThan(
String value, { String? value, {
bool include = false, bool include = false,
bool caseSensitive = true, bool caseSensitive = true,
}) { }) {
@@ -411,8 +437,8 @@ extension JobTourQueryFilter
} }
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comBetween( QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comBetween(
String lower, String? lower,
String upper, { String? upper, {
bool includeLower = true, bool includeLower = true,
bool includeUpper = true, bool includeUpper = true,
bool caseSensitive = true, bool caseSensitive = true,
@@ -939,8 +965,24 @@ extension JobTourQueryFilter
}); });
} }
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'phone',
));
});
}
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'phone',
));
});
}
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneEqualTo( QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneEqualTo(
String value, { String? value, {
bool caseSensitive = true, bool caseSensitive = true,
}) { }) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@@ -953,7 +995,7 @@ extension JobTourQueryFilter
} }
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneGreaterThan( QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneGreaterThan(
String value, { String? value, {
bool include = false, bool include = false,
bool caseSensitive = true, bool caseSensitive = true,
}) { }) {
@@ -968,7 +1010,7 @@ extension JobTourQueryFilter
} }
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneLessThan( QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneLessThan(
String value, { String? value, {
bool include = false, bool include = false,
bool caseSensitive = true, bool caseSensitive = true,
}) { }) {
@@ -983,8 +1025,8 @@ extension JobTourQueryFilter
} }
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneBetween( QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneBetween(
String lower, String? lower,
String upper, { String? upper, {
bool includeLower = true, bool includeLower = true,
bool includeUpper = true, bool includeUpper = true,
bool caseSensitive = true, bool caseSensitive = true,
@@ -1579,10 +1621,10 @@ JobTour _$JobTourFromJson(Map<String, dynamic> json) => JobTour()
..mode = json['mode'] as String ..mode = json['mode'] as String
..comp = json['comp'] as String ..comp = json['comp'] as String
..person = json['person'] as String ..person = json['person'] as String
..phone = json['phone'] as String ..phone = json['phone'] as String?
..street = json['street'] as String ..street = json['street'] as String
..city = json['city'] as String ..city = json['city'] as String
..com = json['com'] as String ..com = json['com'] as String?
..pos = json['pos'] == null ..pos = json['pos'] == null
? null ? null
: TourPosition.fromJson(json['pos'] as Map<String, dynamic>) : TourPosition.fromJson(json['pos'] as Map<String, dynamic>)
+29
View File
@@ -0,0 +1,29 @@
import 'package:isar/isar.dart';
import 'package:json_annotation/json_annotation.dart';
part 'log_entry.g.dart';
enum LogEntrySeverityEnum {
info,
debug,
error
}
@collection
@JsonSerializable()
class LogEntry {
late Id id = Isar.autoIncrement;
late DateTime time;
@enumerated
late LogEntrySeverityEnum severity;
late String text;
LogEntry();
factory LogEntry.fromJson(Map<String, dynamic> json) => _$LogEntryFromJson(json);
Map<String, dynamic> toJson() => _$LogEntryToJson(this);
}
+662
View File
@@ -0,0 +1,662 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'log_entry.dart';
// **************************************************************************
// IsarCollectionGenerator
// **************************************************************************
// 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
extension GetLogEntryCollection on Isar {
IsarCollection<LogEntry> get logEntrys => this.collection();
}
const LogEntrySchema = CollectionSchema(
name: r'LogEntry',
id: -8268688274231935295,
properties: {
r'severity': PropertySchema(
id: 0,
name: r'severity',
type: IsarType.byte,
enumMap: _LogEntryseverityEnumValueMap,
),
r'text': PropertySchema(
id: 1,
name: r'text',
type: IsarType.string,
),
r'time': PropertySchema(
id: 2,
name: r'time',
type: IsarType.dateTime,
)
},
estimateSize: _logEntryEstimateSize,
serialize: _logEntrySerialize,
deserialize: _logEntryDeserialize,
deserializeProp: _logEntryDeserializeProp,
idName: r'id',
indexes: {},
links: {},
embeddedSchemas: {},
getId: _logEntryGetId,
getLinks: _logEntryGetLinks,
attach: _logEntryAttach,
version: '3.1.0+1',
);
int _logEntryEstimateSize(
LogEntry object,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
var bytesCount = offsets.last;
bytesCount += 3 + object.text.length * 3;
return bytesCount;
}
void _logEntrySerialize(
LogEntry object,
IsarWriter writer,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
writer.writeByte(offsets[0], object.severity.index);
writer.writeString(offsets[1], object.text);
writer.writeDateTime(offsets[2], object.time);
}
LogEntry _logEntryDeserialize(
Id id,
IsarReader reader,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
final object = LogEntry();
object.id = id;
object.severity =
_LogEntryseverityValueEnumMap[reader.readByteOrNull(offsets[0])] ??
LogEntrySeverityEnum.info;
object.text = reader.readString(offsets[1]);
object.time = reader.readDateTime(offsets[2]);
return object;
}
P _logEntryDeserializeProp<P>(
IsarReader reader,
int propertyId,
int offset,
Map<Type, List<int>> allOffsets,
) {
switch (propertyId) {
case 0:
return (_LogEntryseverityValueEnumMap[reader.readByteOrNull(offset)] ??
LogEntrySeverityEnum.info) as P;
case 1:
return (reader.readString(offset)) as P;
case 2:
return (reader.readDateTime(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
}
}
const _LogEntryseverityEnumValueMap = {
'info': 0,
'debug': 1,
'error': 2,
};
const _LogEntryseverityValueEnumMap = {
0: LogEntrySeverityEnum.info,
1: LogEntrySeverityEnum.debug,
2: LogEntrySeverityEnum.error,
};
Id _logEntryGetId(LogEntry object) {
return object.id;
}
List<IsarLinkBase<dynamic>> _logEntryGetLinks(LogEntry object) {
return [];
}
void _logEntryAttach(IsarCollection<dynamic> col, Id id, LogEntry object) {
object.id = id;
}
extension LogEntryQueryWhereSort on QueryBuilder<LogEntry, LogEntry, QWhere> {
QueryBuilder<LogEntry, LogEntry, QAfterWhere> anyId() {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(const IdWhereClause.any());
});
}
}
extension LogEntryQueryWhere on QueryBuilder<LogEntry, LogEntry, QWhereClause> {
QueryBuilder<LogEntry, LogEntry, QAfterWhereClause> idEqualTo(Id id) {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(IdWhereClause.between(
lower: id,
upper: id,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterWhereClause> idNotEqualTo(Id id) {
return QueryBuilder.apply(this, (query) {
if (query.whereSort == Sort.asc) {
return query
.addWhereClause(
IdWhereClause.lessThan(upper: id, includeUpper: false),
)
.addWhereClause(
IdWhereClause.greaterThan(lower: id, includeLower: false),
);
} else {
return query
.addWhereClause(
IdWhereClause.greaterThan(lower: id, includeLower: false),
)
.addWhereClause(
IdWhereClause.lessThan(upper: id, includeUpper: false),
);
}
});
}
QueryBuilder<LogEntry, LogEntry, QAfterWhereClause> idGreaterThan(Id id,
{bool include = false}) {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(
IdWhereClause.greaterThan(lower: id, includeLower: include),
);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterWhereClause> idLessThan(Id id,
{bool include = false}) {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(
IdWhereClause.lessThan(upper: id, includeUpper: include),
);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterWhereClause> idBetween(
Id lowerId,
Id upperId, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addWhereClause(IdWhereClause.between(
lower: lowerId,
includeLower: includeLower,
upper: upperId,
includeUpper: includeUpper,
));
});
}
}
extension LogEntryQueryFilter
on QueryBuilder<LogEntry, LogEntry, QFilterCondition> {
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> idEqualTo(Id value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'id',
value: value,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> idGreaterThan(
Id value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'id',
value: value,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> idLessThan(
Id value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'id',
value: value,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> idBetween(
Id lower,
Id upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'id',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> severityEqualTo(
LogEntrySeverityEnum value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'severity',
value: value,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> severityGreaterThan(
LogEntrySeverityEnum value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'severity',
value: value,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> severityLessThan(
LogEntrySeverityEnum value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'severity',
value: value,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> severityBetween(
LogEntrySeverityEnum lower,
LogEntrySeverityEnum upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'severity',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> textEqualTo(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'text',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> textGreaterThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'text',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> textLessThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'text',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> textBetween(
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'text',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> textStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'text',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> textEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'text',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> textContains(
String value,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'text',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> textMatches(
String pattern,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'text',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> textIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'text',
value: '',
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> textIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'text',
value: '',
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> timeEqualTo(
DateTime value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'time',
value: value,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> timeGreaterThan(
DateTime value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'time',
value: value,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> timeLessThan(
DateTime value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'time',
value: value,
));
});
}
QueryBuilder<LogEntry, LogEntry, QAfterFilterCondition> timeBetween(
DateTime lower,
DateTime upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'time',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
}
extension LogEntryQueryObject
on QueryBuilder<LogEntry, LogEntry, QFilterCondition> {}
extension LogEntryQueryLinks
on QueryBuilder<LogEntry, LogEntry, QFilterCondition> {}
extension LogEntryQuerySortBy on QueryBuilder<LogEntry, LogEntry, QSortBy> {
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> sortBySeverity() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'severity', Sort.asc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> sortBySeverityDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'severity', Sort.desc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> sortByText() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'text', Sort.asc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> sortByTextDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'text', Sort.desc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> sortByTime() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'time', Sort.asc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> sortByTimeDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'time', Sort.desc);
});
}
}
extension LogEntryQuerySortThenBy
on QueryBuilder<LogEntry, LogEntry, QSortThenBy> {
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> thenById() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'id', Sort.asc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> thenByIdDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'id', Sort.desc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> thenBySeverity() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'severity', Sort.asc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> thenBySeverityDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'severity', Sort.desc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> thenByText() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'text', Sort.asc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> thenByTextDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'text', Sort.desc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> thenByTime() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'time', Sort.asc);
});
}
QueryBuilder<LogEntry, LogEntry, QAfterSortBy> thenByTimeDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'time', Sort.desc);
});
}
}
extension LogEntryQueryWhereDistinct
on QueryBuilder<LogEntry, LogEntry, QDistinct> {
QueryBuilder<LogEntry, LogEntry, QDistinct> distinctBySeverity() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'severity');
});
}
QueryBuilder<LogEntry, LogEntry, QDistinct> distinctByText(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'text', caseSensitive: caseSensitive);
});
}
QueryBuilder<LogEntry, LogEntry, QDistinct> distinctByTime() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'time');
});
}
}
extension LogEntryQueryProperty
on QueryBuilder<LogEntry, LogEntry, QQueryProperty> {
QueryBuilder<LogEntry, int, QQueryOperations> idProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'id');
});
}
QueryBuilder<LogEntry, LogEntrySeverityEnum, QQueryOperations>
severityProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'severity');
});
}
QueryBuilder<LogEntry, String, QQueryOperations> textProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'text');
});
}
QueryBuilder<LogEntry, DateTime, QQueryOperations> timeProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'time');
});
}
}
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
LogEntry _$LogEntryFromJson(Map<String, dynamic> json) => LogEntry()
..id = json['id'] as int
..time = DateTime.parse(json['time'] as String)
..severity = $enumDecode(_$LogEntrySeverityEnumEnumMap, json['severity'])
..text = json['text'] as String;
Map<String, dynamic> _$LogEntryToJson(LogEntry instance) => <String, dynamic>{
'id': instance.id,
'time': instance.time.toIso8601String(),
'severity': _$LogEntrySeverityEnumEnumMap[instance.severity]!,
'text': instance.text,
};
const _$LogEntrySeverityEnumEnumMap = {
LogEntrySeverityEnum.info: 'info',
LogEntrySeverityEnum.debug: 'debug',
LogEntrySeverityEnum.error: 'error',
};
+11
View File
@@ -5,6 +5,17 @@ import 'package:stadtbote/tools/util.dart';
part 'message.g.dart'; part 'message.g.dart';
@JsonSerializable()
class MessageMessage {
late Message mssg;
MessageMessage();
factory MessageMessage.fromJson(Map<String, dynamic> json) => _$MessageMessageFromJson(json);
Map<String, dynamic> toJson() => _$MessageMessageToJson(this);
}
@collection @collection
@JsonSerializable() @JsonSerializable()
class Message { class Message {
+9
View File
@@ -1098,6 +1098,15 @@ extension MessageQueryProperty
// JsonSerializableGenerator // JsonSerializableGenerator
// ************************************************************************** // **************************************************************************
MessageMessage _$MessageMessageFromJson(Map<String, dynamic> json) =>
MessageMessage()
..mssg = Message.fromJson(json['mssg'] as Map<String, dynamic>);
Map<String, dynamic> _$MessageMessageToJson(MessageMessage instance) =>
<String, dynamic>{
'mssg': instance.mssg,
};
Message _$MessageFromJson(Map<String, dynamic> json) => Message() Message _$MessageFromJson(Map<String, dynamic> json) => Message()
..id = json['id'] as int ..id = json['id'] as int
..time = json['time'] as String ..time = json['time'] as String
+174 -124
View File
@@ -1,5 +1,3 @@
import 'dart:convert';
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';
@@ -8,8 +6,6 @@ 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/messages/refresh_badges_message.dart';
import 'package:stadtbote/tools/mqtt_core.dart'; import 'package:stadtbote/tools/mqtt_core.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;
@@ -20,138 +16,192 @@ Future<void> showAcceptJobsPopup(BuildContext context, List<Job> jobs) async {
await showDialog<void>( await showDialog<void>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertDialog( return WillPopScope(
contentPadding: EdgeInsets.zero, onWillPop: () async {
shadowColor: Colors.transparent, MessageService().unsubscribe(Constants.messageTopicJobDeleted, jobsMap);
backgroundColor: Colors.white, MessageService().unsubscribe(Constants.messageTopicJobReceived, jobsMap);
content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
if (jobsSet.isEmpty) {
Navigator.of(context).pop();
}
return SizedBox( Navigator.of(context).pop();
key: GlobalKey(),
height: MediaQuery.of(context).size.height * 1,
width: MediaQuery.of(context).size.width * 1.2,
child: Container(
height: 100,
padding: const EdgeInsets.all(5),
child: ListView.builder(
itemCount: jobsSet.length,
itemBuilder: (_, i) {
var job = jobsSet.toList()[i];
return ExpandableNotifier( onFinished();
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), return true;
title: Container( },
decoration: BoxDecoration( child: AlertDialog(
borderRadius: BorderRadius.circular(10), contentPadding: EdgeInsets.zero,
border: Border.all( shadowColor: Colors.transparent,
color: Constants.colorPrimary, backgroundColor: Colors.white,
width: 1, content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
), if (jobsMap.isEmpty) {
), Navigator.of(context).pop();
child: badges.Badge(
position: badges.BadgePosition.topEnd(top: -13, end: -5), onFinished();
showBadge: false, }
badgeContent: const Text(
'Neu', MessageService().unsubscribe(Constants.messageTopicJobDeleted, jobsMap);
style: TextStyle( MessageService().unsubscribe(Constants.messageTopicJobReceived, jobsMap);
color: Colors.white,
fontSize: 18.0, MessageService().subscribe<JobDeletedMessage>(Constants.messageTopicJobDeleted, jobsMap, (jobDeletedMessage) async {
jobsMap.removeWhere((key, value) => key == jobDeletedMessage.jobId);
if (context.mounted) {
setState(() {});
}
});
MessageService().subscribe<JobReceivedMessage>(Constants.messageTopicJobReceived, jobsMap, (jobdMessage) async {
if (jobsMap.containsKey(jobdMessage.job.id)) {
jobsMap.removeWhere((key, value) => key == jobdMessage.job.id);
}
jobsMap[jobdMessage.job.id] = jobdMessage.job;
if (context.mounted) {
setState(() {});
}
});
return SizedBox(
key: GlobalKey(),
height: MediaQuery.of(context).size.height * 1,
width: MediaQuery.of(context).size.width * 1.2,
child: Container(
height: 100,
padding: const EdgeInsets.all(5),
child: ListView.builder(
itemCount: jobsMap.length,
itemBuilder: (_, i) {
var job = jobsMap.values.toList()[i];
String remarkString = '';
for (var remark in job.rem) {
remarkString += '$remark\n';
}
remarkString = remarkString.trim();
return ExpandableNotifier(
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
title: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Constants.colorPrimary,
width: 1,
),
), ),
), child: badges.Badge(
badgeStyle: badges.BadgeStyle( position: badges.BadgePosition.topEnd(top: -13, end: -5),
shape: badges.BadgeShape.square, showBadge: false,
badgeColor: Constants.colorPrimary, badgeContent: const Text(
padding: const EdgeInsets.all(5), 'Neu',
borderRadius: BorderRadius.circular(5), style: TextStyle(
borderSide: const BorderSide(color: Constants.colorPrimary, width: 0), color: Colors.white,
), fontSize: 18.0,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
children: [
SizedBox(
width: double.infinity,
child: Text(
DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime)).toString(),
textAlign: TextAlign.left,
style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.yellow : Colors.white),
),
), ),
SizedBox(width: double.infinity, child: Text('Auftragsnummer: ${job.id}', textAlign: TextAlign.left)), ),
SizedBox(width: double.infinity, child: Text(job.tours[0].comp, textAlign: TextAlign.left)), badgeStyle: badges.BadgeStyle(
SizedBox(width: double.infinity, child: Text(job.tours[0].street, textAlign: TextAlign.left)), shape: badges.BadgeShape.square,
SizedBox(width: double.infinity, child: Text(job.tours[0].city, textAlign: TextAlign.left)), badgeColor: Constants.colorPrimary,
Row( padding: const EdgeInsets.all(5),
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(color: Constants.colorPrimary, width: 0),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
children: [ children: [
Image.asset("assets/${mapVehicleTypeToImageName(job.vhtId)}", width: 60, height: 60), SizedBox(
const SizedBox(width: 10), width: double.infinity,
Text(mapVehicleTypeToText(job.vhtId)), child: Text(
], DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime).toLocal()).toString(),
), textAlign: TextAlign.left,
const SizedBox(height: 10), style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.yellow : Colors.transparent),
ScrollOnExpand( ),
scrollOnExpand: true,
scrollOnCollapse: false,
child: ExpandablePanel(
theme: const ExpandableThemeData(
headerAlignment: ExpandablePanelHeaderAlignment.center,
tapBodyToCollapse: true,
), ),
header: const Padding( SizedBox(width: double.infinity, child: Text('Auftragsnummer: ${job.id}', textAlign: TextAlign.left)),
padding: EdgeInsets.all(0), SizedBox(width: double.infinity, child: Text(job.tours[0].comp, textAlign: TextAlign.left)),
child: Text( SizedBox(width: double.infinity, child: Text(job.tours[0].street, textAlign: TextAlign.left)),
"Weitere Infos....", SizedBox(width: double.infinity, child: Text(job.tours[0].city, textAlign: TextAlign.left)),
style: TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.bold), Row(
)), children: [
collapsed: const SizedBox(), Image.asset("assets/${mapVehicleTypeToImageName(job.vhtId)}", width: 60, height: 60),
expanded: Column( const SizedBox(width: 10),
crossAxisAlignment: CrossAxisAlignment.stretch, Text(mapVehicleTypeToText(job.vhtId)),
children: <Widget>[
Container(
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: const Color(0xfffff4e4),
border: Border.all(
color: Colors.grey,
width: 0.5,
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(job.rem),
),
),
], ],
), ),
), const SizedBox(height: 10),
ScrollOnExpand(
scrollOnExpand: true,
scrollOnCollapse: false,
child: ExpandablePanel(
theme: const ExpandableThemeData(
headerAlignment: ExpandablePanelHeaderAlignment.center,
tapBodyToCollapse: true,
),
header: const Padding(
padding: EdgeInsets.all(0),
child: Text(
"Weitere Infos....",
style: TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.bold),
)),
collapsed: const SizedBox(),
expanded: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: const Color(0xfffff4e4),
border: Border.all(
color: Colors.grey,
width: 0.5,
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(remarkString),
),
),
],
),
),
),
const SizedBox(height: 20),
Row(children: [
Expanded(
child: getDefaultButton(!job.global ? 'Ablehnen' : 'Ignorieren',
() {
_sendAnswer(job, !job.global ? 2 : 3);
jobsMap.removeWhere((key, value) => key == job.id);
setState(() {});
}),
),
const SizedBox(width: 20),
Expanded(
child: getDefaultButton('Annehmen', () {
_sendAnswer(job, 1);
jobsMap.removeWhere((key, value) => key == job.id);
setState(() {});
}),
)
])
],
), ),
const SizedBox(height: 20), ),
Row(children: [
Expanded(
child: getDefaultButton(!job.global ? 'Ablehnen' : 'Ignorieren',
() => {_sendAnswer(job, !job.global ? 2 : 3), jobsSet.remove(job), setState(() {})}),
),
const SizedBox(width: 20),
Expanded(
child: getDefaultButton('Annehmen', () => {_sendAnswer(job, 1), jobsSet.remove(job), setState(() {})}),
)
])
],
), ),
), ),
), ),
), );
), },
); )),
}, );
)), })));
);
}));
}); });
} }
+3 -1
View File
@@ -5,7 +5,9 @@ import 'package:stadtbote/tools/mqtt_core.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
void showInfosPopup(BuildContext context, SessionStatus? status) async { void showInfosPopup(BuildContext context, SessionStatus? status) async {
var text = "Versionsnummer: a203\n"; var version = await Util.getAppVersion();
var text = "Versionsnummer: a$version\n";
text += "Verbindungsstatus: ${MqttCore.instance.connectionState == ConnectionStateEnum.connected ? "Verbunden" : "NICHT verbunden"}\n"; text += "Verbindungsstatus: ${MqttCore.instance.connectionState == ConnectionStateEnum.connected ? "Verbunden" : "NICHT verbunden"}\n";
text += "GPS-Status: ${MyApp.currentPosition != null ? MyApp.currentPosition!.timestamp.toString() : "Unbekannt"}\n"; text += "GPS-Status: ${MyApp.currentPosition != null ? MyApp.currentPosition!.timestamp.toString() : "Unbekannt"}\n";
text += "\n"; text += "\n";
+16 -8
View File
@@ -4,6 +4,7 @@ import 'package:animated_toggle_switch/animated_toggle_switch.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart'; import 'package:latlong2/latlong.dart';
import 'package:stadtbote/tools/util.dart';
import '../model/job_tour.dart'; import '../model/job_tour.dart';
@@ -27,12 +28,16 @@ showMapPopup(BuildContext context, JobTour currentTour, List<JobTour> tourList)
tourWidgets.add( tourWidgets.add(
GestureDetector( GestureDetector(
onTap: () async { onTap: () async {
mapController.move(LatLng(tour.pos!.lat, tour.pos!.long), mapController.zoom); if (tour.pos != null) {
mapController.move(LatLng(tour.pos!.lat, tour.pos!.long), mapController.zoom);
streamController[currentTour.sort]!.sink.add(false); streamController[currentTour.sort]!.sink.add(false);
currentTour = tour; currentTour = tour;
streamController[tour.sort]!.sink.add(true); streamController[tour.sort]!.sink.add(true);
} else {
showAlertDialog(context, 'Information', 'Es liegt keine Position für diese Station vor');
}
}, },
child: SizedBox( child: SizedBox(
width: 70, width: 70,
@@ -87,17 +92,20 @@ showMapPopup(BuildContext context, JobTour currentTour, List<JobTour> tourList)
List<Marker> markers = []; List<Marker> markers = [];
for (var tour in tourList) { for (var tour in tourList) {
markers.add(Marker( if (tour.pos != null) {
builder: (context) => const Icon(Icons.person_pin_circle, size: 56, color: Colors.blue), markers.add(Marker(
point: LatLng(tour.pos!.lat, tour.pos!.long))); builder: (context) => const Icon(Icons.person_pin_circle, size: 56, color: Colors.blue),
point: LatLng(tour.pos!.lat, tour.pos!.long)));
}
} }
return Container( return Container(
padding: const EdgeInsets.fromLTRB(30, 0, 30, 0), padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
key: GlobalKey(), key: GlobalKey(),
height: MediaQuery.of(context).size.height * 0.6, height: MediaQuery.of(context).size.height * 0.6,
child: Container( child: Container(
height: 100, height: 100,
width: MediaQuery.of(context).size.width * 1,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
color: Colors.white, color: Colors.white,
@@ -40,10 +40,15 @@ showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String)
controller: textEditingController, controller: textEditingController,
autofocus: true), autofocus: true),
const SizedBox(height: 20), const SizedBox(height: 20),
getDefaultButton('Übernehmen', () => { getDefaultButton('Übernehmen', () {
Navigator.of(context).pop(), if (textEditingController.text.isNotEmpty) {
Navigator.of(context).pop();
onFinished(textEditingController.text)}) onFinished(textEditingController.text);
} else {
showAlertDialog(context, "Fehler", "Sie müssen einen Text eingeben");
}
})
], ],
), ),
), ),
+36 -5
View File
@@ -3,11 +3,19 @@ import 'package:signature/signature.dart';
import 'package:stadtbote/model/task_info.dart'; import 'package:stadtbote/model/task_info.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function() onFinished) async { showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function(String?) onFinished) async {
await showDialog( await showDialog(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertDialog( return WillPopScope(
onWillPop: () async {
Navigator.of(context).pop();
onFinished(null);
return true;
},// False will prevent and true will allow to dismiss
child: AlertDialog(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
shadowColor: Colors.transparent, shadowColor: Colors.transparent,
backgroundColor: Colors.white, backgroundColor: Colors.white,
@@ -18,6 +26,24 @@ showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function() onFinishe
var popupHeight = MediaQuery.of(context).size.height * 0.85; var popupHeight = MediaQuery.of(context).size.height * 0.85;
var popupWidth = MediaQuery.of(context).size.width * 0.85; var popupWidth = MediaQuery.of(context).size.width * 0.85;
String convertPoints(List<Point> points) {
if (points.isNotEmpty) {
String result = "";
for (var point in points) {
if (point.type != PointType.tap) {
result += "${point.offset.dx.toInt()},${point.offset.dy.toInt()};";
} else {
result += "A";
}
}
return result.replaceAll("AA", "A");
}
return "";
}
return SizedBox( return SizedBox(
key: GlobalKey(), key: GlobalKey(),
height: popupHeight, height: popupHeight,
@@ -46,14 +72,19 @@ showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function() onFinishe
), ),
), ),
getDefaultButton('Übernehmen', buttonHeight: 50, () => { getDefaultButton('Übernehmen', buttonHeight: 50, () => {
Navigator.of(context).pop(), if (controller.points.length > 50) {
Navigator.of(context).pop(),
onFinished()}) onFinished(convertPoints(controller.points))
} else {
showAlertDialog(context, "Fehler", "Die Unterschrift ist zu kurz.")
}
})
], ],
), ),
), ),
)); ));
}, },
)); )));
}); });
} }
+27 -13
View File
@@ -1,10 +1,11 @@
import 'package:carousel_slider/carousel_slider.dart'; import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:image/image.dart' as imageLib;
import 'package:stadtbote/model/task_info.dart'; import 'package:stadtbote/model/task_info.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
Future<void> showTakePhotosPopup(BuildContext context, TaskInfo taskInfo, Function() onFinished) async { Future<void> showTakePhotosPopup(BuildContext context, TaskInfo taskInfo, Function(List<Uint8List>) onFinished) async {
List<Uint8List> imageDataList = []; List<Uint8List> imageDataList = [];
List<Widget> imageWidgetsList = []; List<Widget> imageWidgetsList = [];
@@ -19,22 +20,35 @@ Future<void> showTakePhotosPopup(BuildContext context, TaskInfo taskInfo, Functi
backgroundColor: Colors.white, backgroundColor: Colors.white,
content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
void capturePhoto() async { void capturePhoto() async {
var photo = await Util.capturePhoto(); try {
var photo = await Util.capturePhoto();
if (photo != null) { if (photo != null) {
var imageData = await photo.readAsBytes(); var fullsizeImageData = await photo.readAsBytes();
photo.delete();
imageDataList.add(imageData); imageLib.Image? image = imageLib.decodeImage(fullsizeImageData);
imageWidgetsList.add(GestureDetector( if (image != null) {
onTap: () {}, var thumbnail = imageLib.copyResize(image, width: 800);
child: Image.memory(imageData),
));
imageWidgetsListNotifier.value = imageWidgetsList; var resizedImageData = imageLib.encodeJpg(thumbnail, quality: 75);
setState(() {}); photo.delete();
imageDataList.add(resizedImageData);
imageWidgetsList.add(GestureDetector(
onTap: () {},
child: Image.memory(resizedImageData),
));
imageWidgetsListNotifier.value = imageWidgetsList;
setState(() {});
}
}
} catch (ex) {
Util.logException(ex.toString());
} }
} }
@@ -90,7 +104,7 @@ Future<void> showTakePhotosPopup(BuildContext context, TaskInfo taskInfo, Functi
buttonHeight: 50, buttonHeight: 50,
() => { () => {
if (imageDataList.length == taskInfo.task.min! && imageDataList.length <= taskInfo.task.max!) if (imageDataList.length == taskInfo.task.min! && imageDataList.length <= taskInfo.task.max!)
{Navigator.of(context).pop(), onFinished()} {Navigator.of(context).pop(), onFinished(imageDataList)}
else else
{showAlertDialog(context, 'Fehler', 'Sie müssen mindestens ${taskInfo.task.min} Foto(s) aufnehmen')} {showAlertDialog(context, 'Fehler', 'Sie müssen mindestens ${taskInfo.task.min} Foto(s) aufnehmen')}
}) })
@@ -20,7 +20,8 @@ class Reaction {
@JsonSerializable() @JsonSerializable()
@JsonSerializable()class Track { @JsonSerializable()class Track {
late String time; late String time;
late FinTaskPos pos;
FinTaskPos? pos;
Track(); Track();
@@ -21,7 +21,9 @@ Map<String, dynamic> _$ReactionToJson(Reaction instance) => <String, dynamic>{
Track _$TrackFromJson(Map<String, dynamic> json) => Track() Track _$TrackFromJson(Map<String, dynamic> json) => Track()
..time = json['time'] as String ..time = json['time'] as String
..pos = FinTaskPos.fromJson(json['pos'] as Map<String, dynamic>); ..pos = json['pos'] == null
? null
: FinTaskPos.fromJson(json['pos'] as Map<String, dynamic>);
Map<String, dynamic> _$TrackToJson(Track instance) => <String, dynamic>{ Map<String, dynamic> _$TrackToJson(Track instance) => <String, dynamic>{
'time': instance.time, 'time': instance.time,
@@ -0,0 +1,32 @@
import 'package:isar/isar.dart';
import 'package:json_annotation/json_annotation.dart';
part 'acknowledge_job.g.dart';
@JsonSerializable()
class AcknowledgeJob {
late AcknowledgeJobReceived received;
AcknowledgeJob();
factory AcknowledgeJob.fromJson(Map<String, dynamic> json) => _$AcknowledgeJobFromJson(json);
Map<String, dynamic> toJson() => _$AcknowledgeJobToJson(this);
}
@JsonSerializable()
class AcknowledgeJobReceived {
late int id;
late int state;
late int ver;
late int utc;
AcknowledgeJobReceived();
factory AcknowledgeJobReceived.fromJson(Map<String, dynamic> json) => _$AcknowledgeJobReceivedFromJson(json);
Map<String, dynamic> toJson() => _$AcknowledgeJobReceivedToJson(this);
}
@@ -0,0 +1,34 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'acknowledge_job.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
AcknowledgeJob _$AcknowledgeJobFromJson(Map<String, dynamic> json) =>
AcknowledgeJob()
..received = AcknowledgeJobReceived.fromJson(
json['received'] as Map<String, dynamic>);
Map<String, dynamic> _$AcknowledgeJobToJson(AcknowledgeJob instance) =>
<String, dynamic>{
'received': instance.received,
};
AcknowledgeJobReceived _$AcknowledgeJobReceivedFromJson(
Map<String, dynamic> json) =>
AcknowledgeJobReceived()
..id = json['id'] as int
..state = json['state'] as int
..ver = json['ver'] as int
..utc = json['utc'] as int;
Map<String, dynamic> _$AcknowledgeJobReceivedToJson(
AcknowledgeJobReceived instance) =>
<String, dynamic>{
'id': instance.id,
'state': instance.state,
'ver': instance.ver,
'utc': instance.utc,
};
@@ -0,0 +1,18 @@
import 'dart:core';
import 'package:json_annotation/json_annotation.dart';
part 'device_log_request.g.dart';
@JsonSerializable()
class DeviceLogRequest {
late DateTime startDateTime;
late DateTime endDateTime;
DeviceLogRequest();
Map<String, dynamic> toJson() => _$DeviceLogRequestToJson(this);
factory DeviceLogRequest.fromJson(Map<String, dynamic> json) => _$DeviceLogRequestFromJson(json);
}
@@ -0,0 +1,18 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'device_log_request.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DeviceLogRequest _$DeviceLogRequestFromJson(Map<String, dynamic> json) =>
DeviceLogRequest()
..startDateTime = DateTime.parse(json['startDateTime'] as String)
..endDateTime = DateTime.parse(json['endDateTime'] as String);
Map<String, dynamic> _$DeviceLogRequestToJson(DeviceLogRequest instance) =>
<String, dynamic>{
'startDateTime': instance.startDateTime.toIso8601String(),
'endDateTime': instance.endDateTime.toIso8601String(),
};
@@ -0,0 +1,15 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stadtbote/model/log_entry.dart';
part 'device_log_response.g.dart';
@JsonSerializable()
class DeviceLogResponse {
late List<LogEntry> entries;
DeviceLogResponse();
Map<String, dynamic> toJson() => _$DeviceLogResponseToJson(this);
factory DeviceLogResponse.fromJson(Map<String, dynamic> json) => _$DeviceLogResponseFromJson(json);
}
@@ -0,0 +1,18 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'device_log_response.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DeviceLogResponse _$DeviceLogResponseFromJson(Map<String, dynamic> json) =>
DeviceLogResponse()
..entries = (json['entries'] as List<dynamic>)
.map((e) => LogEntry.fromJson(e as Map<String, dynamic>))
.toList();
Map<String, dynamic> _$DeviceLogResponseToJson(DeviceLogResponse instance) =>
<String, dynamic>{
'entries': instance.entries,
};
+1 -1
View File
@@ -35,7 +35,7 @@ class Task {
late String time; late String time;
late FinTaskPos? pos; FinTaskPos? pos;
Task(); Task();
+2 -2
View File
@@ -23,7 +23,7 @@ class FinTour {
late String com; late String com;
late Track track; Track? track;
late List<FinTourTask> tasks; late List<FinTourTask> tasks;
@@ -49,7 +49,7 @@ class FinTourTask {
List<String>? codes; List<String>? codes;
late FinTaskPos pos; FinTaskPos? pos;
FinTourTask(); FinTourTask();
@@ -18,7 +18,9 @@ Map<String, dynamic> _$FinTourMessageToJson(FinTourMessage instance) =>
FinTour _$FinTourFromJson(Map<String, dynamic> json) => FinTour() FinTour _$FinTourFromJson(Map<String, dynamic> json) => FinTour()
..trId = json['tr_id'] as int ..trId = json['tr_id'] as int
..com = json['com'] as String ..com = json['com'] as String
..track = Track.fromJson(json['track'] as Map<String, dynamic>) ..track = json['track'] == null
? null
: Track.fromJson(json['track'] as Map<String, dynamic>)
..tasks = (json['tasks'] as List<dynamic>) ..tasks = (json['tasks'] as List<dynamic>)
.map((e) => FinTourTask.fromJson(e as Map<String, dynamic>)) .map((e) => FinTourTask.fromJson(e as Map<String, dynamic>))
.toList(); .toList();
@@ -37,7 +39,9 @@ FinTourTask _$FinTourTaskFromJson(Map<String, dynamic> json) => FinTourTask()
..code = json['code'] as int? ..code = json['code'] as int?
..sign = json['sign'] as String? ..sign = json['sign'] as String?
..codes = (json['codes'] as List<dynamic>?)?.map((e) => e as String).toList() ..codes = (json['codes'] as List<dynamic>?)?.map((e) => e as String).toList()
..pos = FinTaskPos.fromJson(json['pos'] as Map<String, dynamic>); ..pos = json['pos'] == null
? null
: FinTaskPos.fromJson(json['pos'] as Map<String, dynamic>);
Map<String, dynamic> _$FinTourTaskToJson(FinTourTask instance) => Map<String, dynamic> _$FinTourTaskToJson(FinTourTask instance) =>
<String, dynamic>{ <String, dynamic>{
+19 -6
View File
@@ -4,13 +4,9 @@ part 'logout_message.g.dart';
@JsonSerializable() @JsonSerializable()
class LogoutMessage { class LogoutMessage {
late String time; late bool logout;
late double lat; LogoutMessagePosition? pos;
late double long;
late int acc;
LogoutMessage(); LogoutMessage();
@@ -19,3 +15,20 @@ class LogoutMessage {
Map<String, dynamic> toJson() => _$LogoutMessageToJson(this); Map<String, dynamic> toJson() => _$LogoutMessageToJson(this);
} }
@JsonSerializable()
class LogoutMessagePosition {
late String time;
late double lat;
late double long;
late int acc;
LogoutMessagePosition();
factory LogoutMessagePosition.fromJson(Map<String, dynamic> json) => _$LogoutMessagePositionFromJson(json);
Map<String, dynamic> toJson() => _$LogoutMessagePositionToJson(this);
}
+50
View File
@@ -0,0 +1,50 @@
import 'package:json_annotation/json_annotation.dart';
part 'pic_message.g.dart';
@JsonSerializable()
class PicMessage {
late PicData pic;
PicMessagePos? pos;
PicMessage();
factory PicMessage.fromJson(Map<String, dynamic> json) => _$PicMessageFromJson(json);
Map<String, dynamic> toJson() => _$PicMessageToJson(this);
}
@JsonSerializable()
class PicData
{
@JsonKey(name: "tr_id")
late int trId;
late int num;
late int time;
late String data;
PicData();
factory PicData.fromJson(Map<String, dynamic> json) => _$PicDataFromJson(json);
Map<String, dynamic> toJson() => _$PicDataToJson(this);
}
@JsonSerializable()
class PicMessagePos {
late double lat;
late double long;
late int acc = 0;
PicMessagePos();
factory PicMessagePos.fromJson(Map<String, dynamic> json) => _$PicMessagePosFromJson(json);
Map<String, dynamic> toJson() => _$PicMessagePosToJson(this);
}
+45
View File
@@ -0,0 +1,45 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'pic_message.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
PicMessage _$PicMessageFromJson(Map<String, dynamic> json) => PicMessage()
..pic = PicData.fromJson(json['pic'] as Map<String, dynamic>)
..pos = json['pos'] == null
? null
: PicMessagePos.fromJson(json['pos'] as Map<String, dynamic>);
Map<String, dynamic> _$PicMessageToJson(PicMessage instance) =>
<String, dynamic>{
'pic': instance.pic,
'pos': instance.pos,
};
PicData _$PicDataFromJson(Map<String, dynamic> json) => PicData()
..trId = json['tr_id'] as int
..num = json['num'] as int
..time = json['time'] as int
..data = json['data'] as String;
Map<String, dynamic> _$PicDataToJson(PicData instance) => <String, dynamic>{
'tr_id': instance.trId,
'num': instance.num,
'time': instance.time,
'data': instance.data,
};
PicMessagePos _$PicMessagePosFromJson(Map<String, dynamic> json) =>
PicMessagePos()
..lat = (json['lat'] as num).toDouble()
..long = (json['long'] as num).toDouble()
..acc = json['acc'] as int;
Map<String, dynamic> _$PicMessagePosToJson(PicMessagePos instance) =>
<String, dynamic>{
'lat': instance.lat,
'long': instance.long,
'acc': instance.acc,
};
+1 -1
View File
@@ -4,7 +4,7 @@ part 'track_message.g.dart';
@JsonSerializable() @JsonSerializable()
class TrackMessage { class TrackMessage {
late TrackPosition pos; TrackPosition? pos;
TrackMessage(); TrackMessage();
+3 -1
View File
@@ -7,7 +7,9 @@ part of 'track_message.dart';
// ************************************************************************** // **************************************************************************
TrackMessage _$TrackMessageFromJson(Map<String, dynamic> json) => TrackMessage() TrackMessage _$TrackMessageFromJson(Map<String, dynamic> json) => TrackMessage()
..pos = TrackPosition.fromJson(json['pos'] as Map<String, dynamic>); ..pos = json['pos'] == null
? null
: TrackPosition.fromJson(json['pos'] as Map<String, dynamic>);
Map<String, dynamic> _$TrackMessageToJson(TrackMessage instance) => Map<String, dynamic> _$TrackMessageToJson(TrackMessage instance) =>
<String, dynamic>{ <String, dynamic>{
@@ -10,7 +10,7 @@ class TrackStationMessage {
late String time; late String time;
late FinTaskPos? pos; FinTaskPos? pos;
TrackStationMessage(); TrackStationMessage();
+2 -2
View File
@@ -61,7 +61,7 @@ class ZipReqZip {
class ZipSetPos { class ZipSetPos {
late String zip; late String zip;
late ZipTrack track; ZipTrack? track;
ZipSetPos(); ZipSetPos();
@@ -75,7 +75,7 @@ class ZipSetPos {
class ZipTrack { class ZipTrack {
late String time; late String time;
late ZipTrackPos? pos; ZipTrackPos? pos;
ZipTrack(); ZipTrack();
+34 -14
View File
@@ -298,9 +298,13 @@ int _zipSetPosEstimateSize(
Map<Type, List<int>> allOffsets, Map<Type, List<int>> allOffsets,
) { ) {
var bytesCount = offsets.last; var bytesCount = offsets.last;
bytesCount += 3 + {
ZipTrackSchema.estimateSize( final value = object.track;
object.track, allOffsets[ZipTrack]!, allOffsets); if (value != null) {
bytesCount += 3 +
ZipTrackSchema.estimateSize(value, allOffsets[ZipTrack]!, allOffsets);
}
}
bytesCount += 3 + object.zip.length * 3; bytesCount += 3 + object.zip.length * 3;
return bytesCount; return bytesCount;
} }
@@ -328,11 +332,10 @@ ZipSetPos _zipSetPosDeserialize(
) { ) {
final object = ZipSetPos(); final object = ZipSetPos();
object.track = reader.readObjectOrNull<ZipTrack>( object.track = reader.readObjectOrNull<ZipTrack>(
offsets[0], offsets[0],
ZipTrackSchema.deserialize, ZipTrackSchema.deserialize,
allOffsets, allOffsets,
) ?? );
ZipTrack();
object.zip = reader.readString(offsets[1]); object.zip = reader.readString(offsets[1]);
return object; return object;
} }
@@ -346,11 +349,10 @@ P _zipSetPosDeserializeProp<P>(
switch (propertyId) { switch (propertyId) {
case 0: case 0:
return (reader.readObjectOrNull<ZipTrack>( return (reader.readObjectOrNull<ZipTrack>(
offset, offset,
ZipTrackSchema.deserialize, ZipTrackSchema.deserialize,
allOffsets, allOffsets,
) ?? )) as P;
ZipTrack()) as P;
case 1: case 1:
return (reader.readString(offset)) as P; return (reader.readString(offset)) as P;
default: default:
@@ -360,6 +362,22 @@ P _zipSetPosDeserializeProp<P>(
extension ZipSetPosQueryFilter extension ZipSetPosQueryFilter
on QueryBuilder<ZipSetPos, ZipSetPos, QFilterCondition> { on QueryBuilder<ZipSetPos, ZipSetPos, QFilterCondition> {
QueryBuilder<ZipSetPos, ZipSetPos, QAfterFilterCondition> trackIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'track',
));
});
}
QueryBuilder<ZipSetPos, ZipSetPos, QAfterFilterCondition> trackIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'track',
));
});
}
QueryBuilder<ZipSetPos, ZipSetPos, QAfterFilterCondition> zipEqualTo( QueryBuilder<ZipSetPos, ZipSetPos, QAfterFilterCondition> zipEqualTo(
String value, { String value, {
bool caseSensitive = true, bool caseSensitive = true,
@@ -1046,7 +1064,9 @@ Map<String, dynamic> _$ZipReqZipToJson(ZipReqZip instance) => <String, dynamic>{
ZipSetPos _$ZipSetPosFromJson(Map<String, dynamic> json) => ZipSetPos() ZipSetPos _$ZipSetPosFromJson(Map<String, dynamic> json) => ZipSetPos()
..zip = json['zip'] as String ..zip = json['zip'] as String
..track = ZipTrack.fromJson(json['track'] as Map<String, dynamic>); ..track = json['track'] == null
? null
: ZipTrack.fromJson(json['track'] as Map<String, dynamic>);
Map<String, dynamic> _$ZipSetPosToJson(ZipSetPos instance) => <String, dynamic>{ Map<String, dynamic> _$ZipSetPosToJson(ZipSetPos instance) => <String, dynamic>{
'zip': instance.zip, 'zip': instance.zip,
+1 -1
View File
@@ -11,7 +11,7 @@ class Constants {
static const String messageTopicRankingUpdated = "ranking_updated"; static const String messageTopicRankingUpdated = "ranking_updated";
static const String messageTopicJobReceived = "job_received"; static const String messageTopicJobReceived = "job_received";
static const String messageTopicJobDeleted = "job_deleted"; static const String messageTopicJobDeleted = "job_deleted";
static const String messageTopicRefreshBadges = "refresh_badges"; static const String messageTopicUpdateBadges = "update_badges";
static const String messageTopicMessageReceived = "message_received"; static const String messageTopicMessageReceived = "message_received";
static const String messageTopicPushContentView = "push_content_view"; static const String messageTopicPushContentView = "push_content_view";
static const String messageTopicPopContentView = "pop_content_view"; static const String messageTopicPopContentView = "pop_content_view";
@@ -0,0 +1,4 @@
class UpdateBadgesMessage {
UpdateBadgesMessage();
}
+172 -92
View File
@@ -1,19 +1,25 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:archive/archive.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_client.dart';
import 'package:mqtt_client/mqtt_server_client.dart'; import 'package:mqtt_client/mqtt_server_client.dart';
import 'package:stadtbote/model/rank.dart'; import 'package:stadtbote/model/enqueued_message.dart';
import 'package:stadtbote/model/log_entry.dart';
import 'package:stadtbote/model/ranking.dart';
import 'package:stadtbote/model/status.dart'; 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_request.dart';
import 'package:stadtbote/protocoll_messages/bootstrap_response_payload.dart'; import 'package:stadtbote/protocoll_messages/bootstrap_response_payload.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';
import 'package:stadtbote/model/job.dart'; import 'package:stadtbote/model/job.dart';
import 'package:stadtbote/model/message.dart'; import 'package:stadtbote/model/message.dart';
import 'package:stadtbote/protocoll_messages/device_object.dart'; import 'package:stadtbote/protocoll_messages/payload_container.dart';
import 'package:stadtbote/protocoll_messages/job_del_message.dart';
import 'package:stadtbote/protocoll_messages/start_session_message.dart'; import 'package:stadtbote/protocoll_messages/start_session_message.dart';
import 'package:stadtbote/protocoll_messages/sync_jobs_message.dart'; import 'package:stadtbote/protocoll_messages/sync_jobs_message.dart';
import 'package:stadtbote/protocoll_messages/track_message.dart'; import 'package:stadtbote/protocoll_messages/track_message.dart';
@@ -28,6 +34,7 @@ import 'package:stadtbote/tools/messages/status_info_update.dart';
// ignore: depend_on_referenced_packages // ignore: depend_on_referenced_packages
import 'package:typed_data/typed_buffers.dart'; import 'package:typed_data/typed_buffers.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:uuid/uuid.dart';
import '../main.dart'; import '../main.dart';
import '../model/session_status.dart'; import '../model/session_status.dart';
@@ -49,7 +56,6 @@ class MqttCore {
late String _brokerUri; late String _brokerUri;
late int _brokerPort; late int _brokerPort;
late String _fromServerTopic; late String _fromServerTopic;
late String _clientId;
late String _toServerTopic; late String _toServerTopic;
late MqttServerClient _mqttClient; late MqttServerClient _mqttClient;
@@ -94,7 +100,6 @@ class MqttCore {
_mqttClient.keepAlivePeriod = 20; _mqttClient.keepAlivePeriod = 20;
_mqttClient.autoReconnect = false; _mqttClient.autoReconnect = false;
_mqttClient.onDisconnected = _clientDisconnected; _mqttClient.onDisconnected = _clientDisconnected;
_mqttClient.connectionMessage = MqttConnectMessage() _mqttClient.connectionMessage = MqttConnectMessage()
.withClientIdentifier(await Util.getAppUuid()) .withClientIdentifier(await Util.getAppUuid())
.withWillQos(MqttQos.atMostOnce) .withWillQos(MqttQos.atMostOnce)
@@ -129,73 +134,96 @@ class MqttCore {
} }
} }
publishText(String subtopic, String text) { publishBinary(String topic, List<int> data) {
var buffer = Uint8Buffer();
buffer.addAll(data);
_mqttClient.publishMessage(topic, MqttQos.exactlyOnce, buffer);
Util.logInfo("binary message send to $topic");
}
publishText(String topic, String text) {
var buffer = Uint8Buffer();
buffer.addAll(utf8.encode(text));
_mqttClient.publishMessage(topic, MqttQos.exactlyOnce, buffer);
Util.logInfo("message\n$text\nsend to $topic");
}
publishPayloadMessage(String topic, Map<String, dynamic> payload) {
var payloadContainer = PayloadContainer();
payloadContainer.id = const Uuid().v4().toString();
payloadContainer.recv = topic;
payloadContainer.store = true;
payloadContainer.payload = payload;
var json = jsonEncode(payloadContainer.toJson());
try { try {
var buffer = Uint8Buffer(); publishText(_toServerTopic, json);
buffer.addAll(utf8.encode(text));
_mqttClient.publishMessage(subtopic, MqttQos.exactlyOnce, buffer);
var topic = "$_toServerTopic$subtopic/$_clientId";
_mqttClient.publishMessage( topic, MqttQos.exactlyOnce, buffer);
Util.logInfo("send message $text to $topic");
} catch (e) { } catch (e) {
Util.logException(e.toString()); _enqueueMessage(_toServerTopic, jsonEncode(payloadContainer.toJson()));
} }
} }
void _setupSubscriptions() async { void _setupSubscriptions() async {
Util.logInfo('_setupSubscriptions called'); Util.logInfo('_setupSubscriptions called');
_mqttClient.updates?.listen((List<MqttReceivedMessage<MqttMessage>> messages) { _mqttClient.updates?.listen((List<MqttReceivedMessage<MqttMessage>> c) {
try { try {
for (var mqttMessage in messages) { final MqttPublishMessage message = c[0].payload as MqttPublishMessage;
final MqttPublishMessage message = mqttMessage.payload as MqttPublishMessage; String payload = utf8.decode(MqttPublishPayload.bytesToStringAsString(message.payload.message).codeUnits);
String payload = utf8.decode(MqttPublishPayload.bytesToStringAsString(message.payload.message).codeUnits); var topic = message.variableHeader?.topicName;
var topic = message.variableHeader?.topicName;
if (topic!.endsWith(_clientId)) { Util.logInfo('message received\ntopic: $topic\nmessage: $payload');
Util.logInfo('message received');
Util.logInfo('topic: $topic');
Util.logInfo('mesage: $payload');
var topicArray = topic.split('/'); Map<String, dynamic> messageData = jsonDecode(payload);
var messageType = topicArray[3];
switch(messageType) { for (var entry in messageData.keys) {
case 'session': if (entry == 'payload') {
_sessionMessageReceived(jsonDecode(payload)); var payload = messageData[entry];
break; for (var payloadEntry in payload.keys) {
var payloadData = payload[payloadEntry];
case 'status': switch(payloadEntry) {
_statusMessageReceived(jsonDecode(payload)); case 'session':
break; _sessionMessageReceived(payloadData);
break;
case 'ranking': case 'status':
_rankingMessageReceived(jsonDecode(payload)); _statusMessageReceived(payloadData);
break; break;
case 'job': case 'ranks':
_jobMessageReceived(jsonDecode(payload)); _rankingMessageReceived(payloadData);
break; break;
case 'job_del': case 'jobs':
_jobDeleteReceived(jsonDecode(payload)); _jobMessageReceived(payloadData);
break; break;
case 'sync_request': case 'job_del':
_syncRequestReceived(jsonDecode(payload)); _jobDeleteReceived(payloadData);
break; break;
case "mssg": case 'sync_request':
_messageMessageReceived(payload); _syncRequestReceived(payloadData);
break; break;
default: case "mssg":
Util.logInfo('Unknown topic: $messageType'); _messageMessageReceived(payloadData);
break; break;
case "upload_device_log":
_messageUploadDeviceLogReceived(payloadData);
break;
default:
Util.logInfo('Unknown topic: $payloadEntry');
break;
}
} }
} }
} }
@@ -204,9 +232,8 @@ class MqttCore {
} }
}); });
var topic = "$_fromServerTopic#"; _mqttClient.subscribe(_fromServerTopic, MqttQos.exactlyOnce);
_mqttClient.subscribe(topic, MqttQos.exactlyOnce); Util.logInfo('subscribed to topic: $_fromServerTopic');
Util.logInfo('subscribed to topic: $topic');
MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.connected)); MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.connected));
} }
@@ -216,7 +243,9 @@ class MqttCore {
await _sendSyncMessage(); await _sendSyncMessage();
var sessionStatusMessage = SessionStatus.fromJson(payloadData); await _sendEnqueuedMessages();
var sessionStatusMessage = SessionStatus.fromJson(payloadData['status']);
await MyApp.isarInstance.writeTxn(() async { await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.sessionStatus.clear(); await MyApp.isarInstance.sessionStatus.clear();
@@ -240,42 +269,52 @@ class MqttCore {
} }
void _rankingMessageReceived(List<dynamic> payloadData) async { void _rankingMessageReceived(List<dynamic> payloadData) async {
for (var entry in payloadData) { Map<String, dynamic> rankingMap = {};
var rank = Rank.fromJson(entry); rankingMap["ranks"] = payloadData;
var ranking = Ranking.fromJson(rankingMap);
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.ranks.put(rank);
});
}
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.rankings.put(ranking);
});
MessageService().publish<RankingUpdated>(Constants.messageTopicRankingUpdated, arguments: RankingUpdated()); MessageService().publish<RankingUpdated>(Constants.messageTopicRankingUpdated, arguments: RankingUpdated());
} }
void _jobMessageReceived(payloadData) async { void _jobMessageReceived(payloadData) async {
Job newJob = Job.fromJson(payloadData); for (var foundJobData in payloadData) {
Job newJob = Job.fromJson(foundJobData);
MyApp.isarInstance.writeTxnSync(() async { await MyApp.isarInstance.writeTxn(() async {
MyApp.isarInstance.jobs.putSync(newJob); await MyApp.isarInstance.jobs.put(newJob);
}); });
if (newJob.state == Constants.stateAssigned) { if (newJob.state == Constants.stateAssigned) {
if (newJob.global) { if (newJob.global) {
await Util.playMp3('aaa.mp3'); await Util.playMp3('aaa.mp3');
} else { } else {
await Util.playMp3('job_received.mp3'); await Util.playMp3('job_received.mp3');
}
} }
}
MessageService().publish<JobReceivedMessage>(Constants.messageTopicJobReceived, arguments: JobReceivedMessage(job: newJob)); try {
MessageService().publish<JobReceivedMessage>(Constants.messageTopicJobReceived, arguments: JobReceivedMessage(job: newJob));
} catch (ex) {
Util.logException("publish messageTopicJobReceived failed!");
}
_acknowlegdeJob(newJob);
}
} }
void _jobDeleteReceived(payloadData) async { void _jobDeleteReceived(List<dynamic> payloadData) async {
var jobDelMessage = JobDelMessage.fromJson(payloadData); Map<String, dynamic> map = {};
map["jobDel"] = payloadData;
var jobDelMessage = JobDelMessage.fromJson(map);
await MyApp.isarInstance.writeTxn(() async { for(var jobId in jobDelMessage.jobDel) {
await MyApp.isarInstance.jobs.delete(jobDelMessage.id); await MyApp.isarInstance.writeTxn(() async {
}); await MyApp.isarInstance.jobs.delete(jobId);
});
MessageService().publish<JobDeletedMessage>(Constants.messageTopicJobDeleted, arguments: JobDeletedMessage(id: jobDelMessage.id)); MessageService().publish<JobDeletedMessage>(Constants.messageTopicJobDeleted, arguments: JobDeletedMessage(id: jobDelMessage.id));
} }
@@ -334,19 +373,22 @@ class MqttCore {
void _processBootstrap() async { void _processBootstrap() async {
try { try {
String? responseText = ""; var deviceInfoPlugin = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo;
BaseDeviceInfo deviceInfo = await deviceInfoPlugin.deviceInfo;
var deviceObject = DeviceObject(); var deviceObject = DeviceObject();
deviceObject.manufacturer = "sven"; deviceObject.manufacturer = deviceInfo.data['manufacturer'];
deviceObject.model = "emulator"; deviceObject.model = deviceInfo.data['model'];
deviceObject.os = "hat es"; deviceObject.os = androidInfo.version.release;
deviceObject.osVer = "0.0"; deviceObject.osVer = androidInfo.version.sdkInt.toString();
var handshakeMessage = BootstrapRequest(); var handshakeMessage = BootstrapRequest();
handshakeMessage.app = "sb"; handshakeMessage.app = "sb";
handshakeMessage.mqttClientId = await Util.getAppUuid(); handshakeMessage.mqttClientId = await Util.getAppUuid();
handshakeMessage.deviceObject = deviceObject; handshakeMessage.deviceObject = deviceObject;
handshakeMessage.ver = 200; handshakeMessage.ver = await Util.getAppVersion();
//var jsonMap = handshakeMessage.toJson(); //var jsonMap = handshakeMessage.toJson();
//var json = jsonEncode(jsonMap); //var json = jsonEncode(jsonMap);
@@ -405,12 +447,12 @@ class MqttCore {
if (answer != null) { if (answer != null) {
var trackMessage = TrackMessage(); var trackMessage = TrackMessage();
trackMessage.pos = TrackPosition(); trackMessage.pos = TrackPosition();
trackMessage.pos.time = answer.timestamp.toIso8601String(); trackMessage.pos!.time = position.timestamp.toIso8601String();
trackMessage.pos.lat = answer.latitude; trackMessage.pos!.lat = position.latitude;
trackMessage.pos.long = answer.longitude; trackMessage.pos!.long = position.longitude;
trackMessage.pos.acc = answer.accuracy.toInt(); trackMessage.pos!.acc = position.accuracy.toInt();
publishText("track", jsonEncode(answer.toJson())); publishPayloadMessage("track", trackMessage.toJson());
} }
}); });
} }
@@ -421,4 +463,42 @@ class MqttCore {
_trackTimer = null; _trackTimer = null;
} }
} }
void _enqueueMessage(String receiver, String payload) async {
var enqueuedMessage = EnqueuedMessage();
enqueuedMessage.topic = receiver;
enqueuedMessage.payload = payload;
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.enqueuedMessages.put(enqueuedMessage);
});
}
_sendEnqueuedMessages() async {
var enqueuedMessages = await MyApp.isarInstance.enqueuedMessages.where().findAll();
if (enqueuedMessages.isNotEmpty) {
for (var enqueuedMessage in enqueuedMessages) {
try {
publishText(enqueuedMessage.topic, enqueuedMessage.payload);
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.enqueuedMessages.delete(enqueuedMessage.id);
});
} catch (ex) {
Util.logInfo("resend enqueued message failed: $ex");
}
}
}
}
void _acknowlegdeJob(Job job) {
var message = AcknowledgeJob();
message.received = AcknowledgeJobReceived();
message.received.id = job.id;
message.received.state = job.state;
message.received.ver = job.ver;
message.received.utc = DateTime.now().millisecondsSinceEpoch;
MqttCore.instance.publishPayloadMessage('job', message.toJson());
}
} }
+42 -4
View File
@@ -1,12 +1,14 @@
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:audioplayers/audioplayers.dart'; import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:package_info/package_info.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:stadtbote/main.dart';
import 'package:stadtbote/model/job.dart'; import 'package:stadtbote/model/job.dart';
import 'package:stadtbote/model/log_entry.dart';
import 'package:stadtbote/tools/constants.dart'; import 'package:stadtbote/tools/constants.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
@@ -73,12 +75,44 @@ class Util {
return currentUuid; return currentUuid;
} }
static Future<int> getAppVersion() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
return int.parse(packageInfo.version.replaceAll(".0.0", ""));
}
static _printLongText(String text) {
final pattern = RegExp('.{1,800}'); // 800 is the size of each chunk
pattern.allMatches(text).forEach((match) => debugPrint(match.group(0)));
}
static void _persistLogMessage(String text, LogEntrySeverityEnum severity) async {
var logEntry = LogEntry();
logEntry.time = DateTime.now();
logEntry.text = text;
logEntry.severity = severity;
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.logEntrys.put(logEntry);
});
}
static logInfo(String message) { static logInfo(String message) {
log(message); _printLongText(message);
_persistLogMessage(message, LogEntrySeverityEnum.info);
}
static logDebug(String message) {
_printLongText(message);
_persistLogMessage(message, LogEntrySeverityEnum.debug);
} }
static logException(String message) { static logException(String message) {
log('Exception: $message'); _printLongText(message);
_persistLogMessage(message, LogEntrySeverityEnum.error);
} }
static int fastHash(String string) { static int fastHash(String string) {
@@ -197,7 +231,11 @@ Widget getDefaultButton(String text, Function() onPressed, {Image? image, double
Radius.circular(15), Radius.circular(15),
), ),
), ),
onPressed: onPressed, onPressed: () {
Util.logInfo("Button \"$text\" clicked");
onPressed();
},
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[ children: <Widget>[