Files
HC_APTBS/ViewModels/Dialogs/KlineErrorsViewModel.cs
LucianoDev 37d099cdbd feat: add Ford VP44 unlock progress dialog, K-Line fast unlock, localization, safety dialogs, and settings
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>
2026-04-16 13:22:48 +02:00

141 lines
5.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Threading.Tasks;
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HC_APTBS.Services;
namespace HC_APTBS.ViewModels.Dialogs
{
/// <summary>
/// ViewModel for the WKlineErrors dialog.
///
/// <para>
/// Displays the raw DTC (Diagnostic Trouble Code) text returned by the VP44 ECU
/// over K-Line and provides commands to read or clear fault codes.
/// </para>
/// </summary>
public sealed partial class KlineErrorsViewModel : ObservableObject
{
// ── Services ──────────────────────────────────────────────────────────────
private readonly IKwpService _kwp;
private readonly IConfigurationService _config;
private readonly ILocalizationService _loc;
// ── Constructor ───────────────────────────────────────────────────────────
/// <summary>Initialises the ViewModel and shows the initially known error text.</summary>
public KlineErrorsViewModel(
IKwpService kwpService,
IConfigurationService configService,
ILocalizationService loc,
string initialErrors = "")
{
_kwp = kwpService;
_config = configService;
_loc = loc;
ErrorText = initialErrors;
_kwp.ProgressChanged += OnProgress;
}
// ── Properties ────────────────────────────────────────────────────────────
/// <summary>Raw DTC string returned by the ECU, shown in the text box.</summary>
[ObservableProperty] private string _errorText = string.Empty;
/// <summary>True while a K-Line read or clear operation is in progress.</summary>
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(ReadErrorsCommand))]
[NotifyCanExecuteChangedFor(nameof(ClearErrorsCommand))]
private bool _isBusy;
/// <summary>Progress percentage (0100) for the current K-Line operation.</summary>
[ObservableProperty] private int _progressPercent;
/// <summary>Verbose status message for the current K-Line operation.</summary>
[ObservableProperty] private string _progressMessage = string.Empty;
// ── Commands ──────────────────────────────────────────────────────────────
/// <summary>Reads the current fault codes from the ECU.</summary>
[RelayCommand(CanExecute = nameof(CanOperate))]
private async Task ReadErrorsAsync()
{
string? port = GetPort();
if (port == null) return;
IsBusy = true;
try
{
ErrorText = await _kwp.ReadFaultCodesAsync(port);
}
finally
{
IsBusy = false;
ProgressPercent = 0;
ProgressMessage = string.Empty;
}
}
/// <summary>Clears fault codes on the ECU, then reads back the updated list.</summary>
[RelayCommand(CanExecute = nameof(CanOperate))]
private async Task ClearErrorsAsync()
{
string? port = GetPort();
if (port == null) return;
IsBusy = true;
try
{
ErrorText = await _kwp.ClearFaultCodesAsync(port);
// Re-read after clearing to confirm
ErrorText = await _kwp.ReadFaultCodesAsync(port);
}
finally
{
IsBusy = false;
ProgressPercent = 0;
ProgressMessage = string.Empty;
}
}
/// <summary>Closes the dialog.</summary>
[RelayCommand]
private void Close()
{
_kwp.ProgressChanged -= OnProgress;
RequestClose?.Invoke();
}
// ── Events ────────────────────────────────────────────────────────────────
/// <summary>Raised when the dialog should close itself.</summary>
public event System.Action? RequestClose;
// ── Helpers ───────────────────────────────────────────────────────────────
private bool CanOperate() => !IsBusy;
private string? GetPort()
{
string? port = _kwp.DetectKLinePort();
if (!string.IsNullOrEmpty(port)) return port;
MessageBox.Show(
_loc.GetString("Error.KLineNotFound"),
_loc.GetString("Error.KLineTitle"), MessageBoxButton.OK, MessageBoxImage.Warning);
return null;
}
private void OnProgress(int pct, string msg)
{
Application.Current.Dispatcher.Invoke(() =>
{
ProgressPercent = pct;
ProgressMessage = msg;
});
}
}
}