feat: sync guard - Blockieren alter Clients beim sync

This commit is contained in:
2026-08-20 23:54:04 +02:00
parent 7b883555bf
commit 59bd8abb45
19 changed files with 369 additions and 26 deletions
@@ -512,6 +512,9 @@ public partial class SettingsViewModel : ObservableObject
{
SyncConnectionTestResult.Ok => "Verbindung erfolgreich.",
SyncConnectionTestResult.Unauthorized => "Server erreichbar, aber nicht angemeldet oder Anmeldung abgelaufen.",
SyncConnectionTestResult.IncompatibleVersion =>
"Diese App-Version ist veraltet oder nicht mehr mit dem Sync-Server kompatibel. " +
"Bitte aktualisiere die LehrerApp.",
_ => "Server nicht erreichbar. Bitte Adresse und Internetverbindung prüfen.",
};
}
@@ -1,5 +1,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using LehrerApp.Desktop.Services;
using LehrerApp.Sync;
using LehrerApp.Sync.Models;
@@ -8,11 +9,19 @@ 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.
@@ -21,10 +30,12 @@ public partial class SyncStatusViewModel : ObservableObject
/// schreibt.</summary>
public event Action? DataChanged;
public SyncStatusViewModel(SyncEngine? engine)
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;
@@ -41,6 +52,8 @@ public partial class SyncStatusViewModel : ObservableObject
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
{
@@ -48,9 +61,16 @@ public partial class SyncStatusViewModel : ObservableObject
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))]