import 'package:equatable/equatable.dart'; /// Configuration for a physical monitor that can display 1-4 viewers class PhysicalMonitor extends Equatable { final int id; final String? name; final List viewerIds; // 1-4 viewer IDs in this physical monitor final bool isQuadView; final int row; // Grid row position (1-based) final int col; // Grid column position (1-based) final int rowSpan; // How many rows this monitor spans final int colSpan; // How many columns this monitor spans const PhysicalMonitor({ required this.id, this.name, required this.viewerIds, this.isQuadView = false, this.row = 1, this.col = 1, this.rowSpan = 1, this.colSpan = 1, }); /// Whether this monitor has multiple viewers (quad view) bool get hasMultipleViewers => viewerIds.length > 1; /// Get the primary viewer ID (first one) int get primaryViewerId => viewerIds.isNotEmpty ? viewerIds.first : 0; factory PhysicalMonitor.fromJson(Map json) { final viewers = json['viewer_ids'] as List?; return PhysicalMonitor( id: json['id'] as int, name: json['name'] as String?, viewerIds: viewers?.map((v) => v as int).toList() ?? [], isQuadView: json['is_quad_view'] as bool? ?? false, row: json['row'] as int? ?? 1, col: json['col'] as int? ?? 1, rowSpan: json['row_span'] as int? ?? 1, colSpan: json['col_span'] as int? ?? 1, ); } Map toJson() => { 'id': id, 'name': name, 'viewer_ids': viewerIds, 'is_quad_view': isQuadView, 'row': row, 'col': col, 'row_span': rowSpan, 'col_span': colSpan, }; @override List get props => [id, name, viewerIds, isQuadView, row, col, rowSpan, colSpan]; } /// A section of the video wall (e.g., "Vrchní část", "Pravá část") class WallSection extends Equatable { final String id; final String name; final List monitors; final int columns; // Grid layout columns for this section final int rows; // Grid layout rows for this section const WallSection({ required this.id, required this.name, required this.monitors, this.columns = 8, this.rows = 4, }); factory WallSection.fromJson(Map json) { final monitors = json['monitors'] as List?; return WallSection( id: json['id'] as String, name: json['name'] as String, monitors: monitors ?.map((m) => PhysicalMonitor.fromJson(m as Map)) .toList() ?? [], columns: json['columns'] as int? ?? 8, rows: json['rows'] as int? ?? 4, ); } Map toJson() => { 'id': id, 'name': name, 'monitors': monitors.map((m) => m.toJson()).toList(), 'columns': columns, 'rows': rows, }; @override List get props => [id, name, monitors, columns, rows]; } /// Complete wall configuration with all sections class WallConfig extends Equatable { final String id; final String name; final List sections; final List alarmMonitorIds; // Monitor IDs designated for alarms const WallConfig({ required this.id, required this.name, required this.sections, this.alarmMonitorIds = const [], }); /// Get all viewer IDs across all sections List get allViewerIds { final ids = []; for (final section in sections) { for (final monitor in section.monitors) { ids.addAll(monitor.viewerIds); } } return ids; } /// Get all physical monitors across all sections List get allMonitors { final monitors = []; for (final section in sections) { monitors.addAll(section.monitors); } return monitors; } /// Find physical monitor containing a viewer ID PhysicalMonitor? findMonitorByViewerId(int viewerId) { for (final section in sections) { for (final monitor in section.monitors) { if (monitor.viewerIds.contains(viewerId)) { return monitor; } } } return null; } /// Find section containing a viewer ID WallSection? findSectionByViewerId(int viewerId) { for (final section in sections) { for (final monitor in section.monitors) { if (monitor.viewerIds.contains(viewerId)) { return section; } } } return null; } factory WallConfig.fromJson(Map json) { final sections = json['sections'] as List?; final alarmIds = json['alarm_monitor_ids'] as List?; return WallConfig( id: json['id'] as String, name: json['name'] as String, sections: sections ?.map((s) => WallSection.fromJson(s as Map)) .toList() ?? [], alarmMonitorIds: alarmIds?.map((i) => i as int).toList() ?? [], ); } Map toJson() => { 'id': id, 'name': name, 'sections': sections.map((s) => s.toJson()).toList(), 'alarm_monitor_ids': alarmMonitorIds, }; /// Create sample wall config matching D6 app structure factory WallConfig.sample() { return WallConfig( id: 'wall_1', name: 'Hlavní videostěna', sections: [ // Vrchní část - 8 columns x 4 rows irregular grid WallSection( id: 'top', name: 'Vrchní část', columns: 8, rows: 4, monitors: [ // Row 1-2: Three quad monitors PhysicalMonitor( id: 1, viewerIds: [210, 211, 212, 213], isQuadView: true, row: 1, col: 1, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 2, viewerIds: [214, 215, 216, 217], isQuadView: true, row: 1, col: 3, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 3, viewerIds: [1001, 1002, 1003, 1004], isQuadView: true, row: 1, col: 5, rowSpan: 2, colSpan: 2, ), // Row 4: Single monitor PhysicalMonitor( id: 4, viewerIds: [222], row: 4, col: 2, rowSpan: 1, colSpan: 1, ), // Row 3-4: Three quad monitors PhysicalMonitor( id: 5, viewerIds: [223, 224, 225, 226], isQuadView: true, row: 3, col: 3, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 6, viewerIds: [227, 228, 229, 230], isQuadView: true, row: 3, col: 5, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 7, viewerIds: [231, 232, 233, 234], isQuadView: true, row: 3, col: 7, rowSpan: 2, colSpan: 2, ), ], ), // Levá část - 7 columns x 6 rows WallSection( id: 'left', name: 'Levá část', columns: 7, rows: 6, monitors: [ // Row 1-2: 3x2 monitor + two 2x2 quads PhysicalMonitor( id: 8, viewerIds: [88, 89, 90, 91, 92, 93], row: 1, col: 1, rowSpan: 2, colSpan: 3, ), PhysicalMonitor( id: 9, viewerIds: [40, 41, 42, 43], isQuadView: true, row: 1, col: 4, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 10, viewerIds: [44, 45, 46, 47], isQuadView: true, row: 1, col: 6, rowSpan: 2, colSpan: 2, ), // Row 3-4: Two 2x2 quads PhysicalMonitor( id: 11, viewerIds: [48, 49, 50, 51], isQuadView: true, row: 3, col: 4, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 12, viewerIds: [52, 53, 54, 55], isQuadView: true, row: 3, col: 6, rowSpan: 2, colSpan: 2, ), // Row 5-6: Two 2x2 quads PhysicalMonitor( id: 13, viewerIds: [56, 57, 58, 59], isQuadView: true, row: 5, col: 4, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 14, viewerIds: [60, 61, 62, 63], isQuadView: true, row: 5, col: 6, rowSpan: 2, colSpan: 2, ), ], ), // Střed stěny - 8 columns x 4 rows WallSection( id: 'center', name: 'Střed stěny', columns: 8, rows: 4, monitors: [ // Row 1-2: Quad + 4 tall single monitors PhysicalMonitor( id: 15, viewerIds: [14, 15, 16, 17], isQuadView: true, row: 1, col: 2, rowSpan: 2, colSpan: 2, ), PhysicalMonitor(id: 16, viewerIds: [18], row: 1, col: 4, rowSpan: 2, colSpan: 1), PhysicalMonitor(id: 17, viewerIds: [19], row: 1, col: 5, rowSpan: 2, colSpan: 1), PhysicalMonitor(id: 18, viewerIds: [20], row: 1, col: 6, rowSpan: 2, colSpan: 1), PhysicalMonitor(id: 19, viewerIds: [21], row: 1, col: 7, rowSpan: 2, colSpan: 1), // Row 3-4: Four 2x2 quads PhysicalMonitor( id: 20, viewerIds: [24, 25, 32, 33], isQuadView: true, row: 3, col: 1, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 21, viewerIds: [26, 27, 34, 35], isQuadView: true, row: 3, col: 3, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 22, viewerIds: [28, 29, 36, 37], isQuadView: true, row: 3, col: 5, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 23, viewerIds: [30, 31, 38, 39], isQuadView: true, row: 3, col: 7, rowSpan: 2, colSpan: 2, ), ], ), // Pravá část - 7 columns x 6 rows WallSection( id: 'right', name: 'Pravá část', columns: 7, rows: 6, monitors: [ // Row 1-2: Two 2x2 quads + 3x2 monitor PhysicalMonitor( id: 24, viewerIds: [64, 65, 66, 67], isQuadView: true, row: 1, col: 1, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 25, viewerIds: [68, 69, 70, 71], isQuadView: true, row: 1, col: 3, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 26, viewerIds: [94, 95, 96, 97, 98, 99], row: 1, col: 5, rowSpan: 2, colSpan: 3, ), // Row 3-4: Two 2x2 quads PhysicalMonitor( id: 27, viewerIds: [72, 73, 74, 75], isQuadView: true, row: 3, col: 1, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 28, viewerIds: [76, 77, 78, 79], isQuadView: true, row: 3, col: 3, rowSpan: 2, colSpan: 2, ), // Row 5-6: Two 2x2 quads PhysicalMonitor( id: 29, viewerIds: [80, 81, 82, 83], isQuadView: true, row: 5, col: 1, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 30, viewerIds: [84, 85, 86, 87], isQuadView: true, row: 5, col: 3, rowSpan: 2, colSpan: 2, ), ], ), // Stupínek - 8 columns x 4 rows WallSection( id: 'bottom', name: 'Stupínek', columns: 8, rows: 4, monitors: [ // Row 1-2: Three 2x2 quads PhysicalMonitor( id: 31, viewerIds: [183, 184, 185, 186], isQuadView: true, row: 1, col: 1, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 32, viewerIds: [187, 188, 189, 190], isQuadView: true, row: 1, col: 3, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 33, viewerIds: [191, 192, 193, 194], isQuadView: true, row: 1, col: 5, rowSpan: 2, colSpan: 2, ), // Row 3-4: Two 2x2 quads PhysicalMonitor( id: 34, viewerIds: [195, 196, 197, 198], isQuadView: true, row: 3, col: 5, rowSpan: 2, colSpan: 2, ), PhysicalMonitor( id: 35, viewerIds: [199, 200, 201, 202], isQuadView: true, row: 3, col: 7, rowSpan: 2, colSpan: 2, ), ], ), ], alarmMonitorIds: [222, 223, 224], // Example alarm monitors ); } @override List get props => [id, name, sections, alarmMonitorIds]; }