diff --git a/lib/screens/channels_screen.dart b/lib/screens/channels_screen.dart index d9846db3..2f8b06a9 100644 --- a/lib/screens/channels_screen.dart +++ b/lib/screens/channels_screen.dart @@ -281,7 +281,7 @@ class _ChannelsScreenState extends State ), buildDefaultDragHandles: false, itemCount: filteredChannels.length, - onReorderItem: (oldIndex, newIndex) { + onReorder: (oldIndex, newIndex) { final reordered = List.from( filteredChannels, ); diff --git a/lib/widgets/path_editor_sheet.dart b/lib/widgets/path_editor_sheet.dart index f20aad1c..93594acd 100644 --- a/lib/widgets/path_editor_sheet.dart +++ b/lib/widgets/path_editor_sheet.dart @@ -323,7 +323,7 @@ class _PathEditorSheetState extends State { physics: const NeverScrollableScrollPhysics(), buildDefaultDragHandles: false, itemCount: _hops.length, - onReorderItem: _reorderHop, + onReorder: _reorderHop, itemBuilder: _hopTile, ), const Divider(), diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 379e36fa..93e46829 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST flserial + jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/test/screens/path_trace_test.dart b/test/screens/path_trace_test.dart index 9544d76d..55c10b14 100644 --- a/test/screens/path_trace_test.dart +++ b/test/screens/path_trace_test.dart @@ -11,6 +11,21 @@ import 'package:meshcore_open/services/app_settings_service.dart'; import 'package:meshcore_open/services/map_tile_cache_service.dart'; import 'package:meshcore_open/models/contact.dart'; import 'package:meshcore_open/l10n/app_localizations.dart'; +import 'package:meshcore_open/services/path_history_service.dart'; +import 'package:meshcore_open/services/storage_service.dart'; +import 'package:meshcore_open/models/path_history.dart'; + +class _FakeStorageService extends StorageService { + @override + Future savePathHistory( + String contactPubKeyHex, + ContactPathHistory history, + ) async {} + @override + Future loadPathHistory(String contactPubKeyHex) async => null; + @override + Future clearPathHistory(String contactPubKeyHex) async {} +} class _FakeMeshCoreConnector extends MeshCoreConnector { final StreamController _receivedFramesController = @@ -63,6 +78,9 @@ Widget _buildTestApp({ create: (_) => AppSettingsService(), ), Provider(create: (_) => MapTileCacheService()), + ChangeNotifierProvider( + create: (_) => PathHistoryService(_FakeStorageService()), + ), ], child: MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, @@ -92,8 +110,8 @@ void main() { final sentFrame = connector.sentFrames.first; expect(sentFrame[0], cmdSendTracePath); - // Extract the tag sent in the request (bytes 1-4) - final tag = sentFrame.sublist(1, 5); + // Extract the tag sent in the request (bytes 2-5) + final tag = sentFrame.sublist(2, 6); // Emit respCodeSent (6) final respCodeSentFrame = Uint8List(10); @@ -118,8 +136,8 @@ void main() { // Offset 4..7: tag // Offset 8..11: auth (0) // Offset 12..13: pathBytes [0x12, 0x34] - // Offset 14..15: SNR bytes [12, 16] -> to be mapped to signed 8 bit Snr/4 - final pushTraceFrame = Uint8List(16); + // Offset 14..16: SNR bytes [12, 16, 20] -> to be mapped to signed 8 bit Snr/4 + final pushTraceFrame = Uint8List(17); pushTraceFrame[0] = pushCodeTraceData; pushTraceFrame[1] = 0; // reserved pushTraceFrame[2] = 2; // pathLength @@ -127,11 +145,12 @@ void main() { pushTraceFrame.setRange(4, 8, tag); // auth bytes (8..11) = 0 pushTraceFrame.setRange(12, 14, [0x12, 0x34]); // pathBytes - pushTraceFrame.setRange(14, 16, [12, 16]); // SNR bytes + pushTraceFrame.setRange(14, 17, [12, 16, 20]); // SNR bytes connector.emitFrame(pushTraceFrame); - // pump multiple times to handle async tasks - await tester.pumpAndSettle(); + for (int i = 0; i < 5; i++) { + await tester.pump(const Duration(milliseconds: 100)); + } // Verify it doesn't show "Path trace not available" or similar expect(find.text('Path trace not available.'), findsNothing); @@ -158,8 +177,8 @@ void main() { final sentFrame = connector.sentFrames.first; expect(sentFrame[0], cmdSendTracePath); - // Extract the tag sent in the request (bytes 1-4) - final tag = sentFrame.sublist(1, 5); + // Extract the tag sent in the request (bytes 2-5) + final tag = sentFrame.sublist(2, 6); // Emit respCodeSent (6) final respCodeSentFrame = Uint8List(10); @@ -194,7 +213,9 @@ void main() { pushTraceFrame.setRange(14, 16, [12, 16]); // SNR bytes connector.emitFrame(pushTraceFrame); - await tester.pumpAndSettle(); + for (int i = 0; i < 5; i++) { + await tester.pump(const Duration(milliseconds: 100)); + } // Verify it parsed correctly (should not show the unavailable message) expect(find.text('Path trace not available.'), findsNothing); @@ -336,7 +357,8 @@ void main() { expect(connector.sentFrames.length, 1); final sentFrame = connector.sentFrames.first; - final tag = sentFrame.sublist(1, 5); + // Extract the tag sent in the request (bytes 2-5) + final tag = sentFrame.sublist(2, 6); // Emit respCodeSent (6) final respCodeSentFrame = Uint8List(10); @@ -353,19 +375,21 @@ void main() { // Now emit PUSH_CODE_TRACE_DATA (0x89) // Structure: - // Offset 2: pathLength (2) -> raw byte length count, mode is 0! - // Offset 12..13: pathBytes [0x12, 0x34] + // Offset 2: pathLength (1) -> mode 0, hop count 1. + // Offset 12..13: pathBytes [0x12, 0x34] (1 hop * 2 bytes/hop) final pushTraceFrame = Uint8List(16); pushTraceFrame[0] = pushCodeTraceData; pushTraceFrame[1] = 0; // reserved - pushTraceFrame[2] = 2; // pathLength as raw byte length (2 bytes) + pushTraceFrame[2] = 1; // pathLength encoded (mode 0, 1 hop) pushTraceFrame[3] = 0; // flag pushTraceFrame.setRange(4, 8, tag); pushTraceFrame.setRange(12, 14, [0x12, 0x34]); // pathBytes pushTraceFrame.setRange(14, 16, [12, 16]); // SNR bytes connector.emitFrame(pushTraceFrame); - await tester.pumpAndSettle(); + for (int i = 0; i < 5; i++) { + await tester.pump(const Duration(milliseconds: 100)); + } // Verify it parsed correctly (should not show the unavailable message) expect(find.text('Path trace not available.'), findsNothing); diff --git a/test/services/path_history_service_test.dart b/test/services/path_history_service_test.dart index 87ae729d..3ea6acf1 100644 --- a/test/services/path_history_service_test.dart +++ b/test/services/path_history_service_test.dart @@ -549,12 +549,15 @@ void main() { final pubKey = _hex('w004'); await _seed(svc, pubKey, pathBytes: [0x01], hopCount: 1, weight: 0.3); - svc.recordPathResult( - pubKey, - const PathSelection(pathBytes: [0x01], hopCount: 1, useFlood: false), - success: false, - failureDecrement: 0.5, // 0.3 - 0.5 = -0.2 → remove - ); + // The service requires failureCount >= 3 to remove a path + for (int i = 0; i < 3; i++) { + svc.recordPathResult( + pubKey, + const PathSelection(pathBytes: [0x01], hopCount: 1, useFlood: false), + success: false, + failureDecrement: 0.5, // 0.3 - 0.5 = -0.2 → remove + ); + } await _flush(); final paths = svc.getRecentPaths(pubKey); diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index f02857f4..533a1712 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -11,6 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST flserial flutter_local_notifications_windows + jni ) set(PLUGIN_BUNDLED_LIBRARIES)