Unlock progress UI:
- UnlockProgressDialog with dark-themed progress ring, phase indicator, elapsed
time, and cancel/close buttons (non-modal, draggable borderless window)
- UnlockProgressViewModel with event-driven progress tracking via IUnlockService
- Triggers on pump selection (manual or K-Line auto-detect), not test start
UnlockService rewrite:
- Persistent CAN senders that outlive the unlock sequence (StopSenders on pump change)
- Concurrent K-Line fast unlock: awaits session Connected, sends RAM timer shortcut
({02 88 02 03 A8 01 00}), verifies via CAN TestUnlock before skipping wait
- Fix Type 1 verification (Value == 0 means unlocked, was inverted)
K-Line fast unlock support:
- IKwpService.TryFastUnlockAsync / KwpService implementation
Additional features:
- ILocalizationService with ES/EN resource dictionaries and runtime switching
- Safety dialogs: VoltageWarning, OilPumpConfirm, RpmSafetyWarning
- SettingsDialog for app configuration
- BenchService enhancements, ConfigurationService improvements, PDF report updates
- All UI strings localized via DynamicResource
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
154 lines
6.1 KiB
C#
154 lines
6.1 KiB
C#
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using HC_APTBS.Models;
|
|
using HC_APTBS.Services;
|
|
|
|
namespace HC_APTBS.ViewModels
|
|
{
|
|
/// <summary>
|
|
/// A single result row shown in the results grid for one receive parameter.
|
|
/// </summary>
|
|
public sealed partial class ResultRowViewModel : ObservableObject
|
|
{
|
|
private readonly ILocalizationService _loc;
|
|
|
|
/// <summary>Initialises a new result row with a localization service.</summary>
|
|
public ResultRowViewModel(ILocalizationService loc) => _loc = loc;
|
|
|
|
[ObservableProperty] private string _phaseName = string.Empty;
|
|
[ObservableProperty] private string _parameterName = string.Empty;
|
|
[ObservableProperty] private double _target;
|
|
[ObservableProperty] private double _tolerance;
|
|
[ObservableProperty] private double _average;
|
|
[ObservableProperty] private bool _passed;
|
|
|
|
/// <summary>Localised "PASS" or "FAIL" label.</summary>
|
|
public string ResultLabel => Passed ? _loc.GetString("Common.Pass") : _loc.GetString("Common.Fail");
|
|
}
|
|
|
|
/// <summary>
|
|
/// ViewModel for the ResultDisplay user control.
|
|
///
|
|
/// <para>
|
|
/// Shows a flat table of all phase/parameter combinations with their
|
|
/// measured average, target, tolerance, and pass/fail result.
|
|
/// </para>
|
|
/// </summary>
|
|
public sealed partial class ResultDisplayViewModel : ObservableObject
|
|
{
|
|
private readonly ILocalizationService _loc;
|
|
|
|
/// <summary>Initialises a new result display with a localization service.</summary>
|
|
public ResultDisplayViewModel(ILocalizationService loc) => _loc = loc;
|
|
|
|
// ── Properties ────────────────────────────────────────────────────────────
|
|
|
|
/// <summary>Name of the test whose results are displayed.</summary>
|
|
[ObservableProperty] private string _testName = string.Empty;
|
|
|
|
/// <summary>Overall pass/fail for all displayed results.</summary>
|
|
[ObservableProperty] private bool _overallPassed;
|
|
|
|
/// <summary>All result rows.</summary>
|
|
public ObservableCollection<ResultRowViewModel> Results { get; } = new();
|
|
|
|
// ── Public API ────────────────────────────────────────────────────────────
|
|
|
|
/// <summary>
|
|
/// Populates the results table from a completed <see cref="TestDefinition"/>.
|
|
/// </summary>
|
|
public void LoadResults(TestDefinition test)
|
|
{
|
|
TestName = test.Name;
|
|
Results.Clear();
|
|
|
|
bool allPassed = true;
|
|
foreach (var phase in test.Phases)
|
|
{
|
|
if (!phase.Enabled || phase.Receives == null) continue;
|
|
foreach (var tp in phase.Receives)
|
|
{
|
|
if (tp.Result == null) continue;
|
|
allPassed = allPassed && tp.Result.Passed;
|
|
Results.Add(new ResultRowViewModel(_loc)
|
|
{
|
|
PhaseName = phase.Name,
|
|
ParameterName = tp.Name,
|
|
Target = tp.Value,
|
|
Tolerance = tp.Tolerance,
|
|
Average = tp.Result.Average,
|
|
Passed = tp.Result.Passed
|
|
});
|
|
}
|
|
}
|
|
OverallPassed = allPassed && Results.Count > 0;
|
|
}
|
|
|
|
/// <summary>Adds or updates a live measurement row during test execution.</summary>
|
|
public void UpdateLiveValue(string phaseName, string paramName, double currentValue,
|
|
double target, double tolerance)
|
|
{
|
|
foreach (var row in Results)
|
|
{
|
|
if (row.PhaseName == phaseName && row.ParameterName == paramName)
|
|
{
|
|
row.Average = currentValue;
|
|
return;
|
|
}
|
|
}
|
|
Results.Add(new ResultRowViewModel(_loc)
|
|
{
|
|
PhaseName = phaseName,
|
|
ParameterName = paramName,
|
|
Target = target,
|
|
Tolerance = tolerance,
|
|
Average = currentValue
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Populates the results table from all completed tests in the pump's test list.
|
|
/// Clears existing results first, then appends rows from every test that has results.
|
|
/// </summary>
|
|
/// <param name="tests">All test definitions for the current pump.</param>
|
|
public void LoadAllResults(IReadOnlyList<TestDefinition> tests)
|
|
{
|
|
Results.Clear();
|
|
bool allPassed = true;
|
|
|
|
foreach (var test in tests)
|
|
{
|
|
foreach (var phase in test.Phases)
|
|
{
|
|
if (!phase.Enabled || phase.Receives == null) continue;
|
|
foreach (var tp in phase.Receives)
|
|
{
|
|
if (tp.Result == null) continue;
|
|
allPassed = allPassed && tp.Result.Passed;
|
|
Results.Add(new ResultRowViewModel(_loc)
|
|
{
|
|
PhaseName = phase.Name,
|
|
ParameterName = tp.Name,
|
|
Target = tp.Value,
|
|
Tolerance = tp.Tolerance,
|
|
Average = tp.Result.Average,
|
|
Passed = tp.Result.Passed
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
TestName = tests.Count > 0 ? _loc.GetString("Result.AllTests") : string.Empty;
|
|
OverallPassed = allPassed && Results.Count > 0;
|
|
}
|
|
|
|
/// <summary>Clears all results.</summary>
|
|
public void Clear()
|
|
{
|
|
Results.Clear();
|
|
OverallPassed = false;
|
|
}
|
|
}
|
|
}
|