feat(S2-b): connect durable MQTT sync to capture workflow
This commit is contained in:
@@ -4,6 +4,7 @@ using CommunityToolkit.Mvvm.Input;
|
||||
using FieldLogger.Models;
|
||||
using FieldLogger.Services;
|
||||
using FieldLogger.Services.Data;
|
||||
using FieldLogger.Services.Sync;
|
||||
|
||||
namespace FieldLogger.ViewModels;
|
||||
|
||||
@@ -14,6 +15,7 @@ public sealed partial class HomeViewModel : ObservableObject
|
||||
private readonly PointLogger _pointLogger;
|
||||
private readonly AppDatabase _database;
|
||||
private readonly SettingsService _settings;
|
||||
private readonly IMqttSyncService _sync;
|
||||
|
||||
public DeviceConnectionManager Manager => _manager;
|
||||
|
||||
@@ -35,20 +37,27 @@ public sealed partial class HomeViewModel : ObservableObject
|
||||
[ObservableProperty]
|
||||
private string _fixAccuracy = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _syncStatus = "";
|
||||
|
||||
public ObservableCollection<LoggedPoint> RecentPoints { get; } = new();
|
||||
|
||||
public HomeViewModel(DeviceConnectionManager manager, MaglinkService gps,
|
||||
PointLogger pointLogger, AppDatabase database, SettingsService settings)
|
||||
PointLogger pointLogger, AppDatabase database, SettingsService settings, IMqttSyncService sync)
|
||||
{
|
||||
_manager = manager;
|
||||
_gps = gps;
|
||||
_pointLogger = pointLogger;
|
||||
_database = database;
|
||||
_settings = settings;
|
||||
_sync = sync;
|
||||
SyncStatus = sync.Status;
|
||||
|
||||
_gps.FixReceived += OnFixReceived;
|
||||
_pointLogger.PointSaved += OnPointSaved;
|
||||
_pointLogger.PacketIgnoredNoJob += OnPacketIgnoredNoJob;
|
||||
_sync.StatusChanged += OnSyncStatusChanged;
|
||||
_sync.PointRejected += OnPointRejected;
|
||||
}
|
||||
|
||||
/// <summary>Called from the page's OnAppearing.</summary>
|
||||
@@ -146,4 +155,14 @@ public sealed partial class HomeViewModel : ObservableObject
|
||||
"A point was logged on the receiver, but no job is active so it was not saved. Create or select a job first.",
|
||||
"OK");
|
||||
}
|
||||
|
||||
private void OnSyncStatusChanged(object? sender, string status) =>
|
||||
MainThread.BeginInvokeOnMainThread(() => SyncStatus = status);
|
||||
|
||||
private void OnPointRejected(object? sender, PointSyncFailureEventArgs e) =>
|
||||
MainThread.BeginInvokeOnMainThread(async () =>
|
||||
await Shell.Current.DisplayAlert(
|
||||
"Point Saved Locally — Sync Needs Attention",
|
||||
$"Point #{e.Point.Id} remains on this device and was not uploaded. Reason: {e.ReasonCode}.",
|
||||
"OK"));
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using FieldLogger.Models;
|
||||
using FieldLogger.Services;
|
||||
using FieldLogger.Services.Sync;
|
||||
|
||||
namespace FieldLogger.ViewModels;
|
||||
|
||||
@@ -9,23 +10,104 @@ public sealed partial class SettingsViewModel : ObservableObject
|
||||
{
|
||||
private readonly DeviceConnectionManager _manager;
|
||||
private readonly SettingsService _settings;
|
||||
private readonly IMqttSyncService _sync;
|
||||
|
||||
public DeviceConnectionManager Manager => _manager;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _mapsApiKey = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _mqttEnabled;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _mqttHost = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _mqttPort = "8884";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _mqttOrgId = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _mqttPassword = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _syncStatus = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isSavingSync;
|
||||
|
||||
public string MqttClientId => _settings.MqttClientId;
|
||||
|
||||
public string AppVersion => AppInfo.Current.VersionString;
|
||||
|
||||
public SettingsViewModel(DeviceConnectionManager manager, SettingsService settings)
|
||||
public SettingsViewModel(DeviceConnectionManager manager, SettingsService settings, IMqttSyncService sync)
|
||||
{
|
||||
_manager = manager;
|
||||
_settings = settings;
|
||||
_sync = sync;
|
||||
MapsApiKey = settings.GoogleMapsApiKey;
|
||||
MqttEnabled = settings.MqttEnabled;
|
||||
MqttHost = settings.MqttHost;
|
||||
MqttPort = settings.MqttPort.ToString();
|
||||
MqttOrgId = settings.MqttOrgId;
|
||||
SyncStatus = sync.Status;
|
||||
_sync.StatusChanged += OnSyncStatusChanged;
|
||||
}
|
||||
|
||||
partial void OnMapsApiKeyChanged(string value) => _settings.GoogleMapsApiKey = value.Trim();
|
||||
|
||||
[RelayCommand]
|
||||
private async Task SaveSyncAsync()
|
||||
{
|
||||
if (!int.TryParse(MqttPort, out var port) || port is < 1 or > 65535)
|
||||
{
|
||||
await Shell.Current.DisplayAlert("Invalid MQTT Port", "Enter a port between 1 and 65535.", "OK");
|
||||
return;
|
||||
}
|
||||
if (MqttEnabled && (string.IsNullOrWhiteSpace(MqttHost) || string.IsNullOrWhiteSpace(MqttOrgId)))
|
||||
{
|
||||
await Shell.Current.DisplayAlert("Incomplete Sync Settings", "Host and organization id are required.", "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
IsSavingSync = true;
|
||||
try
|
||||
{
|
||||
_settings.MqttHost = MqttHost;
|
||||
_settings.MqttPort = port;
|
||||
_settings.MqttOrgId = MqttOrgId;
|
||||
_settings.MqttEnabled = MqttEnabled;
|
||||
if (!string.IsNullOrWhiteSpace(MqttPassword))
|
||||
{
|
||||
await _settings.SetMqttPasswordAsync(MqttPassword);
|
||||
MqttPassword = "";
|
||||
}
|
||||
|
||||
if (MqttEnabled)
|
||||
{
|
||||
await _sync.ConnectAsync();
|
||||
await Shell.Current.DisplayAlert("Sync Connected", "The durable MQTT queue is connected.", "OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
await _sync.DisconnectAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Shell.Current.DisplayAlert("Sync Connection Failed", ex.Message, "OK");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsSavingSync = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSyncStatusChanged(object? sender, string status) =>
|
||||
MainThread.BeginInvokeOnMainThread(() => SyncStatus = status);
|
||||
|
||||
[RelayCommand]
|
||||
private Task ChangeLocatorAsync() => Shell.Current.GoToAsync($"devicescan?kind={DeviceKind.Locator}");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user