From 07b1df336961f5c55b0fa11787f14997d4536070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20M=C3=BCllner?= Date: Thu, 5 Mar 2026 08:37:13 +0100 Subject: [PATCH] perf: reduce scanner OCR workload --- lib/scanner_screen.dart | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/scanner_screen.dart b/lib/scanner_screen.dart index be7c858..ada97ec 100644 --- a/lib/scanner_screen.dart +++ b/lib/scanner_screen.dart @@ -31,6 +31,11 @@ class ScannerScreen extends StatefulWidget { } class _ScannerScreenState extends State { + static const _autoScanTickInterval = Duration(milliseconds: 700); + static const _scanCooldownSuccess = Duration(milliseconds: 1500); + static const _scanCooldownNoMatch = Duration(milliseconds: 2200); + static const _scanCooldownError = Duration(milliseconds: 2600); + CameraController? _cameraController; late final TextRecognizer _textRecognizer; bool _isBusy = false; @@ -42,6 +47,7 @@ class _ScannerScreenState extends State { String? _activeCollectionId; bool _autoScanEnabled = false; Timer? _autoScanTimer; + DateTime _nextScanAllowedAt = DateTime.fromMillisecondsSinceEpoch(0); @override void initState() { @@ -76,7 +82,7 @@ class _ScannerScreenState extends State { _cameraController = CameraController( backCamera, - ResolutionPreset.high, + ResolutionPreset.medium, enableAudio: false, ); @@ -88,8 +94,9 @@ class _ScannerScreenState extends State { void _startAutoScanLoop() { _autoScanTimer?.cancel(); - _autoScanTimer = Timer.periodic(const Duration(milliseconds: 1400), (_) { + _autoScanTimer = Timer.periodic(_autoScanTickInterval, (_) { if (!_autoScanEnabled || _isBusy || !_cameraReady || !mounted) return; + if (DateTime.now().isBefore(_nextScanAllowedAt)) return; _captureAndScan(); }); } @@ -105,6 +112,7 @@ class _ScannerScreenState extends State { /// Capture a photo, run OCR, and look for a Hot Wheels ID. Future _captureAndScan() async { if (_isBusy || _cameraController == null || !_cameraController!.value.isInitialized) return; + if (_cameraController!.value.isTakingPicture) return; setState(() { _isBusy = true; @@ -131,11 +139,13 @@ class _ScannerScreenState extends State { if (!mounted) return; if (found != null) { + _nextScanAllowedAt = DateTime.now().add(_scanCooldownSuccess); setState(() => _lastDetected = found); if (widget.onDetected != null) { await _submitDetected(found); } } else { + _nextScanAllowedAt = DateTime.now().add(_scanCooldownNoMatch); setState(() { _scanAccepted = false; _scanNotFound = true; @@ -143,6 +153,7 @@ class _ScannerScreenState extends State { }); } } catch (e) { + _nextScanAllowedAt = DateTime.now().add(_scanCooldownError); if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Scan error: $e'), backgroundColor: Colors.red),