diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 920f7ab..06b85eb 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -112,5 +112,12 @@
+
+
+
+
+
+
diff --git a/lib/ble/ble_responses.dart b/lib/ble/ble_responses.dart
index 6c1abab..02d2ff9 100644
--- a/lib/ble/ble_responses.dart
+++ b/lib/ble/ble_responses.dart
@@ -156,6 +156,11 @@ class ChannelMessageReceivedResponse extends BleResponse {
final String text;
final int snr;
final int pathLength;
+
+ /// Wire txt_type from the V3 response -- also packed into the original
+ /// over-the-air ciphertext's plaintext header, needed to reconstruct that
+ /// plaintext exactly for raw-frame correlation (see channel_crypto.dart).
+ final int txtType;
final bool isFromSelf;
ChannelMessageReceivedResponse({
@@ -166,6 +171,7 @@ class ChannelMessageReceivedResponse extends BleResponse {
required this.text,
required this.snr,
required this.pathLength,
+ required this.txtType,
required this.isFromSelf,
}) : super(BleConstants.respChannelMsgRecvV3);
}
@@ -529,7 +535,7 @@ class BleResponseParser {
reader.readByte(); // reserved2
final channelIndex = reader.readByte();
final pathLength = reader.readByte() & 0x3F; // bits 5–0 are hop count
- final txtType = reader.readByte(); // txt_type (ignored for now)
+ final txtType = reader.readByte();
final timestamp = reader.readUInt32LE();
// Read remaining bytes as text
@@ -543,6 +549,7 @@ class BleResponseParser {
text: text,
snr: snr,
pathLength: pathLength,
+ txtType: txtType,
isFromSelf: false, // V3 doesn't indicate this
);
}
diff --git a/lib/ble/raw_packet_log.dart b/lib/ble/raw_packet_log.dart
new file mode 100644
index 0000000..109c2f6
--- /dev/null
+++ b/lib/ble/raw_packet_log.dart
@@ -0,0 +1,174 @@
+// Copyright (c) 2026 tmacinc
+// Licensed under CC BY-NC-SA 4.0
+
+import 'dart:typed_data';
+
+import 'package:crypto/crypto.dart' as crypto;
+
+/// A parsed raw radio packet, sourced from a PUSH_LOG_RX_DATA (0x88) BLE
+/// frame: `[0x88][snr int8][rssi int8][raw mesh packet]`. The raw packet
+/// structure itself matches MeshCore's over-the-air format (see
+/// docs/packet_format.md in the firmware repo):
+/// `[header][transport_codes?][path_length][path][payload]`.
+///
+/// This is the data firmware's own decoded message responses (V3) never
+/// expose: the actual per-hop path bytes and true RSSI, plus one entry per
+/// physical reception rather than one per logical (deduped) message.
+class RawPacketFrame {
+ /// Raw int8 SNR value scaled by 4 (matches Messages.snr's encoding from
+ /// the V3 message responses -- same firmware-side scaling, no conversion
+ /// needed to compare the two).
+ final int snr;
+
+ /// Raw RSSI in dBm.
+ final int rssi;
+
+ final int routeType;
+ final int payloadType;
+ final int payloadVersion;
+
+ /// Raw wire path_length byte (hash-size mode packed with hop count).
+ final int pathByte;
+
+ /// Raw hop-hash bytes, hop_count * hash_size long.
+ final Uint8List pathBytes;
+
+ /// Remaining packet bytes after path -- ciphertext for TXT_MSG/GRP_TXT.
+ final Uint8List payload;
+
+ /// SHA-256(payload_type byte + payload bytes)[:16 hex, uppercase] --
+ /// matches MeshCore firmware's Packet::calculatePacketHash(). Identical
+ /// across flood-relayed copies of the same logical packet regardless of
+ /// path, since it excludes routing/path bytes entirely.
+ final String packetHash;
+
+ final int receivedAtMs;
+
+ RawPacketFrame({
+ required this.snr,
+ required this.rssi,
+ required this.routeType,
+ required this.payloadType,
+ required this.payloadVersion,
+ required this.pathByte,
+ required this.pathBytes,
+ required this.payload,
+ required this.packetHash,
+ required this.receivedAtMs,
+ });
+}
+
+/// Payload type of a text/channel-text packet, per docs/packet_format.md.
+const int payloadTypeTxtMsg = 0x02;
+const int payloadTypeGrpTxt = 0x05;
+
+/// Parses a PUSH_LOG_RX_DATA (0x88) BLE frame into a [RawPacketFrame].
+/// Returns null for malformed/too-short frames.
+RawPacketFrame? parseRawPacketLogFrame(Uint8List frame, {DateTime? now}) {
+ // frame[0] is the 0x88 push code itself (caller strips or includes it --
+ // this function expects it included, matching the raw BLE payload).
+ // Minimum viable length: code + snr + rssi + header + path_byte.
+ if (frame.length < 5) return null;
+
+ final snr = frame[1].toSigned(8);
+ final rssi = frame[2].toSigned(8);
+ final packet = frame.sublist(3);
+
+ return parseRawMeshPacket(packet, snr: snr, rssi: rssi, now: now);
+}
+
+/// Parses the raw mesh packet bytes (without the 0x88/snr/rssi BLE prefix).
+/// Exposed separately so it can be unit-tested against known packet bytes.
+RawPacketFrame? parseRawMeshPacket(
+ Uint8List packet, {
+ required int snr,
+ required int rssi,
+ DateTime? now,
+}) {
+ if (packet.length < 2) return null;
+
+ var offset = 0;
+ final header = packet[offset++];
+ final routeType = header & 0x03;
+ final payloadType = (header >> 2) & 0x0F;
+ final payloadVersion = (header >> 6) & 0x03;
+
+ // ROUTE_TYPE_TRANSPORT_FLOOD (0x00) and ROUTE_TYPE_TRANSPORT_DIRECT (0x03)
+ // carry 4 bytes of transport codes before the path byte.
+ if (routeType == 0x00 || routeType == 0x03) {
+ if (packet.length < offset + 4) return null;
+ offset += 4;
+ }
+
+ if (packet.length < offset + 1) return null;
+ final pathByte = packet[offset++];
+ final hashSize = ((pathByte & 0xC0) >> 6) + 1;
+ final hopCount = pathByte & 0x3F;
+ final pathByteLen = hopCount * hashSize;
+
+ if (packet.length < offset + pathByteLen) return null;
+ final pathBytes = packet.sublist(offset, offset + pathByteLen);
+ offset += pathByteLen;
+
+ final payload = packet.sublist(offset);
+
+ final hashInput = Uint8List(1 + payload.length)
+ ..[0] = payloadType
+ ..setRange(1, 1 + payload.length, payload);
+ final packetHash = crypto.sha256
+ .convert(hashInput)
+ .toString()
+ .substring(0, 16)
+ .toUpperCase();
+
+ return RawPacketFrame(
+ snr: snr,
+ rssi: rssi,
+ routeType: routeType,
+ payloadType: payloadType,
+ payloadVersion: payloadVersion,
+ pathByte: pathByte,
+ pathBytes: pathBytes,
+ payload: payload,
+ packetHash: packetHash,
+ receivedAtMs: (now ?? DateTime.now()).millisecondsSinceEpoch,
+ );
+}
+
+/// Short-lived buffer of recently-seen raw packets, used to correlate a
+/// decoded chat message (arriving via the normal, separate sync path) back
+/// to the raw reception(s) it came from. Bounded by both age and count so
+/// it can't grow unbounded on a busy channel.
+class RawPacketLog {
+ static const Duration _maxAge = Duration(seconds: 60);
+ static const int _maxEntries = 200;
+
+ final List _frames = [];
+
+ void add(RawPacketFrame frame) {
+ _frames.add(frame);
+ _prune();
+ }
+
+ /// All buffered frames matching [packetHash], oldest first.
+ List byPacketHash(String packetHash) {
+ _prune();
+ return _frames.where((f) => f.packetHash == packetHash).toList();
+ }
+
+ /// All buffered frames of a given payload type, for brute-force matching
+ /// against a known plaintext (caller re-encrypts and compares payload
+ /// bytes directly rather than relying on this method to filter by hash).
+ List byPayloadType(int payloadType) {
+ _prune();
+ return _frames.where((f) => f.payloadType == payloadType).toList();
+ }
+
+ void _prune() {
+ final cutoff = DateTime.now().subtract(_maxAge).millisecondsSinceEpoch;
+ _frames.removeWhere((f) => f.receivedAtMs < cutoff);
+ if (_frames.length > _maxEntries) {
+ _frames.removeRange(0, _frames.length - _maxEntries);
+ }
+ }
+}
diff --git a/lib/database/daos/contacts_dao.dart b/lib/database/daos/contacts_dao.dart
index 8d49d44..1620380 100644
--- a/lib/database/daos/contacts_dao.dart
+++ b/lib/database/daos/contacts_dao.dart
@@ -112,6 +112,49 @@ class ContactsDao extends DatabaseAccessor
return null;
}
+ /// Get all contacts matching the first [prefixLength] bytes of their
+ /// public key, unlike [getContactByPublicKeyPrefix] which only returns
+ /// the first match. Used to detect and surface ambiguity when resolving
+ /// a short raw path-hop hash (1-3 bytes) against known contacts, since a
+ /// short prefix can legitimately collide between multiple contacts.
+ Future> getContactsByPublicKeyPrefix(
+ Uint8List prefix, {
+ int prefixLength = 6,
+ String? companionKey,
+ }) async {
+ if (prefix.isEmpty) return const [];
+ if (prefixLength <= 0) return const [];
+
+ final effectivePrefixLength =
+ prefixLength > prefix.length ? prefix.length : prefixLength;
+
+ final query = select(contacts);
+ if (companionKey != null && companionKey.isNotEmpty) {
+ query.where((t) => t.companionDeviceKey.equals(companionKey));
+ }
+
+ final allContacts = await query.get();
+ final matches = [];
+ for (final contact in allContacts) {
+ final pk = contact.publicKey;
+ if (pk.length < effectivePrefixLength) continue;
+
+ bool isMatch = true;
+ for (int i = 0; i < effectivePrefixLength; i++) {
+ if (pk[i] != prefix[i]) {
+ isMatch = false;
+ break;
+ }
+ }
+
+ if (isMatch) {
+ matches.add(contact);
+ }
+ }
+
+ return matches;
+ }
+
/// Get a single contact by hash (derived from full public key)
/// Returns first match if multiple contacts have same hash
Future getContactByHash(int hash) {
@@ -433,8 +476,7 @@ class ContactsDao extends DatabaseAccessor
);
final controller = StreamController();
- final contactsSub =
- watchContactsByCompanion(companionKey).listen((_) {
+ final contactsSub = watchContactsByCompanion(companionKey).listen((_) {
if (!controller.isClosed) controller.add(null);
});
final messagesSub = db.messagesDao.watchMessageCount().listen((_) {
diff --git a/lib/database/daos/message_paths_dao.dart b/lib/database/daos/message_paths_dao.dart
new file mode 100644
index 0000000..9b2569c
--- /dev/null
+++ b/lib/database/daos/message_paths_dao.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2026 tmacinc
+// Licensed under CC BY-NC-SA 4.0
+// http://creativecommons.org/licenses/by-nc-sa/4.0/
+//
+// This file is part of TEAM-Flutter.
+// Non-commercial use only. See LICENSE file for details.
+
+import 'package:drift/drift.dart';
+import '../database.dart';
+import '../tables.dart';
+
+part 'message_paths_dao.g.dart';
+
+/// DAO for per-message radio path observations (see MessagePaths table doc).
+@DriftAccessor(tables: [MessagePaths])
+class MessagePathsDao extends DatabaseAccessor
+ with _$MessagePathsDaoMixin {
+ MessagePathsDao(super.db);
+
+ /// Get all observed paths for a message, oldest first.
+ Future> getPathsByMessage(String messageId) {
+ return (select(messagePaths)
+ ..where((t) => t.messageId.equals(messageId))
+ ..orderBy([
+ (t) =>
+ OrderingTerm(expression: t.receivedAt, mode: OrderingMode.asc),
+ ]))
+ .get();
+ }
+
+ /// Insert a newly-correlated path observation for a message. Silently
+ /// ignores a conflict on the (messageId, pathBytes) unique constraint --
+ /// correlation can run concurrently for the same message (delivered via
+ /// PUSH and then again via a later sync), so this is the atomic
+ /// alternative to an application-side check-then-insert race.
+ Future insertPath(MessagePathsCompanion path) {
+ return into(messagePaths).insert(path, mode: InsertMode.insertOrIgnore);
+ }
+
+ /// Delete paths older than a timestamp (retention cleanup).
+ Future deletePathsOlderThan(int timestamp) {
+ return (delete(messagePaths)
+ ..where((t) => t.receivedAt.isSmallerThanValue(timestamp)))
+ .go();
+ }
+}
diff --git a/lib/database/daos/message_paths_dao.g.dart b/lib/database/daos/message_paths_dao.g.dart
new file mode 100644
index 0000000..6c070d4
--- /dev/null
+++ b/lib/database/daos/message_paths_dao.g.dart
@@ -0,0 +1,8 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'message_paths_dao.dart';
+
+// ignore_for_file: type=lint
+mixin _$MessagePathsDaoMixin on DatabaseAccessor {
+ $MessagePathsTable get messagePaths => attachedDatabase.messagePaths;
+}
diff --git a/lib/database/daos/messages_dao.dart b/lib/database/daos/messages_dao.dart
index 5ce6928..cf3da51 100644
--- a/lib/database/daos/messages_dao.dart
+++ b/lib/database/daos/messages_dao.dart
@@ -19,14 +19,17 @@ class MessagesDao extends DatabaseAccessor
with _$MessagesDaoMixin {
MessagesDao(super.db);
- /// Get all messages for a channel, ordered by timestamp
+ /// Strict local receive order. Messages has no INTEGER PRIMARY KEY, so
+ /// SQLite maintains an implicit rowid that's atomically assigned in
+ /// insertion order -- immune to the sender-embedded (and untrusted)
+ /// `timestamp` column, with no app-side bookkeeping required.
+ static const Expression _rowid = CustomExpression('rowid');
+
+ /// Get all messages for a channel, in local receive order
Future> getMessagesByChannel(int channelHash) {
return (select(messages)
..where((t) => t.channelHash.equals(channelHash))
- ..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc),
- ]))
+ ..orderBy([(t) => OrderingTerm(expression: _rowid)]))
.get();
}
@@ -37,10 +40,7 @@ class MessagesDao extends DatabaseAccessor
..where((t) =>
t.channelHash.equals(channelHash) &
t.companionDeviceKey.equals(companionKey))
- ..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc),
- ]))
+ ..orderBy([(t) => OrderingTerm(expression: _rowid)]))
.get();
}
@@ -50,10 +50,7 @@ class MessagesDao extends DatabaseAccessor
return (select(messages)
..where((t) =>
t.isPrivate.equals(true) & t.channelHash.equals(contactHash))
- ..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc),
- ]))
+ ..orderBy([(t) => OrderingTerm(expression: _rowid)]))
.get();
}
@@ -65,10 +62,7 @@ class MessagesDao extends DatabaseAccessor
t.isPrivate.equals(true) &
t.channelHash.equals(contactHash) &
t.companionDeviceKey.equals(companionKey))
- ..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc),
- ]))
+ ..orderBy([(t) => OrderingTerm(expression: _rowid)]))
.get();
}
@@ -77,10 +71,16 @@ class MessagesDao extends DatabaseAccessor
return (select(messages)..where((t) => t.id.equals(id))).getSingleOrNull();
}
- /// Insert a new message and return the inserted data
+ /// Insert a new message and return the inserted data.
+ ///
+ /// `receivedAt` (this device's own clock) is always assigned here, not by
+ /// callers -- ordering itself comes from SQLite's rowid, assigned
+ /// atomically by the single INSERT below.
Future insertMessage(MessagesCompanion message) async {
try {
- await into(messages).insert(message);
+ await into(messages).insert(message.copyWith(
+ receivedAt: Value(DateTime.now().millisecondsSinceEpoch),
+ ));
// Query the inserted message by ID
return await getMessageById(message.id.value);
} catch (e) {
@@ -143,8 +143,7 @@ class MessagesDao extends DatabaseAccessor
return (select(messages)
..where((t) => t.deliveryStatus.equals('SENDING'))
..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc),
+ (t) => OrderingTerm(expression: _rowid),
]))
.get();
}
@@ -154,8 +153,7 @@ class MessagesDao extends DatabaseAccessor
return (select(messages)
..where((t) => t.isSentByMe.equals(true))
..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.desc),
+ (t) => OrderingTerm(expression: _rowid, mode: OrderingMode.desc),
]))
.get();
}
@@ -200,8 +198,7 @@ class MessagesDao extends DatabaseAccessor
return (select(messages)
..where((t) => t.channelHash.equals(channelHash))
..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc),
+ (t) => OrderingTerm(expression: _rowid),
]))
.watch();
}
@@ -214,8 +211,7 @@ class MessagesDao extends DatabaseAccessor
t.channelHash.equals(channelHash) &
t.companionDeviceKey.equals(companionKey))
..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc),
+ (t) => OrderingTerm(expression: _rowid),
]))
.watch();
}
@@ -227,8 +223,7 @@ class MessagesDao extends DatabaseAccessor
..where((t) =>
t.isPrivate.equals(true) & t.channelHash.equals(contactHash))
..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc),
+ (t) => OrderingTerm(expression: _rowid),
]))
.watch();
}
@@ -242,8 +237,7 @@ class MessagesDao extends DatabaseAccessor
t.channelHash.equals(contactHash) &
t.companionDeviceKey.equals(companionKey))
..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc),
+ (t) => OrderingTerm(expression: _rowid),
]))
.watch();
}
@@ -259,8 +253,7 @@ class MessagesDao extends DatabaseAccessor
return (select(messages)
..where((t) => t.deliveryStatus.equals('SENDING'))
..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc),
+ (t) => OrderingTerm(expression: _rowid),
]))
.watch();
}
@@ -270,8 +263,7 @@ class MessagesDao extends DatabaseAccessor
Stream> watchAllMessages() {
return (select(messages)
..orderBy([
- (t) =>
- OrderingTerm(expression: t.timestamp, mode: OrderingMode.desc),
+ (t) => OrderingTerm(expression: _rowid, mode: OrderingMode.desc),
]))
.watch();
}
@@ -448,38 +440,34 @@ class MessagesDao extends DatabaseAccessor
));
}
- /// Get the first unread message timestamp for a channel (for divider)
- Future getFirstUnreadTimestampByChannel(int channelHash) async {
+ /// Get the ID of the first unread message for a channel (for divider)
+ Future getFirstUnreadMessageIdByChannel(int channelHash) async {
final query = select(messages)
..where((t) =>
t.channelHash.equals(channelHash) &
t.isPrivate.equals(false) &
t.isRead.equals(false) &
t.isSentByMe.equals(false))
- ..orderBy([
- (t) => OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc)
- ])
+ ..orderBy([(t) => OrderingTerm(expression: _rowid)])
..limit(1);
final result = await query.getSingleOrNull();
- return result?.timestamp;
+ return result?.id;
}
- /// Get the first unread message timestamp for a contact (for divider)
- Future getFirstUnreadTimestampByContact(int contactHash) async {
+ /// Get the ID of the first unread message for a contact (for divider)
+ Future getFirstUnreadMessageIdByContact(int contactHash) async {
final query = select(messages)
..where((t) =>
t.channelHash.equals(contactHash) &
t.isPrivate.equals(true) &
t.isRead.equals(false) &
t.isSentByMe.equals(false))
- ..orderBy([
- (t) => OrderingTerm(expression: t.timestamp, mode: OrderingMode.asc)
- ])
+ ..orderBy([(t) => OrderingTerm(expression: _rowid)])
..limit(1);
final result = await query.getSingleOrNull();
- return result?.timestamp;
+ return result?.id;
}
/// Get total unread count across all channels
diff --git a/lib/database/database.dart b/lib/database/database.dart
index 3de9b72..c61de2b 100644
--- a/lib/database/database.dart
+++ b/lib/database/database.dart
@@ -15,6 +15,7 @@ import 'tables.dart';
import 'daos/contacts_dao.dart';
import 'daos/channels_dao.dart';
import 'daos/messages_dao.dart';
+import 'daos/message_paths_dao.dart';
import 'daos/waypoints_dao.dart';
import 'daos/ack_records_dao.dart';
import 'daos/companion_devices_dao.dart';
@@ -44,6 +45,7 @@ typedef AckRecord = AckRecordData;
Contacts,
Channels,
Messages,
+ MessagePaths,
Waypoints,
CompanionDevices,
ContactDisplayStates,
@@ -56,6 +58,7 @@ typedef AckRecord = AckRecordData;
ContactsDao,
ChannelsDao,
MessagesDao,
+ MessagePathsDao,
WaypointsDao,
AckRecordsDao,
CompanionDevicesDao,
@@ -70,7 +73,7 @@ class AppDatabase extends _$AppDatabase {
AppDatabase.forTesting(QueryExecutor executor) : super(executor);
@override
- int get schemaVersion => 8;
+ int get schemaVersion => 9;
@override
MigrationStrategy get migration => MigrationStrategy(
@@ -161,7 +164,27 @@ class AppDatabase extends _$AppDatabase {
await customStatement(
'ALTER TABLE channels ADD COLUMN is_favorite INTEGER NOT NULL DEFAULT 0',
);
- print('[Migration] v7->v8: importedOverlayMaps, favorites, channel notification mode');
+ print(
+ '[Migration] v7->v8: importedOverlayMaps, favorites, channel notification mode');
+ }
+
+ // Migration from schema version 8 to 9: per-message hop count/SNR,
+ // the message_paths table for multi-path routing detail, and a
+ // local receivedAt display time independent of the untrusted
+ // sender-embedded timestamp. Ordering uses SQLite's implicit
+ // rowid, not a dedicated column.
+ if (from <= 8 && to >= 9) {
+ await m.addColumn(messages, messages.hopCount);
+ await m.addColumn(messages, messages.snr);
+ await m.addColumn(messages, messages.receivedAt);
+ await m.createTable(messagePaths);
+ // True historical receive time isn't recoverable for existing
+ // rows -- best-effort backfill from the existing (untrusted)
+ // timestamp. Only affects rows inserted before this migration.
+ await customStatement(
+ 'UPDATE messages SET received_at = timestamp');
+ print(
+ '[Migration] v8->v9: added hopCount/snr/receivedAt to messages, created message_paths table');
}
},
);
diff --git a/lib/database/database.g.dart b/lib/database/database.g.dart
index 056f521..b36ebae 100644
--- a/lib/database/database.g.dart
+++ b/lib/database/database.g.dart
@@ -1547,6 +1547,25 @@ class $MessagesTable extends Messages
late final GeneratedColumn companionDeviceKey =
GeneratedColumn('companion_device_key', aliasedName, true,
type: DriftSqlType.string, requiredDuringInsert: false);
+ static const VerificationMeta _hopCountMeta =
+ const VerificationMeta('hopCount');
+ @override
+ late final GeneratedColumn hopCount = GeneratedColumn(
+ 'hop_count', aliasedName, true,
+ type: DriftSqlType.int, requiredDuringInsert: false);
+ static const VerificationMeta _snrMeta = const VerificationMeta('snr');
+ @override
+ late final GeneratedColumn snr = GeneratedColumn(
+ 'snr', aliasedName, true,
+ type: DriftSqlType.int, requiredDuringInsert: false);
+ static const VerificationMeta _receivedAtMeta =
+ const VerificationMeta('receivedAt');
+ @override
+ late final GeneratedColumn receivedAt = GeneratedColumn(
+ 'received_at', aliasedName, false,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ defaultValue: const Constant(0));
@override
List get $columns => [
id,
@@ -1562,7 +1581,10 @@ class $MessagesTable extends Messages
attempt,
isSentByMe,
isRead,
- companionDeviceKey
+ companionDeviceKey,
+ hopCount,
+ snr,
+ receivedAt
];
@override
String get aliasedName => _alias ?? actualTableName;
@@ -1659,6 +1681,20 @@ class $MessagesTable extends Messages
companionDeviceKey.isAcceptableOrUnknown(
data['companion_device_key']!, _companionDeviceKeyMeta));
}
+ if (data.containsKey('hop_count')) {
+ context.handle(_hopCountMeta,
+ hopCount.isAcceptableOrUnknown(data['hop_count']!, _hopCountMeta));
+ }
+ if (data.containsKey('snr')) {
+ context.handle(
+ _snrMeta, snr.isAcceptableOrUnknown(data['snr']!, _snrMeta));
+ }
+ if (data.containsKey('received_at')) {
+ context.handle(
+ _receivedAtMeta,
+ receivedAt.isAcceptableOrUnknown(
+ data['received_at']!, _receivedAtMeta));
+ }
return context;
}
@@ -1696,6 +1732,12 @@ class $MessagesTable extends Messages
.read(DriftSqlType.bool, data['${effectivePrefix}is_read'])!,
companionDeviceKey: attachedDatabase.typeMapping.read(
DriftSqlType.string, data['${effectivePrefix}companion_device_key']),
+ hopCount: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}hop_count']),
+ snr: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}snr']),
+ receivedAt: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}received_at'])!,
);
}
@@ -1720,6 +1762,9 @@ class MessageData extends DataClass implements Insertable {
final bool isSentByMe;
final bool isRead;
final String? companionDeviceKey;
+ final int? hopCount;
+ final int? snr;
+ final int receivedAt;
const MessageData(
{required this.id,
required this.senderId,
@@ -1734,7 +1779,10 @@ class MessageData extends DataClass implements Insertable {
required this.attempt,
required this.isSentByMe,
required this.isRead,
- this.companionDeviceKey});
+ this.companionDeviceKey,
+ this.hopCount,
+ this.snr,
+ required this.receivedAt});
@override
Map toColumns(bool nullToAbsent) {
final map = {};
@@ -1758,6 +1806,13 @@ class MessageData extends DataClass implements Insertable {
if (!nullToAbsent || companionDeviceKey != null) {
map['companion_device_key'] = Variable(companionDeviceKey);
}
+ if (!nullToAbsent || hopCount != null) {
+ map['hop_count'] = Variable(hopCount);
+ }
+ if (!nullToAbsent || snr != null) {
+ map['snr'] = Variable(snr);
+ }
+ map['received_at'] = Variable(receivedAt);
return map;
}
@@ -1783,6 +1838,11 @@ class MessageData extends DataClass implements Insertable {
companionDeviceKey: companionDeviceKey == null && nullToAbsent
? const Value.absent()
: Value(companionDeviceKey),
+ hopCount: hopCount == null && nullToAbsent
+ ? const Value.absent()
+ : Value(hopCount),
+ snr: snr == null && nullToAbsent ? const Value.absent() : Value(snr),
+ receivedAt: Value(receivedAt),
);
}
@@ -1805,6 +1865,9 @@ class MessageData extends DataClass implements Insertable {
isRead: serializer.fromJson(json['isRead']),
companionDeviceKey:
serializer.fromJson(json['companionDeviceKey']),
+ hopCount: serializer.fromJson(json['hopCount']),
+ snr: serializer.fromJson(json['snr']),
+ receivedAt: serializer.fromJson(json['receivedAt']),
);
}
@override
@@ -1825,6 +1888,9 @@ class MessageData extends DataClass implements Insertable {
'isSentByMe': serializer.toJson(isSentByMe),
'isRead': serializer.toJson(isRead),
'companionDeviceKey': serializer.toJson(companionDeviceKey),
+ 'hopCount': serializer.toJson(hopCount),
+ 'snr': serializer.toJson(snr),
+ 'receivedAt': serializer.toJson(receivedAt),
};
}
@@ -1842,7 +1908,10 @@ class MessageData extends DataClass implements Insertable {
int? attempt,
bool? isSentByMe,
bool? isRead,
- Value companionDeviceKey = const Value.absent()}) =>
+ Value companionDeviceKey = const Value.absent(),
+ Value hopCount = const Value.absent(),
+ Value snr = const Value.absent(),
+ int? receivedAt}) =>
MessageData(
id: id ?? this.id,
senderId: senderId ?? this.senderId,
@@ -1860,6 +1929,9 @@ class MessageData extends DataClass implements Insertable {
companionDeviceKey: companionDeviceKey.present
? companionDeviceKey.value
: this.companionDeviceKey,
+ hopCount: hopCount.present ? hopCount.value : this.hopCount,
+ snr: snr.present ? snr.value : this.snr,
+ receivedAt: receivedAt ?? this.receivedAt,
);
MessageData copyWithCompanion(MessagesCompanion data) {
return MessageData(
@@ -1887,6 +1959,10 @@ class MessageData extends DataClass implements Insertable {
companionDeviceKey: data.companionDeviceKey.present
? data.companionDeviceKey.value
: this.companionDeviceKey,
+ hopCount: data.hopCount.present ? data.hopCount.value : this.hopCount,
+ snr: data.snr.present ? data.snr.value : this.snr,
+ receivedAt:
+ data.receivedAt.present ? data.receivedAt.value : this.receivedAt,
);
}
@@ -1906,7 +1982,10 @@ class MessageData extends DataClass implements Insertable {
..write('attempt: $attempt, ')
..write('isSentByMe: $isSentByMe, ')
..write('isRead: $isRead, ')
- ..write('companionDeviceKey: $companionDeviceKey')
+ ..write('companionDeviceKey: $companionDeviceKey, ')
+ ..write('hopCount: $hopCount, ')
+ ..write('snr: $snr, ')
+ ..write('receivedAt: $receivedAt')
..write(')'))
.toString();
}
@@ -1926,7 +2005,10 @@ class MessageData extends DataClass implements Insertable {
attempt,
isSentByMe,
isRead,
- companionDeviceKey);
+ companionDeviceKey,
+ hopCount,
+ snr,
+ receivedAt);
@override
bool operator ==(Object other) =>
identical(this, other) ||
@@ -1944,7 +2026,10 @@ class MessageData extends DataClass implements Insertable {
other.attempt == this.attempt &&
other.isSentByMe == this.isSentByMe &&
other.isRead == this.isRead &&
- other.companionDeviceKey == this.companionDeviceKey);
+ other.companionDeviceKey == this.companionDeviceKey &&
+ other.hopCount == this.hopCount &&
+ other.snr == this.snr &&
+ other.receivedAt == this.receivedAt);
}
class MessagesCompanion extends UpdateCompanion {
@@ -1962,6 +2047,9 @@ class MessagesCompanion extends UpdateCompanion {
final Value isSentByMe;
final Value isRead;
final Value companionDeviceKey;
+ final Value hopCount;
+ final Value snr;
+ final Value receivedAt;
final Value rowid;
const MessagesCompanion({
this.id = const Value.absent(),
@@ -1978,6 +2066,9 @@ class MessagesCompanion extends UpdateCompanion {
this.isSentByMe = const Value.absent(),
this.isRead = const Value.absent(),
this.companionDeviceKey = const Value.absent(),
+ this.hopCount = const Value.absent(),
+ this.snr = const Value.absent(),
+ this.receivedAt = const Value.absent(),
this.rowid = const Value.absent(),
});
MessagesCompanion.insert({
@@ -1995,6 +2086,9 @@ class MessagesCompanion extends UpdateCompanion {
required bool isSentByMe,
this.isRead = const Value.absent(),
this.companionDeviceKey = const Value.absent(),
+ this.hopCount = const Value.absent(),
+ this.snr = const Value.absent(),
+ this.receivedAt = const Value.absent(),
this.rowid = const Value.absent(),
}) : id = Value(id),
senderId = Value(senderId),
@@ -2019,6 +2113,9 @@ class MessagesCompanion extends UpdateCompanion {
Expression? isSentByMe,
Expression? isRead,
Expression? companionDeviceKey,
+ Expression? hopCount,
+ Expression? snr,
+ Expression? receivedAt,
Expression? rowid,
}) {
return RawValuesInsertable({
@@ -2037,6 +2134,9 @@ class MessagesCompanion extends UpdateCompanion {
if (isRead != null) 'is_read': isRead,
if (companionDeviceKey != null)
'companion_device_key': companionDeviceKey,
+ if (hopCount != null) 'hop_count': hopCount,
+ if (snr != null) 'snr': snr,
+ if (receivedAt != null) 'received_at': receivedAt,
if (rowid != null) 'rowid': rowid,
});
}
@@ -2056,6 +2156,9 @@ class MessagesCompanion extends UpdateCompanion {
Value? isSentByMe,
Value? isRead,
Value? companionDeviceKey,
+ Value? hopCount,
+ Value? snr,
+ Value? receivedAt,
Value? rowid}) {
return MessagesCompanion(
id: id ?? this.id,
@@ -2072,6 +2175,9 @@ class MessagesCompanion extends UpdateCompanion {
isSentByMe: isSentByMe ?? this.isSentByMe,
isRead: isRead ?? this.isRead,
companionDeviceKey: companionDeviceKey ?? this.companionDeviceKey,
+ hopCount: hopCount ?? this.hopCount,
+ snr: snr ?? this.snr,
+ receivedAt: receivedAt ?? this.receivedAt,
rowid: rowid ?? this.rowid,
);
}
@@ -2080,71 +2186,460 @@ class MessagesCompanion extends UpdateCompanion {
Map toColumns(bool nullToAbsent) {
final map = {};
if (id.present) {
- map['id'] = Variable(id.value);
- }
- if (senderId.present) {
- map['sender_id'] = Variable(senderId.value);
- }
- if (senderName.present) {
- map['sender_name'] = Variable(senderName.value);
- }
- if (channelHash.present) {
- map['channel_hash'] = Variable(channelHash.value);
- }
- if (content.present) {
- map['content'] = Variable(content.value);
- }
- if (timestamp.present) {
- map['timestamp'] = Variable(timestamp.value);
- }
- if (isPrivate.present) {
- map['is_private'] = Variable(isPrivate.value);
- }
- if (ackChecksum.present) {
- map['ack_checksum'] = Variable(ackChecksum.value);
- }
- if (deliveryStatus.present) {
- map['delivery_status'] = Variable(deliveryStatus.value);
+ map['id'] = Variable(id.value);
+ }
+ if (senderId.present) {
+ map['sender_id'] = Variable(senderId.value);
+ }
+ if (senderName.present) {
+ map['sender_name'] = Variable(senderName.value);
+ }
+ if (channelHash.present) {
+ map['channel_hash'] = Variable(channelHash.value);
+ }
+ if (content.present) {
+ map['content'] = Variable(content.value);
+ }
+ if (timestamp.present) {
+ map['timestamp'] = Variable(timestamp.value);
+ }
+ if (isPrivate.present) {
+ map['is_private'] = Variable(isPrivate.value);
+ }
+ if (ackChecksum.present) {
+ map['ack_checksum'] = Variable(ackChecksum.value);
+ }
+ if (deliveryStatus.present) {
+ map['delivery_status'] = Variable(deliveryStatus.value);
+ }
+ if (heardByCount.present) {
+ map['heard_by_count'] = Variable(heardByCount.value);
+ }
+ if (attempt.present) {
+ map['attempt'] = Variable(attempt.value);
+ }
+ if (isSentByMe.present) {
+ map['is_sent_by_me'] = Variable(isSentByMe.value);
+ }
+ if (isRead.present) {
+ map['is_read'] = Variable(isRead.value);
+ }
+ if (companionDeviceKey.present) {
+ map['companion_device_key'] = Variable(companionDeviceKey.value);
+ }
+ if (hopCount.present) {
+ map['hop_count'] = Variable(hopCount.value);
+ }
+ if (snr.present) {
+ map['snr'] = Variable(snr.value);
+ }
+ if (receivedAt.present) {
+ map['received_at'] = Variable(receivedAt.value);
+ }
+ if (rowid.present) {
+ map['rowid'] = Variable(rowid.value);
+ }
+ return map;
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('MessagesCompanion(')
+ ..write('id: $id, ')
+ ..write('senderId: $senderId, ')
+ ..write('senderName: $senderName, ')
+ ..write('channelHash: $channelHash, ')
+ ..write('content: $content, ')
+ ..write('timestamp: $timestamp, ')
+ ..write('isPrivate: $isPrivate, ')
+ ..write('ackChecksum: $ackChecksum, ')
+ ..write('deliveryStatus: $deliveryStatus, ')
+ ..write('heardByCount: $heardByCount, ')
+ ..write('attempt: $attempt, ')
+ ..write('isSentByMe: $isSentByMe, ')
+ ..write('isRead: $isRead, ')
+ ..write('companionDeviceKey: $companionDeviceKey, ')
+ ..write('hopCount: $hopCount, ')
+ ..write('snr: $snr, ')
+ ..write('receivedAt: $receivedAt, ')
+ ..write('rowid: $rowid')
+ ..write(')'))
+ .toString();
+ }
+}
+
+class $MessagePathsTable extends MessagePaths
+ with TableInfo<$MessagePathsTable, MessagePathData> {
+ @override
+ final GeneratedDatabase attachedDatabase;
+ final String? _alias;
+ $MessagePathsTable(this.attachedDatabase, [this._alias]);
+ static const VerificationMeta _idMeta = const VerificationMeta('id');
+ @override
+ late final GeneratedColumn id = GeneratedColumn(
+ 'id', aliasedName, false,
+ hasAutoIncrement: true,
+ type: DriftSqlType.int,
+ requiredDuringInsert: false,
+ defaultConstraints:
+ GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+ static const VerificationMeta _messageIdMeta =
+ const VerificationMeta('messageId');
+ @override
+ late final GeneratedColumn messageId = GeneratedColumn(
+ 'message_id', aliasedName, false,
+ type: DriftSqlType.string, requiredDuringInsert: true);
+ static const VerificationMeta _pathByteMeta =
+ const VerificationMeta('pathByte');
+ @override
+ late final GeneratedColumn pathByte = GeneratedColumn(
+ 'path_byte', aliasedName, false,
+ type: DriftSqlType.int, requiredDuringInsert: true);
+ static const VerificationMeta _pathBytesMeta =
+ const VerificationMeta('pathBytes');
+ @override
+ late final GeneratedColumn pathBytes = GeneratedColumn(
+ 'path_bytes', aliasedName, false,
+ type: DriftSqlType.blob, requiredDuringInsert: true);
+ static const VerificationMeta _snrMeta = const VerificationMeta('snr');
+ @override
+ late final GeneratedColumn snr = GeneratedColumn(
+ 'snr', aliasedName, true,
+ type: DriftSqlType.int, requiredDuringInsert: false);
+ static const VerificationMeta _rssiMeta = const VerificationMeta('rssi');
+ @override
+ late final GeneratedColumn rssi = GeneratedColumn(
+ 'rssi', aliasedName, true,
+ type: DriftSqlType.int, requiredDuringInsert: false);
+ static const VerificationMeta _receivedAtMeta =
+ const VerificationMeta('receivedAt');
+ @override
+ late final GeneratedColumn receivedAt = GeneratedColumn(
+ 'received_at', aliasedName, false,
+ type: DriftSqlType.int, requiredDuringInsert: true);
+ @override
+ List get $columns =>
+ [id, messageId, pathByte, pathBytes, snr, rssi, receivedAt];
+ @override
+ String get aliasedName => _alias ?? actualTableName;
+ @override
+ String get actualTableName => $name;
+ static const String $name = 'message_paths';
+ @override
+ VerificationContext validateIntegrity(Insertable instance,
+ {bool isInserting = false}) {
+ final context = VerificationContext();
+ final data = instance.toColumns(true);
+ if (data.containsKey('id')) {
+ context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
+ }
+ if (data.containsKey('message_id')) {
+ context.handle(_messageIdMeta,
+ messageId.isAcceptableOrUnknown(data['message_id']!, _messageIdMeta));
+ } else if (isInserting) {
+ context.missing(_messageIdMeta);
+ }
+ if (data.containsKey('path_byte')) {
+ context.handle(_pathByteMeta,
+ pathByte.isAcceptableOrUnknown(data['path_byte']!, _pathByteMeta));
+ } else if (isInserting) {
+ context.missing(_pathByteMeta);
+ }
+ if (data.containsKey('path_bytes')) {
+ context.handle(_pathBytesMeta,
+ pathBytes.isAcceptableOrUnknown(data['path_bytes']!, _pathBytesMeta));
+ } else if (isInserting) {
+ context.missing(_pathBytesMeta);
+ }
+ if (data.containsKey('snr')) {
+ context.handle(
+ _snrMeta, snr.isAcceptableOrUnknown(data['snr']!, _snrMeta));
+ }
+ if (data.containsKey('rssi')) {
+ context.handle(
+ _rssiMeta, rssi.isAcceptableOrUnknown(data['rssi']!, _rssiMeta));
+ }
+ if (data.containsKey('received_at')) {
+ context.handle(
+ _receivedAtMeta,
+ receivedAt.isAcceptableOrUnknown(
+ data['received_at']!, _receivedAtMeta));
+ } else if (isInserting) {
+ context.missing(_receivedAtMeta);
+ }
+ return context;
+ }
+
+ @override
+ Set get $primaryKey => {id};
+ @override
+ List> get uniqueKeys => [
+ {messageId, pathBytes},
+ ];
+ @override
+ MessagePathData map(Map data, {String? tablePrefix}) {
+ final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+ return MessagePathData(
+ id: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
+ messageId: attachedDatabase.typeMapping
+ .read(DriftSqlType.string, data['${effectivePrefix}message_id'])!,
+ pathByte: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}path_byte'])!,
+ pathBytes: attachedDatabase.typeMapping
+ .read(DriftSqlType.blob, data['${effectivePrefix}path_bytes'])!,
+ snr: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}snr']),
+ rssi: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}rssi']),
+ receivedAt: attachedDatabase.typeMapping
+ .read(DriftSqlType.int, data['${effectivePrefix}received_at'])!,
+ );
+ }
+
+ @override
+ $MessagePathsTable createAlias(String alias) {
+ return $MessagePathsTable(attachedDatabase, alias);
+ }
+}
+
+class MessagePathData extends DataClass implements Insertable {
+ final int id;
+ final String messageId;
+ final int pathByte;
+ final Uint8List pathBytes;
+ final int? snr;
+ final int? rssi;
+ final int receivedAt;
+ const MessagePathData(
+ {required this.id,
+ required this.messageId,
+ required this.pathByte,
+ required this.pathBytes,
+ this.snr,
+ this.rssi,
+ required this.receivedAt});
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ map['id'] = Variable(id);
+ map['message_id'] = Variable(messageId);
+ map['path_byte'] = Variable(pathByte);
+ map['path_bytes'] = Variable(pathBytes);
+ if (!nullToAbsent || snr != null) {
+ map['snr'] = Variable(snr);
+ }
+ if (!nullToAbsent || rssi != null) {
+ map['rssi'] = Variable(rssi);
+ }
+ map['received_at'] = Variable(receivedAt);
+ return map;
+ }
+
+ MessagePathsCompanion toCompanion(bool nullToAbsent) {
+ return MessagePathsCompanion(
+ id: Value(id),
+ messageId: Value(messageId),
+ pathByte: Value(pathByte),
+ pathBytes: Value(pathBytes),
+ snr: snr == null && nullToAbsent ? const Value.absent() : Value(snr),
+ rssi: rssi == null && nullToAbsent ? const Value.absent() : Value(rssi),
+ receivedAt: Value(receivedAt),
+ );
+ }
+
+ factory MessagePathData.fromJson(Map json,
+ {ValueSerializer? serializer}) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return MessagePathData(
+ id: serializer.fromJson(json['id']),
+ messageId: serializer.fromJson(json['messageId']),
+ pathByte: serializer.fromJson(json['pathByte']),
+ pathBytes: serializer.fromJson(json['pathBytes']),
+ snr: serializer.fromJson(json['snr']),
+ rssi: serializer.fromJson(json['rssi']),
+ receivedAt: serializer.fromJson(json['receivedAt']),
+ );
+ }
+ @override
+ Map toJson({ValueSerializer? serializer}) {
+ serializer ??= driftRuntimeOptions.defaultSerializer;
+ return {
+ 'id': serializer.toJson(id),
+ 'messageId': serializer.toJson(messageId),
+ 'pathByte': serializer.toJson(pathByte),
+ 'pathBytes': serializer.toJson(pathBytes),
+ 'snr': serializer.toJson(snr),
+ 'rssi': serializer.toJson(rssi),
+ 'receivedAt': serializer.toJson(receivedAt),
+ };
+ }
+
+ MessagePathData copyWith(
+ {int? id,
+ String? messageId,
+ int? pathByte,
+ Uint8List? pathBytes,
+ Value snr = const Value.absent(),
+ Value rssi = const Value.absent(),
+ int? receivedAt}) =>
+ MessagePathData(
+ id: id ?? this.id,
+ messageId: messageId ?? this.messageId,
+ pathByte: pathByte ?? this.pathByte,
+ pathBytes: pathBytes ?? this.pathBytes,
+ snr: snr.present ? snr.value : this.snr,
+ rssi: rssi.present ? rssi.value : this.rssi,
+ receivedAt: receivedAt ?? this.receivedAt,
+ );
+ MessagePathData copyWithCompanion(MessagePathsCompanion data) {
+ return MessagePathData(
+ id: data.id.present ? data.id.value : this.id,
+ messageId: data.messageId.present ? data.messageId.value : this.messageId,
+ pathByte: data.pathByte.present ? data.pathByte.value : this.pathByte,
+ pathBytes: data.pathBytes.present ? data.pathBytes.value : this.pathBytes,
+ snr: data.snr.present ? data.snr.value : this.snr,
+ rssi: data.rssi.present ? data.rssi.value : this.rssi,
+ receivedAt:
+ data.receivedAt.present ? data.receivedAt.value : this.receivedAt,
+ );
+ }
+
+ @override
+ String toString() {
+ return (StringBuffer('MessagePathData(')
+ ..write('id: $id, ')
+ ..write('messageId: $messageId, ')
+ ..write('pathByte: $pathByte, ')
+ ..write('pathBytes: $pathBytes, ')
+ ..write('snr: $snr, ')
+ ..write('rssi: $rssi, ')
+ ..write('receivedAt: $receivedAt')
+ ..write(')'))
+ .toString();
+ }
+
+ @override
+ int get hashCode => Object.hash(id, messageId, pathByte,
+ $driftBlobEquality.hash(pathBytes), snr, rssi, receivedAt);
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ (other is MessagePathData &&
+ other.id == this.id &&
+ other.messageId == this.messageId &&
+ other.pathByte == this.pathByte &&
+ $driftBlobEquality.equals(other.pathBytes, this.pathBytes) &&
+ other.snr == this.snr &&
+ other.rssi == this.rssi &&
+ other.receivedAt == this.receivedAt);
+}
+
+class MessagePathsCompanion extends UpdateCompanion {
+ final Value id;
+ final Value messageId;
+ final Value pathByte;
+ final Value pathBytes;
+ final Value snr;
+ final Value rssi;
+ final Value receivedAt;
+ const MessagePathsCompanion({
+ this.id = const Value.absent(),
+ this.messageId = const Value.absent(),
+ this.pathByte = const Value.absent(),
+ this.pathBytes = const Value.absent(),
+ this.snr = const Value.absent(),
+ this.rssi = const Value.absent(),
+ this.receivedAt = const Value.absent(),
+ });
+ MessagePathsCompanion.insert({
+ this.id = const Value.absent(),
+ required String messageId,
+ required int pathByte,
+ required Uint8List pathBytes,
+ this.snr = const Value.absent(),
+ this.rssi = const Value.absent(),
+ required int receivedAt,
+ }) : messageId = Value(messageId),
+ pathByte = Value(pathByte),
+ pathBytes = Value(pathBytes),
+ receivedAt = Value(receivedAt);
+ static Insertable custom({
+ Expression? id,
+ Expression? messageId,
+ Expression? pathByte,
+ Expression? pathBytes,
+ Expression? snr,
+ Expression? rssi,
+ Expression? receivedAt,
+ }) {
+ return RawValuesInsertable({
+ if (id != null) 'id': id,
+ if (messageId != null) 'message_id': messageId,
+ if (pathByte != null) 'path_byte': pathByte,
+ if (pathBytes != null) 'path_bytes': pathBytes,
+ if (snr != null) 'snr': snr,
+ if (rssi != null) 'rssi': rssi,
+ if (receivedAt != null) 'received_at': receivedAt,
+ });
+ }
+
+ MessagePathsCompanion copyWith(
+ {Value? id,
+ Value? messageId,
+ Value? pathByte,
+ Value? pathBytes,
+ Value? snr,
+ Value? rssi,
+ Value? receivedAt}) {
+ return MessagePathsCompanion(
+ id: id ?? this.id,
+ messageId: messageId ?? this.messageId,
+ pathByte: pathByte ?? this.pathByte,
+ pathBytes: pathBytes ?? this.pathBytes,
+ snr: snr ?? this.snr,
+ rssi: rssi ?? this.rssi,
+ receivedAt: receivedAt ?? this.receivedAt,
+ );
+ }
+
+ @override
+ Map toColumns(bool nullToAbsent) {
+ final map = {};
+ if (id.present) {
+ map['id'] = Variable(id.value);
}
- if (heardByCount.present) {
- map['heard_by_count'] = Variable(heardByCount.value);
+ if (messageId.present) {
+ map['message_id'] = Variable(messageId.value);
}
- if (attempt.present) {
- map['attempt'] = Variable(attempt.value);
+ if (pathByte.present) {
+ map['path_byte'] = Variable(pathByte.value);
}
- if (isSentByMe.present) {
- map['is_sent_by_me'] = Variable(isSentByMe.value);
+ if (pathBytes.present) {
+ map['path_bytes'] = Variable(pathBytes.value);
}
- if (isRead.present) {
- map['is_read'] = Variable(isRead.value);
+ if (snr.present) {
+ map['snr'] = Variable(snr.value);
}
- if (companionDeviceKey.present) {
- map['companion_device_key'] = Variable(companionDeviceKey.value);
+ if (rssi.present) {
+ map['rssi'] = Variable(rssi.value);
}
- if (rowid.present) {
- map['rowid'] = Variable(rowid.value);
+ if (receivedAt.present) {
+ map['received_at'] = Variable(receivedAt.value);
}
return map;
}
@override
String toString() {
- return (StringBuffer('MessagesCompanion(')
+ return (StringBuffer('MessagePathsCompanion(')
..write('id: $id, ')
- ..write('senderId: $senderId, ')
- ..write('senderName: $senderName, ')
- ..write('channelHash: $channelHash, ')
- ..write('content: $content, ')
- ..write('timestamp: $timestamp, ')
- ..write('isPrivate: $isPrivate, ')
- ..write('ackChecksum: $ackChecksum, ')
- ..write('deliveryStatus: $deliveryStatus, ')
- ..write('heardByCount: $heardByCount, ')
- ..write('attempt: $attempt, ')
- ..write('isSentByMe: $isSentByMe, ')
- ..write('isRead: $isRead, ')
- ..write('companionDeviceKey: $companionDeviceKey, ')
- ..write('rowid: $rowid')
+ ..write('messageId: $messageId, ')
+ ..write('pathByte: $pathByte, ')
+ ..write('pathBytes: $pathBytes, ')
+ ..write('snr: $snr, ')
+ ..write('rssi: $rssi, ')
+ ..write('receivedAt: $receivedAt')
..write(')'))
.toString();
}
@@ -5863,6 +6358,7 @@ abstract class _$AppDatabase extends GeneratedDatabase {
late final $ContactsTable contacts = $ContactsTable(this);
late final $ChannelsTable channels = $ChannelsTable(this);
late final $MessagesTable messages = $MessagesTable(this);
+ late final $MessagePathsTable messagePaths = $MessagePathsTable(this);
late final $WaypointsTable waypoints = $WaypointsTable(this);
late final $CompanionDevicesTable companionDevices =
$CompanionDevicesTable(this);
@@ -5878,6 +6374,8 @@ abstract class _$AppDatabase extends GeneratedDatabase {
late final ContactsDao contactsDao = ContactsDao(this as AppDatabase);
late final ChannelsDao channelsDao = ChannelsDao(this as AppDatabase);
late final MessagesDao messagesDao = MessagesDao(this as AppDatabase);
+ late final MessagePathsDao messagePathsDao =
+ MessagePathsDao(this as AppDatabase);
late final WaypointsDao waypointsDao = WaypointsDao(this as AppDatabase);
late final AckRecordsDao ackRecordsDao = AckRecordsDao(this as AppDatabase);
late final CompanionDevicesDao companionDevicesDao =
@@ -5894,6 +6392,7 @@ abstract class _$AppDatabase extends GeneratedDatabase {
contacts,
channels,
messages,
+ messagePaths,
waypoints,
companionDevices,
contactDisplayStates,
@@ -6533,6 +7032,9 @@ typedef $$MessagesTableCreateCompanionBuilder = MessagesCompanion Function({
required bool isSentByMe,
Value isRead,
Value companionDeviceKey,
+ Value hopCount,
+ Value snr,
+ Value receivedAt,
Value rowid,
});
typedef $$MessagesTableUpdateCompanionBuilder = MessagesCompanion Function({
@@ -6550,6 +7052,9 @@ typedef $$MessagesTableUpdateCompanionBuilder = MessagesCompanion Function({
Value isSentByMe,
Value isRead,
Value companionDeviceKey,
+ Value hopCount,
+ Value snr,
+ Value receivedAt,
Value rowid,
});
@@ -6605,6 +7110,15 @@ class $$MessagesTableFilterComposer
ColumnFilters get companionDeviceKey => $composableBuilder(
column: $table.companionDeviceKey,
builder: (column) => ColumnFilters(column));
+
+ ColumnFilters get hopCount => $composableBuilder(
+ column: $table.hopCount, builder: (column) => ColumnFilters(column));
+
+ ColumnFilters get snr => $composableBuilder(
+ column: $table.snr, builder: (column) => ColumnFilters(column));
+
+ ColumnFilters get receivedAt => $composableBuilder(
+ column: $table.receivedAt, builder: (column) => ColumnFilters(column));
}
class $$MessagesTableOrderingComposer
@@ -6660,6 +7174,15 @@ class $$MessagesTableOrderingComposer
ColumnOrderings get companionDeviceKey => $composableBuilder(
column: $table.companionDeviceKey,
builder: (column) => ColumnOrderings(column));
+
+ ColumnOrderings get hopCount => $composableBuilder(
+ column: $table.hopCount, builder: (column) => ColumnOrderings(column));
+
+ ColumnOrderings get snr => $composableBuilder(
+ column: $table.snr, builder: (column) => ColumnOrderings(column));
+
+ ColumnOrderings get receivedAt => $composableBuilder(
+ column: $table.receivedAt, builder: (column) => ColumnOrderings(column));
}
class $$MessagesTableAnnotationComposer
@@ -6712,6 +7235,15 @@ class $$MessagesTableAnnotationComposer
GeneratedColumn get companionDeviceKey => $composableBuilder(
column: $table.companionDeviceKey, builder: (column) => column);
+
+ GeneratedColumn get hopCount =>
+ $composableBuilder(column: $table.hopCount, builder: (column) => column);
+
+ GeneratedColumn get snr =>
+ $composableBuilder(column: $table.snr, builder: (column) => column);
+
+ GeneratedColumn get receivedAt => $composableBuilder(
+ column: $table.receivedAt, builder: (column) => column);
}
class $$MessagesTableTableManager extends RootTableManager<
@@ -6751,6 +7283,9 @@ class $$MessagesTableTableManager extends RootTableManager<
Value isSentByMe = const Value.absent(),
Value isRead = const Value.absent(),
Value companionDeviceKey = const Value.absent(),
+ Value hopCount = const Value.absent(),
+ Value snr = const Value.absent(),
+ Value