feat: Add TCP connection support and UI integration

- Implemented TCP transport service for native platforms.
- Added TCP connection screen with input fields for host and port.
- Integrated TCP connection options into the scanner and USB screens.
- Updated localization files for new TCP-related strings.
- Added tests for TCP connection flow and error handling.
- Enhanced USB screen to include TCP connection option.
- Improved layout to ensure no overflow in narrow widths for scanner and USB screens.
This commit is contained in:
just-stuff-tm
2026-03-07 20:07:19 -05:00
parent a1b77bb29b
commit 7a2bb20bf7
43 changed files with 2391 additions and 123 deletions
+65 -18
View File
@@ -116,12 +116,7 @@ void main() {
);
await tester.pumpAndSettle();
await tester.tap(
find.ancestor(
of: find.text('Connect'),
matching: find.bySubtype<ElevatedButton>(),
),
);
await tester.tap(find.byType(ListTile).first);
await tester.pump();
expect(connector.connectUsbCalls, 0);
@@ -145,12 +140,7 @@ void main() {
);
await tester.pumpAndSettle();
await tester.tap(
find.ancestor(
of: find.text('Connect'),
matching: find.bySubtype<ElevatedButton>(),
),
);
await tester.tap(find.byType(ListTile).first);
await tester.pump();
expect(connector.connectUsbCalls, 1);
@@ -179,6 +169,68 @@ void main() {
await tester.pump(const Duration(milliseconds: 60));
});
testWidgets('ScannerScreen narrow width keeps actions without overflow', (
tester,
) async {
await tester.binding.setSurfaceSize(const Size(320, 700));
addTearDown(() => tester.binding.setSurfaceSize(null));
final connector = _FakeMeshCoreConnector();
await tester.pumpWidget(
_buildTestApp(connector: connector, child: const ScannerScreen()),
);
await tester.pumpAndSettle();
expect(tester.takeException(), isNull);
final context = tester.element(find.byType(ScannerScreen));
final l10n = AppLocalizations.of(context);
expect(find.text(l10n.scanner_scan), findsOneWidget);
if (PlatformInfo.supportsUsbSerial) {
expect(find.text(l10n.connectionChoiceUsbLabel), findsOneWidget);
}
if (!PlatformInfo.isWeb) {
expect(find.text(l10n.connectionChoiceTcpLabel), findsOneWidget);
}
await tester.pumpWidget(const SizedBox.shrink());
await tester.pump(const Duration(milliseconds: 60));
});
testWidgets('UsbScreen narrow width long status text does not overflow', (
tester,
) async {
await tester.binding.setSurfaceSize(const Size(320, 700));
addTearDown(() => tester.binding.setSurfaceSize(null));
final connector =
_FakeMeshCoreConnector(initialState: MeshCoreConnectionState.connected)
..fakeUsbTransportConnected = true
..fakeActiveUsbPortDisplayLabel =
'/dev/bus/usb/001/002 - KD3CGK mesh-utility.org very long label';
await tester.pumpWidget(
_buildTestApp(connector: connector, child: const UsbScreen()),
);
await tester.pumpAndSettle();
expect(tester.takeException(), isNull);
final context = tester.element(find.byType(UsbScreen));
final l10n = AppLocalizations.of(context);
expect(
find.text(
l10n.scanner_connectedTo(connector.fakeActiveUsbPortDisplayLabel!),
),
findsOneWidget,
);
await tester.pumpWidget(const SizedBox.shrink());
await tester.pump(const Duration(milliseconds: 60));
});
group('Error Handling', () {
testWidgets('shows error SnackBar when listing ports fails', (
tester,
@@ -212,12 +264,7 @@ void main() {
);
await tester.pumpAndSettle();
await tester.tap(
find.ancestor(
of: find.text('Connect'),
matching: find.bySubtype<ElevatedButton>(),
),
);
await tester.tap(find.byType(ListTile).first);
await tester.pumpAndSettle();
expect(connectAttempted, isTrue);