Zeiterfassung + Änderungen

This commit is contained in:
ViperioN1339 2025-04-24 10:51:14 +02:00
parent dbd708aab7
commit 8abc9fc2f4
10 changed files with 226 additions and 6 deletions

View File

@ -0,0 +1,29 @@
// Datei: Controller/LoginController.cs
using ChronoFlow.Model;
using System.Collections.Generic;
using System.Linq;
namespace ChronoFlow.Controller;
///<summary>
/// Verwaltet die Authentifizierung von Benutzern.
/// </summary>
public class LoginController
{
//Beispielhafte Benutzerliste (später DB)
private List<User> _users = new()
{
new User { Username = "admin", Password = "admin123", Role = "Admin" },
new User { Username = "max", Password = "max123", Role = "Mitarbeiter" }
};
/// <summary>
/// Prüft, ob ein Benutzer mit den eingegebenen Daten existiert.
/// </summary>
public User? Authenticate(string username, string password)
{
return _users.FirstOrDefault(u => u.Username == username && u.Password == password);
}
}

14
ChronoFlow.Model/User.cs Normal file
View File

@ -0,0 +1,14 @@
namespace ChronoFlow.Model
{
///<summary>
/// Repräsentiert einen Benutzer mit Benutzernamen, Passwort und Rolle.
/// </summary>
public class User
{
public string Username { get; set; }
public string Password { get; set; } //vorerst im Klartext, wird später geändert
public string Role { get; set; } //"Admin" oder "Mitarbeiter"
}
}

View File

@ -1,6 +1,6 @@
<Application xmlns="https://github.com/avaloniaui" <Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ChronoFlow.View.App" x:Class="ChronoFlow.App"
RequestedThemeVariant="Default"> RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. --> <!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->

View File

@ -1,8 +1,9 @@
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using ChronoFlow.View;
namespace ChronoFlow.View; namespace ChronoFlow;
public partial class App : Application public partial class App : Application
{ {
@ -15,7 +16,8 @@ public partial class App : Application
{ {
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
desktop.MainWindow = new MainWindow(); // Starte das Programm mit dem Login-Fenster
desktop.MainWindow = new LoginWindow();
} }
base.OnFrameworkInitializationCompleted(); base.OnFrameworkInitializationCompleted();

View File

@ -24,4 +24,14 @@
<ProjectReference Include="..\ChronoFlow.Controller\ChronoFlow.Controller.csproj" /> <ProjectReference Include="..\ChronoFlow.Controller\ChronoFlow.Controller.csproj" />
<ProjectReference Include="..\ChronoFlow.Model\ChronoFlow.Model.csproj" /> <ProjectReference Include="..\ChronoFlow.Model\ChronoFlow.Model.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Assets\" />
</ItemGroup>
<ItemGroup>
<Compile Update="ZeiterfassungView.axaml.cs">
<DependentUpon>ZeiterfassungView.axaml</DependentUpon>
</Compile>
</ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,18 @@
<!-- Datei: View/LoginWindow.axaml -->
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ChronoFlow.View.LoginWindow"
Title="ChronoFlow Login" Width="400" Height="250" WindowStartupLocation="CenterScreen">
<StackPanel Margin="20" Spacing="10">
<TextBlock Text="ChronoFlow Login" FontWeight="Bold" FontSize="18" HorizontalAlignment="Center"/>
<TextBox x:Name="UsernameBox" Watermark="Benutzername"/>
<TextBlock Text="PasswordBox" FontSize="18" TextAlignment="Center" Margin="0,0,0,10"/>
<TextBox x:Name = "PasswordBox" PasswordChar="*" Text="Enabled"/>
<TextBlock x:Name="ErrorText" Foreground="Red" IsVisible="False"/>
<Button Content="Anmelden" Click="LoginButton_Click" HorizontalAlignment="Center"/>
</StackPanel>
</Window>

View File

@ -0,0 +1,46 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using ChronoFlow.Controller;
namespace ChronoFlow.View
{
/// <summary>
/// Das Fenster für den Benutzer-Login.
/// </summary>
public partial class LoginWindow : Window
{
private LoginController _loginController;
public LoginWindow()
{
InitializeComponent(); // Verbindet XAML mit diesem Code
_loginController = new LoginController(); // Unsere "Logik-Klasse"
}
/// <summary>
/// Wird ausgeführt, wenn der Benutzer auf "Anmelden" klickt.
/// </summary>
private void LoginButton_Click(object? sender, RoutedEventArgs e)
{
// Holt Benutzername und Passwort aus den Eingabefeldern
string username = UsernameBox?.Text ?? string.Empty;
string password = PasswordBox?.Text ?? string.Empty;
// Übergibt die Eingaben an den LoginController
var user = _loginController.Authenticate(username, password);
if (user != null)
{
// Wenn erfolgreich: öffne das MainWindow
var main = new MainWindow(user);
main.Show();
this.Close(); // Schließe das Login-Fenster
}
else
{
// Wenn fehlgeschlagen: Fehlermeldung anzeigen
ErrorText.Text = "Login fehlgeschlagen. Bitte prüfen Sie Ihre Eingaben.";
ErrorText.IsVisible = true;
}
}
}
}

View File

@ -5,5 +5,21 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ChronoFlow.View.MainWindow" x:Class="ChronoFlow.View.MainWindow"
Title="ChronoFlow.View"> Title="ChronoFlow.View">
Welcome to Avalonia!
<SplitView x:Name="PaneView" DisplayMode="CompactInline" IsPaneOpen="True" CompactPaneLength="40" OpenPaneLength="150">
<SplitView.Pane>
<StackPanel>
<Button Content="☰" Click="PaneOpenClose_Click"/>
<Button Content="⏱ Zeiterfassung" Click="Zeiterfassung_Click"/>
<Button Content="📄 Auswertung"/>
<Button Content="⚙ Einstellungen"/>
</StackPanel>
</SplitView.Pane>
<SplitView.Content>
<ContentControl x:Name="ContentArea" />
</SplitView.Content>
</SplitView>
</Window> </Window>

View File

@ -1,11 +1,48 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity;
using ChronoFlow.Model;
namespace ChronoFlow.View; namespace ChronoFlow.View;
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
public MainWindow() private readonly ViewManager _viewManager;
private readonly User _loggedInUser;
public MainWindow(User user)
{ {
InitializeComponent(); InitializeComponent();
_loggedInUser = user;
// ✅ Workaround: Lokale Kopie für Lambda-Nutzung im Register
var currentUser = _loggedInUser;
_viewManager = new ViewManager(ContentArea);
// ✅ Register-Aufruf mit stabiler local variable
_viewManager.Register("Zeiterfassung", () => new ZeiterfassungView(currentUser));
// Begrüßungsanzeige
ContentArea.Content = new TextBlock
{
Text = $"Willkommen bei ChronoFlow, {currentUser.Username}!",
FontSize = 24,
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center
};
// Fenstertitel dynamisch setzen
this.Title = $"ChronoFlow - Willkommen {currentUser.Username} ({currentUser.Role})";
}
private void PaneOpenClose_Click(object sender, RoutedEventArgs e)
{
PaneView.IsPaneOpen = !PaneView.IsPaneOpen;
}
private void Zeiterfassung_Click(object? sender, RoutedEventArgs e)
{
_viewManager.Show("Zeiterfassung");
} }
} }

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using Avalonia.Collections;
using Avalonia.Controls;
namespace ChronoFlow.View
{
///<summary>
/// Verwaltet alle Views der Anwendung und wechselt sie bei Bedarf.
/// </summary>
public class ViewManager
{
private readonly ContentControl _targetControl;
private readonly Dictionary<string, Func<UserControl>> _registieredViews = new();
public ViewManager(ContentControl targetControl)
{
_targetControl = targetControl;
}
///<summary>
/// Registriert eine View mit einem Namen
/// </summary>
public void Show(string name, Func<UserControl> viewFactory)
{
_registieredViews[name] = viewFactory;
}
///<summary>
/// Zeigt die View mit dem gegebenen Namen an.
/// </summary>
public void Show(string name)
{
if(_registieredViews.TryGetValue(name, out var factory))
_targetControl.Content = factory();
else
{
throw new InvalidOperationException($"View {name} is not registered");
}
}
public void Register(string name, Func<UserControl> viewFactory)
{
_registieredViews[name] = viewFactory;
}
}
}