fix: Remove relay labels, add signal bars #123

This commit is contained in:
Janez T
2026-03-16 22:01:41 +01:00
parent 9b14ff4e1a
commit cfd233d38e
5 changed files with 50 additions and 81 deletions

View File

@@ -402,6 +402,30 @@ class _HomeScreenState extends State<HomeScreen>
); );
} }
Widget _buildMiniSignalBars({
required int activeBars,
required Color color,
}) {
final inactive = Colors.grey.withValues(alpha: 0.3);
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
for (var i = 0; i < 5; i++) ...[
if (i > 0) const SizedBox(width: 1.5),
Container(
width: 2.5,
height: 4.0 + (i * 2),
decoration: BoxDecoration(
color: i < activeBars ? color : inactive,
borderRadius: BorderRadius.circular(1.5),
),
),
],
],
);
}
Widget _buildCompactActivityIndicator({ Widget _buildCompactActivityIndicator({
required bool rxActive, required bool rxActive,
required bool txActive, required bool txActive,
@@ -1008,17 +1032,11 @@ class _HomeScreenState extends State<HomeScreen>
if (!isTcpConnected && if (!isTcpConnected &&
deviceInfo.signalRssi != null) ...[ deviceInfo.signalRssi != null) ...[
const SizedBox(width: 4), const SizedBox(width: 4),
SizedBox( _buildMiniSignalBars(
width: 28, activeBars: BatteryDisplayHelper.getSignalBars(
child: Text( deviceInfo.signalRssi!,
'${deviceInfo.signalRssi}',
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w600,
color: signalColor,
),
maxLines: 1,
), ),
color: signalColor,
), ),
], ],
if (deviceInfo.batteryPercent != null) ...[ if (deviceInfo.batteryPercent != null) ...[
@@ -1033,20 +1051,16 @@ class _HomeScreenState extends State<HomeScreen>
deviceInfo.batteryPercent!, deviceInfo.batteryPercent!,
), ),
), ),
const SizedBox(width: 4), const SizedBox(width: 2),
SizedBox( Text(
width: 30, '${deviceInfo.batteryPercent!.round()}%',
child: Text( style: TextStyle(
'${deviceInfo.batteryPercent!.round()}%', fontSize: 10,
overflow: TextOverflow.ellipsis, fontWeight: FontWeight.w600,
style: TextStyle( color:
fontSize: 10, BatteryDisplayHelper.getBatteryColor(
fontWeight: FontWeight.w600, deviceInfo.batteryPercent!,
color: ),
BatteryDisplayHelper.getBatteryColor(
deviceInfo.batteryPercent!,
),
),
), ),
), ),
], ],

View File

@@ -24,4 +24,14 @@ class BatteryDisplayHelper {
if (rssi > -70) return Colors.orange; if (rssi > -70) return Colors.orange;
return Colors.red; return Colors.red;
} }
/// Number of active signal bars (0-5) for a BLE RSSI value.
static int getSignalBars(int rssi) {
if (rssi > -50) return 5;
if (rssi > -60) return 4;
if (rssi > -70) return 3;
if (rssi > -80) return 2;
if (rssi > -90) return 1;
return 0;
}
} }

View File

@@ -265,7 +265,7 @@ class _ContactTraceSheetState extends State<ContactTraceSheet> {
), ),
title: Text(entry.value.label), title: Text(entry.value.label),
subtitle: Text( subtitle: Text(
'Relay${entry.value.keyLabel == null ? '' : '${entry.value.keyLabel}'}${entry.value.matchSummary == null ? '' : '${entry.value.matchSummary}'}${entry.value.resolved.cycleSummary == null ? '' : '${entry.value.resolved.cycleSummary}'}', 'Path node${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 trailing: entry.value.resolved.canCycle
? const Icon(Icons.sync_alt) ? const Icon(Icons.sync_alt)

View File

@@ -905,12 +905,6 @@ class _MessageBubbleState extends State<MessageBubble> {
label: l10n.floodFallback, label: l10n.floodFallback,
value: l10n.yes, value: l10n.yes,
), ),
if (routeMetadata?.relayName case final relayName?)
_detailRow(
sheetContext,
label: 'Relay',
value: relayName,
),
if (routeMetadata?.canonicalPath if (routeMetadata?.canonicalPath
case final routePath?) case final routePath?)
_detailRow( _detailRow(

View File

@@ -149,8 +149,6 @@ class _MessageTraceSheetState extends State<MessageTraceSheet> {
.map((n) => LatLng(n.latitude, n.longitude)) .map((n) => LatLng(n.latitude, n.longitude))
.toList(); .toList();
final hasMapPath = mapPoints.length >= 2; final hasMapPath = mapPoints.length >= 2;
final relayNodes = _relayNodes(trace);
return SizedBox( return SizedBox(
height: MediaQuery.of(context).size.height * 0.75, height: MediaQuery.of(context).size.height * 0.75,
child: Column( child: Column(
@@ -317,41 +315,13 @@ class _MessageTraceSheetState extends State<MessageTraceSheet> {
), ),
title: Text(entry.value.label), title: Text(entry.value.label),
subtitle: Text( subtitle: Text(
'Relay${entry.value.keyLabel == null ? '' : '${entry.value.keyLabel}'}${entry.value.matchSummary == null ? '' : '${entry.value.matchSummary}'}${entry.value.resolved.cycleSummary == null ? '' : '${entry.value.resolved.cycleSummary}'}', 'Path node${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 trailing: entry.value.resolved.canCycle
? const Icon(Icons.sync_alt) ? const Icon(Icons.sync_alt)
: null, : null,
), ),
), ),
const SizedBox(height: 12),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
'Relays (${relayNodes.length})',
style: Theme.of(context).textTheme.titleMedium,
),
),
if (relayNodes.isEmpty)
const Padding(
padding: EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: Text(
'No relay nodes could be matched for this message.',
),
),
...relayNodes.map(
(node) => ListTile(
leading: const Icon(Icons.router),
title: Text(node.name),
subtitle: Text(
'${node.publicKey.substring(0, math.min(12, node.publicKey.length))}'
'${node.latitude.toStringAsFixed(5)}, ${node.longitude.toStringAsFixed(5)}',
),
),
),
], ],
), ),
), ),
@@ -363,25 +333,6 @@ class _MessageTraceSheetState extends State<MessageTraceSheet> {
); );
} }
List<MeshMapNode> _relayNodes(_TraceResult trace) {
final concrete = trace.matchedPathNodes
.map((entry) => entry.node)
.whereType<MeshMapNode>()
.toList();
if (concrete.isEmpty) return const [];
if (trace.mode == TraceMode.packetPath) {
if (widget.message == null) {
return concrete;
}
if (concrete.length <= 1) return const [];
return concrete.sublist(1);
}
if (concrete.length <= 2) return const [];
return concrete.sublist(1, concrete.length - 1);
}
List<_RouteDisplayEntry> _displayRouteEntries(_TraceResult trace) { List<_RouteDisplayEntry> _displayRouteEntries(_TraceResult trace) {
if (trace.mode == TraceMode.packetPath) { if (trace.mode == TraceMode.packetPath) {
return trace.matchedPathNodes.asMap().entries.map((entry) { return trace.matchedPathNodes.asMap().entries.map((entry) {