Refactor: Remove GlobalVar and replace with IAppSettings; restructure affected infrastructure, services, and view models for dependency injection.

This commit is contained in:
2025-12-26 11:43:20 +01:00
parent 1ee0fc61f6
commit 4d5b093ea0
15 changed files with 103 additions and 463 deletions

View File

@@ -10,7 +10,6 @@ namespace Jugenddienst_Stunden.ViewModels;
/// </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);
@@ -59,9 +58,8 @@ public partial class LoginViewModel : ObservableObject {
// 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) {
public LoginViewModel(IAuthService auth) {
_auth = auth;
_settings = settings;
// gespeicherte Präferenz für Logintyp laden
var lt = Preferences.Default.Get("logintype", "qr");
@@ -81,7 +79,7 @@ public partial class LoginViewModel : ObservableObject {
}
// DI-Konstruktor: AlertService anbinden und Alerts an VM-Event weiterreichen (analog StundeViewModel)
internal LoginViewModel(IAuthService auth, IAppSettings settings, IAlertService alertService) : this(auth, settings) {
internal LoginViewModel(IAuthService auth, IAlertService alertService) : this(auth) {
_alerts = alertService;
if (alertService is not null) {
alertService.AlertRaised += (s, msg) => AlertEvent?.Invoke(this, msg);
@@ -102,7 +100,7 @@ public partial class LoginViewModel : ObservableObject {
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");

View File

@@ -19,13 +19,13 @@ namespace Jugenddienst_Stunden.ViewModels;
/// </summary>
public partial class StundeViewModel : ObservableObject, IQueryAttributable {
private readonly IHoursService _hoursService;
private readonly IAppSettings _settings;
private readonly IAlertService _alertService;
public int Id { get; set; }
public string Title { get; set; } = "Eintrag bearbeiten";
public string SubTitle { get; set; } = DateTime.Today.ToString("dddd, d. MMMM yyyy");
//private HoursBase HoursBase = new HoursBase();
internal Settings Settings = new Settings();
public event EventHandler<string> AlertEvent;
public event EventHandler<string> InfoEvent;
@@ -77,36 +77,19 @@ public partial class StundeViewModel : ObservableObject, IQueryAttributable {
//public ICommand LoadDataCommand { get; private set; }
public StundeViewModel(IHoursService hoursService, IAlertService alertService) {
public StundeViewModel(IHoursService hoursService, IAlertService alertService, IAppSettings settings) {
_hoursService = hoursService;
_settings = settings;
_alertService = alertService;
SaveCommand = new AsyncRelayCommand(Save);
DeleteConfirmCommand = new Command(async () => await DeleteConfirm());
if (alertService is not null) {
alertService.AlertRaised += (s, msg) => AlertEvent?.Invoke(this, msg);
}
//LoadSettingsAsync();
_alertService.AlertRaised += (s, msg) => AlertEvent?.Invoke(this, msg);
}
private async void LoadSettingsAsync() {
try {
Settings = await _hoursService.GetSettingsAsync();
GlobalVar.Settings = Settings;
OptionsGemeinde = Settings.Gemeinden;
OptionsProjekt = Settings.Projekte;
OptionsFreistellung = Settings.Freistellungen;
GemeindeAktivSet = Settings.GemeindeAktivSet;
ProjektAktivSet = Settings.ProjektAktivSet;
} catch (Exception e) {
AlertEvent?.Invoke(this, e.Message);
}
}
private async void UpdateSettingsAsync(Settings settings) {
GlobalVar.Settings = settings;
private void UpdateSettings(Settings settings) {
_settings.Settings = settings;
OptionsGemeinde = settings.Gemeinden;
OptionsProjekt = settings.Projekte;
OptionsFreistellung = settings.Freistellungen;
@@ -126,7 +109,7 @@ public partial class StundeViewModel : ObservableObject, IQueryAttributable {
}
//Projekt ist ein Pflichtfeld
if (Settings.ProjektAktivSet) {
if (_settings.Settings.ProjektAktivSet) {
var projektId = DayTime.ProjektAktiv?.Id ?? 0;
if (projektId == 0) {
proceed = false;
@@ -135,7 +118,7 @@ public partial class StundeViewModel : ObservableObject, IQueryAttributable {
}
//Gemeinde ist ein Pflichtfeld
if (Settings.GemeindeAktivSet) {
if (_settings.Settings.GemeindeAktivSet) {
var gemeindeId = DayTime.GemeindeAktiv?.Id ?? 0;
if (gemeindeId == 0) {
proceed = false;
@@ -200,17 +183,18 @@ public partial class StundeViewModel : ObservableObject, IQueryAttributable {
//DateTime heute = DateTime.Now;
try {
//var entry = await _hoursService.GetEntryAsync(Convert.ToInt32(query["load"]));
var (entry, settings, daytimes) = await _hoursService.GetEntryWithSettingsAsync(Convert.ToInt32(query["load"]));
UpdateSettingsAsync(settings);
var (entry, settings, daytimes) =
await _hoursService.GetEntryWithSettingsAsync(Convert.ToInt32(query["load"]));
UpdateSettings(settings);
DayTime = entry;
DayTime.TimeSpanVon = entry.Begin.ToTimeSpan();
DayTime.TimeSpanBis = entry.End.ToTimeSpan();
DayTime.GemeindeAktiv = OptionsGemeinde.FirstOrDefault(Gemeinde => Gemeinde.Id == DayTime.Gemeinde) ??
new Gemeinde();
new Gemeinde();
DayTime.ProjektAktiv = OptionsProjekt.FirstOrDefault(Projekt => Projekt.Id == DayTime.Projekt) ??
new Projekt();
new Projekt();
DayTime.FreistellungAktiv =
OptionsFreistellung.FirstOrDefault(Freistellung => Freistellung.Id == DayTime.Free) ??
new Freistellung();
@@ -229,11 +213,6 @@ public partial class StundeViewModel : ObservableObject, IQueryAttributable {
OnPropertyChanged(nameof(DayTimes));
} catch (Exception e) {
AlertEvent?.Invoke(this, e.Message);
} finally {
//Evtl. noch die anderen Zeiten des gleichen Tages holen
//var day = await _hoursService.GetDayWithSettingsAsync(DayTime.Day);
//DayTimes = day.dayTimes;
//OnPropertyChanged(nameof(DayTimes));
}
//OnPropertyChanged(nameof(DayTime));
@@ -246,7 +225,7 @@ public partial class StundeViewModel : ObservableObject, IQueryAttributable {
//Bei neuem Eintrag die vorhandenen des gleichen Tages anzeigen
try {
var (list, settings) = await _hoursService.GetDayWithSettingsAsync(_date);
UpdateSettingsAsync(settings);
UpdateSettings(settings);
DayTimes = list;
OnPropertyChanged(nameof(DayTimes));
} catch (Exception) {
@@ -257,7 +236,7 @@ public partial class StundeViewModel : ObservableObject, IQueryAttributable {
} finally {
DayTime = new DayTime();
DayTime.Day = _date;
DayTime.EmployeeId = GlobalVar.EmployeeId;
DayTime.EmployeeId = _settings.EmployeeId;
DayTime.GemeindeAktiv = new Gemeinde();
DayTime.ProjektAktiv = new Projekt();
DayTime.FreistellungAktiv = new Freistellung();

View File

@@ -15,6 +15,7 @@ namespace Jugenddienst_Stunden.ViewModels;
/// </summary>
public partial class StundenViewModel : ObservableObject, IQueryAttributable, INotifyPropertyChanged {
private readonly IHoursService _hoursService;
private readonly IAppSettings _settings;
public ICommand NewEntryCommand { get; }
public ICommand SelectEntryCommand { get; }
@@ -50,7 +51,13 @@ public partial class StundenViewModel : ObservableObject, IQueryAttributable, IN
/// </summary>
[ObservableProperty] private List<DayTime> dayTimes = new List<DayTime>();
public string Title { get; set; } = GlobalVar.Name + " " + GlobalVar.Surname;
/// <summary>
/// Der Titel der Stundenübersicht ist der aktuelle Benutzername
/// </summary>
public string Title {
get => _settings.Name + " " + _settings.Surname;
set;
}
[ObservableProperty] private Hours hours;
@@ -82,14 +89,10 @@ public partial class StundenViewModel : ObservableObject, IQueryAttributable, IN
LoadOverview = "Lade Summen für " + dateToday.ToString("MMMM yy");
// Task.Run(() => LoadDay(value));
// NICHT Task.Run: LoadDay aktualisiert UI-gebundene Properties
MainThread.BeginInvokeOnMainThread(async () =>
{
try
{
MainThread.BeginInvokeOnMainThread(async () => {
try {
await LoadDay(dateToday);
}
catch (Exception ex)
{
} catch (Exception ex) {
AlertEvent?.Invoke(this, ex.Message);
}
});
@@ -162,8 +165,9 @@ public partial class StundenViewModel : ObservableObject, IQueryAttributable, IN
/// <summary>
/// CTOR (DI)
/// </summary>
public StundenViewModel(IHoursService hoursService) {
public StundenViewModel(IHoursService hoursService, IAppSettings appSettings) {
_hoursService = hoursService;
_settings = appSettings;
Hours = new Hours();
LoadOverview = "Lade Summen für " + DateToday.ToString("MMMM");
@@ -177,19 +181,15 @@ public partial class StundenViewModel : ObservableObject, IQueryAttributable, IN
// Task task = LoadDay(DateTime.Today);
// Beim Startup NICHT direkt im CTOR laden (kann Startup/Navigation blockieren)
// Stattdessen via Dispatcher "nach" dem Aufbau starten:
MainThread.BeginInvokeOnMainThread(async () =>
{
try
{
MainThread.BeginInvokeOnMainThread(async () => {
try {
await LoadDay(DateTime.Today);
}
catch (Exception ex)
{
} catch (Exception ex) {
AlertEvent?.Invoke(this, ex.Message);
}
});
}
/// <summary>
@@ -244,16 +244,14 @@ public partial class StundenViewModel : ObservableObject, IQueryAttributable, IN
/// </summary>
public async Task LoadDay(DateTime date) {
// kleine Initialwerte sind ok, aber UI-Thread sicher setzen:
await MainThread.InvokeOnMainThreadAsync(() =>
{
await MainThread.InvokeOnMainThreadAsync(() => {
DayTotal = new TimeOnly(0);
Sollstunden = new TimeOnly(0);
});
try {
var (dayTimes, settings) = await _hoursService.GetDayWithSettingsAsync(date);
await MainThread.InvokeOnMainThreadAsync(() =>
{
await MainThread.InvokeOnMainThreadAsync(() => {
DayTimes = dayTimes;
Settings = settings;
GemeindeAktivSet = Settings.GemeindeAktivSet;
@@ -275,8 +273,7 @@ public partial class StundenViewModel : ObservableObject, IQueryAttributable, IN
}
_soll = Settings.Nominal.Where(w => w.Timetable == dt.TimeTable && w.Wochentag == dt.Wday).ToList();
if (_soll.Count > 0)
{
if (_soll.Count > 0) {
var soll = TimeOnly.FromTimeSpan(TimeSpan.FromHours(_soll[0].Zeit));
await MainThread.InvokeOnMainThreadAsync(() => Sollstunden = soll);
}
@@ -288,17 +285,15 @@ public partial class StundenViewModel : ObservableObject, IQueryAttributable, IN
//Nach der Tagessumme die anderen Tage anhängen
if (DayTimes != null) {
var more = await _hoursService.GetDayRangeAsync(date.AddDays(1), date.AddDays(3));
if (more != null && more.Count > 0)
{
if (more != null && more.Count > 0) {
await MainThread.InvokeOnMainThreadAsync(() =>
DayTimes = DayTimes.Concat(more).ToList()
);
}
}
} catch (Exception e) {
await MainThread.InvokeOnMainThreadAsync(() =>
{
await MainThread.InvokeOnMainThreadAsync(() => {
DayTimes = new List<DayTime>();
//TODO: hier könnte auch ein Fehler kommen, dann wäre InfoEvent falsch.
@@ -310,12 +305,11 @@ public partial class StundenViewModel : ObservableObject, IQueryAttributable, IN
InfoEvent?.Invoke(this, e.Message);
}
});
} finally {
await MainThread.InvokeOnMainThreadAsync(() =>
{
await MainThread.InvokeOnMainThreadAsync(() => {
OnPropertyChanged(nameof(DayTotal));
OnPropertyChanged(nameof(Sollstunden));
OnPropertyChanged(nameof(DateToday));