Files
COPILOT/copilot_keyboard/lib/presentation/widgets/wall_grid/viewer_tile.dart
klas 40143734fc Initial commit: COPILOT D6 Flutter keyboard controller
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>
2026-02-12 14:57:38 +01:00

114 lines
3.5 KiB
Dart

import 'package:flutter/material.dart';
import '../../blocs/wall/wall_state.dart';
/// A single viewer tile within a physical monitor
class ViewerTile extends StatelessWidget {
final int viewerId;
final ViewerState viewerState;
final bool isSelected;
final bool isPartOfQuad;
final VoidCallback onTap;
const ViewerTile({
super.key,
required this.viewerId,
required this.viewerState,
required this.isSelected,
this.isPartOfQuad = false,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
decoration: BoxDecoration(
color: _getBackgroundColor(context),
border: isSelected && !isPartOfQuad
? Border.all(color: const Color(0xFF00D4FF), width: 3)
: Border.all(color: const Color(0xFF4A5568), width: 1),
borderRadius: BorderRadius.circular(4),
),
child: Stack(
children: [
// Main content
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Viewer ID
Text(
'$viewerId',
style: TextStyle(
color: Colors.white,
fontSize: isPartOfQuad ? 12 : 16,
fontWeight: FontWeight.bold,
fontFamily: 'monospace',
),
),
// Camera ID if assigned
if (viewerState.hasCamera)
Text(
'${viewerState.currentCameraId}',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.7),
fontSize: isPartOfQuad ? 9 : 11,
fontFamily: 'monospace',
),
),
],
),
),
// Lock indicator
if (viewerState.isLocked)
Positioned(
top: 2,
right: 2,
child: Icon(
Icons.lock,
size: isPartOfQuad ? 10 : 14,
color: viewerState.isLockedByOther
? Colors.red
: Colors.green,
),
),
// Live/Playback indicator
if (viewerState.hasCamera && !viewerState.isLive)
Positioned(
bottom: 2,
left: 2,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 2),
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(2),
),
child: Text(
'PvZ',
style: TextStyle(
color: Colors.white,
fontSize: isPartOfQuad ? 7 : 9,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
);
}
Color _getBackgroundColor(BuildContext context) {
if (viewerState.hasAlarm) {
return const Color(0xFFDC2626); // Red for alarm
}
if (viewerState.hasCamera) {
return const Color(0xFF2D3748); // Dark gray with camera
}
return const Color(0xFF1A202C); // Darker gray without camera
}
}