Flutter web app replacing legacy WPF CCTV surveillance keyboard controller. Includes wall overview, section view with monitor grid, camera input, PTZ control, alarm/lock/sequence BLoCs, and legacy-matching UI styling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
91 lines
2.8 KiB
Dart
91 lines
2.8 KiB
Dart
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
import '../../../data/services/coordination_service.dart';
|
|
import '../../../domain/entities/sequence.dart';
|
|
import 'sequence_event.dart';
|
|
import 'sequence_state.dart';
|
|
|
|
class SequenceBloc extends Bloc<SequenceEvent, SequenceState> {
|
|
final CoordinationService _coordinationService;
|
|
|
|
SequenceBloc({required CoordinationService coordinationService})
|
|
: _coordinationService = coordinationService,
|
|
super(const SequenceState()) {
|
|
on<LoadSequences>(_onLoadSequences);
|
|
on<StartSequence>(_onStartSequence);
|
|
on<StopSequence>(_onStopSequence);
|
|
on<SelectCategory>(_onSelectCategory);
|
|
}
|
|
|
|
Future<void> _onLoadSequences(
|
|
LoadSequences event, Emitter<SequenceState> emit) async {
|
|
emit(state.copyWith(isLoading: true, clearError: true));
|
|
|
|
try {
|
|
final sequencesJson = await _coordinationService.getSequences();
|
|
final categoriesJson = await _coordinationService.getSequenceCategories();
|
|
final runningJson = await _coordinationService.getRunningSequences();
|
|
|
|
final sequences = sequencesJson
|
|
.map((j) => SequenceDefinition.fromJson(j))
|
|
.toList();
|
|
final categories =
|
|
categoriesJson.map((j) => SequenceCategory.fromJson(j)).toList();
|
|
|
|
final running = <int, RunningSequence>{};
|
|
for (final j in runningJson) {
|
|
final rs = RunningSequence.fromJson(j);
|
|
running[rs.viewerId] = rs;
|
|
}
|
|
|
|
emit(state.copyWith(
|
|
sequences: sequences,
|
|
categories: categories,
|
|
running: running,
|
|
isLoading: false,
|
|
));
|
|
} catch (e) {
|
|
emit(state.copyWith(isLoading: false, error: e.toString()));
|
|
}
|
|
}
|
|
|
|
Future<void> _onStartSequence(
|
|
StartSequence event, Emitter<SequenceState> emit) async {
|
|
try {
|
|
final result = await _coordinationService.startSequence(
|
|
event.viewerId, event.sequenceId);
|
|
|
|
if (result != null) {
|
|
final rs = RunningSequence.fromJson(result);
|
|
final running = Map<int, RunningSequence>.from(state.running);
|
|
running[rs.viewerId] = rs;
|
|
emit(state.copyWith(running: running));
|
|
}
|
|
} catch (e) {
|
|
emit(state.copyWith(error: e.toString()));
|
|
}
|
|
}
|
|
|
|
Future<void> _onStopSequence(
|
|
StopSequence event, Emitter<SequenceState> emit) async {
|
|
try {
|
|
await _coordinationService.stopSequence(event.viewerId);
|
|
|
|
final running = Map<int, RunningSequence>.from(state.running);
|
|
running.remove(event.viewerId);
|
|
emit(state.copyWith(running: running));
|
|
} catch (e) {
|
|
emit(state.copyWith(error: e.toString()));
|
|
}
|
|
}
|
|
|
|
void _onSelectCategory(
|
|
SelectCategory event, Emitter<SequenceState> emit) {
|
|
if (event.categoryId == null) {
|
|
emit(state.copyWith(clearCategory: true));
|
|
} else {
|
|
emit(state.copyWith(selectedCategoryId: event.categoryId));
|
|
}
|
|
}
|
|
}
|