import 'dart:async'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../data/services/coordination_service.dart'; import '../../../domain/entities/camera_lock.dart'; import 'lock_event.dart'; import 'lock_state.dart'; class LockBloc extends Bloc { final CoordinationService _coordinationService; StreamSubscription? _locksSub; StreamSubscription? _notifSub; StreamSubscription? _connSub; LockBloc({ required CoordinationService coordinationService, required String keyboardId, }) : _coordinationService = coordinationService, super(const LockState()) { on(_onTryLock); on(_onReleaseLock); on(_onReleaseAllLocks); on(_onRequestTakeover); on(_onConfirmTakeover); on(_onResetLockExpiration); on(_onLocksUpdated); on(_onLockNotificationReceived); on(_onCoordinatorConnectionChanged); // Subscribe to coordinator streams _locksSub = _coordinationService.locks.listen((locks) { add(LocksUpdated(locks)); }); _notifSub = _coordinationService.notifications.listen((notification) { if (notification != null) { add(LockNotificationReceived(notification)); } }); _connSub = _coordinationService.connected.listen((connected) { add(CoordinatorConnectionChanged(connected)); }); } Future _onTryLock(TryLock event, Emitter emit) async { final result = await _coordinationService.tryLock( event.cameraId, priority: event.priority, ); if (!result.acquired) { final lock = result.lock; final owner = lock?.ownerName ?? 'unknown'; emit(state.copyWith( lastNotification: 'Camera ${event.cameraId} locked by $owner', )); } } Future _onReleaseLock( ReleaseLock event, Emitter emit) async { await _coordinationService.releaseLock(event.cameraId); } Future _onReleaseAllLocks( ReleaseAllLocks event, Emitter emit) async { final myLocks = await _coordinationService.getMyLockedCameras(); for (final cameraId in myLocks) { await _coordinationService.releaseLock(cameraId); } } Future _onRequestTakeover( RequestTakeover event, Emitter emit) async { final success = await _coordinationService.requestTakeover( event.cameraId, priority: event.priority, ); if (success) { emit(state.copyWith( lastNotification: 'Takeover requested for camera ${event.cameraId}', )); } } Future _onConfirmTakeover( ConfirmTakeover event, Emitter emit) async { await _coordinationService.confirmTakeover( event.cameraId, event.confirm); emit(state.copyWith(clearPendingTakeover: true)); } Future _onResetLockExpiration( ResetLockExpiration event, Emitter emit) async { await _coordinationService.resetExpiration(event.cameraId); } void _onLocksUpdated(LocksUpdated event, Emitter emit) { emit(state.copyWith(locks: event.locks)); } void _onLockNotificationReceived( LockNotificationReceived event, Emitter emit) { final notification = event.notification; switch (notification.type) { case CameraLockNotificationType.confirmTakeOver: // Show takeover confirmation dialog emit(state.copyWith( pendingTakeover: TakeoverRequest( cameraId: notification.cameraId, requestingKeyboard: notification.copilotName, ), )); break; case CameraLockNotificationType.takenOver: emit(state.copyWith( lastNotification: 'Camera ${notification.cameraId} taken over by ${notification.copilotName}', )); break; case CameraLockNotificationType.expireSoon: emit(state.copyWith( lastNotification: 'Lock on camera ${notification.cameraId} expiring soon', )); break; case CameraLockNotificationType.confirmed: emit(state.copyWith( lastNotification: 'Takeover confirmed for camera ${notification.cameraId}', )); break; case CameraLockNotificationType.rejected: emit(state.copyWith( lastNotification: 'Takeover rejected for camera ${notification.cameraId}', )); break; case CameraLockNotificationType.unlocked: case CameraLockNotificationType.acquired: // Handled by lock state updates break; } } void _onCoordinatorConnectionChanged( CoordinatorConnectionChanged event, Emitter emit) { emit(state.copyWith(coordinatorConnected: event.connected)); } @override Future close() { _locksSub?.cancel(); _notifSub?.cancel(); _connSub?.cancel(); return super.close(); } }