feat: implement SavePump/SaveAlarms, fix config round-trip bugs, redesign PDF reports
Config system fixes: - Implement SavePump() — full XML serialization with insert/update by pump ID - Add CanBusParameter.ToPumpXml() for legacy P1-P6 pump param format - Fix LastRotationDirection never loaded in LoadSettings() - Add SaveAlarms() to ConfigurationService and IConfigurationService - Remove dead fields AppSettings.Clients and AppSettings.PumpIds PDF report redesign: - Professional layout with charts, verdict badges, and tolerance bands - Add ReportChartRenderer (SVG) and ReportTheme styling constants - Embed default_logo.png as fallback report logo Documentation: - Add gap analysis docs (config validation, ford unlock, missing features) - Update CLAUDE.md architecture, known gaps, and debt tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
74
docs/gap-ford-unlock-ui.md
Normal file
74
docs/gap-ford-unlock-ui.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Gap: Ford Unlock Progress UI
|
||||
|
||||
## Problem
|
||||
The `UnlockService` backend is fully functional (Phase 1 + Phase 2 + verification), but there is no dedicated UI for displaying unlock progress. The old app had `WUnlocker.xaml` — a modal dialog with a visual progress ring and status text.
|
||||
|
||||
## Current State
|
||||
- `UnlockService.StatusChanged` fires every 1000ms with `"Unlocking... {pct}% ({MM:SS})"`
|
||||
- `UnlockService.UnlockCompleted` fires once with `true`/`false`
|
||||
- `MainViewModel` subscribes and pipes status into `VerboseStatus` (displayed as plain text somewhere in MainWindow)
|
||||
- No progress bar, no percentage display, no cancel button, no dedicated dialog
|
||||
|
||||
## Old UI Reference (`WUnlocker.xaml`)
|
||||
- Standalone modal `Window` (300x400px), dark background (#FF2B2929), Topmost, centered on owner
|
||||
- Decorative `Ellipse` ring (200x200, #4D4D4D stroke, 10px thick) as the focal point
|
||||
- Inside the ring: large percentage (Courier New 60pt), "P R O G R E S S" label, elapsed time (MM:SS)
|
||||
- `LBLState` at top: live lock/immo status from CAN feedback ("Bloqueada/Desbloqueada")
|
||||
- `LBLVerbose` at bottom: phase description ("Unlocking...", "Testing...", "Sending")
|
||||
- "Cerrar" (Close) button disabled until progress reaches 100%
|
||||
- Window close prevented via `OnWindowClosing` until completion
|
||||
|
||||
## Spec for New Implementation
|
||||
|
||||
### UnlockDialog.xaml (View)
|
||||
- Modal dialog (MVVM, no code-behind logic)
|
||||
- Progress bar (0-100%) + percentage text
|
||||
- Elapsed time display (MM:SS)
|
||||
- Phase indicator: "Phase 1: Sending unlock signals" / "Phase 2: Testing" / "Verifying..."
|
||||
- Current unlock type indicator (Type 1 / Type 2)
|
||||
- Cancel button (disabled during Phase 2 — it cannot be cancelled once started)
|
||||
- Close button (enabled only after completion)
|
||||
- Result indicator: green checkmark (success) / red X (failed)
|
||||
|
||||
### UnlockViewModel.cs (ViewModel)
|
||||
- `[ObservableProperty] double Progress`
|
||||
- `[ObservableProperty] string ElapsedTime`
|
||||
- `[ObservableProperty] string Phase`
|
||||
- `[ObservableProperty] string Result`
|
||||
- `[ObservableProperty] bool IsComplete`
|
||||
- `[ObservableProperty] bool CanCancel`
|
||||
- `[RelayCommand] Cancel()` — calls `CancellationTokenSource.Cancel()`
|
||||
- Subscribe to `IUnlockService.StatusChanged` — parse percentage from status string
|
||||
- Subscribe to `IUnlockService.UnlockCompleted` — set result and enable close
|
||||
|
||||
### Integration
|
||||
- Trigger: button in MainViewModel (currently exists but needs to open the dialog)
|
||||
- The dialog should be shown via a dialog service or `Window.ShowDialog()` from MainViewModel
|
||||
- Marshal all event handlers to UI thread
|
||||
|
||||
## Protocol Reference
|
||||
|
||||
### Type 1 (CAN IDs 0x700 + 0x300)
|
||||
| Phase | ID | Data | Interval |
|
||||
|-------|----|------|----------|
|
||||
| Msg1 | 0x700 | `B2 00 00 00 00 00 00 00` | 500 ms |
|
||||
| Msg2 | 0x300 | `01 48 50 C3 00 00 00 00` | 50 ms |
|
||||
| TestUnlock states | 0x700 | `B2`, `B6`, `23`, `24` (byte[0]) x2 | 500 ms each |
|
||||
| Verify | TestUnlock param | Success when value != 0 | One-shot |
|
||||
|
||||
### Type 2 (CAN IDs 0x700 + 0x500)
|
||||
| Phase | ID | Data | Interval |
|
||||
|-------|----|------|----------|
|
||||
| Msg1 | 0x700 | `00 00 00 B2 00 00 00 00` | 500 ms |
|
||||
| Msg2 | 0x500 | `00 00 00 00 78 00 00 00` | 50 ms |
|
||||
| TestUnlock states | 0x700 | `B2`, `24`, `24`, `24` (byte[3]) x2 | 500 ms each |
|
||||
| Verify | TestUnlock param | Success when value == 0xE4 | One-shot |
|
||||
|
||||
### Duration
|
||||
Phase 1: 600,500 ms (10 min 0.5 sec). Phase 2: ~4 sec (8 messages x 500ms). Total: ~604.5 sec.
|
||||
|
||||
## Known Issue in Unlock Verification
|
||||
The **Type 1 verification logic may be inverted** compared to the old code. Old: `Lock = (valor != 0)` meant non-zero = LOCKED. New: `Value != 0` returned as SUCCESS (unlocked). Needs hardware testing to confirm which is correct.
|
||||
|
||||
## Missing Feature: TestImmo Check
|
||||
Old code tracked both `TestUnlock` and `TestImmo` CAN parameters and displayed combined status. New code only checks `TestUnlock`, ignoring `TestImmo` entirely. Consider adding the immobilizer state check for completeness.
|
||||
Reference in New Issue
Block a user