initial commit
This commit is contained in:
137
ViewModels/Dialogs/KlineErrorsViewModel.cs
Normal file
137
ViewModels/Dialogs/KlineErrorsViewModel.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
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;
|
||||
|
||||
// ── Constructor ───────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>Initialises the ViewModel and shows the initially known error text.</summary>
|
||||
public KlineErrorsViewModel(
|
||||
IKwpService kwpService,
|
||||
IConfigurationService configService,
|
||||
string initialErrors = "")
|
||||
{
|
||||
_kwp = kwpService;
|
||||
_config = configService;
|
||||
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 (0–100) 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(
|
||||
"K-Line device not found. Check that the FTDI adapter is connected.",
|
||||
"K-Line Error", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnProgress(int pct, string msg)
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
ProgressPercent = pct;
|
||||
ProgressMessage = msg;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
36
ViewModels/Dialogs/ProgressViewModel.cs
Normal file
36
ViewModels/Dialogs/ProgressViewModel.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace HC_APTBS.ViewModels.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// ViewModel for the WProgressDisplay dialog.
|
||||
///
|
||||
/// <para>
|
||||
/// Shows a progress bar (0–100) and a verbose text line during long-running
|
||||
/// K-Line operations. The dialog is closed by the parent when the operation
|
||||
/// completes; this ViewModel simply exposes observable properties for binding.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed partial class ProgressViewModel : ObservableObject
|
||||
{
|
||||
/// <summary>Title text shown in the dialog's title bar.</summary>
|
||||
[ObservableProperty] private string _title = string.Empty;
|
||||
|
||||
/// <summary>Current progress value (0–100).</summary>
|
||||
[ObservableProperty] private int _progressPercent;
|
||||
|
||||
/// <summary>Verbose status message describing the current step.</summary>
|
||||
[ObservableProperty] private string _verboseMessage = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Updates both <see cref="ProgressPercent"/> and <see cref="VerboseMessage"/>
|
||||
/// in a single call. Thread-safe: may be called from any thread because
|
||||
/// the consumer is expected to marshal to the UI thread before calling.
|
||||
/// </summary>
|
||||
public void Update(int percent, string message)
|
||||
{
|
||||
ProgressPercent = percent;
|
||||
VerboseMessage = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
158
ViewModels/Dialogs/ReportViewModel.cs
Normal file
158
ViewModels/Dialogs/ReportViewModel.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using HC_APTBS.Services;
|
||||
|
||||
namespace HC_APTBS.ViewModels.Dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// ViewModel for the WReport dialog.
|
||||
///
|
||||
/// <para>
|
||||
/// Lets the operator fill in client and company information before generating
|
||||
/// the PDF report. The client list is backed by the
|
||||
/// <see cref="IConfigurationService"/> and persisted when the dialog is accepted.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed partial class ReportViewModel : ObservableObject
|
||||
{
|
||||
// ── Services ──────────────────────────────────────────────────────────────
|
||||
|
||||
private readonly IConfigurationService _config;
|
||||
|
||||
// ── Constructor ───────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>Initialises and populates the dialog from configuration.</summary>
|
||||
public ReportViewModel(IConfigurationService configService)
|
||||
{
|
||||
_config = configService;
|
||||
|
||||
CompanyName = _config.Settings.CompanyName;
|
||||
CompanyInfo = _config.Settings.CompanyInfo;
|
||||
|
||||
foreach (var name in _config.Clients.Keys)
|
||||
ClientNames.Add(name);
|
||||
}
|
||||
|
||||
// ── Company ───────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>Company name shown in the report header.</summary>
|
||||
[ObservableProperty] private string _companyName = string.Empty;
|
||||
|
||||
/// <summary>Company address / contact info shown in the report header.</summary>
|
||||
[ObservableProperty] private string _companyInfo = string.Empty;
|
||||
|
||||
// ── Client ────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>List of known client names for the autocomplete combo box.</summary>
|
||||
public ObservableCollection<string> ClientNames { get; } = new();
|
||||
|
||||
/// <summary>Currently selected or typed client name.</summary>
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(SaveClientCommand))]
|
||||
[NotifyCanExecuteChangedFor(nameof(DeleteClientCommand))]
|
||||
private string _selectedClientName = string.Empty;
|
||||
|
||||
/// <summary>Free-text notes for the selected client.</summary>
|
||||
[ObservableProperty] private string _clientInfo = string.Empty;
|
||||
|
||||
/// <summary>Operator name.</summary>
|
||||
[ObservableProperty] private string _operatorName = string.Empty;
|
||||
|
||||
/// <summary>Free-text observations appended to the report.</summary>
|
||||
[ObservableProperty] private string _observations = string.Empty;
|
||||
|
||||
// ── Dialog result ─────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>True after the user clicks Accept; false if they cancel.</summary>
|
||||
public bool Accepted { get; private set; }
|
||||
|
||||
// ── Commands ──────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>Saves the current client entry, closes the dialog with Accepted=true.</summary>
|
||||
[RelayCommand]
|
||||
private void Accept()
|
||||
{
|
||||
SaveCurrentClient();
|
||||
|
||||
_config.Settings.CompanyName = CompanyName;
|
||||
_config.Settings.CompanyInfo = CompanyInfo;
|
||||
_config.SaveClients();
|
||||
_config.SaveSettings();
|
||||
|
||||
Accepted = true;
|
||||
RequestClose?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>Closes the dialog without saving.</summary>
|
||||
[RelayCommand]
|
||||
private void Cancel()
|
||||
{
|
||||
Accepted = false;
|
||||
RequestClose?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>Persists the current client entry and refreshes the client list.</summary>
|
||||
[RelayCommand(CanExecute = nameof(HasClientName))]
|
||||
private void SaveClient()
|
||||
{
|
||||
SaveCurrentClient();
|
||||
RefreshClientList();
|
||||
}
|
||||
|
||||
/// <summary>Deletes the currently selected client from the list.</summary>
|
||||
[RelayCommand(CanExecute = nameof(HasClientName))]
|
||||
private void DeleteClient()
|
||||
{
|
||||
string name = SelectedClientName.Trim();
|
||||
if (string.IsNullOrEmpty(name)) return;
|
||||
|
||||
if (_config.Clients.ContainsKey(name))
|
||||
_config.Clients.Remove(name);
|
||||
|
||||
SelectedClientName = string.Empty;
|
||||
ClientInfo = string.Empty;
|
||||
RefreshClientList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the user picks a client name from the combo box.
|
||||
/// Loads the associated info text.
|
||||
/// </summary>
|
||||
public void SelectClient(string name)
|
||||
{
|
||||
SelectedClientName = name ?? string.Empty;
|
||||
if (!string.IsNullOrEmpty(name) && _config.Clients.TryGetValue(name, out var info))
|
||||
ClientInfo = info;
|
||||
}
|
||||
|
||||
// ── Events ────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>Raised when the dialog should close itself.</summary>
|
||||
public event System.Action? RequestClose;
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
private bool HasClientName() => !string.IsNullOrWhiteSpace(SelectedClientName);
|
||||
|
||||
private void SaveCurrentClient()
|
||||
{
|
||||
string name = SelectedClientName.Trim();
|
||||
if (string.IsNullOrEmpty(name)) return;
|
||||
|
||||
if (_config.Clients.ContainsKey(name))
|
||||
_config.Clients[name] = ClientInfo;
|
||||
else
|
||||
_config.Clients.Add(name, ClientInfo);
|
||||
}
|
||||
|
||||
private void RefreshClientList()
|
||||
{
|
||||
ClientNames.Clear();
|
||||
foreach (var name in _config.Clients.Keys)
|
||||
ClientNames.Add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user