// ignore_for_file: invalid_use_of_protected_member part of '../../registration_page.dart'; extension _RegistrationScanPart on _RegistrationPageState { void _startScanListening() { _scanSubscription ??= _scannerService.scanResults.listen(_onScan); } Future _stopScanListening() async { final subscription = _scanSubscription; _scanSubscription = null; await subscription?.cancel(); } void _restartScanListening() { _scanSubscription?.cancel(); _scanSubscription = null; _startScanListening(); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { _focusNode.requestFocus(); } }); } void _onKeyEvent(KeyEvent event) { if (event is! KeyDownEvent) return; if (_isLockToggleKey(event)) { _cycleMode(); return; } if (event.logicalKey == LogicalKeyboardKey.enter) { _submit(); } } bool _isLockToggleKey(KeyEvent event) { final key = event.logicalKey; return key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.gameButtonRight1; } void _onScan(ScanResult result) { final parsed = CodeParser.parse(result.barcode); switch (parsed.type) { case CodeType.zongpaiNo: _handleZongpaiScan(parsed.value); case CodeType.locationNormal: case CodeType.locationTransit: _handleLocationScan(parsed.value, parsed.type); case CodeType.invalid: _feedbackService.trigger(FeedbackEvent.scanInvalid); _showStatusOverride( '无效码:${result.barcode}', StatusDotColor.red, const Duration(seconds: 2), ); } } void _handleLocationScan(String locationCode, CodeType locationType) { // In singleCode mode or no existing data, switch directly if (_mode == RegistrationMode.singleCode || _zongpaiNos.isEmpty) { _feedbackService.trigger(FeedbackEvent.scanValid); setState(() { _locationCode = locationCode; _locationType = locationType; _clearStatusOverride(); }); return; } // In multiCode mode with existing data, confirm before switching _showLocationSwitchDialog(locationCode, locationType); } void _handleZongpaiScan(String zongpaiNo) { // If cross-paicha dialog is showing, just vibrate and discard if (_crossPaichaPending) { _triggerDoubleVibration(); return; } // In multiCode mode with existing data, check for cross-paicha scan if (_mode == RegistrationMode.multiCode && _zongpaiNos.isNotEmpty && _overview?.success == true && !_overview!.items.any((item) => item.zongpaiNo == zongpaiNo)) { _crossPaichaPending = true; _triggerDoubleVibration(); _showCrossPaichaDialog(zongpaiNo); return; } final shouldRefresh = _overviewZongpaiNo != zongpaiNo; _feedbackService.trigger(FeedbackEvent.scanValid); setState(() { if (_mode == RegistrationMode.multiCode) { if (!_zongpaiNos.contains(zongpaiNo)) { _zongpaiNos.add(zongpaiNo); } } else { if (_zongpaiNos.isEmpty) { _zongpaiNos.add(zongpaiNo); } else { _zongpaiNos[0] = zongpaiNo; } } _clearStatusOverride(); }); if (shouldRefresh) { _loadOverview(zongpaiNo); } } void _triggerDoubleVibration() { Vibration.vibrate(pattern: [0, 200, 100, 200]); } void _removeZongpai(String zongpaiNo) { setState(() { _zongpaiNos.remove(zongpaiNo); }); } }