Refactor USB screen, add debug logging, fix UI issues

- Rewrite UsbScreen to mirror ScannerScreen patterns (status bar,
  tap-to-connect port list, bottom FABs, SnackBar errors)
- Extract MeshCoreUsbManager from MeshCoreConnector for cleaner
  USB transport ownership
- Add debug logging throughout USB connection flow (connector,
  manager, web/native services)
- Print debug logs to console in debug mode even when app debug
  log setting is disabled
- Localize remaining hardcoded strings (Web Serial Device fallback
  label, USB status bar keys, companion firmware timeout hint)
- Fix Swedish misspelling in translations (stöderliga → stödda)
- Guard Linux notification init against missing D-Bus session bus
- Fix SNRIndicator hit-test error by adding minimum size constraints
- Update USB flow tests for new UI patterns
This commit is contained in:
zjs81 2026-03-07 12:38:28 -07:00
parent 8238b6197f
commit fef73b7b62
42 changed files with 981 additions and 553 deletions

View file

@ -19,6 +19,7 @@ class _FakeMeshCoreConnector extends MeshCoreConnector {
final List<String> _ports;
String? requestPortLabel;
String? fallbackDeviceName;
int connectUsbCalls = 0;
String? lastConnectPortName;
String? fakeActiveUsbPort;
@ -30,6 +31,9 @@ class _FakeMeshCoreConnector extends MeshCoreConnector {
@override
MeshCoreConnectionState get state => initialState;
@override
MeshCoreTransportType get activeTransport => MeshCoreTransportType.usb;
@override
String? get activeUsbPort => fakeActiveUsbPort;
@ -64,6 +68,11 @@ class _FakeMeshCoreConnector extends MeshCoreConnector {
void setUsbRequestPortLabel(String label) {
requestPortLabel = label;
}
@override
void setUsbFallbackDeviceName(String label) {
fallbackDeviceName = label;
}
}
Widget _buildTestApp({
@ -107,16 +116,23 @@ void main() {
);
await tester.pumpAndSettle();
await tester.tap(find.widgetWithText(FilledButton, 'Connect'));
await tester.tap(find.ancestor(
of: find.text('Connect'),
matching: find.bySubtype<ElevatedButton>(),
));
await tester.pump();
expect(connector.connectUsbCalls, 0);
expect(find.byType(CircularProgressIndicator), findsNothing);
// UsbScreen.dispose() schedules disconnect work that debounces notify.
// Drain that debounce timer before test teardown.
await tester.pumpWidget(const SizedBox.shrink());
await tester.pump(const Duration(milliseconds: 60));
},
);
testWidgets(
'UsbScreen keeps raw selection when connector USB display label changes',
'UsbScreen sends raw port name when tapping Connect',
(tester) async {
final connector = _FakeMeshCoreConnector(
ports: <String>['COM6 - USB Serial Device (COM6)'],
@ -127,12 +143,10 @@ void main() {
);
await tester.pumpAndSettle();
connector.fakeActiveUsbPortDisplayLabel =
'COM6 - KD3CGK mesh-utility.org';
connector.notifyListeners();
await tester.pump(const Duration(milliseconds: 60));
await tester.tap(find.widgetWithText(FilledButton, 'Connect'));
await tester.tap(find.ancestor(
of: find.text('Connect'),
matching: find.bySubtype<ElevatedButton>(),
));
await tester.pump();
expect(connector.connectUsbCalls, 1);
@ -163,7 +177,8 @@ void main() {
});
group('Error Handling', () {
testWidgets('shows error message when listing ports fails', (tester) async {
testWidgets('shows error SnackBar when listing ports fails',
(tester) async {
final connector = _FakeMeshCoreConnector();
connector.listUsbPortsImpl = () async {
throw PlatformException(
@ -180,7 +195,7 @@ void main() {
expect(find.text('USB permission was denied.'), findsOneWidget);
});
testWidgets('connection failure completes without leaving loading state', (
testWidgets('connection failure shows SnackBar error', (
tester,
) async {
final connector = _FakeMeshCoreConnector(ports: <String>['COM1']);
@ -195,11 +210,17 @@ void main() {
);
await tester.pumpAndSettle();
await tester.tap(find.widgetWithText(FilledButton, 'Connect'));
await tester.tap(find.ancestor(
of: find.text('Connect'),
matching: find.bySubtype<ElevatedButton>(),
));
await tester.pumpAndSettle();
expect(connectAttempted, isTrue);
expect(find.byType(CircularProgressIndicator), findsNothing);
expect(
find.text('Another USB connection request is already in progress.'),
findsOneWidget,
);
});
});
}