Refactor LoginPage to MVVM
This commit is contained in:
@@ -1,33 +1,145 @@
|
||||
namespace Jugenddienst_Stunden.ViewModels;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Jugenddienst_Stunden.Interfaces;
|
||||
|
||||
namespace Jugenddienst_Stunden.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Die Loginseite
|
||||
/// ViewModel für die Loginseite (MVVM)
|
||||
/// </summary>
|
||||
public class LoginViewModel {
|
||||
/// <summary>
|
||||
/// Name der Anwendung
|
||||
/// </summary>
|
||||
public string AppTitle => AppInfo.Name;
|
||||
public partial class LoginViewModel : ObservableObject {
|
||||
private readonly IAuthService _auth;
|
||||
private readonly IAppSettings _settings;
|
||||
private readonly IAlertService? _alerts;
|
||||
private DateTime _lastDetectionTime = DateTime.MinValue;
|
||||
private readonly TimeSpan _detectionInterval = TimeSpan.FromSeconds(5);
|
||||
|
||||
/// <summary>
|
||||
/// Programmversion
|
||||
/// </summary>
|
||||
public string Version => AppInfo.VersionString;
|
||||
public event EventHandler<string>? AlertEvent;
|
||||
public event EventHandler<string>? InfoEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Kurze Mitteilung für den Anwender
|
||||
/// </summary>
|
||||
public string Message { get; set; } = "Scanne den QR-Code von deinem Benutzerprofil auf der Stundenseite.";
|
||||
/// <summary>
|
||||
/// Name der Anwendung
|
||||
/// </summary>
|
||||
public string AppTitle => AppInfo.Name;
|
||||
|
||||
/// <summary>
|
||||
/// Genutzer Server für die API
|
||||
/// </summary>
|
||||
public string Server { get; set; } = "Server: " + Preferences.Default.Get("apiUrl", "").Replace("/appapi", "")
|
||||
.Replace("https://", "").Replace("http://", "");
|
||||
/// <summary>
|
||||
/// Programmversion
|
||||
/// </summary>
|
||||
public string Version => AppInfo.VersionString;
|
||||
|
||||
/// <summary>
|
||||
/// Titel der Seite - im Moment der aktuelle Anwender
|
||||
/// </summary>
|
||||
public string Title { get; set; } = Preferences.Default.Get("name", "Nicht") + " " +
|
||||
Preferences.Default.Get("surname", "eingeloggt");
|
||||
[ObservableProperty]
|
||||
private string message = "Scanne den QR-Code von deinem Benutzerprofil auf der Stundenseite.";
|
||||
|
||||
[ObservableProperty]
|
||||
private string? server;
|
||||
|
||||
[ObservableProperty]
|
||||
private string title = Preferences.Default.Get("name", "Nicht") + " " + Preferences.Default.Get("surname", "eingeloggt");
|
||||
|
||||
[ObservableProperty]
|
||||
private string? username;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? password;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isManualMode;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isBusy;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isDetecting;
|
||||
|
||||
// Explizite Command-Property für den QR-Scanner-Event, damit das Binding in XAML zuverlässig greift
|
||||
public IAsyncRelayCommand<object?> QrDetectedCommand { get; }
|
||||
|
||||
public LoginViewModel(IAuthService auth, IAppSettings settings) {
|
||||
_auth = auth;
|
||||
_settings = settings;
|
||||
|
||||
// gespeicherte Präferenz für Logintyp laden
|
||||
var lt = Preferences.Default.Get("logintype", "qr");
|
||||
isManualMode = string.Equals(lt, "manual", StringComparison.OrdinalIgnoreCase);
|
||||
// Scanner standardmäßig nur im QR-Modus aktivieren
|
||||
IsDetecting = !isManualMode;
|
||||
|
||||
// Serveranzeige vorbereiten
|
||||
var apiUrl = Preferences.Default.Get("apiUrl", string.Empty);
|
||||
if (!string.IsNullOrWhiteSpace(apiUrl)) {
|
||||
Server = "Server: " + apiUrl.Replace("/appapi", "").Replace("https://", "").Replace("http://", "");
|
||||
}
|
||||
|
||||
// Command initialisieren
|
||||
QrDetectedCommand = new AsyncRelayCommand<object?>(QrDetectedAsync);
|
||||
}
|
||||
|
||||
// DI-Konstruktor: AlertService anbinden und Alerts an VM-Event weiterreichen (analog StundeViewModel)
|
||||
internal LoginViewModel(IAuthService auth, IAppSettings settings, IAlertService alertService) : this(auth, settings) {
|
||||
_alerts = alertService;
|
||||
if (alertService is not null) {
|
||||
alertService.AlertRaised += (s, msg) => AlertEvent?.Invoke(this, msg);
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnIsManualModeChanged(bool value) {
|
||||
Preferences.Default.Set("logintype", value ? "manual" : "qr");
|
||||
// Scanner nur aktiv, wenn QR-Modus aktiv ist
|
||||
IsDetecting = !value;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task LoginAsync() {
|
||||
if (IsBusy) return;
|
||||
try {
|
||||
IsBusy = true;
|
||||
var user = await _auth.LoginWithCredentials(Username?.Trim() ?? string.Empty,
|
||||
Password ?? string.Empty,
|
||||
(Server ?? string.Empty).Replace("Server:", string.Empty).Trim());
|
||||
|
||||
Title = $"{user.Name} {user.Surname}";
|
||||
InfoEvent?.Invoke(this, "Login erfolgreich");
|
||||
|
||||
await Shell.Current.GoToAsync("//StundenPage");
|
||||
} catch (Exception ex) {
|
||||
if (_alerts is not null) {
|
||||
_alerts.Raise(ex.Message);
|
||||
} else {
|
||||
AlertEvent?.Invoke(this, ex.Message);
|
||||
}
|
||||
} finally {
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task QrDetectedAsync(object? args) {
|
||||
var now = DateTime.Now;
|
||||
if ((now - _lastDetectionTime) <= _detectionInterval) return;
|
||||
_lastDetectionTime = now;
|
||||
|
||||
try {
|
||||
var token = ExtractFirstBarcodeValue(args);
|
||||
if (string.IsNullOrWhiteSpace(token)) return;
|
||||
|
||||
var user = await _auth.LoginWithToken(token);
|
||||
Title = $"{user.Name} {user.Surname}";
|
||||
|
||||
await Shell.Current.GoToAsync("//StundenPage");
|
||||
} catch (Exception ex) {
|
||||
if (_alerts is not null) {
|
||||
_alerts.Raise(ex.Message);
|
||||
} else {
|
||||
AlertEvent?.Invoke(this, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string? ExtractFirstBarcodeValue(object? args) {
|
||||
try {
|
||||
if (args is ZXing.Net.Maui.BarcodeDetectionEventArgs e && e.Results is not null) {
|
||||
return e.Results.FirstOrDefault()?.Value;
|
||||
}
|
||||
} catch { }
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user