using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Jugenddienst_Stunden.Interfaces; namespace Jugenddienst_Stunden.ViewModels; /// /// ViewModel für die Loginseite (MVVM) /// 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? AlertEvent; public event EventHandler? InfoEvent; /// /// Name der Anwendung /// public string AppTitle => AppInfo.Name; /// /// Programmversion /// 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 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 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(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; } }