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>
138 lines
3.6 KiB
Dart
138 lines
3.6 KiB
Dart
import 'package:equatable/equatable.dart';
|
|
|
|
/// Alarm state enumeration matching SDK PlcViewerAlarmState
|
|
enum AlarmStatus {
|
|
newAlarm(0, 'vasNewAlarm'),
|
|
presented(1, 'vasPresented'),
|
|
stacked(2, 'vasStacked'),
|
|
confirmed(3, 'vasConfirmed'),
|
|
removed(4, 'vasRemoved'),
|
|
lastConfirmed(5, 'vasLastConfirmed'),
|
|
lastRemoved(6, 'vasLastRemoved');
|
|
|
|
final int value;
|
|
final String name;
|
|
const AlarmStatus(this.value, this.name);
|
|
|
|
static AlarmStatus fromValue(int value) {
|
|
return AlarmStatus.values.firstWhere(
|
|
(s) => s.value == value,
|
|
orElse: () => AlarmStatus.newAlarm,
|
|
);
|
|
}
|
|
|
|
/// Check if this status blocks the monitor
|
|
bool get blocksMonitor =>
|
|
this == AlarmStatus.newAlarm || this == AlarmStatus.presented;
|
|
}
|
|
|
|
/// State of a single alarm/event
|
|
class AlarmState extends Equatable {
|
|
final int eventId;
|
|
final String eventName;
|
|
final int typeId;
|
|
final int foreignKey; // Camera or contact ID
|
|
final String? serverId;
|
|
final DateTime startedAt;
|
|
final DateTime? stoppedAt;
|
|
final bool isActive;
|
|
final AlarmStatus status;
|
|
final int? associatedMonitor;
|
|
|
|
const AlarmState({
|
|
required this.eventId,
|
|
required this.eventName,
|
|
required this.typeId,
|
|
required this.foreignKey,
|
|
this.serverId,
|
|
required this.startedAt,
|
|
this.stoppedAt,
|
|
required this.isActive,
|
|
this.status = AlarmStatus.newAlarm,
|
|
this.associatedMonitor,
|
|
});
|
|
|
|
/// Check if this alarm blocks a monitor
|
|
bool get blocksMonitor => isActive && status.blocksMonitor;
|
|
|
|
/// Create a stopped alarm
|
|
AlarmState stopped() {
|
|
return AlarmState(
|
|
eventId: eventId,
|
|
eventName: eventName,
|
|
typeId: typeId,
|
|
foreignKey: foreignKey,
|
|
serverId: serverId,
|
|
startedAt: startedAt,
|
|
stoppedAt: DateTime.now(),
|
|
isActive: false,
|
|
status: AlarmStatus.removed,
|
|
associatedMonitor: associatedMonitor,
|
|
);
|
|
}
|
|
|
|
/// Create alarm with updated status
|
|
AlarmState withStatus(AlarmStatus newStatus) {
|
|
return AlarmState(
|
|
eventId: eventId,
|
|
eventName: eventName,
|
|
typeId: typeId,
|
|
foreignKey: foreignKey,
|
|
serverId: serverId,
|
|
startedAt: startedAt,
|
|
stoppedAt: stoppedAt,
|
|
isActive: isActive,
|
|
status: newStatus,
|
|
associatedMonitor: associatedMonitor,
|
|
);
|
|
}
|
|
|
|
factory AlarmState.fromJson(Map<String, dynamic> json) {
|
|
return AlarmState(
|
|
eventId: json['event_id'] as int? ?? 0,
|
|
eventName: json['event_name'] as String? ?? '',
|
|
typeId: json['type_id'] as int? ?? 0,
|
|
foreignKey: json['foreign_key'] as int? ?? 0,
|
|
serverId: json['server_id'] as String?,
|
|
startedAt: json['started_at'] != null
|
|
? DateTime.parse(json['started_at'] as String)
|
|
: DateTime.now(),
|
|
stoppedAt: json['stopped_at'] != null
|
|
? DateTime.parse(json['stopped_at'] as String)
|
|
: null,
|
|
isActive: json['is_active'] as bool? ?? true,
|
|
status: AlarmStatus.fromValue(json['status'] as int? ?? 0),
|
|
associatedMonitor: json['associated_monitor'] as int?,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'event_id': eventId,
|
|
'event_name': eventName,
|
|
'type_id': typeId,
|
|
'foreign_key': foreignKey,
|
|
'server_id': serverId,
|
|
'started_at': startedAt.toIso8601String(),
|
|
'stopped_at': stoppedAt?.toIso8601String(),
|
|
'is_active': isActive,
|
|
'status': status.value,
|
|
'associated_monitor': associatedMonitor,
|
|
};
|
|
}
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
eventId,
|
|
eventName,
|
|
typeId,
|
|
foreignKey,
|
|
serverId,
|
|
startedAt,
|
|
stoppedAt,
|
|
isActive,
|
|
status,
|
|
associatedMonitor,
|
|
];
|
|
}
|