diff --git a/lib/screens/contacts_screen.dart b/lib/screens/contacts_screen.dart index 97e47b1..13f116a 100644 --- a/lib/screens/contacts_screen.dart +++ b/lib/screens/contacts_screen.dart @@ -1266,31 +1266,32 @@ class _ContactsScreenState extends State if (isRepeater) ...[ ListTile( leading: const Icon(Icons.radar, color: Colors.green), - title: Text( - contact.pathBytesForDisplay.isNotEmpty - ? context.l10n.contacts_pathTrace - : context.l10n.contacts_ping, - ), + title: Text(context.l10n.contacts_pathTrace), onTap: () { final hw = context .read() .pathHashByteWidth; + // A flood route is stored as all-zero bytes = "no real route", + // so trace the target directly instead of routing through (and + // sending) an all-zero/empty path. (#150) + final route = contact.pathBytesForDisplay; + final hasRoute = route.isNotEmpty && route.any((b) => b != 0); Navigator.push( context, MaterialPageRoute( builder: (context) => PathTraceMapScreen( - title: contact.pathBytesForDisplay.isNotEmpty + title: hasRoute ? context.l10n.contacts_repeaterPathTrace : context.l10n.contacts_repeaterPing, - path: contact.pathBytesForDisplay.isNotEmpty - ? contact.pathBytesForDisplay + path: hasRoute + ? route : Uint8List.fromList( contact.publicKey.sublist( 0, PathHelper.traceHopBytes(hw), ), ), - flipPathAround: contact.pathBytesForDisplay.isNotEmpty, + flipPathAround: hasRoute, targetContact: contact, pathHashByteWidth: hw, ), diff --git a/lib/screens/path_trace_map.dart b/lib/screens/path_trace_map.dart index 3e15297..493b7d2 100644 --- a/lib/screens/path_trace_map.dart +++ b/lib/screens/path_trace_map.dart @@ -199,17 +199,15 @@ class _PathTraceMapScreenState extends State { final hopBytes = PathHelper.traceHopBytes(widget.pathHashByteWidth); final pk = widget.targetContact?.publicKey; - if (pathBytes.isEmpty) { - // Direct target: send its own width prefix. + // Empty path, or an all-zero "flood" marker, means no real route — trace + // the target's own width prefix directly. Never return an empty payload: + // the firmware rejects an empty trace with error 1. (#150) + if (pathBytes.isEmpty || pathBytes.every((b) => b == 0)) { if (pk != null && pk.length >= hopBytes) { return Uint8List.fromList(pk.sublist(0, hopBytes)); } return Uint8List.fromList([pk != null && pk.isNotEmpty ? pk[0] : 0]); } - // An all-zero path is the "no known path" marker → no trace payload. - if (pathBytes.every((b) => b == 0)) { - return Uint8List(0); - } final throughTarget = widget.targetContact?.type == advTypeRepeater || @@ -246,6 +244,23 @@ class _PathTraceMapScreenState extends State { final path = widget.flipPathAround ? buildPath(pathTmp) : pathTmp; + if (path.isEmpty) { + // No route to trace — don't send an empty payload (firmware error 1); + // surface "not available" instead. (#150) + appLogger.info( + 'Path trace skipped: no route to trace', + tag: 'PathTraceMapScreen', + noNotify: !mounted, + ); + if (mounted) { + setState(() { + _isLoading = false; + _failed2Loaded = true; + }); + } + return; + } + appLogger.info( 'Initiating path trace with path: ${_formatPathPrefixes(path)}', tag: 'PathTraceMapScreen', diff --git a/pubspec.yaml b/pubspec.yaml index bae4e47..a1964f1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.1.2-rc.1+49 +version: 1.1.2-rc.1+50 environment: sdk: ^3.9.2