Add advanced path management, debug logging, and fix channel sync

New features:
- In-app debug log viewer with copy/clear functionality
- Advanced path management UI with history and custom path builder
- Battery indicator widget with voltage/percentage toggle
- Contact/channel filtering and sorting improvements
- Repeater command ACK tracking with path history integration

Fixes:
- Switch channel sync from parallel to sequential to prevent timeouts
- Preserve path overrides when contacts refresh from device
- Fix ACK hash computation for SMAZ-encoded messages
- Proper cleanup of pending operations on disconnect
This commit is contained in:
zach
2026-01-02 14:22:39 -07:00
parent 361dfb7808
commit ad911a1d80
32 changed files with 2914 additions and 849 deletions
+18 -4
View File
@@ -46,6 +46,11 @@ class Contact {
}
String get pathLabel {
if (pathOverride != null) {
if (pathOverride! < 0) return 'Flood (forced)';
if (pathOverride == 0) return 'Direct (forced)';
return '$pathOverride hops (forced)';
}
if (pathLength < 0) return 'Flood';
if (pathLength == 0) return 'Direct';
return '$pathLength hops';
@@ -83,12 +88,13 @@ class Contact {
}
String get pathIdList {
if (path.isEmpty) return '';
final pathBytes = _pathBytesForDisplay;
if (pathBytes.isEmpty) return '';
final parts = <String>[];
final groupSize = pathHashSize;
for (int i = 0; i < path.length; i += groupSize) {
final end = (i + groupSize) <= path.length ? (i + groupSize) : path.length;
final chunk = path.sublist(i, end);
for (int i = 0; i < pathBytes.length; i += groupSize) {
final end = (i + groupSize) <= pathBytes.length ? (i + groupSize) : pathBytes.length;
final chunk = pathBytes.sublist(i, end);
parts.add(
chunk.map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase()).join(),
);
@@ -96,6 +102,14 @@ class Contact {
return parts.join(',');
}
Uint8List get _pathBytesForDisplay {
if (pathOverride != null) {
if (pathOverride! < 0) return Uint8List(0);
return pathOverrideBytes ?? Uint8List(0);
}
return path;
}
static Contact? fromFrame(Uint8List data) {
if (data.length < contactFrameSize) return null;
if (data[0] != respCodeContact) return null;