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>
This commit is contained in:
klas
2026-02-12 14:57:38 +01:00
commit 40143734fc
125 changed files with 65073 additions and 0 deletions

View File

@@ -0,0 +1,268 @@
---
title: "System Architecture"
description: "Component diagrams, dependency graph, and deployment model"
---
# System Architecture
## Component Dependency Graph
```mermaid
graph TB
subgraph "Copilot.App.exe (WPF Client)"
App["App.cs<br/>.NET Generic Host"]
MW["MainWindow<br/>Input Router"]
SVM["SegmentViewModel<br/>Main Screen Logic"]
PVM["PlaybackViewModel"]
CSVM["CameraSearchViewModel"]
PreVM["PrepositionsViewModel"]
SeqVM["SequenceCategoriesViewModel<br/>SequencesViewModel"]
SvcVM["ServiceMenuViewModel"]
subgraph "App Services"
CCS["CameraControllerService"]
CLS["CameraLockService"]
CAS["CameraAlarmService"]
SeqS["SequenceService"]
FBS["FunctionButtonsService"]
PBS["PlaybackStateService"]
CfgS["ConfigurationService"]
NAS["NetworkAvailabilityState"]
end
subgraph "Navigation"
NS["NavigationService"]
NStore["NavigationStore"]
end
end
subgraph "Copilot.Device.dll"
CD["CopilotDevice"]
SP["SerialPortDataProvider"]
HID["JoystickHidDataProvider"]
end
subgraph "Copilot.Common.dll"
Config["Configuration System"]
Hub["ICopilotHub<br/>ICopilotHubEvents"]
Prov["ICopilotInfoProvider"]
end
subgraph "Copilot.Common.Services.dll"
MCS["MediaChannelService"]
VSS["ViewerStateService"]
CSDP["CameraServerDriverProvider"]
CenDP["CentralServerDriverProvider"]
end
subgraph "Copilot.Drivers.Common.dll"
IMC["IMovementController"]
ICSD["ICameraServerDriver"]
ICenD["ICentralServerDriver"]
IVC["IViewerController"]
end
subgraph "Copilot.Drivers.GeViScope.dll"
GscD["GeViScopeDriver"]
GscMC["GeViScopeMovementController"]
GscVC["GeviScopeViewerController"]
end
subgraph "Copilot.Drivers.GCore.dll"
GcD["GCoreDriver"]
GcMC["GCoreMovementController"]
GcVC["GCoreViewerController"]
end
subgraph "Copilot.AppServer.Client.dll"
ASC["AppServerClient<br/>(SignalR)"]
Avail["AvailabilityState"]
end
App --> MW
MW --> CD
MW --> SVM
SVM --> CCS
SVM --> CLS
SVM --> FBS
SVM --> CAS
CLS --> Hub
CAS --> Hub
SeqS --> Hub
CfgS --> Hub
CCS --> CSDP
CCS --> MCS
CSDP --> GscD
CSDP --> GcD
CenDP --> GscD
GscD --> GscMC
GscD --> GscVC
GcD --> GcMC
GcD --> GcVC
GscMC -.->|implements| IMC
GcMC -.->|implements| IMC
GscD -.->|implements| ICSD
GcD -.->|implements| ICSD
Hub --> ASC
```
## Service Lifetime & Registration
All services are registered via `Microsoft.Extensions.DependencyInjection` in `App.cs`:
```mermaid
graph LR
subgraph "Singletons (one instance)"
MainWindow
SegmentViewModel
NavigationStore
NavigationService
CameraLockService
PlaybackStateService
ConfigurationService
CameraAlarmService
CameraControllerService
PrepositionService
SequenceService
NetworkAvailabilityState
end
subgraph "Transient (new per request)"
CameraSearchViewModel
PlaybackViewModel
PrepositionsViewModel
SequenceCategoriesViewModel
SequencesViewModel
ServiceMenuViewModel
ErrorViewModel
CameraAlarmHistoryViewModel
end
subgraph "Hosted Services (background workers)"
StartupConfigurationCheckWorker
ViewerStatesInitWorker
CameraAlarmsUpdateWorker
NetworkAvailabilityWorker
SequenceService_Hosted["SequenceService<br/>(also IHostedService)"]
ProcessMonitorServiceHost
end
```
## Startup Sequence
```mermaid
sequenceDiagram
participant App as App.cs
participant Host as .NET Host
participant MW as MainWindow
participant Nav as NavigationService
participant Device as CopilotDevice
participant Hub as SignalR Hub
participant Config as ConfigurationService
App->>Host: Build & ConfigureServices
Host->>Host: Register all DI services
App->>Host: StartAsync()
Host->>Host: Start background workers
Note over Host: StartupConfigurationCheckWorker starts
Note over Host: ViewerStatesInitWorker starts
Note over Host: CameraAlarmsUpdateWorker starts
Note over Host: NetworkAvailabilityWorker starts
App->>Nav: Navigate<SegmentsPage>(wallId)
App->>MW: Show()
MW->>Device: Subscribe JoystickMoved
MW->>Device: Subscribe VirtualKeyDown/Up
alt Firmware outdated
MW->>Nav: Navigate<UpdateFirmwarePage>
end
App->>Config: UpdateAllConfigurationsIfChanged()
Config->>Hub: GetConfigurationFile() for each manager
Config->>Config: Write updated configs to disk
Note over App: Application Ready
```
## Navigation System
The app uses a custom stack-based navigation system (not WPF Navigation):
```mermaid
stateDiagram-v2
[*] --> SegmentsPage: Initial (select segment)
SegmentsPage --> SegmentPage: Select segment
SegmentPage --> CameraSearchPage: Search button
SegmentPage --> PrepositionsPage: Prepositions button
SegmentPage --> PlaybackPage: Playback button
SegmentPage --> SequenceCategoriesPage: Sequence button
SegmentPage --> CameraAlarmHistoryPage: Alarm history
SegmentPage --> ServiceMenuPage: Hold Backspace 3s
SegmentPage --> CameraLockExpirationView: Lock expiring
CameraSearchPage --> SegmentPage: Back
PrepositionsPage --> PrepositionAddPage: Add preset
PrepositionAddPage --> PrepositionsPage: Back
PrepositionsPage --> SegmentPage: Back
PlaybackPage --> SegmentPage: Back
SequenceCategoriesPage --> SequencesPage: Select category
SequencesPage --> SegmentPage: Start sequence
ServiceMenuPage --> UpdateFirmwarePage: Update firmware
```
## Two Communication Paths
The app communicates with two distinct backends simultaneously:
### Path 1: Direct SDK (Camera Operations)
```
App → CameraServerDriverProvider → GeViScope/GCore Driver → Native SDK → Camera Server
```
- **Used for:** CrossSwitch, PTZ, Playback, Viewer control
- **Latency:** < 50ms (direct TCP connection to camera server)
- **Reconnection:** Automatic, 2-second retry interval
### Path 2: SignalR Hub (Coordination)
```
App → CopilotHub (SignalR) → AppServer → Database/Logic → Response
```
- **Used for:** Camera locks, sequences, config sync, alarm history, viewer state
- **Latency:** ~100-200ms (HTTPS + server processing)
- **Reconnection:** Automatic via SignalR reconnection policy
```mermaid
graph LR
subgraph "App"
SVM["SegmentViewModel"]
end
subgraph "Path 1: Direct (low latency)"
Driver["GeViScope/GCore Driver"]
SDK["Native SDK (TCP)"]
end
subgraph "Path 2: Coordinated"
HubC["SignalR Client"]
HTTPS["HTTPS/WSS"]
end
subgraph "Camera Server"
CS["GeViScope / G-Core"]
end
subgraph "AppServer"
HubS["SignalR Hub"]
DB["SQLite DB"]
end
SVM -->|"CrossSwitch, PTZ,<br/>Playback"| Driver
Driver --> SDK --> CS
SVM -->|"Locks, Sequences,<br/>Config, Alarms"| HubC
HubC --> HTTPS --> HubS
HubS --> DB
```