Files
COPILOT/Docs/plans/2026-02-03-flutter-ui-design.md
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

395 lines
12 KiB
Markdown

# Flutter COPILOT Keyboard UI Design
## Overview
This document defines the Flutter UI implementation based on the existing D6 application and the Klavesnice Business Analysis specification.
## Screen Structure
### 1. Main Screen (Basic View)
The main screen consists of three primary areas:
```
+--------------------------------------------------+
| Connection Status Bar |
+--------------------------------------------------+
| |
| Video Wall Grid |
| (Physical Monitors with Viewers) |
| |
+--------------------------------------------------+
| Bottom Toolbar |
+--------------------------------------------------+
```
### 2. Video Wall Grid
Based on D6 screenshots, the wall is divided into **5 sections**:
- Vrchní část (Top section) - monitors 210-234
- Pravá část (Right section)
- Levá část (Left section)
- Dolní část (Bottom section)
- Střední část (Middle section)
Each section contains:
- Section header with name
- Grid of physical monitors
- Each physical monitor can contain 1-4 viewers (quad view)
#### Monitor Display States
| State | Visual |
|-------|--------|
| Normal | Dark background, white text |
| Selected (touched) | Cyan/blue border (thick) |
| Active Alarm | Red background |
| Alarm + Selected | Red background + cyan border |
| Locked by current user | Lock icon visible |
| Locked by other user | Lock icon + disabled |
#### Viewer Number Display
- Each viewer shows its viewer number (e.g., 210, 211, 212, 213)
- Quad view: 4 viewers in one physical monitor with visible border around physical monitor
- Single view: One viewer fills the physical monitor
### 3. Bottom Toolbar (Button Strip)
Dynamic button strip that changes based on context:
#### Default State (No Selection)
```
[Search] [500] [501] [502] [HOME] [F1] [F2] [F3] [F4] [F5] [F6] [F7]
```
#### Monitor Selected (Camera View)
```
[←] [PREPOS] [PvZ] [ALARM] [LOCK/UNLOCK] [SEARCH]
```
Where:
- **←** Back to default
- **PREPOS** Open preposition list (only for PTZ cameras when unlocked)
- **PvZ** Enter playback mode (only if keyboard has permission)
- **ALARM** Open alarm history list
- **LOCK/UNLOCK** Toggle PTZ lock
- **SEARCH** Open camera search dialog
### 4. Camera Prefix Selection
Three prefix buttons for camera number input:
- **500** - GeViScope cameras (500001-500999)
- **501** - G-CORE cameras (501001-501999)
- **502** - GeViServer cameras (502001-502999)
Selected prefix is highlighted. User then types 3-digit camera number.
### 5. Camera Number Input
```
+----------------------------------+
| Input Field: [500] + [ ] |
| Current: 500201 |
+----------------------------------+
| [1] [2] [3] |
| [4] [5] [6] |
| [7] [8] [9] |
| [C] [0] [OK] |
+----------------------------------+
```
- Number input via touchscreen or physical USB keyboard
- C = Clear, OK = Confirm CrossSwitch
- ESC/Back = Cancel
---
## Secondary Screens
### 6. Search Screen
Opened via Search button when monitor is selected:
```
+--------------------------------------------------+
| Search Camera [X] |
+--------------------------------------------------+
| Camera Number: [________] |
| |
| [Keyboard toggle] |
+--------------------------------------------------+
| Search Results: |
| [500001 - Jindřišská, tramvaj] |
| [500002 - Václavské náměstí] |
| ... |
+--------------------------------------------------+
| [←] [OK] |
+--------------------------------------------------+
```
### 7. Preposition List Screen
```
+--------------------------------------------------+
| PREPOZICE - Kamera 500005 [X] |
+--------------------------------------------------+
| [2] Jindřišská, tramvajový ostrůvek |
| [10] Jindřišská, křižovatka [●] |
| [15] U Bulhara směr centrum |
| ... |
+--------------------------------------------------+
| [←] [+] [🗑] [✓] |
+--------------------------------------------------+
```
- Blue highlight on selected preposition
- [+] Add new preposition (disabled if AppServer unavailable)
- [🗑] Delete preposition (disabled if editable=0 or positions 1-9)
- [✓] Confirm/go to selected preposition
### 8. Add Preposition Screen
```
+--------------------------------------------------+
| Nová prepozice - Kamera 500005 [X] |
+--------------------------------------------------+
| Číslo prepozice: [__] (10-99 only) |
| |
| Název prepozice: [________________] |
| |
| [Keyboard] |
+--------------------------------------------------+
| [←] [ULOŽIT] |
+--------------------------------------------------+
```
Save button disabled until both fields filled.
### 9. Playback Mode (PvZ) Screen
Overlay controls on main view:
```
+--------------------------------------------------+
| PvZ: Kamera 500005 |
| Čas: 2026-02-03 14:35:22 |
+--------------------------------------------------+
| [|◄] [◄◄] [◄] [⏸] [►] [►►] [►|] [LIVE] |
+--------------------------------------------------+
| Speed: [-7 ... -1] [0] [+1 ... +7] |
+--------------------------------------------------+
```
Jog-shuttle speed table:
- Position -7 to -1: Reverse (slow to fast)
- Position 0: Pause
- Position +1 to +7: Forward (slow to fast)
### 10. Alarm List Screen
```
+--------------------------------------------------+
| Alarmy - Kamera 500005 [X] |
+--------------------------------------------------+
| Od: [2026-02-01] [📅] Do: [2026-02-03] [📅] |
+--------------------------------------------------+
| Začátek | Konec |
| 02-03 14:30:15 | 02-03 14:32:45 [●] |
| 02-03 12:15:30 | 02-03 12:18:22 |
| 02-02 23:45:00 | 02-02 23:47:15 |
+--------------------------------------------------+
| [←] [LIVE] [⏩] [▶⏩] [◄◄] [⏸] |
+--------------------------------------------------+
```
- [⏩] Jump to timestamp (paused)
- [▶⏩] Jump to timestamp and play
- [◄◄] Reverse playback
- [⏸] Stop playback
- [LIVE] Return to live stream
### 11. Function Button Config (F1-F7, HOME)
Each function button triggers predefined wall configuration:
- Stored on Application Server
- Can set camera or sequence per monitor
- Before CrossSwitch, check if sequence is running and stop it
### 12. Service Menu
Activated by holding Backspace for 3 seconds:
```
+----------------------------------+
| Servisní Menu [X] |
+----------------------------------+
| (1) Restartovat aplikaci |
| (2) Restartovat klávesnici |
| (3) Vypnout klávesnici |
+----------------------------------+
```
---
## Component Specifications
### Color Palette
| Element | Color | Hex |
|---------|-------|-----|
| Background | Dark blue-gray | #1a2332 |
| Monitor normal | Dark gray | #2d3748 |
| Monitor selected | Cyan border | #00d4ff |
| Monitor alarm | Red | #ff4444 |
| Button active | Blue | #3182ce |
| Button disabled | Gray | #4a5568 |
| Text primary | White | #ffffff |
| Text secondary | Gray | #a0aec0 |
| Preposition highlight | Blue | #2b6cb0 |
### Typography
- Monitor numbers: Monospace, bold, 16-20px
- Section headers: Sans-serif, semibold, 14px
- Button labels: Sans-serif, medium, 12-14px
- Input fields: Monospace, regular, 16px
### Touch Targets
- Minimum touch target: 44x44 pixels
- Monitor tiles: Variable (based on grid)
- Toolbar buttons: 48px height
- List items: 48px height minimum
---
## State Management (BLoC)
### Required BLoCs
1. **ConnectionBloc** - Server connection states
2. **WallBloc** - Video wall state, monitor selection
3. **AlarmBloc** - Active alarms, alarm history
4. **CameraBloc** - Camera input, CrossSwitch operations
5. **PTZBloc** - Lock state, telemetry controls
6. **PlaybackBloc** - PvZ mode, jog-shuttle
7. **PrepositionBloc** - Preposition list, add/delete
8. **FunctionButtonBloc** - Function button configurations
9. **SequenceBloc** - Sequence state per monitor
### Events & States Example (WallBloc)
```dart
// Events
abstract class WallEvent {}
class LoadWallConfig extends WallEvent {}
class SelectMonitor extends WallEvent { final int viewerId; }
class DeselectMonitor extends WallEvent {}
class CrossSwitchCamera extends WallEvent { final int cameraId; final int viewerId; }
// States
abstract class WallState {}
class WallLoading extends WallState {}
class WallLoaded extends WallState {
final List<WallSection> sections;
final int? selectedViewerId;
final int? selectedPhysicalMonitorId;
}
```
---
## Implementation Priority
### Phase 1: Core UI (MVP)
1. Main screen layout with wall grid
2. Monitor selection (touch)
3. Camera number input (prefix + digits)
4. CrossSwitch command
5. Connection status bar
### Phase 2: Alarms & Status
1. Alarm state display (red monitors)
2. Alarm blocking (prevent CrossSwitch on active alarm)
3. Monitor lock indicators
### Phase 3: PTZ & Playback
1. PTZ lock/unlock
2. Telemetry controls (pan/tilt/zoom)
3. Playback mode (PvZ)
4. Jog-shuttle controls
### Phase 4: Advanced Features
1. Preposition management
2. Alarm history list
3. Function buttons (F1-F7, HOME)
4. Sequences
5. Search functionality
### Phase 5: Polish
1. Service menu
2. CAMEA integration
3. Autonomous mode fallbacks
4. Error handling dialogs
---
## Autonomous Mode Behavior
When Application Server is unavailable:
| Feature | Available | Notes |
|---------|-----------|-------|
| CrossSwitch | ✓ | Direct to bridge |
| PTZ Lock | ✓ | Local lock only |
| CAMEA Reserve | ✓ | Direct to CAMEA |
| Preposition List | ✓ | Cached config |
| Add Preposition | ✗ | Requires AppServer |
| Delete Preposition | ✗ | Requires AppServer |
| Sequences | ✗ | Run by AppServer |
| Function Buttons | ✓ | Cached config |
| Alarm Management | ✗ | Run by GeViSoft |
---
## File Structure
```
lib/
├── presentation/
│ ├── screens/
│ │ ├── main_screen.dart
│ │ ├── search_screen.dart
│ │ ├── preposition_screen.dart
│ │ ├── alarm_list_screen.dart
│ │ ├── playback_overlay.dart
│ │ └── service_menu_dialog.dart
│ ├── widgets/
│ │ ├── wall_grid/
│ │ │ ├── wall_grid.dart
│ │ │ ├── wall_section.dart
│ │ │ ├── physical_monitor.dart
│ │ │ └── viewer_tile.dart
│ │ ├── toolbar/
│ │ │ ├── bottom_toolbar.dart
│ │ │ ├── prefix_buttons.dart
│ │ │ ├── function_buttons.dart
│ │ │ └── action_buttons.dart
│ │ ├── input/
│ │ │ ├── camera_input.dart
│ │ │ ├── numeric_keypad.dart
│ │ │ └── datetime_picker.dart
│ │ └── common/
│ │ ├── connection_status_bar.dart
│ │ └── confirmation_dialog.dart
│ └── blocs/
│ ├── wall/
│ ├── alarm/
│ ├── camera/
│ ├── ptz/
│ ├── playback/
│ ├── preposition/
│ └── function_button/
```