perf(scanner): add adaptive cooldown backoff for repeated OCR misses

This commit is contained in:
Lukas Müllner 2026-03-05 14:45:00 +01:00
parent 7c25ab7c6f
commit edacf7ad1a

View file

@ -37,6 +37,7 @@ class _ScannerScreenState extends State<ScannerScreen>
static const _scanCooldownSuccess = Duration(milliseconds: 1500);
static const _scanCooldownNoMatch = Duration(milliseconds: 2200);
static const _scanCooldownError = Duration(milliseconds: 2600);
static const _scanCooldownNoMatchMax = Duration(milliseconds: 5000);
CameraController? _cameraController;
late final TextRecognizer _textRecognizer;
@ -52,6 +53,7 @@ class _ScannerScreenState extends State<ScannerScreen>
DateTime _nextScanAllowedAt = DateTime.fromMillisecondsSinceEpoch(0);
bool _isInitializingCamera = false;
String? _cameraError;
int _consecutiveMisses = 0;
@override
void initState() {
@ -202,13 +204,23 @@ class _ScannerScreenState extends State<ScannerScreen>
if (!mounted) return;
if (found != null) {
_consecutiveMisses = 0;
_nextScanAllowedAt = DateTime.now().add(_scanCooldownSuccess);
setState(() => _lastDetected = found);
if (widget.onDetected != null) {
await _submitDetected(found);
}
} else {
_nextScanAllowedAt = DateTime.now().add(_scanCooldownNoMatch);
_consecutiveMisses += 1;
final missBackoffMs = (_scanCooldownNoMatch.inMilliseconds +
(_consecutiveMisses * 300))
.clamp(
_scanCooldownNoMatch.inMilliseconds,
_scanCooldownNoMatchMax.inMilliseconds,
);
_nextScanAllowedAt = DateTime.now().add(
Duration(milliseconds: missBackoffMs),
);
setState(() {
_scanAccepted = false;
_scanNotFound = true;
@ -216,6 +228,7 @@ class _ScannerScreenState extends State<ScannerScreen>
});
}
} catch (e) {
_consecutiveMisses += 1;
_nextScanAllowedAt = DateTime.now().add(_scanCooldownError);
if (!mounted) return;
logError('scanner.capture', e);