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 {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
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
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
+2 -2
View File
@@ -1,9 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.assecutor.stadtbote">
<application
android:label="stadtbote"
android:label="Stadtbote"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/launcher_icon">
<activity
android:name=".MainActivity"
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() {
Future.delayed(const Duration(seconds: 0), () async {
_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;
@@ -88,8 +94,8 @@ class _AcceptedJobsPageState extends State<AcceptedJobsPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime)).toString(),
style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.yellow : Colors.white),
DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime).toLocal()).toString(),
style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.yellow : Colors.transparent),
textAlign: TextAlign.left,
),
Text(
+43 -54
View File
@@ -1,12 +1,13 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:isar/isar.dart';
import 'package:stadtbote/content_views/utils/content_view_widget.dart';
import 'package:stadtbote/content_views/utils/header_info.dart';
import 'package:stadtbote/model/rank.dart';
import 'package:stadtbote/model/ranking.dart';
import 'package:stadtbote/popups/tasks_popups/zip_popup.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 '../main.dart';
@@ -43,21 +44,30 @@ class ApproachAreaPage extends ContentViewWidget {
}
class _ApproachAreaPageState extends State<ApproachAreaPage> {
late List<Rank>? _rankings;
late Ranking? _ranking;
late bool _initCompleted = false;
@override
void initState() {
super.initState();
Future.delayed(const Duration(seconds: 0), () async {
_rankings = await MyApp.isarInstance.ranks.where().findAll();
_ranking = await MyApp.isarInstance.rankings.where().findFirst();
_initCompleted = true;
setState(() {});
});
super.initState();
_initMessages();
}
@override
void deactivate() {
super.deactivate();
MessageService().unsubscribe(Constants.messageTopicRankingUpdated, this);
}
@override
@@ -84,18 +94,16 @@ class _ApproachAreaPageState extends State<ApproachAreaPage> {
List<Widget> _fillColumns() {
List<Widget> columns = [];
if (_rankings != null) {
for (int i = 0; i < _rankings!.length; i++) {
var rank = _rankings![i];
if (_ranking != null) {
for (int i = 0; i < _ranking!.ranks.length; i++) {
var rank = _ranking!.ranks[i];
List<Widget> entries = [];
entries.add(
GestureDetector(
onTap: ()=> {
onTap: () => {
if (i == 0) {
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(
@@ -103,7 +111,7 @@ class _ApproachAreaPageState extends State<ApproachAreaPage> {
margin: const EdgeInsets.all(2),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: i == 0 ? Colors.lightGreen : Colors.white,
color: i == 0 ? Constants.colorPrimary : Colors.white,
border: Border.all(
color: Colors.grey,
width: 0.5,
@@ -114,10 +122,11 @@ class _ApproachAreaPageState extends State<ApproachAreaPage> {
child: Column(children: [
Text(
rank.zip,
style: const TextStyle(fontSize: 20),
style: TextStyle(fontSize: 20, color: (i == 0 ? Colors.white : Colors.black)),
),
Text(
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) {
var message = ZipMessage();
var zipMessage = ZipMessage();
if (mode == ModeEnum.set) {
var position = MyApp.currentPosition;
message.setPos = ZipSetPos();
message.setPos!.zip = zip;
zipMessage.setPos = ZipSetPos();
zipMessage.setPos!.zip = zip;
if (position != null) {
message.setPos!.track = ZipTrack();
message.setPos!.track.time = DateTime.now().toIso8601String();
message.setPos!.track.pos = ZipTrackPos();
message.setPos!.track.pos!.lat = position.latitude;
message.setPos!.track.pos!.long = position.longitude;
message.setPos!.track.pos!.acc = position.accuracy.toInt();
zipMessage.setPos!.track = ZipTrack();
zipMessage.setPos!.track!.time = DateTime.now().toIso8601String();
zipMessage.setPos!.track!.pos = ZipTrackPos();
zipMessage.setPos!.track!.pos!.lat = position.latitude;
zipMessage.setPos!.track!.pos!.long = position.longitude;
zipMessage.setPos!.track!.pos!.acc = position.accuracy.toInt();
}
} else {
message.reqZip = ZipReqZip();
message.reqZip!.id = rank.id;
message.reqZip!.zip = zip;
zipMessage.reqZip = ZipReqZip();
zipMessage.reqZip!.id = rank.id;
zipMessage.reqZip!.zip = zip;
}
MqttCore.instance.publishText("set_location", jsonEncode(message.toJson()));
MqttCore.instance.publishPayloadMessage("rank", zipMessage.toJson());
}
}
/*
private void SendMessage(int columnNumber, string zipNumber)
{
var payloadObject = new JObject();
_initMessages() {
MessageService().subscribe<RankingUpdated>(Constants.messageTopicRankingUpdated, this, (rankingUpdateMessage) async {
_ranking = await MyApp.isarInstance.rankings.where().findFirst();
if (columnNumber == 0)
{
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);
}
*/
setState(() {});
});
}
}
+11 -5
View File
@@ -1,5 +1,3 @@
import 'dart:convert';
import 'package:expandable/expandable.dart';
import 'package:flutter/material.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/fin_task_message.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 '../main.dart';
@@ -53,6 +51,8 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> {
Future.delayed(const Duration(seconds: 0), () async {
_entries = await _createListEntries();
_initMessages();
_initCompleted = true;
setState(() {});
@@ -86,6 +86,12 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> {
var jobs = await MyApp.isarInstance.jobs.filter().stateEqualTo(Constants.stateAssigned).findAll();
for (var job in jobs) {
String remarkString = '';
for (var remark in job.rem) {
remarkString += '$remark\n';
}
remarkString = remarkString.trim();
entries.add(ExpandableNotifier(
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
@@ -119,7 +125,7 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> {
child: Column(
children: [
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,
style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.yellow : Colors.white),
),
@@ -144,7 +150,7 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> {
)),
collapsed: const SizedBox(),
expanded: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
height: 200,
+1 -1
View File
@@ -88,7 +88,7 @@ class _FinishedJobsPageState extends State<FinishedJobsPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
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,
),
Text(
+60 -13
View File
@@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:isar/isar.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/header_info.dart';
import 'package:stadtbote/model/job.dart';
import 'package:stadtbote/model/log_entry.dart';
import 'package:stadtbote/model/message.dart';
import 'package:stadtbote/model/session_status.dart';
import 'package:stadtbote/model/status.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/tools/message_service.dart';
import 'package:stadtbote/tools/messages/job_deleted_message.dart';
import 'package:stadtbote/tools/messages/job_received_message.dart';
import 'package:stadtbote/tools/messages/message_message.dart';
import 'package:stadtbote/tools/messages/refresh_badges_message.dart';
import 'package:stadtbote/tools/messages/session_info_update.dart';
import 'package:badges/badges.dart' as badges;
import 'package:stadtbote/tools/messages/status_info_update.dart';
import 'package:stadtbote/tools/messages/update_badges_message.dart';
import 'package:stadtbote/tools/mqtt_core.dart';
import '../main.dart';
@@ -30,8 +33,8 @@ import '../tools/constants.dart';
import '../tools/util.dart';
class MainPage extends ContentViewWidget {
final ValueNotifier<String> _zipValueNotifier = ValueNotifier("----");
final ValueNotifier<String> sidValueNotifier = ValueNotifier("----");
final ValueNotifier<String> _zipValueNotifier = ValueNotifier("-----");
final ValueNotifier<String> sidValueNotifier = ValueNotifier("-----");
MainPage({super.key});
@@ -233,7 +236,13 @@ class _MainPageState extends State<MainPage> {
getDefaultButton(
_loggedOut ? 'Anmelden' : 'Abmelden',
image: Image.asset(_loggedOut ? 'assets/anmelden.png' : 'assets/abmelden.png', width: 30, height: 30),
() async => {_logout()}),
() async {
if (!kDebugMode) {
_logout(context);
} else {
_test();
}
}),
Expanded(
child: Container(
decoration: BoxDecoration(
@@ -278,7 +287,7 @@ class _MainPageState extends State<MainPage> {
_refreshBadges();
});
MessageService().subscribe<RefreshBadgesMessage>(Constants.messageTopicRefreshBadges, this, (RefreshBadgesMessage refreshMessage) {
MessageService().subscribe<UpdateBadgesMessage>(Constants.messageTopicUpdateBadges, this, (UpdateBadgesMessage message) {
_refreshBadges();
});
}
@@ -312,20 +321,58 @@ class _MainPageState extends State<MainPage> {
}
}
_logout() {
_logout(context) {
if (!_loggedOut) {
_sendLogoutMessage();
Future.delayed(const Duration(seconds: 1), () async {
MqttCore.instance.diconnect();
});
showLogoutAlertDialog(context);
} else {
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() {
+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/main.dart';
import 'package:stadtbote/model/message.dart' as sbmessage;
import 'package:stadtbote/model/message.dart';
import 'package:stadtbote/model/session_status.dart';
import 'package:stadtbote/tools/mqtt_core.dart';
@@ -95,16 +96,17 @@ class _MessagesPageState extends State<MessagesPage> {
void _handleSendPressed(types.PartialText text) async {
var now = DateTime.now();
var message = sbmessage.Message();
message.text = [text.text];
message.from = _sid;
message.subj = '';
message.time = now.toIso8601String();
message.read = true;
message.id = await sbmessage.Message.getNextId();
var message = MessageMessage();
message.mssg = sbmessage.Message();
message.mssg.text = [text.text];
message.mssg.from = _sid;
message.mssg.subj = '';
message.mssg.time = now.toUtc().toIso8601String();
message.mssg.read = true;
message.mssg.id = await sbmessage.Message.getNextId();
MyApp.isarInstance.writeTxnSync(() {
MyApp.isarInstance.messages.putSync(message);
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.messages.put(message.mssg);
});
var json = jsonEncode(message.toJson());
@@ -114,7 +116,7 @@ class _MessagesPageState extends State<MessagesPage> {
_messages.insert(0, types.TextMessage(
author: _user,
createdAt: now.millisecondsSinceEpoch,
id: message.id.toString(),
id: message.mssg.id.toString(),
text: text.text,
));
@@ -132,18 +134,18 @@ class _MessagesPageState extends State<MessagesPage> {
}
text = text.trim();
_messages.insert(0, types.TextMessage(
_messages.add(types.TextMessage(
author: message.from == _sid ? _user : _central,
createdAt: DateTime
.parse(message.time)
.millisecondsSinceEpoch,
createdAt: DateTime.parse(message.time).toLocal().millisecondsSinceEpoch,
id: message.id.toString(),
text: text,
));
_messages.sort((a, b) => b.createdAt! > a.createdAt! ? 1 : 0);
message.read = true;
MyApp.isarInstance.writeTxnSync(() {
MyApp.isarInstance.messages.putSync(message);
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.messages.put(message);
});
}
@@ -181,8 +183,8 @@ class _MessagesPageState extends State<MessagesPage> {
),
const SizedBox(width: 20),
Expanded(
child: getDefaultButton('Ja', () => {
MyApp.isarInstance.writeTxnSync(() => {MyApp.isarInstance.messages.deleteSync(int.parse(message.id))}),
child: getDefaultButton('Ja', () async => {
await MyApp.isarInstance.writeTxnSync(() async => { await MyApp.isarInstance.messages.delete(int.parse(message.id))}),
_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/fin_task_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/message_service.dart';
import 'package:stadtbote/tools/mqtt_core.dart';
@@ -64,11 +65,17 @@ class _TaskListPageState extends State<TaskListPage> {
late List<TaskInfo> _taskList;
List<Uint8List> _photos = [];
late String _commisionNumber;
@override
void initState() {
Future.delayed(const Duration(seconds: 0), () async {
_taskList = await _fetchTaskList();
_commisionNumber = widget.tour.com ?? "";
_initCompleted = true;
setState(() {});
@@ -93,8 +100,21 @@ class _TaskListPageState extends State<TaskListPage> {
child: AbsorbPointer(
absorbing: widget.readOnly,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: steps,
children: [
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,
top: i == 0 ? 40 : 40,
child: Container(
height: i == widget.tour.tasks!.length - 1 ? 0 : 20,
height: i == widget.tour.tasks.length - 1 ? 0 : 20,
width: 6,
color: isTaskActive(i) ? Constants.colorPrimary : Constants.colorPrimaryOpaque,
),
@@ -159,12 +179,16 @@ class _TaskListPageState extends State<TaskListPage> {
),
),
const SizedBox(height: 5),
Text(
taskInfo.additionalText ?? '',
textAlign: TextAlign.left,
style: TextStyle(
color: textColor,
fontSize: 12.0,
SizedBox(
width: MediaQuery.of(context).size.width * 0.7,
child: Text(
taskInfo.additionalText ?? '',
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: textColor,
fontSize: 12.0,
),
),
),
],
@@ -187,7 +211,7 @@ class _TaskListPageState extends State<TaskListPage> {
Future<List<TaskInfo>> _fetchTaskList() async {
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();
if (taskInfo == null) {
taskInfo = TaskInfo();
@@ -268,6 +292,8 @@ class _TaskListPageState extends State<TaskListPage> {
taskInfo.additionalText = comissionNumber;
taskInfo.completed = true;
_commisionNumber = comissionNumber;
setState(() {});
_finishTaskProcessing(taskInfo);
@@ -282,6 +308,7 @@ class _TaskListPageState extends State<TaskListPage> {
answer.codes!.add(barcode);
}
taskInfo.answer = jsonEncode(answer.toJson());
taskInfo.additionalText = "Barcodes gescannt";
taskInfo.completed = true;
@@ -292,13 +319,17 @@ class _TaskListPageState extends State<TaskListPage> {
}
_processTakePhotos(TaskInfo taskInfo) {
showTakePhotosPopup(context, taskInfo, () {
taskInfo.additionalText = "Fotos aufgenommen";
taskInfo.completed = true;
showTakePhotosPopup(context, taskInfo, (List<Uint8List>? photos) {
if (photos != null) {
_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;
taskInfo.answer = jsonEncode(answer.toJson());
taskInfo.additionalText = notice;
taskInfo.completed = true;
_finishTaskProcessing(taskInfo);
@@ -349,23 +381,29 @@ class _TaskListPageState extends State<TaskListPage> {
}
void _processSignature(TaskInfo taskInfo) {
MyApp.suppressAcceptDialog = true;
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]);
Future.delayed(const Duration(seconds: 1), () async {
showSignaturePopup(context, taskInfo, () {
var answer = _createAnswerHeader(taskInfo);
answer.sign = 'A110';
taskInfo.answer = jsonEncode(answer.toJson());
taskInfo.completed = true;
showSignaturePopup(context, taskInfo, (String? signature) {
MyApp.suppressAcceptDialog = false;
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;
}
MqttCore.instance.publishText("fin_task", jsonEncode(message.toJson()));
MqttCore.instance.publishPayloadMessage("job", finTaskMessage.toJson());
}
FinTourTask _createAnswerHeader(TaskInfo taskInfo) {
+27 -10
View File
@@ -63,7 +63,7 @@ class _TourListPageState extends State<TourListPage> {
return Util.getWaitWidget(context);
}
late List<Widget> jobWidgets = _createjobWidgets();
late List<Widget> jobWidgets = _createTourWidgets();
return Padding(
padding: const EdgeInsets.all(18.0),
@@ -124,14 +124,26 @@ class _TourListPageState extends State<TourListPage> {
);
}
List<Widget> _createjobWidgets() {
List<Widget> jobWidgets = [];
List<Widget> _createTourWidgets() {
List<Widget> tourWidgets = [];
JobTour? lastTour;
for (var tour in _tours) {
bool tourActive = false;
if (lastTour == null) {
tourActive = true;
} else {
if (lastTour.state != 0) {
tourActive = true;
}
}
Color color = Colors.transparent;
switch (tour.state) {
case 0:
color = Colors.white;
color = tourActive ? Colors.white : Colors.grey;
break;
case 1:
@@ -143,11 +155,17 @@ class _TourListPageState extends State<TourListPage> {
break;
}
jobWidgets.add(
lastTour = tour;
tourWidgets.add(
ListTile(
contentPadding: const EdgeInsets.all(0),
onTap: () {
_clicked(tour);
if (tourActive) {
_clicked(tour, false);
} else {
_clicked(tour, true);
}
},
title: Container(
decoration: BoxDecoration(
@@ -179,11 +197,10 @@ class _TourListPageState extends State<TourListPage> {
);
}
return jobWidgets;
return tourWidgets;
}
void _clicked(JobTour tour) {
MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView,
arguments: TourDetailsPage(job: widget.job, tour: tour, readOnly: tour.state != 0));
void _clicked(JobTour tour, bool readOnly) {
MessageService().publish<ContentViewWidget>(Constants.messageTopicPushContentView, arguments: TourDetailsPage(job: widget.job, tour: tour, readOnly: readOnly));
}
}
+24 -5
View File
@@ -5,8 +5,10 @@ import 'package:geolocator/geolocator.dart';
import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.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/rank.dart';
import 'package:stadtbote/model/ranking.dart';
import 'package:stadtbote/model/status.dart';
import 'package:stadtbote/model/task_info.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/message_service.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/utils/content_view_widget.dart';
import 'content_views/utils/widget_stack.dart';
@@ -34,7 +37,9 @@ Future<void> main() async {
JobSchema,
TaskInfoSchema,
MessageSchema,
RankSchema
RankingSchema,
EnqueuedMessageSchema,
LogEntrySchema
], directory: dir.path);
runZonedGuarded(() {}, (error, stackTrace) {
@@ -60,6 +65,8 @@ class MyApp extends StatelessWidget {
static Position? currentPosition;
static bool suppressAcceptDialog = false;
@override
Widget build(BuildContext context) {
return MaterialApp(
@@ -149,6 +156,8 @@ class _MainState extends State<Main> with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _animation;
bool _dialogOpened = false;
@override
void initState() {
super.initState();
@@ -417,8 +426,18 @@ class _MainState extends State<Main> with SingleTickerProviderStateMixin {
}
void _jobReceived(Job job) async {
if (job.state == 0) {
await showAcceptJobsPopup(context, await MyApp.isarInstance.jobs.filter().stateEqualTo(0).findAll());
if (!MyApp.suppressAcceptDialog) {
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 comp;
late String person;
late String phone;
late String? phone;
late String street;
late String city;
late String com;
late String? com;
late TourPosition? pos;
late String rem;
late List<TourTask>? tasks;
+60 -18
View File
@@ -94,11 +94,21 @@ int _jobTourEstimateSize(
) {
var bytesCount = offsets.last;
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.mode.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;
if (value != null) {
@@ -164,12 +174,12 @@ JobTour _jobTourDeserialize(
) {
final object = JobTour();
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.id = reader.readLong(offsets[3]);
object.mode = reader.readString(offsets[4]);
object.person = reader.readString(offsets[5]);
object.phone = reader.readString(offsets[6]);
object.phone = reader.readStringOrNull(offsets[6]);
object.pos = reader.readObjectOrNull<TourPosition>(
offsets[7],
TourPositionSchema.deserialize,
@@ -198,7 +208,7 @@ P _jobTourDeserializeProp<P>(
case 0:
return (reader.readString(offset)) as P;
case 1:
return (reader.readString(offset)) as P;
return (reader.readStringOrNull(offset)) as P;
case 2:
return (reader.readString(offset)) as P;
case 3:
@@ -208,7 +218,7 @@ P _jobTourDeserializeProp<P>(
case 5:
return (reader.readString(offset)) as P;
case 6:
return (reader.readString(offset)) as P;
return (reader.readStringOrNull(offset)) as P;
case 7:
return (reader.readObjectOrNull<TourPosition>(
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(
String value, {
String? value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
@@ -381,7 +407,7 @@ extension JobTourQueryFilter
}
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comGreaterThan(
String value, {
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
@@ -396,7 +422,7 @@ extension JobTourQueryFilter
}
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comLessThan(
String value, {
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
@@ -411,8 +437,8 @@ extension JobTourQueryFilter
}
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> comBetween(
String lower,
String upper, {
String? lower,
String? upper, {
bool includeLower = true,
bool includeUpper = 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(
String value, {
String? value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
@@ -953,7 +995,7 @@ extension JobTourQueryFilter
}
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneGreaterThan(
String value, {
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
@@ -968,7 +1010,7 @@ extension JobTourQueryFilter
}
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneLessThan(
String value, {
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
@@ -983,8 +1025,8 @@ extension JobTourQueryFilter
}
QueryBuilder<JobTour, JobTour, QAfterFilterCondition> phoneBetween(
String lower,
String upper, {
String? lower,
String? upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
@@ -1579,10 +1621,10 @@ JobTour _$JobTourFromJson(Map<String, dynamic> json) => JobTour()
..mode = json['mode'] as String
..comp = json['comp'] as String
..person = json['person'] as String
..phone = json['phone'] as String
..phone = json['phone'] as String?
..street = json['street'] as String
..city = json['city'] as String
..com = json['com'] as String
..com = json['com'] as String?
..pos = json['pos'] == null
? null
: 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';
@JsonSerializable()
class MessageMessage {
late Message mssg;
MessageMessage();
factory MessageMessage.fromJson(Map<String, dynamic> json) => _$MessageMessageFromJson(json);
Map<String, dynamic> toJson() => _$MessageMessageToJson(this);
}
@collection
@JsonSerializable()
class Message {
+9
View File
@@ -1098,6 +1098,15 @@ extension MessageQueryProperty
// 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()
..id = json['id'] as int
..time = json['time'] as String
+174 -124
View File
@@ -1,5 +1,3 @@
import 'dart:convert';
import 'package:expandable/expandable.dart';
import 'package:flutter/material.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/protocoll_messages/fin_task_message.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/util.dart';
import 'package:badges/badges.dart' as badges;
@@ -20,138 +16,192 @@ Future<void> showAcceptJobsPopup(BuildContext context, List<Job> jobs) async {
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
shadowColor: Colors.transparent,
backgroundColor: Colors.white,
content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
if (jobsSet.isEmpty) {
Navigator.of(context).pop();
}
return WillPopScope(
onWillPop: () async {
MessageService().unsubscribe(Constants.messageTopicJobDeleted, jobsMap);
MessageService().unsubscribe(Constants.messageTopicJobReceived, jobsMap);
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: jobsSet.length,
itemBuilder: (_, i) {
var job = jobsSet.toList()[i];
Navigator.of(context).pop();
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(
position: badges.BadgePosition.topEnd(top: -13, end: -5),
showBadge: false,
badgeContent: const Text(
'Neu',
style: TextStyle(
color: Colors.white,
fontSize: 18.0,
onFinished();
return true;
},
child: AlertDialog(
contentPadding: EdgeInsets.zero,
shadowColor: Colors.transparent,
backgroundColor: Colors.white,
content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
if (jobsMap.isEmpty) {
Navigator.of(context).pop();
onFinished();
}
MessageService().unsubscribe(Constants.messageTopicJobDeleted, jobsMap);
MessageService().unsubscribe(Constants.messageTopicJobReceived, jobsMap);
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,
),
),
),
badgeStyle: badges.BadgeStyle(
shape: badges.BadgeShape.square,
badgeColor: Constants.colorPrimary,
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: [
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),
),
child: badges.Badge(
position: badges.BadgePosition.topEnd(top: -13, end: -5),
showBadge: false,
badgeContent: const Text(
'Neu',
style: TextStyle(
color: Colors.white,
fontSize: 18.0,
),
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)),
SizedBox(width: double.infinity, child: Text(job.tours[0].street, textAlign: TextAlign.left)),
SizedBox(width: double.infinity, child: Text(job.tours[0].city, textAlign: TextAlign.left)),
Row(
),
badgeStyle: badges.BadgeStyle(
shape: badges.BadgeShape.square,
badgeColor: Constants.colorPrimary,
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: [
Image.asset("assets/${mapVehicleTypeToImageName(job.vhtId)}", width: 60, height: 60),
const SizedBox(width: 10),
Text(mapVehicleTypeToText(job.vhtId)),
],
),
const SizedBox(height: 10),
ScrollOnExpand(
scrollOnExpand: true,
scrollOnCollapse: false,
child: ExpandablePanel(
theme: const ExpandableThemeData(
headerAlignment: ExpandablePanelHeaderAlignment.center,
tapBodyToCollapse: true,
SizedBox(
width: double.infinity,
child: Text(
DateFormat('dd.MM.yyyy HH:mm').format(DateTime.parse(job.ordertime).toLocal()).toString(),
textAlign: TextAlign.left,
style: TextStyle(backgroundColor: isJobInFuture(job) ? Colors.yellow : Colors.transparent),
),
),
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(job.rem),
),
),
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)),
SizedBox(width: double.infinity, child: Text(job.tours[0].street, textAlign: TextAlign.left)),
SizedBox(width: double.infinity, child: Text(job.tours[0].city, textAlign: TextAlign.left)),
Row(
children: [
Image.asset("assets/${mapVehicleTypeToImageName(job.vhtId)}", width: 60, height: 60),
const SizedBox(width: 10),
Text(mapVehicleTypeToText(job.vhtId)),
],
),
),
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';
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 += "GPS-Status: ${MyApp.currentPosition != null ? MyApp.currentPosition!.timestamp.toString() : "Unbekannt"}\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_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:stadtbote/tools/util.dart';
import '../model/job_tour.dart';
@@ -27,12 +28,16 @@ showMapPopup(BuildContext context, JobTour currentTour, List<JobTour> tourList)
tourWidgets.add(
GestureDetector(
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;
streamController[tour.sort]!.sink.add(true);
currentTour = tour;
streamController[tour.sort]!.sink.add(true);
} else {
showAlertDialog(context, 'Information', 'Es liegt keine Position für diese Station vor');
}
},
child: SizedBox(
width: 70,
@@ -87,17 +92,20 @@ showMapPopup(BuildContext context, JobTour currentTour, List<JobTour> tourList)
List<Marker> markers = [];
for (var tour in tourList) {
markers.add(Marker(
builder: (context) => const Icon(Icons.person_pin_circle, size: 56, color: Colors.blue),
point: LatLng(tour.pos!.lat, tour.pos!.long)));
if (tour.pos != null) {
markers.add(Marker(
builder: (context) => const Icon(Icons.person_pin_circle, size: 56, color: Colors.blue),
point: LatLng(tour.pos!.lat, tour.pos!.long)));
}
}
return Container(
padding: const EdgeInsets.fromLTRB(30, 0, 30, 0),
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
key: GlobalKey(),
height: MediaQuery.of(context).size.height * 0.6,
child: Container(
height: 100,
width: MediaQuery.of(context).size.width * 1,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
@@ -40,10 +40,15 @@ showReceiptGiverPopup(BuildContext context, TaskInfo taskInfo, Function(String)
controller: textEditingController,
autofocus: true),
const SizedBox(height: 20),
getDefaultButton('Übernehmen', () => {
Navigator.of(context).pop(),
getDefaultButton('Übernehmen', () {
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/tools/util.dart';
showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function() onFinished) async {
showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function(String?) onFinished) async {
await showDialog(
context: 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,
shadowColor: Colors.transparent,
backgroundColor: Colors.white,
@@ -18,6 +26,24 @@ showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function() onFinishe
var popupHeight = MediaQuery.of(context).size.height * 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(
key: GlobalKey(),
height: popupHeight,
@@ -46,14 +72,19 @@ showSignaturePopup(BuildContext context, TaskInfo taskInfo, Function() onFinishe
),
),
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:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image/image.dart' as imageLib;
import 'package:stadtbote/model/task_info.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<Widget> imageWidgetsList = [];
@@ -19,22 +20,35 @@ Future<void> showTakePhotosPopup(BuildContext context, TaskInfo taskInfo, Functi
backgroundColor: Colors.white,
content: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
void capturePhoto() async {
var photo = await Util.capturePhoto();
try {
var photo = await Util.capturePhoto();
if (photo != null) {
var imageData = await photo.readAsBytes();
photo.delete();
if (photo != null) {
var fullsizeImageData = await photo.readAsBytes();
imageDataList.add(imageData);
imageLib.Image? image = imageLib.decodeImage(fullsizeImageData);
imageWidgetsList.add(GestureDetector(
onTap: () {},
child: Image.memory(imageData),
));
if (image != null) {
var thumbnail = imageLib.copyResize(image, width: 800);
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,
() => {
if (imageDataList.length == taskInfo.task.min! && imageDataList.length <= taskInfo.task.max!)
{Navigator.of(context).pop(), onFinished()}
{Navigator.of(context).pop(), onFinished(imageDataList)}
else
{showAlertDialog(context, 'Fehler', 'Sie müssen mindestens ${taskInfo.task.min} Foto(s) aufnehmen')}
})
@@ -20,7 +20,8 @@ class Reaction {
@JsonSerializable()
@JsonSerializable()class Track {
late String time;
late FinTaskPos pos;
FinTaskPos? pos;
Track();
@@ -21,7 +21,9 @@ Map<String, dynamic> _$ReactionToJson(Reaction instance) => <String, dynamic>{
Track _$TrackFromJson(Map<String, dynamic> json) => Track()
..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>{
'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 FinTaskPos? pos;
FinTaskPos? pos;
Task();
+2 -2
View File
@@ -23,7 +23,7 @@ class FinTour {
late String com;
late Track track;
Track? track;
late List<FinTourTask> tasks;
@@ -49,7 +49,7 @@ class FinTourTask {
List<String>? codes;
late FinTaskPos pos;
FinTaskPos? pos;
FinTourTask();
@@ -18,7 +18,9 @@ Map<String, dynamic> _$FinTourMessageToJson(FinTourMessage instance) =>
FinTour _$FinTourFromJson(Map<String, dynamic> json) => FinTour()
..trId = json['tr_id'] as int
..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>)
.map((e) => FinTourTask.fromJson(e as Map<String, dynamic>))
.toList();
@@ -37,7 +39,9 @@ FinTourTask _$FinTourTaskFromJson(Map<String, dynamic> json) => FinTourTask()
..code = json['code'] as int?
..sign = json['sign'] as String?
..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) =>
<String, dynamic>{
+19 -6
View File
@@ -4,13 +4,9 @@ part 'logout_message.g.dart';
@JsonSerializable()
class LogoutMessage {
late String time;
late bool logout;
late double lat;
late double long;
late int acc;
LogoutMessagePosition? pos;
LogoutMessage();
@@ -19,3 +15,20 @@ class LogoutMessage {
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()
class TrackMessage {
late TrackPosition pos;
TrackPosition? pos;
TrackMessage();
+3 -1
View File
@@ -7,7 +7,9 @@ part of 'track_message.dart';
// **************************************************************************
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) =>
<String, dynamic>{
@@ -10,7 +10,7 @@ class TrackStationMessage {
late String time;
late FinTaskPos? pos;
FinTaskPos? pos;
TrackStationMessage();
+2 -2
View File
@@ -61,7 +61,7 @@ class ZipReqZip {
class ZipSetPos {
late String zip;
late ZipTrack track;
ZipTrack? track;
ZipSetPos();
@@ -75,7 +75,7 @@ class ZipSetPos {
class ZipTrack {
late String time;
late ZipTrackPos? pos;
ZipTrackPos? pos;
ZipTrack();
+34 -14
View File
@@ -298,9 +298,13 @@ int _zipSetPosEstimateSize(
Map<Type, List<int>> allOffsets,
) {
var bytesCount = offsets.last;
bytesCount += 3 +
ZipTrackSchema.estimateSize(
object.track, allOffsets[ZipTrack]!, allOffsets);
{
final value = object.track;
if (value != null) {
bytesCount += 3 +
ZipTrackSchema.estimateSize(value, allOffsets[ZipTrack]!, allOffsets);
}
}
bytesCount += 3 + object.zip.length * 3;
return bytesCount;
}
@@ -328,11 +332,10 @@ ZipSetPos _zipSetPosDeserialize(
) {
final object = ZipSetPos();
object.track = reader.readObjectOrNull<ZipTrack>(
offsets[0],
ZipTrackSchema.deserialize,
allOffsets,
) ??
ZipTrack();
offsets[0],
ZipTrackSchema.deserialize,
allOffsets,
);
object.zip = reader.readString(offsets[1]);
return object;
}
@@ -346,11 +349,10 @@ P _zipSetPosDeserializeProp<P>(
switch (propertyId) {
case 0:
return (reader.readObjectOrNull<ZipTrack>(
offset,
ZipTrackSchema.deserialize,
allOffsets,
) ??
ZipTrack()) as P;
offset,
ZipTrackSchema.deserialize,
allOffsets,
)) as P;
case 1:
return (reader.readString(offset)) as P;
default:
@@ -360,6 +362,22 @@ P _zipSetPosDeserializeProp<P>(
extension ZipSetPosQueryFilter
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(
String value, {
bool caseSensitive = true,
@@ -1046,7 +1064,9 @@ Map<String, dynamic> _$ZipReqZipToJson(ZipReqZip instance) => <String, dynamic>{
ZipSetPos _$ZipSetPosFromJson(Map<String, dynamic> json) => ZipSetPos()
..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>{
'zip': instance.zip,
+1 -1
View File
@@ -11,7 +11,7 @@ class Constants {
static const String messageTopicRankingUpdated = "ranking_updated";
static const String messageTopicJobReceived = "job_received";
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 messageTopicPushContentView = "push_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:convert';
import 'dart:io';
import 'dart:math';
import 'package:archive/archive.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:isar/isar.dart';
import 'package:mqtt_client/mqtt_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/protocoll_messages/acknowledge_job.dart';
import 'package:stadtbote/protocoll_messages/bootstrap_request.dart';
import 'package:stadtbote/protocoll_messages/bootstrap_response_payload.dart';
import 'package:stadtbote/protocoll_messages/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/message.dart';
import 'package:stadtbote/protocoll_messages/device_object.dart';
import 'package:stadtbote/protocoll_messages/job_del_message.dart';
import 'package:stadtbote/protocoll_messages/payload_container.dart';
import 'package:stadtbote/protocoll_messages/start_session_message.dart';
import 'package:stadtbote/protocoll_messages/sync_jobs_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
import 'package:typed_data/typed_buffers.dart';
import 'package:http/http.dart' as http;
import 'package:uuid/uuid.dart';
import '../main.dart';
import '../model/session_status.dart';
@@ -49,7 +56,6 @@ class MqttCore {
late String _brokerUri;
late int _brokerPort;
late String _fromServerTopic;
late String _clientId;
late String _toServerTopic;
late MqttServerClient _mqttClient;
@@ -94,7 +100,6 @@ class MqttCore {
_mqttClient.keepAlivePeriod = 20;
_mqttClient.autoReconnect = false;
_mqttClient.onDisconnected = _clientDisconnected;
_mqttClient.connectionMessage = MqttConnectMessage()
.withClientIdentifier(await Util.getAppUuid())
.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 {
var buffer = Uint8Buffer();
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");
publishText(_toServerTopic, json);
} catch (e) {
Util.logException(e.toString());
_enqueueMessage(_toServerTopic, jsonEncode(payloadContainer.toJson()));
}
}
void _setupSubscriptions() async {
Util.logInfo('_setupSubscriptions called');
_mqttClient.updates?.listen((List<MqttReceivedMessage<MqttMessage>> messages) {
_mqttClient.updates?.listen((List<MqttReceivedMessage<MqttMessage>> c) {
try {
for (var mqttMessage in messages) {
final MqttPublishMessage message = mqttMessage.payload as MqttPublishMessage;
String payload = utf8.decode(MqttPublishPayload.bytesToStringAsString(message.payload.message).codeUnits);
var topic = message.variableHeader?.topicName;
final MqttPublishMessage message = c[0].payload as MqttPublishMessage;
String payload = utf8.decode(MqttPublishPayload.bytesToStringAsString(message.payload.message).codeUnits);
var topic = message.variableHeader?.topicName;
if (topic!.endsWith(_clientId)) {
Util.logInfo('message received');
Util.logInfo('topic: $topic');
Util.logInfo('mesage: $payload');
Util.logInfo('message received\ntopic: $topic\nmessage: $payload');
var topicArray = topic.split('/');
var messageType = topicArray[3];
Map<String, dynamic> messageData = jsonDecode(payload);
switch(messageType) {
case 'session':
_sessionMessageReceived(jsonDecode(payload));
break;
for (var entry in messageData.keys) {
if (entry == 'payload') {
var payload = messageData[entry];
for (var payloadEntry in payload.keys) {
var payloadData = payload[payloadEntry];
case 'status':
_statusMessageReceived(jsonDecode(payload));
break;
switch(payloadEntry) {
case 'session':
_sessionMessageReceived(payloadData);
break;
case 'ranking':
_rankingMessageReceived(jsonDecode(payload));
break;
case 'status':
_statusMessageReceived(payloadData);
break;
case 'job':
_jobMessageReceived(jsonDecode(payload));
break;
case 'ranks':
_rankingMessageReceived(payloadData);
break;
case 'job_del':
_jobDeleteReceived(jsonDecode(payload));
break;
case 'jobs':
_jobMessageReceived(payloadData);
break;
case 'sync_request':
_syncRequestReceived(jsonDecode(payload));
break;
case 'job_del':
_jobDeleteReceived(payloadData);
break;
case "mssg":
_messageMessageReceived(payload);
break;
case 'sync_request':
_syncRequestReceived(payloadData);
break;
default:
Util.logInfo('Unknown topic: $messageType');
break;
case "mssg":
_messageMessageReceived(payloadData);
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(topic, MqttQos.exactlyOnce);
Util.logInfo('subscribed to topic: $topic');
_mqttClient.subscribe(_fromServerTopic, MqttQos.exactlyOnce);
Util.logInfo('subscribed to topic: $_fromServerTopic');
MessageService().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.connected));
}
@@ -216,7 +243,9 @@ class MqttCore {
await _sendSyncMessage();
var sessionStatusMessage = SessionStatus.fromJson(payloadData);
await _sendEnqueuedMessages();
var sessionStatusMessage = SessionStatus.fromJson(payloadData['status']);
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.sessionStatus.clear();
@@ -240,42 +269,52 @@ class MqttCore {
}
void _rankingMessageReceived(List<dynamic> payloadData) async {
for (var entry in payloadData) {
var rank = Rank.fromJson(entry);
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.ranks.put(rank);
});
}
Map<String, dynamic> rankingMap = {};
rankingMap["ranks"] = payloadData;
var ranking = Ranking.fromJson(rankingMap);
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.rankings.put(ranking);
});
MessageService().publish<RankingUpdated>(Constants.messageTopicRankingUpdated, arguments: RankingUpdated());
}
void _jobMessageReceived(payloadData) async {
Job newJob = Job.fromJson(payloadData);
for (var foundJobData in payloadData) {
Job newJob = Job.fromJson(foundJobData);
MyApp.isarInstance.writeTxnSync(() async {
MyApp.isarInstance.jobs.putSync(newJob);
});
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.jobs.put(newJob);
});
if (newJob.state == Constants.stateAssigned) {
if (newJob.global) {
await Util.playMp3('aaa.mp3');
} else {
await Util.playMp3('job_received.mp3');
if (newJob.state == Constants.stateAssigned) {
if (newJob.global) {
await Util.playMp3('aaa.mp3');
} else {
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 {
var jobDelMessage = JobDelMessage.fromJson(payloadData);
void _jobDeleteReceived(List<dynamic> payloadData) async {
Map<String, dynamic> map = {};
map["jobDel"] = payloadData;
var jobDelMessage = JobDelMessage.fromJson(map);
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.jobs.delete(jobDelMessage.id);
});
for(var jobId in jobDelMessage.jobDel) {
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.jobs.delete(jobId);
});
MessageService().publish<JobDeletedMessage>(Constants.messageTopicJobDeleted, arguments: JobDeletedMessage(id: jobDelMessage.id));
}
@@ -334,19 +373,22 @@ class MqttCore {
void _processBootstrap() async {
try {
String? responseText = "";
var deviceInfoPlugin = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo;
BaseDeviceInfo deviceInfo = await deviceInfoPlugin.deviceInfo;
var deviceObject = DeviceObject();
deviceObject.manufacturer = "sven";
deviceObject.model = "emulator";
deviceObject.os = "hat es";
deviceObject.osVer = "0.0";
deviceObject.manufacturer = deviceInfo.data['manufacturer'];
deviceObject.model = deviceInfo.data['model'];
deviceObject.os = androidInfo.version.release;
deviceObject.osVer = androidInfo.version.sdkInt.toString();
var handshakeMessage = BootstrapRequest();
handshakeMessage.app = "sb";
handshakeMessage.mqttClientId = await Util.getAppUuid();
handshakeMessage.deviceObject = deviceObject;
handshakeMessage.ver = 200;
handshakeMessage.ver = await Util.getAppVersion();
//var jsonMap = handshakeMessage.toJson();
//var json = jsonEncode(jsonMap);
@@ -405,12 +447,12 @@ class MqttCore {
if (answer != null) {
var trackMessage = TrackMessage();
trackMessage.pos = TrackPosition();
trackMessage.pos.time = answer.timestamp.toIso8601String();
trackMessage.pos.lat = answer.latitude;
trackMessage.pos.long = answer.longitude;
trackMessage.pos.acc = answer.accuracy.toInt();
trackMessage.pos!.time = position.timestamp.toIso8601String();
trackMessage.pos!.lat = position.latitude;
trackMessage.pos!.long = position.longitude;
trackMessage.pos!.acc = position.accuracy.toInt();
publishText("track", jsonEncode(answer.toJson()));
publishPayloadMessage("track", trackMessage.toJson());
}
});
}
@@ -421,4 +463,42 @@ class MqttCore {
_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 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:package_info/package_info.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:stadtbote/main.dart';
import 'package:stadtbote/model/job.dart';
import 'package:stadtbote/model/log_entry.dart';
import 'package:stadtbote/tools/constants.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:uuid/uuid.dart';
@@ -73,12 +75,44 @@ class Util {
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) {
log(message);
_printLongText(message);
_persistLogMessage(message, LogEntrySeverityEnum.info);
}
static logDebug(String message) {
_printLongText(message);
_persistLogMessage(message, LogEntrySeverityEnum.debug);
}
static logException(String message) {
log('Exception: $message');
_printLongText(message);
_persistLogMessage(message, LogEntrySeverityEnum.error);
}
static int fastHash(String string) {
@@ -197,7 +231,11 @@ Widget getDefaultButton(String text, Function() onPressed, {Image? image, double
Radius.circular(15),
),
),
onPressed: onPressed,
onPressed: () {
Util.logInfo("Button \"$text\" clicked");
onPressed();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[