80 lines
3.5 KiB
C#
80 lines
3.5 KiB
C#
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using LehrerApp.Desktop.Services;
|
|
using LehrerApp.Sync;
|
|
using LehrerApp.Sync.Models;
|
|
|
|
namespace LehrerApp.Desktop.ViewModels;
|
|
|
|
public partial class SyncStatusViewModel : ObservableObject
|
|
{
|
|
private readonly SyncEngine? _engine;
|
|
private readonly NotificationService? _notifications;
|
|
private bool _incompatibleNotificationShown;
|
|
|
|
public const string IncompatibleVersionMessage =
|
|
"Diese App-Version ist veraltet oder nicht mit dem Sync-Server kompatibel. " +
|
|
"Bitte aktualisiere die LehrerApp. Die Synchronisierung wurde zum Schutz deiner Daten angehalten.";
|
|
|
|
[ObservableProperty] private string _statusText = "Kein Server konfiguriert";
|
|
[ObservableProperty] private string _lastSyncText = "";
|
|
[ObservableProperty] private bool _isSyncing;
|
|
[ObservableProperty] private bool _isServerConfigured;
|
|
[ObservableProperty] private bool _isIncompatibleVersion;
|
|
[ObservableProperty] private bool _canAttemptSync;
|
|
[ObservableProperty] private int _pendingCount;
|
|
|
|
/// <summary>Feuert, wenn ein Sync tatsächlich Daten angewendet hat (siehe SyncEngine.
|
|
/// DataChanged, TODO 10.1.11) - MainWindowViewModel nutzt das, um die gerade sichtbare Seite
|
|
/// neu zu laden, da EventApplier absichtlich an jedem ViewModel vorbei direkt auf die LiteDB
|
|
/// schreibt.</summary>
|
|
public event Action? DataChanged;
|
|
|
|
public SyncStatusViewModel(SyncEngine? engine, NotificationService? notifications = null)
|
|
{
|
|
_engine = engine;
|
|
_notifications = notifications;
|
|
IsServerConfigured = engine is not null;
|
|
CanAttemptSync = IsServerConfigured;
|
|
if (_engine is not null)
|
|
{
|
|
_engine.StatusChanged += OnStatus;
|
|
_engine.DataChanged += () => DataChanged?.Invoke();
|
|
// SyncEngine feuert sein erstes StatusChanged bereits im eigenen Konstruktor
|
|
// (UpdateStatus) - der läuft aber schon, während wir hier noch in GetService<SyncEngine>()
|
|
// stecken, also VOR dem obigen Abonnieren. Ohne diesen Nachhol-Aufruf bliebe StatusText
|
|
// nach jedem Neustart beim Default "Kein Server konfiguriert", bis der nächste
|
|
// Auto-Sync oder Klick auf "Jetzt synchronisieren" den Text erstmals aktualisiert.
|
|
OnStatus(_engine.Status);
|
|
}
|
|
}
|
|
|
|
private void OnStatus(SyncStatus s)
|
|
{
|
|
IsSyncing = s.State == SyncState.Syncing;
|
|
IsIncompatibleVersion = s.State == SyncState.IncompatibleVersion;
|
|
CanAttemptSync = IsServerConfigured && !IsIncompatibleVersion;
|
|
PendingCount = s.PendingEvents;
|
|
StatusText = s.State switch
|
|
{
|
|
SyncState.Idle => PendingCount > 0 ? $"{PendingCount} ausstehend" : "Synchronisiert",
|
|
SyncState.Syncing => "Synchronisiere…",
|
|
SyncState.Offline => "Offline",
|
|
SyncState.Error => $"Fehler: {s.ErrorMessage}",
|
|
SyncState.IncompatibleVersion => "Update erforderlich",
|
|
_ => "",
|
|
};
|
|
LastSyncText = s.LastSyncAt.HasValue ? $"Zuletzt: {s.LastSyncAt:HH:mm}" : "Noch nie";
|
|
|
|
if (IsIncompatibleVersion && !_incompatibleNotificationShown)
|
|
{
|
|
_incompatibleNotificationShown = true;
|
|
_notifications?.ShowError(IncompatibleVersionMessage);
|
|
}
|
|
}
|
|
|
|
[RelayCommand(CanExecute = nameof(CanSync))]
|
|
private async Task SyncNow() { if (_engine is not null) await _engine.SyncNowAsync(); }
|
|
private bool CanSync() => _engine is not null && !IsSyncing;
|
|
}
|