This commit is contained in:
2026-03-29 23:47:31 +02:00
commit 216d5d2280
75 changed files with 5702 additions and 0 deletions

View File

@@ -0,0 +1,158 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using LehrerApp.Data;
using LehrerApp.Sync;
using LehrerApp.Sync.Models;
namespace LehrerApp.Desktop.ViewModels;
/// <summary>
/// Steuert den Dialog zum Einrichten eines neuen Geräts.
///
/// Zwei Modi:
/// Sender → "Neues Gerät hinzufügen" erzeugt Snapshot und zeigt Code
/// Empfänger → "Mit bestehendem Account verbinden" Code eingeben, Restore
/// </summary>
public partial class DevicePairingViewModel : ObservableObject
{
private readonly SnapshotService _snapshotService;
// ── Gemeinsamer State ─────────────────────────────────────────────────────
[ObservableProperty] private PairingMode _mode = PairingMode.SelectMode;
[ObservableProperty] private bool _isBusy;
[ObservableProperty] private string _statusMessage = "";
[ObservableProperty] private int _progressPercent;
[ObservableProperty] private bool _isError;
[ObservableProperty] private bool _isComplete;
// ── Sender-State ─────────────────────────────────────────────────────────
[ObservableProperty] private string _generatedCode = "";
[ObservableProperty] private DateTime _codeExpiresAt;
[ObservableProperty] private string _codeExpiresText = "";
// ── Empfänger-State ───────────────────────────────────────────────────────
[ObservableProperty] private string _inputCode = "";
public DevicePairingViewModel(SnapshotService snapshotService)
{
_snapshotService = snapshotService;
_snapshotService.ProgressChanged += OnProgress;
}
// ── Navigation zwischen Modi ──────────────────────────────────────────────
[RelayCommand]
private void SelectSender() => Mode = PairingMode.Sender;
[RelayCommand]
private void SelectReceiver() => Mode = PairingMode.Receiver;
[RelayCommand]
private void Back()
{
Mode = PairingMode.SelectMode;
Reset();
}
// ── Sender: Snapshot erstellen ────────────────────────────────────────────
[RelayCommand(CanExecute = nameof(CanCreateSnapshot))]
private async Task CreateSnapshotAsync()
{
IsBusy = true;
IsError = false;
IsComplete = false;
try
{
var result = await _snapshotService.CreateAndUploadAsync();
GeneratedCode = result.Code;
CodeExpiresAt = result.ExpiresAt;
CodeExpiresText = $"Gültig bis {result.ExpiresAt:HH:mm} Uhr " +
$"({result.ExpiresAt:dd.MM.yyyy})";
Mode = PairingMode.SenderShowCode;
}
catch (Exception ex)
{
IsError = true;
StatusMessage = $"Fehler: {ex.Message}";
}
finally
{
IsBusy = false;
}
}
private bool CanCreateSnapshot() => !IsBusy;
// ── Empfänger: Snapshot wiederherstellen ──────────────────────────────────
[RelayCommand(CanExecute = nameof(CanRestore))]
private async Task RestoreAsync(string targetDbPath)
{
IsBusy = true;
IsError = false;
IsComplete = false;
try
{
// Schlüssel wird aus dem Code extrahiert und lokal gespeichert
// → App-Neustart lädt ihn automatisch
await _snapshotService.RestoreFromCodeAsync(
InputCode.Trim(), targetDbPath);
IsComplete = true;
StatusMessage = "Erfolgreich! Bitte die App neu starten.";
Mode = PairingMode.ReceiverDone;
}
catch (SnapshotNotFoundException ex)
{
IsError = true;
StatusMessage = ex.Message;
}
catch (Exception ex)
{
IsError = true;
StatusMessage = $"Fehler beim Wiederherstellen: {ex.Message}";
}
finally
{
IsBusy = false;
}
}
private bool CanRestore() =>
!IsBusy && InputCode.Trim().Length >= 5;
// ── Hilfsmethoden ─────────────────────────────────────────────────────────
private void OnProgress(SnapshotProgress progress)
{
StatusMessage = progress.Message;
ProgressPercent = progress.PercentComplete;
}
private void Reset()
{
StatusMessage = "";
ProgressPercent = 0;
IsError = false;
IsComplete = false;
GeneratedCode = "";
InputCode = "";
IsBusy = false;
}
}
public enum PairingMode
{
SelectMode, // Startbildschirm: Sender oder Empfänger wählen
Sender, // Sender bereit, Snapshot erstellen
SenderShowCode, // Code wird angezeigt
Receiver, // Code-Eingabe
ReceiverDone, // Erfolgreich wiederhergestellt
}