mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
Fix RX advert data parsing
This commit is contained in:
@@ -45,6 +45,7 @@ import 'system_message_bubble.dart';
|
||||
/// - Grouped messages (expandable recipient list)
|
||||
class MessageBubble extends StatefulWidget {
|
||||
final Message message;
|
||||
final int receivedCopies;
|
||||
final VoidCallback? onTap;
|
||||
final VoidCallback? onReply;
|
||||
final bool isHighlighted;
|
||||
@@ -56,6 +57,7 @@ class MessageBubble extends StatefulWidget {
|
||||
const MessageBubble({
|
||||
super.key,
|
||||
required this.message,
|
||||
this.receivedCopies = 1,
|
||||
this.onTap,
|
||||
this.onReply,
|
||||
this.isHighlighted = false,
|
||||
@@ -576,6 +578,7 @@ class _MessageBubbleState extends State<MessageBubble> {
|
||||
'Sender to receipt ms: ${receptionDetails?.senderToReceiptMs ?? '-'}',
|
||||
'Estimated transmit ms: ${receptionDetails?.estimatedTransmitMs ?? '-'}',
|
||||
'Post-transmit delay ms: ${receptionDetails?.postTransmitDelayMs ?? '-'}',
|
||||
'Received copies: ${widget.receivedCopies}',
|
||||
'Expected ACK tag: ${widget.message.expectedAckTag ?? '-'}',
|
||||
'Suggested timeout ms: ${widget.message.suggestedTimeoutMs ?? '-'}',
|
||||
'Round-trip ms: ${widget.message.roundTripTimeMs ?? '-'}',
|
||||
@@ -846,6 +849,12 @@ class _MessageBubbleState extends State<MessageBubble> {
|
||||
receptionDetails!.postTransmitDelayMs!,
|
||||
),
|
||||
),
|
||||
if (widget.receivedCopies > 1)
|
||||
_detailRow(
|
||||
context,
|
||||
label: 'Received copies',
|
||||
value: '${widget.receivedCopies}',
|
||||
),
|
||||
if (widget.message.suggestedTimeoutMs != null)
|
||||
_detailRow(
|
||||
context,
|
||||
|
||||
@@ -154,8 +154,8 @@ class _MessageTraceSheetState extends State<MessageTraceSheet> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
trace.mode == TraceMode.packetPath
|
||||
? 'Route from packet path bytes'
|
||||
: 'Route inferred from hop count (${widget.message.pathLen})',
|
||||
? 'Relay path from packet path bytes'
|
||||
: 'Relay path inferred from hop count (${widget.message.pathLen})',
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
),
|
||||
@@ -222,14 +222,7 @@ class _MessageTraceSheetState extends State<MessageTraceSheet> {
|
||||
child: CircleAvatar(
|
||||
radius: 16,
|
||||
backgroundColor:
|
||||
entry.key == 0
|
||||
? Colors.green
|
||||
: (entry.key ==
|
||||
concretePathNodes
|
||||
.length -
|
||||
1
|
||||
? Colors.red
|
||||
: Colors.blue),
|
||||
Colors.blue,
|
||||
child: Text(
|
||||
'${entry.key + 1}',
|
||||
style: const TextStyle(
|
||||
@@ -259,7 +252,7 @@ class _MessageTraceSheetState extends State<MessageTraceSheet> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
'Route',
|
||||
'Relay path',
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
@@ -286,11 +279,7 @@ class _MessageTraceSheetState extends State<MessageTraceSheet> {
|
||||
: null,
|
||||
leading: CircleAvatar(
|
||||
radius: 14,
|
||||
backgroundColor: entry.key == 0
|
||||
? Colors.green
|
||||
: (entry.key == routeEntries.length - 1
|
||||
? Colors.red
|
||||
: Colors.blue),
|
||||
backgroundColor: Colors.blue,
|
||||
child: Text(
|
||||
'${entry.key + 1}',
|
||||
style: const TextStyle(
|
||||
@@ -302,7 +291,7 @@ class _MessageTraceSheetState extends State<MessageTraceSheet> {
|
||||
),
|
||||
title: Text(entry.value.label),
|
||||
subtitle: Text(
|
||||
'${_routeRoleLabel(entry.key, routeEntries.length)}${entry.value.keyLabel == null ? '' : ' • ${entry.value.keyLabel}'}${entry.value.matchSummary == null ? '' : ' • ${entry.value.matchSummary}'}${entry.value.resolved.cycleSummary == null ? '' : ' • ${entry.value.resolved.cycleSummary}'}',
|
||||
'Relay${entry.value.keyLabel == null ? '' : ' • ${entry.value.keyLabel}'}${entry.value.matchSummary == null ? '' : ' • ${entry.value.matchSummary}'}${entry.value.resolved.cycleSummary == null ? '' : ' • ${entry.value.resolved.cycleSummary}'}',
|
||||
),
|
||||
trailing: entry.value.resolved.canCycle
|
||||
? const Icon(Icons.sync_alt)
|
||||
@@ -365,28 +354,8 @@ class _MessageTraceSheetState extends State<MessageTraceSheet> {
|
||||
}
|
||||
|
||||
List<_RouteDisplayEntry> _displayRouteEntries(_TraceResult trace) {
|
||||
final pathNodes = trace.matchedPathNodes
|
||||
.map((entry) => entry.node)
|
||||
.whereType<MeshMapNode>()
|
||||
.toList();
|
||||
if (pathNodes.isEmpty) {
|
||||
return [
|
||||
if (trace.sender.node != null)
|
||||
_RouteDisplayEntry.fromResolved(
|
||||
trace.sender,
|
||||
target: const _RouteEntryTarget.sender(),
|
||||
),
|
||||
if (trace.recipient.node != null &&
|
||||
trace.recipient.node!.publicKey != trace.sender.node?.publicKey)
|
||||
_RouteDisplayEntry.fromResolved(
|
||||
trace.recipient,
|
||||
target: const _RouteEntryTarget.recipient(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
if (trace.mode == TraceMode.packetPath) {
|
||||
final entries = trace.matchedPathNodes.asMap().entries.map((entry) {
|
||||
return trace.matchedPathNodes.asMap().entries.map((entry) {
|
||||
final hashHex = trace.pathHashes[entry.key].toUpperCase();
|
||||
return _RouteDisplayEntry(
|
||||
resolved: entry.value,
|
||||
@@ -398,54 +367,24 @@ class _MessageTraceSheetState extends State<MessageTraceSheet> {
|
||||
target: _RouteEntryTarget.pathNode(entry.key),
|
||||
);
|
||||
}).toList();
|
||||
final lastKey = pathNodes.last.publicKey;
|
||||
return [
|
||||
...entries,
|
||||
if (trace.recipient.node != null &&
|
||||
trace.recipient.node!.publicKey != lastKey)
|
||||
_RouteDisplayEntry.fromResolved(
|
||||
trace.recipient,
|
||||
target: const _RouteEntryTarget.recipient(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
final firstKey = pathNodes.first.publicKey;
|
||||
final lastKey = pathNodes.last.publicKey;
|
||||
return [
|
||||
if (trace.sender.node != null && trace.sender.node!.publicKey != firstKey)
|
||||
_RouteDisplayEntry.fromResolved(
|
||||
trace.sender,
|
||||
target: const _RouteEntryTarget.sender(),
|
||||
),
|
||||
...trace.matchedPathNodes
|
||||
.asMap()
|
||||
.entries
|
||||
.where((entry) => entry.value.node != null)
|
||||
.map(
|
||||
(entry) => _RouteDisplayEntry.fromResolved(
|
||||
entry.value,
|
||||
target: _RouteEntryTarget.pathNode(entry.key),
|
||||
),
|
||||
return trace.matchedPathNodes
|
||||
.asMap()
|
||||
.entries
|
||||
.where((entry) => entry.value.node != null)
|
||||
.map(
|
||||
(entry) => _RouteDisplayEntry.fromResolved(
|
||||
entry.value,
|
||||
target: _RouteEntryTarget.pathNode(entry.key),
|
||||
),
|
||||
if (trace.recipient.node != null &&
|
||||
trace.recipient.node!.publicKey != lastKey)
|
||||
_RouteDisplayEntry.fromResolved(
|
||||
trace.recipient,
|
||||
target: const _RouteEntryTarget.recipient(),
|
||||
),
|
||||
];
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
String _prefixKeyLabel(String publicKey) =>
|
||||
publicKey.substring(0, math.min(12, publicKey.length));
|
||||
|
||||
String _routeRoleLabel(int index, int total) {
|
||||
if (index == 0) return 'Sender';
|
||||
if (index == total - 1) return 'Recipient';
|
||||
return 'Relay';
|
||||
}
|
||||
|
||||
String? _toPrefixHex(List<int>? key) {
|
||||
if (key == null || key.isEmpty) return null;
|
||||
final take = key.length < 6 ? key.length : 6;
|
||||
@@ -521,7 +460,7 @@ class _MessageTraceSheetState extends State<MessageTraceSheet> {
|
||||
final hopHashes = LogRxRouteDecoder.splitHopHashes(
|
||||
packetPath,
|
||||
hashSize: hashSize,
|
||||
).reversed.toList();
|
||||
);
|
||||
final matched = _matchNodesFromPathHashes(
|
||||
nodes: nodes,
|
||||
localPublicKeys: localPublicKeys,
|
||||
@@ -731,22 +670,6 @@ class _TraceResult {
|
||||
|
||||
_TraceResult cycleEntry(_RouteEntryTarget target) {
|
||||
switch (target.kind) {
|
||||
case _RouteEntryKind.sender:
|
||||
return _TraceResult(
|
||||
mode: mode,
|
||||
sender: sender.cycle(),
|
||||
recipient: recipient,
|
||||
pathHashes: pathHashes,
|
||||
matchedPathNodes: matchedPathNodes,
|
||||
);
|
||||
case _RouteEntryKind.recipient:
|
||||
return _TraceResult(
|
||||
mode: mode,
|
||||
sender: sender,
|
||||
recipient: recipient.cycle(),
|
||||
pathHashes: pathHashes,
|
||||
matchedPathNodes: matchedPathNodes,
|
||||
);
|
||||
case _RouteEntryKind.pathNode:
|
||||
final updated = matchedPathNodes.toList();
|
||||
updated[target.index] = updated[target.index].cycle();
|
||||
@@ -796,7 +719,7 @@ class _RouteDisplayEntry {
|
||||
}
|
||||
}
|
||||
|
||||
enum _RouteEntryKind { sender, recipient, pathNode }
|
||||
enum _RouteEntryKind { pathNode }
|
||||
|
||||
class _RouteEntryTarget {
|
||||
final _RouteEntryKind kind;
|
||||
@@ -804,8 +727,6 @@ class _RouteEntryTarget {
|
||||
|
||||
const _RouteEntryTarget._(this.kind, [this.index = 0]);
|
||||
|
||||
const _RouteEntryTarget.sender() : this._(_RouteEntryKind.sender);
|
||||
const _RouteEntryTarget.recipient() : this._(_RouteEntryKind.recipient);
|
||||
const _RouteEntryTarget.pathNode(int index)
|
||||
: this._(_RouteEntryKind.pathNode, index);
|
||||
}
|
||||
|
||||
@@ -2,13 +2,14 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../../models/message.dart';
|
||||
import '../../providers/messages_provider.dart';
|
||||
import '../common/bidirectional_refresh.dart';
|
||||
import '../../widgets/messages/message_bubble.dart';
|
||||
|
||||
class MessagesContent extends StatelessWidget {
|
||||
static const double defaultPadding = 8;
|
||||
|
||||
final List<Message> messages;
|
||||
final List<DisplayMessageEntry> messages;
|
||||
final ScrollController scrollController;
|
||||
final String? highlightedMessageId;
|
||||
final double bottomContentPadding;
|
||||
@@ -84,11 +85,13 @@ class MessagesContent extends StatelessWidget {
|
||||
),
|
||||
itemCount: messages.length,
|
||||
itemBuilder: (context, index) {
|
||||
final message = messages[index];
|
||||
final entry = messages[index];
|
||||
final message = entry.message;
|
||||
|
||||
return MessageBubble(
|
||||
key: ValueKey(message.id),
|
||||
message: message,
|
||||
receivedCopies: entry.occurrenceCount,
|
||||
isHighlighted: message.id == highlightedMessageId,
|
||||
onNavigateToMap: onNavigateToMap,
|
||||
onTap: onMessageTap == null
|
||||
|
||||
Reference in New Issue
Block a user