mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-08-04 15:03:00 +10:00
Refactor USB port handling to introduce display labels and improve state management
This commit is contained in:
committed by
just-stuff-tm
parent
a0feb129e1
commit
5216e00807
@@ -115,7 +115,8 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
final UsbSerialService _usbSerialService = UsbSerialService();
|
final UsbSerialService _usbSerialService = UsbSerialService();
|
||||||
StreamSubscription<Uint8List>? _usbFrameSubscription;
|
StreamSubscription<Uint8List>? _usbFrameSubscription;
|
||||||
MeshCoreTransportType _activeTransport = MeshCoreTransportType.bluetooth;
|
MeshCoreTransportType _activeTransport = MeshCoreTransportType.bluetooth;
|
||||||
String? _activeUsbPort;
|
String? _activeUsbPortKey;
|
||||||
|
String? _activeUsbPortLabel;
|
||||||
|
|
||||||
final List<ScanResult> _scanResults = [];
|
final List<ScanResult> _scanResults = [];
|
||||||
final List<Contact> _contacts = [];
|
final List<Contact> _contacts = [];
|
||||||
@@ -229,7 +230,9 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
String get deviceIdLabel => _deviceId ?? 'Unknown';
|
String get deviceIdLabel => _deviceId ?? 'Unknown';
|
||||||
|
|
||||||
MeshCoreTransportType get activeTransport => _activeTransport;
|
MeshCoreTransportType get activeTransport => _activeTransport;
|
||||||
String? get activeUsbPort => _activeUsbPort;
|
String? get activeUsbPort => _activeUsbPortKey;
|
||||||
|
String? get activeUsbPortDisplayLabel =>
|
||||||
|
_activeUsbPortLabel ?? _activeUsbPortKey;
|
||||||
bool get isUsbTransportConnected =>
|
bool get isUsbTransportConnected =>
|
||||||
_state == MeshCoreConnectionState.connected &&
|
_state == MeshCoreConnectionState.connected &&
|
||||||
_activeTransport == MeshCoreTransportType.usb;
|
_activeTransport == MeshCoreTransportType.usb;
|
||||||
@@ -778,7 +781,8 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_activeTransport = MeshCoreTransportType.bluetooth;
|
_activeTransport = MeshCoreTransportType.bluetooth;
|
||||||
_activeUsbPort = null;
|
_activeUsbPortKey = null;
|
||||||
|
_activeUsbPortLabel = null;
|
||||||
|
|
||||||
await stopScan();
|
await stopScan();
|
||||||
_setState(MeshCoreConnectionState.connecting);
|
_setState(MeshCoreConnectionState.connecting);
|
||||||
@@ -955,14 +959,16 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_activeTransport = MeshCoreTransportType.bluetooth;
|
_activeTransport = MeshCoreTransportType.bluetooth;
|
||||||
_activeUsbPort = null;
|
_activeUsbPortKey = null;
|
||||||
|
_activeUsbPortLabel = null;
|
||||||
|
|
||||||
await stopScan();
|
await stopScan();
|
||||||
_cancelReconnectTimer();
|
_cancelReconnectTimer();
|
||||||
_manualDisconnect = false;
|
_manualDisconnect = false;
|
||||||
_resetConnectionHandshakeState();
|
_resetConnectionHandshakeState();
|
||||||
_activeTransport = MeshCoreTransportType.usb;
|
_activeTransport = MeshCoreTransportType.usb;
|
||||||
_activeUsbPort = portName;
|
_activeUsbPortKey = portName;
|
||||||
|
_activeUsbPortLabel = portName;
|
||||||
unawaited(_backgroundService?.start());
|
unawaited(_backgroundService?.start());
|
||||||
_setState(MeshCoreConnectionState.connecting);
|
_setState(MeshCoreConnectionState.connecting);
|
||||||
|
|
||||||
@@ -1178,7 +1184,8 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
_reactionSendQueueSequence = 0;
|
_reactionSendQueueSequence = 0;
|
||||||
|
|
||||||
_activeTransport = MeshCoreTransportType.bluetooth;
|
_activeTransport = MeshCoreTransportType.bluetooth;
|
||||||
_activeUsbPort = null;
|
_activeUsbPortKey = null;
|
||||||
|
_activeUsbPortLabel = null;
|
||||||
|
|
||||||
_setState(MeshCoreConnectionState.disconnected);
|
_setState(MeshCoreConnectionState.disconnected);
|
||||||
if (!manual && transportAtDisconnect == MeshCoreTransportType.bluetooth) {
|
if (!manual && transportAtDisconnect == MeshCoreTransportType.bluetooth) {
|
||||||
@@ -2218,7 +2225,8 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
selfName != null &&
|
selfName != null &&
|
||||||
selfName.isNotEmpty) {
|
selfName.isNotEmpty) {
|
||||||
_usbSerialService.updateConnectedLabel(selfName);
|
_usbSerialService.updateConnectedLabel(selfName);
|
||||||
_activeUsbPort = _usbSerialService.activePortName ?? _activeUsbPort;
|
_activeUsbPortLabel =
|
||||||
|
_usbSerialService.activePortDisplayLabel ?? _activeUsbPortLabel;
|
||||||
}
|
}
|
||||||
_awaitingSelfInfo = false;
|
_awaitingSelfInfo = false;
|
||||||
_selfInfoRetryTimer?.cancel();
|
_selfInfoRetryTimer?.cancel();
|
||||||
|
|||||||
+18
-14
@@ -23,6 +23,7 @@ class _UsbScreenState extends State<UsbScreen> {
|
|||||||
bool _navigatedToContacts = false;
|
bool _navigatedToContacts = false;
|
||||||
bool _didScheduleInitialLoad = false;
|
bool _didScheduleInitialLoad = false;
|
||||||
String? _selectedPort;
|
String? _selectedPort;
|
||||||
|
String? _connectedPortDisplayLabel;
|
||||||
String? _errorText;
|
String? _errorText;
|
||||||
late final MeshCoreConnector _connector;
|
late final MeshCoreConnector _connector;
|
||||||
late final VoidCallback _connectionListener;
|
late final VoidCallback _connectionListener;
|
||||||
@@ -33,21 +34,19 @@ class _UsbScreenState extends State<UsbScreen> {
|
|||||||
_connector = context.read<MeshCoreConnector>();
|
_connector = context.read<MeshCoreConnector>();
|
||||||
_connectionListener = () {
|
_connectionListener = () {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
final activeUsbPort = _connector.activeUsbPort;
|
final activeUsbPortDisplayLabel = _connector.activeUsbPortDisplayLabel;
|
||||||
if (activeUsbPort != null &&
|
final shouldUpdateDisplayLabel =
|
||||||
activeUsbPort.isNotEmpty &&
|
activeUsbPortDisplayLabel != _connectedPortDisplayLabel;
|
||||||
activeUsbPort != _selectedPort) {
|
|
||||||
setState(() {
|
|
||||||
_selectedPort = activeUsbPort;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (_connector.state == MeshCoreConnectionState.disconnected) {
|
if (_connector.state == MeshCoreConnectionState.disconnected) {
|
||||||
_navigatedToContacts = false;
|
_navigatedToContacts = false;
|
||||||
if (_isConnecting) {
|
setState(() {
|
||||||
setState(() {
|
_isConnecting = false;
|
||||||
_isConnecting = false;
|
_connectedPortDisplayLabel = activeUsbPortDisplayLabel;
|
||||||
});
|
});
|
||||||
}
|
} else if (shouldUpdateDisplayLabel) {
|
||||||
|
setState(() {
|
||||||
|
_connectedPortDisplayLabel = activeUsbPortDisplayLabel;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (_connector.state == MeshCoreConnectionState.connected &&
|
if (_connector.state == MeshCoreConnectionState.connected &&
|
||||||
_connector.isUsbTransportConnected &&
|
_connector.isUsbTransportConnected &&
|
||||||
@@ -167,7 +166,12 @@ class _UsbScreenState extends State<UsbScreen> {
|
|||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
child: Chip(
|
child: Chip(
|
||||||
label: Text(
|
label: Text(
|
||||||
_selectedPort == null
|
_connectedPortDisplayLabel != null &&
|
||||||
|
_connectedPortDisplayLabel!.isNotEmpty
|
||||||
|
? _friendlyPortName(
|
||||||
|
_connectedPortDisplayLabel!,
|
||||||
|
)
|
||||||
|
: _selectedPort == null
|
||||||
? l10n.usbScreenStatus
|
? l10n.usbScreenStatus
|
||||||
: _friendlyPortName(_selectedPort!),
|
: _friendlyPortName(_selectedPort!),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
|||||||
@@ -26,11 +26,14 @@ class UsbSerialService {
|
|||||||
StreamSubscription<dynamic>? _androidDataSubscription;
|
StreamSubscription<dynamic>? _androidDataSubscription;
|
||||||
StreamSubscription<FlSerialEventArgs>? _dataSubscription;
|
StreamSubscription<FlSerialEventArgs>? _dataSubscription;
|
||||||
UsbSerialStatus _status = UsbSerialStatus.disconnected;
|
UsbSerialStatus _status = UsbSerialStatus.disconnected;
|
||||||
String? _connectedPortName;
|
String? _connectedPortKey;
|
||||||
|
String? _connectedPortLabel;
|
||||||
FlSerial? _serial;
|
FlSerial? _serial;
|
||||||
|
|
||||||
UsbSerialStatus get status => _status;
|
UsbSerialStatus get status => _status;
|
||||||
String? get activePortName => _connectedPortName;
|
String? get activePortKey => _connectedPortKey;
|
||||||
|
String? get activePortDisplayLabel =>
|
||||||
|
_connectedPortLabel ?? _connectedPortKey;
|
||||||
Stream<Uint8List> get frameStream => _frameController.stream;
|
Stream<Uint8List> get frameStream => _frameController.stream;
|
||||||
bool get _useAndroidUsbHost =>
|
bool get _useAndroidUsbHost =>
|
||||||
!kIsWeb && defaultTargetPlatform == TargetPlatform.android;
|
!kIsWeb && defaultTargetPlatform == TargetPlatform.android;
|
||||||
@@ -126,7 +129,8 @@ class UsbSerialService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_connectedPortName = normalizedPortName;
|
_connectedPortKey = normalizedPortName;
|
||||||
|
_connectedPortLabel = normalizedPortName;
|
||||||
if (_useAndroidUsbHost) {
|
if (_useAndroidUsbHost) {
|
||||||
_androidDataSubscription = _androidEventChannel
|
_androidDataSubscription = _androidEventChannel
|
||||||
.receiveBroadcastStream()
|
.receiveBroadcastStream()
|
||||||
@@ -168,7 +172,8 @@ class UsbSerialService {
|
|||||||
if (_status == UsbSerialStatus.disconnected) return;
|
if (_status == UsbSerialStatus.disconnected) return;
|
||||||
|
|
||||||
_status = UsbSerialStatus.disconnecting;
|
_status = UsbSerialStatus.disconnecting;
|
||||||
_connectedPortName = null;
|
_connectedPortKey = null;
|
||||||
|
_connectedPortLabel = null;
|
||||||
await _androidDataSubscription?.cancel();
|
await _androidDataSubscription?.cancel();
|
||||||
_androidDataSubscription = null;
|
_androidDataSubscription = null;
|
||||||
await _dataSubscription?.cancel();
|
await _dataSubscription?.cancel();
|
||||||
@@ -204,7 +209,10 @@ class UsbSerialService {
|
|||||||
if (trimmed.isEmpty) {
|
if (trimmed.isEmpty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_connectedPortName = trimmed;
|
_connectedPortLabel = buildUsbDisplayLabel(
|
||||||
|
basePortLabel: _connectedPortKey ?? trimmed,
|
||||||
|
deviceName: trimmed,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ class UsbSerialService {
|
|||||||
String _requestPortLabel = 'Choose USB Device';
|
String _requestPortLabel = 'Choose USB Device';
|
||||||
|
|
||||||
UsbSerialStatus get status => _status;
|
UsbSerialStatus get status => _status;
|
||||||
String? get activePortName => _connectedPortName;
|
String? get activePortKey => _connectedPortKey;
|
||||||
|
String? get activePortDisplayLabel => _connectedPortName ?? _connectedPortKey;
|
||||||
Stream<Uint8List> get frameStream => _frameController.stream;
|
Stream<Uint8List> get frameStream => _frameController.stream;
|
||||||
bool get isConnected => _status == UsbSerialStatus.connected;
|
bool get isConnected => _status == UsbSerialStatus.connected;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class _FakeMeshCoreConnector extends MeshCoreConnector {
|
|||||||
int connectUsbCalls = 0;
|
int connectUsbCalls = 0;
|
||||||
String? lastConnectPortName;
|
String? lastConnectPortName;
|
||||||
String? fakeActiveUsbPort;
|
String? fakeActiveUsbPort;
|
||||||
|
String? fakeActiveUsbPortDisplayLabel;
|
||||||
bool fakeUsbTransportConnected = false;
|
bool fakeUsbTransportConnected = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -29,6 +30,10 @@ class _FakeMeshCoreConnector extends MeshCoreConnector {
|
|||||||
@override
|
@override
|
||||||
String? get activeUsbPort => fakeActiveUsbPort;
|
String? get activeUsbPort => fakeActiveUsbPort;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get activeUsbPortDisplayLabel =>
|
||||||
|
fakeActiveUsbPortDisplayLabel ?? fakeActiveUsbPort;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isUsbTransportConnected => fakeUsbTransportConnected;
|
bool get isUsbTransportConnected => fakeUsbTransportConnected;
|
||||||
|
|
||||||
@@ -99,6 +104,33 @@ void main() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'UsbScreen keeps raw selection while showing connector USB display label',
|
||||||
|
(tester) async {
|
||||||
|
final connector = _FakeMeshCoreConnector(
|
||||||
|
ports: <String>['COM6 - USB Serial Device (COM6)'],
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
_buildTestApp(connector: connector, child: const UsbScreen()),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
connector.fakeActiveUsbPortDisplayLabel =
|
||||||
|
'COM6 - KD3CGK mesh-utility.org';
|
||||||
|
connector.notifyListeners();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(find.text('KD3CGK mesh-utility.org'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.widgetWithText(FilledButton, 'Connect'));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(connector.connectUsbCalls, 1);
|
||||||
|
expect(connector.lastConnectPortName, 'COM6');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
testWidgets('ConnectionChoiceScreen USB button reflects platform support', (
|
testWidgets('ConnectionChoiceScreen USB button reflects platform support', (
|
||||||
tester,
|
tester,
|
||||||
) async {
|
) async {
|
||||||
|
|||||||
Reference in New Issue
Block a user