import 'package:flutter/material.dart'; import '../../../domain/entities/wall_config.dart'; import '../../blocs/wall/wall_state.dart'; /// Overview screen showing all wall sections in spatial layout (matching D6) class WallOverview extends StatelessWidget { final WallConfig config; final WallState wallState; final Function(String sectionId) onSectionTap; const WallOverview({ super.key, required this.config, required this.wallState, required this.onSectionTap, }); @override Widget build(BuildContext context) { return Container( color: const Color(0xFF5A5A5A), // D6 background color child: LayoutBuilder( builder: (context, constraints) { return Stack( children: _buildSpatialLayout(constraints), ); }, ), ); } List _buildSpatialLayout(BoxConstraints constraints) { final widgets = []; final width = constraints.maxWidth; final height = constraints.maxHeight; // Position sections based on D6 layout // The D6 app shows: // - "4. Vrchní část" (top) at the top center // - "1. Levá část" (left), "2. Střed stěny" (center), "3. Pravá část" (right) in middle row // - "5. Stupínek" (bottom) at the bottom center for (final section in config.sections) { final position = _getSectionPosition(section.id, width, height); final size = _getSectionSize(section.id, width, height); widgets.add( Positioned( left: position.dx, top: position.dy, width: size.width, height: size.height, child: _SectionTile( section: section, wallState: wallState, onTap: () => onSectionTap(section.id), ), ), ); } return widgets; } Offset _getSectionPosition(String sectionId, double width, double height) { // Layout matching D6 screenshot switch (sectionId) { case 'top': // 4. Vrchní část - top center return Offset(width * 0.35, height * 0.05); case 'left': // 1. Levá část - middle left return Offset(width * 0.08, height * 0.35); case 'center': // 2. Střed stěny - middle center return Offset(width * 0.33, height * 0.35); case 'right': // 3. Pravá část - middle right return Offset(width * 0.58, height * 0.35); case 'bottom': // 5. Stupínek - bottom center return Offset(width * 0.33, height * 0.68); default: return Offset.zero; } } Size _getSectionSize(String sectionId, double width, double height) { // Sizes proportional to D6 layout switch (sectionId) { case 'top': return Size(width * 0.30, height * 0.22); case 'left': return Size(width * 0.22, height * 0.25); case 'center': return Size(width * 0.22, height * 0.25); case 'right': return Size(width * 0.22, height * 0.25); case 'bottom': return Size(width * 0.30, height * 0.25); default: return Size(width * 0.2, height * 0.2); } } } class _SectionTile extends StatelessWidget { final WallSection section; final WallState wallState; final VoidCallback onTap; const _SectionTile({ required this.section, required this.wallState, required this.onTap, }); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Section label Padding( padding: const EdgeInsets.only(bottom: 4), child: Text( '${_getSectionNumber(section.id)}. ${section.name}', style: const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500, ), ), ), // Mini monitors grid Expanded( child: _MiniMonitorsGrid( section: section, wallState: wallState, ), ), ], ), ); } int _getSectionNumber(String id) { switch (id) { case 'left': return 1; case 'center': return 2; case 'right': return 3; case 'top': return 4; case 'bottom': return 5; default: return 0; } } } class _MiniMonitorsGrid extends StatelessWidget { final WallSection section; final WallState wallState; const _MiniMonitorsGrid({ required this.section, required this.wallState, }); @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { final monitors = section.monitors; final gridCols = section.columns; final gridRows = section.rows; // Calculate cell dimensions based on grid size final cellWidth = constraints.maxWidth / gridCols; final cellHeight = constraints.maxHeight / gridRows; // Position monitors using their explicit row/col values (matching detail view) return Stack( children: monitors.map((monitor) { // Convert 1-based row/col to 0-based for positioning final row = monitor.row - 1; final col = monitor.col - 1; return Positioned( left: col * cellWidth, top: row * cellHeight, width: monitor.colSpan * cellWidth, height: monitor.rowSpan * cellHeight, child: _MiniPhysicalMonitor( monitor: monitor, wallState: wallState, ), ); }).toList(), ); }, ); } } class _MiniPhysicalMonitor extends StatelessWidget { final PhysicalMonitor monitor; final WallState wallState; const _MiniPhysicalMonitor({ required this.monitor, required this.wallState, }); @override Widget build(BuildContext context) { final viewers = monitor.viewerIds; final gridCols = monitor.colSpan; final gridRows = monitor.rowSpan; // Overview: no cyan borders, just dark grid lines between viewers return Container( color: const Color(0xFF4A4A4A), // Dark background shows as grid lines child: Column( children: List.generate(gridRows, (row) { return Expanded( child: Row( children: List.generate(gridCols, (col) { final index = row * gridCols + col; if (index >= viewers.length) { return Expanded( child: Padding( padding: const EdgeInsets.all(0.5), child: Container( color: const Color(0xFF6A6A6A), ), ), ); } final viewerId = viewers[index]; final viewerState = wallState.getViewerState(viewerId); Color tileColor; if (viewerState.hasAlarm) { tileColor = const Color(0xFFDC2626); } else { tileColor = const Color(0xFF6A6A6A); } return Expanded( child: Padding( padding: const EdgeInsets.all(0.5), child: Container( color: tileColor, ), ), ); }), ), ); }), ), ); } }