Files
Jugenddienst-Stunden/Jugenddienst Stunden/ViewModels/LoginViewModel.cs

161 lines
4.7 KiB
C#

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Jugenddienst_Stunden.Interfaces;
using Jugenddienst_Stunden.Models;
namespace Jugenddienst_Stunden.ViewModels;
/// <summary>
/// ViewModel für die Loginseite (MVVM)
/// </summary>
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);
public event EventHandler<string>? AlertEvent;
//public event EventHandler<string>? InfoEvent;
public event EventHandler<ConfirmationEventArgs>? InfoEvent;
/// <summary>
/// Name der Anwendung
/// </summary>
public string AppTitle => AppInfo.Name;
/// <summary>
/// Programmversion
/// </summary>
public string Version => AppInfo.VersionString;
[ObservableProperty]
private string message = "Scanne den QR-Code von deinem Benutzerprofil auf der Stundenseite.";
[ObservableProperty]
private string? server;
[ObservableProperty]
private string? serverLabel;
[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 = apiUrl.Replace("/appapi", "").Replace("https://", "").Replace("http://", "");
ServerLabel = "Server: " + Server;
}
// 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).Trim());
Title = $"{user.Name} {user.Surname}";
// Info zeigen und auf Bestätigung warten
var args = new ConfirmationEventArgs("Information:", "Login erfolgreich");
InfoEvent?.Invoke(this, args);
bool confirmed = await args.Task;
if (confirmed) {
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}";
// Info zeigen und auf Bestätigung warten
var infoArgs = new ConfirmationEventArgs("Information:", "Login erfolgreich");
InfoEvent?.Invoke(this, infoArgs);
bool confirmed = await infoArgs.Task;
if (confirmed) {
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;
}
}