ObjectBox

This commit is contained in:
Sven committed 2025-10-23 11:48:22 +02:00
1 parent f8317be627
commit 809bffc7a2
9 files changed
+125 -42

No files matched your search

+1 -1
View File
@@ -76,7 +76,7 @@ class _AcceptedJobsPageState extends State<AcceptedJobsPage>
for (var job in _jobs) { for (var job in _jobs) {
var bottomText = var bottomText =
"${job.id}\n${job.tours[0].comp}\n${job.tours[0].street}\n${job.tours[0].city}"; "${job.externalId}\n${job.tours[0].comp}\n${job.tours[0].street}\n${job.tours[0].city}";
if (job.rem.trim().isNotEmpty) { if (job.rem.trim().isNotEmpty) {
bottomText += "\n\n${job.rem.trim()}"; bottomText += "\n\n${job.rem.trim()}";
} }
+7 -7
View File
@@ -143,7 +143,7 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> with ProducerMixin,
), ),
], ],
), ),
Text('Auftragsnummer: ${job.id}'), Text('Auftragsnummer: ${job.externalId}'),
Text(job.tours[0].comp), Text(job.tours[0].comp),
Text(job.tours[0].street), Text(job.tours[0].street),
Text(job.tours[0].city), Text(job.tours[0].city),
@@ -187,9 +187,9 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> with ProducerMixin,
Row(children: [ Row(children: [
Expanded( Expanded(
child: getDefaultButton(!job.global ? 'Ablehnen' : 'Ignorieren', () { child: getDefaultButton(!job.global ? 'Ablehnen' : 'Ignorieren', () {
job.sendMessage( sendMessage(
routingKey: Constants.messageTopicRemoveJob, routingKey: Constants.messageTopicRemoveJob,
payload: RemoveJobMessage(id: job.id), payload: RemoveJobMessage(id: job.externalId),
); );
_sendAnswer(job, !job.global ? 2 : 3); _sendAnswer(job, !job.global ? 2 : 3);
@@ -202,9 +202,9 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> with ProducerMixin,
const SizedBox(width: 20), const SizedBox(width: 20),
Expanded( Expanded(
child: getDefaultButton('Annehmen', () { child: getDefaultButton('Annehmen', () {
job.sendMessage( sendMessage(
routingKey: Constants.messageTopicRemoveJob, routingKey: Constants.messageTopicRemoveJob,
payload: RemoveJobMessage(id: job.id), payload: RemoveJobMessage(id: job.externalId),
); );
_sendAnswer(job, 1); _sendAnswer(job, 1);
@@ -231,7 +231,7 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> with ProducerMixin,
var currentPosition = await MyApp.getCurrentPosition(); var currentPosition = await MyApp.getCurrentPosition();
var message = Reaction(); var message = Reaction();
message.id = job.id; message.id = job.externalId; // Use external ID for network communication
message.ver = job.ver.toString(); message.ver = job.ver.toString();
message.item = item; message.item = item;
message.track = Track(); message.track = Track();
@@ -244,7 +244,7 @@ class _AssignedJobsPageState extends State<AssignedJobsPage> with ProducerMixin,
sendMessage( sendMessage(
routingKey: Constants.messageTopicRemoveState0JobFromMap, routingKey: Constants.messageTopicRemoveState0JobFromMap,
payload: RemoveState0JobFromMapMessage(jobId: job.id), payload: RemoveState0JobFromMapMessage(jobId: job.externalId), // Use external ID
); );
sendMessage( sendMessage(
+1 -1
View File
@@ -69,7 +69,7 @@ class _FinishedJobsPageState extends State<FinishedJobsPage>
for (var job in _jobs) { for (var job in _jobs) {
var bottomText = var bottomText =
"${job.id}\n${job.tours[0].comp}\n${job.tours[0].street}\n${job.tours[0].city}"; "${job.externalId}\n${job.tours[0].comp}\n${job.tours[0].street}\n${job.tours[0].city}";
if (job.rem.trim().isNotEmpty) { if (job.rem.trim().isNotEmpty) {
bottomText += "\n\n${job.rem.trim()}"; bottomText += "\n\n${job.rem.trim()}";
} }
+16 -5
View File
@@ -1,5 +1,5 @@
import 'package:objectbox/objectbox.dart';
import 'package:stadtbote/main.dart'; import 'package:stadtbote/main.dart';
import 'package:stadtbote/objectbox.g.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
@Entity() @Entity()
@@ -7,6 +7,10 @@ class ChatMessage {
@Id() @Id()
int id = 0; int id = 0;
// External ID from server
@Unique()
late int externalId;
late int time; late int time;
late String from; late String from;
@@ -21,7 +25,8 @@ class ChatMessage {
factory ChatMessage.fromJson(Map<String, dynamic> json) { factory ChatMessage.fromJson(Map<String, dynamic> json) {
final message = ChatMessage(); final message = ChatMessage();
message.id = json['id'] as int? ?? 0; message.id = 0; // Let ObjectBox assign the ID
message.externalId = json['id'] as int; // Store external ID separately
message.time = json['time'] as int; message.time = json['time'] as int;
message.from = json['from'] as String; message.from = json['from'] as String;
message.subj = json['subj'] as String; message.subj = json['subj'] as String;
@@ -32,7 +37,7 @@ class ChatMessage {
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'id': id, 'id': externalId, // Use external ID for JSON
'time': time, 'time': time,
'from': from, 'from': from,
'subj': subj, 'subj': subj,
@@ -42,10 +47,16 @@ class ChatMessage {
} }
static Future<ChatMessage> mergeFromJson(Map<String, dynamic> json) async { static Future<ChatMessage> mergeFromJson(Map<String, dynamic> json) async {
var availableMessage = MyApp.objectBoxStore.box<ChatMessage>().get(json["id"] as int); final box = MyApp.objectBoxStore.box<ChatMessage>();
final externalId = json["id"] as int;
// Find message by external ID
final query = box.query(ChatMessage_.externalId.equals(externalId)).build();
var availableMessage = query.findFirst();
query.close();
if (availableMessage != null) { if (availableMessage != null) {
availableMessage.id = json["id"]; availableMessage.externalId = json["id"];
availableMessage.time = json["time"]; availableMessage.time = json["time"];
availableMessage.from = json["from"]; availableMessage.from = json["from"];
availableMessage.subj = json["subj"]; availableMessage.subj = json["subj"];
+8 -4
View File
@@ -1,13 +1,16 @@
import 'dart:convert'; import 'dart:convert';
import 'package:dart_mq/dart_mq.dart';
import 'package:objectbox/objectbox.dart'; import 'package:objectbox/objectbox.dart';
import 'package:stadtbote/model/job_tour.dart'; import 'package:stadtbote/model/job_tour.dart';
@Entity() @Entity()
class Job with ProducerMixin { class Job {
@Id() @Id()
int id = 0; int id = 0;
// External ID from server
@Unique()
late int externalId;
late String ver; late String ver;
late int state; late int state;
String? crFilter; String? crFilter;
@@ -35,7 +38,8 @@ class Job with ProducerMixin {
factory Job.fromJson(Map<String, dynamic> json) { factory Job.fromJson(Map<String, dynamic> json) {
final job = Job(); final job = Job();
job.id = json['id'] as int? ?? 0; job.id = 0; // Let ObjectBox assign the ID
job.externalId = json['id'] as int; // Store external ID separately
job.ver = json['ver'] as String; job.ver = json['ver'] as String;
job.state = json['state'] as int; job.state = json['state'] as int;
job.crFilter = json['cr_filter'] as String?; job.crFilter = json['cr_filter'] as String?;
@@ -53,7 +57,7 @@ class Job with ProducerMixin {
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'id': id, 'id': externalId, // Use external ID for JSON
'ver': ver, 'ver': ver,
'state': state, 'state': state,
'cr_filter': crFilter, 'cr_filter': crFilter,
+17 -3
View File
@@ -34,7 +34,7 @@
}, },
{ {
"id": "3:808686831791135454", "id": "3:808686831791135454",
"lastPropertyId": "11:3214338916427673014", "lastPropertyId": "12:5320049580625017283",
"name": "Job", "name": "Job",
"properties": [ "properties": [
{ {
@@ -92,6 +92,13 @@
"id": "11:3214338916427673014", "id": "11:3214338916427673014",
"name": "toursJson", "name": "toursJson",
"type": 9 "type": 9
},
{
"id": "12:5320049580625017283",
"name": "externalId",
"type": 6,
"flags": 40,
"indexId": "1:2108836818156887439"
} }
], ],
"relations": [] "relations": []
@@ -297,7 +304,7 @@
}, },
{ {
"id": "11:8606238749478059367", "id": "11:8606238749478059367",
"lastPropertyId": "6:7798301556204918939", "lastPropertyId": "7:4056540326670791484",
"name": "ChatMessage", "name": "ChatMessage",
"properties": [ "properties": [
{ {
@@ -330,6 +337,13 @@
"id": "6:7798301556204918939", "id": "6:7798301556204918939",
"name": "read", "name": "read",
"type": 1 "type": 1
},
{
"id": "7:4056540326670791484",
"name": "externalId",
"type": 6,
"flags": 40,
"indexId": "2:428171949166894655"
} }
], ],
"relations": [] "relations": []
@@ -370,7 +384,7 @@
} }
], ],
"lastEntityId": "12:4865606913057136676", "lastEntityId": "12:4865606913057136676",
"lastIndexId": "0:0", "lastIndexId": "2:428171949166894655",
"lastRelationId": "0:0", "lastRelationId": "0:0",
"lastSequenceId": "0:0", "lastSequenceId": "0:0",
"modelVersion": 5, "modelVersion": 5,
+44 -6
View File
@@ -65,7 +65,7 @@ final _entities = <obx_int.ModelEntity>[
obx_int.ModelEntity( obx_int.ModelEntity(
id: const obx_int.IdUid(3, 808686831791135454), id: const obx_int.IdUid(3, 808686831791135454),
name: 'Job', name: 'Job',
lastPropertyId: const obx_int.IdUid(11, 3214338916427673014), lastPropertyId: const obx_int.IdUid(12, 5320049580625017283),
flags: 0, flags: 0,
properties: <obx_int.ModelProperty>[ properties: <obx_int.ModelProperty>[
obx_int.ModelProperty( obx_int.ModelProperty(
@@ -134,6 +134,13 @@ final _entities = <obx_int.ModelEntity>[
type: 9, type: 9,
flags: 0, flags: 0,
), ),
obx_int.ModelProperty(
id: const obx_int.IdUid(12, 5320049580625017283),
name: 'externalId',
type: 6,
flags: 40,
indexId: const obx_int.IdUid(1, 2108836818156887439),
),
], ],
relations: <obx_int.ModelRelation>[], relations: <obx_int.ModelRelation>[],
backlinks: <obx_int.ModelBacklink>[], backlinks: <obx_int.ModelBacklink>[],
@@ -375,7 +382,7 @@ final _entities = <obx_int.ModelEntity>[
obx_int.ModelEntity( obx_int.ModelEntity(
id: const obx_int.IdUid(11, 8606238749478059367), id: const obx_int.IdUid(11, 8606238749478059367),
name: 'ChatMessage', name: 'ChatMessage',
lastPropertyId: const obx_int.IdUid(6, 7798301556204918939), lastPropertyId: const obx_int.IdUid(7, 4056540326670791484),
flags: 0, flags: 0,
properties: <obx_int.ModelProperty>[ properties: <obx_int.ModelProperty>[
obx_int.ModelProperty( obx_int.ModelProperty(
@@ -414,6 +421,13 @@ final _entities = <obx_int.ModelEntity>[
type: 1, type: 1,
flags: 0, flags: 0,
), ),
obx_int.ModelProperty(
id: const obx_int.IdUid(7, 4056540326670791484),
name: 'externalId',
type: 6,
flags: 40,
indexId: const obx_int.IdUid(2, 428171949166894655),
),
], ],
relations: <obx_int.ModelRelation>[], relations: <obx_int.ModelRelation>[],
backlinks: <obx_int.ModelBacklink>[], backlinks: <obx_int.ModelBacklink>[],
@@ -499,7 +513,7 @@ obx_int.ModelDefinition getObjectBoxModel() {
final model = obx_int.ModelInfo( final model = obx_int.ModelInfo(
entities: _entities, entities: _entities,
lastEntityId: const obx_int.IdUid(12, 4865606913057136676), lastEntityId: const obx_int.IdUid(12, 4865606913057136676),
lastIndexId: const obx_int.IdUid(0, 0), lastIndexId: const obx_int.IdUid(2, 428171949166894655),
lastRelationId: const obx_int.IdUid(0, 0), lastRelationId: const obx_int.IdUid(0, 0),
lastSequenceId: const obx_int.IdUid(0, 0), lastSequenceId: const obx_int.IdUid(0, 0),
retiredEntityUids: const [3121960281516643928, 3330049220205502332], retiredEntityUids: const [3121960281516643928, 3330049220205502332],
@@ -578,7 +592,7 @@ obx_int.ModelDefinition getObjectBoxModel() {
: fbb.writeString(object.crFilter!); : fbb.writeString(object.crFilter!);
final remOffset = fbb.writeString(object.rem); final remOffset = fbb.writeString(object.rem);
final toursJsonOffset = fbb.writeString(object.toursJson); final toursJsonOffset = fbb.writeString(object.toursJson);
fbb.startTable(12); fbb.startTable(13);
fbb.addInt64(0, object.id); fbb.addInt64(0, object.id);
fbb.addOffset(1, verOffset); fbb.addOffset(1, verOffset);
fbb.addInt64(2, object.state); fbb.addInt64(2, object.state);
@@ -590,6 +604,7 @@ obx_int.ModelDefinition getObjectBoxModel() {
fbb.addOffset(8, remOffset); fbb.addOffset(8, remOffset);
fbb.addInt64(9, object.delayOrderTime); fbb.addInt64(9, object.delayOrderTime);
fbb.addOffset(10, toursJsonOffset); fbb.addOffset(10, toursJsonOffset);
fbb.addInt64(11, object.externalId);
fbb.finish(fbb.endTable()); fbb.finish(fbb.endTable());
return object.id; return object.id;
}, },
@@ -636,7 +651,13 @@ obx_int.ModelDefinition getObjectBoxModel() {
) )
..toursJson = const fb.StringReader( ..toursJson = const fb.StringReader(
asciiOptimization: true, asciiOptimization: true,
).vTableGet(buffer, rootOffset, 24, ''); ).vTableGet(buffer, rootOffset, 24, '')
..externalId = const fb.Int64Reader().vTableGet(
buffer,
rootOffset,
26,
0,
);
return object; return object;
}, },
@@ -894,13 +915,14 @@ obx_int.ModelDefinition getObjectBoxModel() {
final fromOffset = fbb.writeString(object.from); final fromOffset = fbb.writeString(object.from);
final subjOffset = fbb.writeString(object.subj); final subjOffset = fbb.writeString(object.subj);
final textOffset = fbb.writeString(object.text); final textOffset = fbb.writeString(object.text);
fbb.startTable(7); fbb.startTable(8);
fbb.addInt64(0, object.id); fbb.addInt64(0, object.id);
fbb.addInt64(1, object.time); fbb.addInt64(1, object.time);
fbb.addOffset(2, fromOffset); fbb.addOffset(2, fromOffset);
fbb.addOffset(3, subjOffset); fbb.addOffset(3, subjOffset);
fbb.addOffset(4, textOffset); fbb.addOffset(4, textOffset);
fbb.addBool(5, object.read); fbb.addBool(5, object.read);
fbb.addInt64(6, object.externalId);
fbb.finish(fbb.endTable()); fbb.finish(fbb.endTable());
return object.id; return object.id;
}, },
@@ -925,6 +947,12 @@ obx_int.ModelDefinition getObjectBoxModel() {
rootOffset, rootOffset,
14, 14,
false, false,
)
..externalId = const fb.Int64Reader().vTableGet(
buffer,
rootOffset,
16,
0,
); );
return object; return object;
@@ -1055,6 +1083,11 @@ class Job_ {
static final toursJson = obx.QueryStringProperty<Job>( static final toursJson = obx.QueryStringProperty<Job>(
_entities[1].properties[10], _entities[1].properties[10],
); );
/// See [Job.externalId].
static final externalId = obx.QueryIntegerProperty<Job>(
_entities[1].properties[11],
);
} }
/// [LocationStatus] entity fields to define ObjectBox queries. /// [LocationStatus] entity fields to define ObjectBox queries.
@@ -1251,6 +1284,11 @@ class ChatMessage_ {
static final read = obx.QueryBooleanProperty<ChatMessage>( static final read = obx.QueryBooleanProperty<ChatMessage>(
_entities[8].properties[5], _entities[8].properties[5],
); );
/// See [ChatMessage.externalId].
static final externalId = obx.QueryIntegerProperty<ChatMessage>(
_entities[8].properties[6],
);
} }
/// [TaskInfo] entity fields to define ObjectBox queries. /// [TaskInfo] entity fields to define ObjectBox queries.
+12 -11
View File
@@ -13,6 +13,7 @@ import 'package:stadtbote/tools/messages/job_deleted_message.dart';
import 'package:stadtbote/tools/messages/job_received_message.dart'; import 'package:stadtbote/tools/messages/job_received_message.dart';
import 'package:stadtbote/tools/messages/refresh_badges_message.dart'; import 'package:stadtbote/tools/messages/refresh_badges_message.dart';
import 'package:stadtbote/tools/messages/remove_job_message.dart'; import 'package:stadtbote/tools/messages/remove_job_message.dart';
import 'package:stadtbote/tools/mqtt_core.dart';
import 'package:stadtbote/tools/util.dart'; import 'package:stadtbote/tools/util.dart';
import '../tools/messages/publish_payload_message.dart'; import '../tools/messages/publish_payload_message.dart';
@@ -216,9 +217,9 @@ Future<List<Widget>> _fetchJobWidgets(StateSetter dialogState, Function() onFini
jobMap.remove(job.id); jobMap.remove(job.id);
job.sendMessage( MqttCore.instance.sendMessage(
routingKey: Constants.messageTopicRemoveJob, routingKey: Constants.messageTopicRemoveJob,
payload: RemoveJobMessage(id: job.id), payload: RemoveJobMessage(id: job.externalId),
); );
setState(() {}); setState(() {});
@@ -233,9 +234,9 @@ Future<List<Widget>> _fetchJobWidgets(StateSetter dialogState, Function() onFini
jobMap.remove(job.id); jobMap.remove(job.id);
job.sendMessage( MqttCore.instance.sendMessage(
routingKey: Constants.messageTopicRemoveJob, routingKey: Constants.messageTopicRemoveJob,
payload: RemoveJobMessage(id: job.id), payload: RemoveJobMessage(id: job.externalId),
); );
setState(() {}); setState(() {});
@@ -350,9 +351,9 @@ Future<List<Widget>> _fetchJobWidgets(StateSetter dialogState, Function() onFini
jobMap.remove(job.id); jobMap.remove(job.id);
job.sendMessage( MqttCore.instance.sendMessage(
routingKey: Constants.messageTopicRemoveJob, routingKey: Constants.messageTopicRemoveJob,
payload: RemoveJobMessage(id: job.id), payload: RemoveJobMessage(id: job.externalId),
); );
setState(() {}); setState(() {});
@@ -367,9 +368,9 @@ Future<List<Widget>> _fetchJobWidgets(StateSetter dialogState, Function() onFini
jobMap.remove(job.id); jobMap.remove(job.id);
job.sendMessage( MqttCore.instance.sendMessage(
routingKey: Constants.messageTopicRemoveJob, routingKey: Constants.messageTopicRemoveJob,
payload: RemoveJobMessage(id: job.id), payload: RemoveJobMessage(id: job.externalId),
); );
setState(() {}); setState(() {});
@@ -394,7 +395,7 @@ _sendAnswer(SharedMapReference mapReference, Job job, int item) async {
var currentPosition = await MyApp.getCurrentPosition(); var currentPosition = await MyApp.getCurrentPosition();
var message = Reaction(); var message = Reaction();
message.id = job.id; message.id = job.externalId; // Use external ID for network communication
message.ver = job.ver.toString(); message.ver = job.ver.toString();
message.item = item; message.item = item;
message.track = Track(); message.track = Track();
@@ -405,12 +406,12 @@ _sendAnswer(SharedMapReference mapReference, Job job, int item) async {
message.track.pos!.long = currentPosition != null ? currentPosition.longitude : 0.0; message.track.pos!.long = currentPosition != null ? currentPosition.longitude : 0.0;
message.track.pos!.acc = currentPosition != null ? currentPosition.accuracy.toInt() : 0; message.track.pos!.acc = currentPosition != null ? currentPosition.accuracy.toInt() : 0;
job.sendMessage( MqttCore.instance.sendMessage(
routingKey: Constants.messageTopicPublishPayload, routingKey: Constants.messageTopicPublishPayload,
payload: PublishPayloadMessage(topic: "reaction", message: message.toJson(), acknowledgeRequired: true), payload: PublishPayloadMessage(topic: "reaction", message: message.toJson(), acknowledgeRequired: true),
); );
job.sendMessage( MqttCore.instance.sendMessage(
routingKey: Constants.messageTopicUpdateBadges, routingKey: Constants.messageTopicUpdateBadges,
payload: RefreshBadgesMessage(), payload: RefreshBadgesMessage(),
); );
+19 -4
View File
@@ -394,6 +394,17 @@ class MqttCore with ProducerMixin, ConsumerMixin {
Job newJob = Job.fromJson(payloadData); Job newJob = Job.fromJson(payloadData);
final box = MyApp.objectBoxStore.box<Job>(); final box = MyApp.objectBoxStore.box<Job>();
// Check if job already exists by externalId
final query = box.query(Job_.externalId.equals(newJob.externalId)).build();
final existingJob = query.findFirst();
query.close();
if (existingJob != null) {
// Update existing job
newJob.id = existingJob.id;
}
box.put(newJob); box.put(newJob);
if (newJob.state == Constants.stateAssigned) { if (newJob.state == Constants.stateAssigned) {
@@ -416,10 +427,14 @@ class MqttCore with ProducerMixin, ConsumerMixin {
var jobDelMessage = JobDelMessage.fromJson(payloadData); var jobDelMessage = JobDelMessage.fromJson(payloadData);
final box = MyApp.objectBoxStore.box<Job>(); final box = MyApp.objectBoxStore.box<Job>();
var job = box.get(jobDelMessage.id);
// Find job by external ID
final query = box.query(Job_.externalId.equals(jobDelMessage.id)).build();
final job = query.findFirst();
query.close();
if (job != null) { if (job != null) {
box.remove(jobDelMessage.id); box.remove(job.id); // Use ObjectBox ID for removal
sendMessage( sendMessage(
routingKey: Constants.messageTopicJobDeleted, routingKey: Constants.messageTopicJobDeleted,
@@ -613,7 +628,7 @@ class MqttCore with ProducerMixin, ConsumerMixin {
for (var job in jobs) { for (var job in jobs) {
SyncJobMessageJob syncJob = SyncJobMessageJob(); SyncJobMessageJob syncJob = SyncJobMessageJob();
syncJob.state = job.state; syncJob.state = job.state;
syncJob.id = job.id; syncJob.id = job.externalId; // Use external ID for network communication
syncJob.ver = job.ver.toString(); syncJob.ver = job.ver.toString();
answer.sync.jobs.add(syncJob); answer.sync.jobs.add(syncJob);
} }
@@ -687,7 +702,7 @@ class MqttCore with ProducerMixin, ConsumerMixin {
void _acknowlegdeJob(Job job) { void _acknowlegdeJob(Job job) {
var message = AcknowledgeJobReceived(); var message = AcknowledgeJobReceived();
message.id = job.id; message.id = job.externalId; // Use external ID for network communication
message.state = job.state; message.state = job.state;
message.ver = job.ver; message.ver = job.ver;
message.utc = Util.nowUnixSecondsUtc(); message.utc = Util.nowUnixSecondsUtc();