import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hl_lieferservice/widget/operations/bloc/operation_event.dart'; import 'package:hl_lieferservice/widget/operations/bloc/operation_state.dart'; class OperationBloc extends Bloc { /// Counts how many in-flight mutations want to show the blocking overlay. /// Allows multiple parallel mutations without one prematurely closing the /// overlay before the others complete. int _inFlightCount = 0; /// When the current overlay session began (set when [_inFlightCount] /// transitions 0 → 1). Used to enforce [_minimumDisplayDuration]. DateTime? _overlayStartedAt; /// Minimum time the overlay stays visible, even if the underlying request /// completes faster. Prevents a "did anything happen?" UX where a sub-100 ms /// roundtrip flashes the overlay for one frame. static const Duration _minimumDisplayDuration = Duration(milliseconds: 350); OperationBloc() : super(OperationIdle()) { on(_startOperation); on(_failOperation); on(_finishOperation); } Future _startOperation( StartOperation event, Emitter emit, ) async { if (_inFlightCount == 0) { _overlayStartedAt = DateTime.now(); } _inFlightCount += 1; emit(OperationInProgress(message: event.message)); } Future _finishOperation( FinishOperation event, Emitter emit, ) async { _inFlightCount = (_inFlightCount - 1).clamp(0, 1 << 30); if (event.message != null) { emit(OperationFinished(message: event.message)); await Future.delayed(const Duration(seconds: 5)); } if (_inFlightCount > 0) { emit(OperationInProgress()); } else { await _awaitMinimumOverlayDuration(); _overlayStartedAt = null; emit(OperationIdle()); } } Future _failOperation( FailOperation event, Emitter emit, ) async { _inFlightCount = (_inFlightCount - 1).clamp(0, 1 << 30); emit(OperationFailed(message: event.message)); await Future.delayed(const Duration(seconds: 5)); if (_inFlightCount > 0) { emit(OperationInProgress()); } else { _overlayStartedAt = null; emit(OperationIdle()); } } Future _awaitMinimumOverlayDuration() async { final startedAt = _overlayStartedAt; if (startedAt == null) return; final elapsed = DateTime.now().difference(startedAt); if (elapsed < _minimumDisplayDuration) { await Future.delayed(_minimumDisplayDuration - elapsed); } } }