Started working on main page
This commit is contained in:
9
src/WorkTime.Mobile/Pages/AnalysisPage.xaml
Normal file
9
src/WorkTime.Mobile/Pages/AnalysisPage.xaml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="WorkTime.Mobile.Pages.AnalysisPage">
|
||||
<ContentPage.Content>
|
||||
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
13
src/WorkTime.Mobile/Pages/AnalysisPage.xaml.cs
Normal file
13
src/WorkTime.Mobile/Pages/AnalysisPage.xaml.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WorkTime.Mobile.Pages;
|
||||
|
||||
public partial class AnalysisPage : ContentPage {
|
||||
public AnalysisPage() {
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
38
src/WorkTime.Mobile/Pages/CapturePage.xaml
Normal file
38
src/WorkTime.Mobile/Pages/CapturePage.xaml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:components="clr-namespace:WorkTime.Mobile.Pages.Components"
|
||||
xmlns:pages="clr-namespace:WorkTime.Mobile.Pages"
|
||||
xmlns:mi="http://www.aathifmahir.com/dotnet/2022/maui/icons"
|
||||
xmlns:models="clr-namespace:WorkTime.Models;assembly=WorkTime.Models"
|
||||
x:Class="WorkTime.Mobile.Pages.CapturePage"
|
||||
x:DataType="pages:CapturePageModel">
|
||||
|
||||
<ContentPage.Content>
|
||||
<Grid Margin="10" RowSpacing="10" RowDefinitions="Auto,*,Auto">
|
||||
<components:DateSelector Grid.Row="0"
|
||||
Command="{Binding LoadDateCommand}" />
|
||||
|
||||
<ScrollView Grid.Row="1">
|
||||
<CollectionView ItemsSource="{Binding Entries}">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:TimeEntry">
|
||||
<HorizontalStackLayout Spacing="5">
|
||||
<Label Text="{Binding Timestamp}" />
|
||||
<Label Text="{Binding Type}" />
|
||||
</HorizontalStackLayout>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</ScrollView>
|
||||
|
||||
<HorizontalStackLayout Grid.Row="2" HorizontalOptions="Center" Spacing="20">
|
||||
<Button Text="{Binding CurrentTypeName}"
|
||||
Command="{Binding RegisterEntryCommand}" />
|
||||
|
||||
<Button mi:MauiIcon.Value="{mi:Material Icon=Add}" />
|
||||
</HorizontalStackLayout>
|
||||
</Grid>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
106
src/WorkTime.Mobile/Pages/CapturePage.xaml.cs
Normal file
106
src/WorkTime.Mobile/Pages/CapturePage.xaml.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using WorkTime.Models;
|
||||
using WorkTime.Models.Repositories;
|
||||
|
||||
namespace WorkTime.Mobile.Pages;
|
||||
|
||||
public partial class CapturePage : ContentPage {
|
||||
private readonly CapturePageModel _model;
|
||||
|
||||
public CapturePage(CapturePageModel model) {
|
||||
InitializeComponent();
|
||||
BindingContext = model;
|
||||
_model = model;
|
||||
}
|
||||
|
||||
protected override void OnAppearing() {
|
||||
base.OnAppearing();
|
||||
|
||||
if (_model.AppearingCommand.CanExecute(null))
|
||||
_model.AppearingCommand.Execute(null);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class CapturePageModel(ITimeEntryRepository entryRepository) : ObservableObject {
|
||||
|
||||
private DateOnly _currentDate = DateOnly.FromDateTime(DateTime.Now);
|
||||
|
||||
[ObservableProperty]
|
||||
public partial ObservableCollection<TimeEntry> Entries { get; set; } = new();
|
||||
|
||||
[ObservableProperty]
|
||||
public partial EntryType CurrentType { get; set; } = EntryType.Login;
|
||||
|
||||
public string CurrentTypeName => CurrentType switch {
|
||||
EntryType.Login => "Einstempeln",
|
||||
EntryType.LoginHome => "Einstempeln (mobA)",
|
||||
EntryType.LoginTrip => "Dienstreise starten",
|
||||
EntryType.Logout => "Ausstempeln",
|
||||
EntryType.LogoutHome => "Ausstempeln (mobA)",
|
||||
EntryType.LogoutTrip => "Dienstreise beenden",
|
||||
_ => "UNKNOWN"
|
||||
};
|
||||
|
||||
partial void OnCurrentTypeChanged(EntryType value) {
|
||||
OnPropertyChanged(nameof(CurrentTypeName));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task LoadDate(DateOnly date) {
|
||||
_currentDate = date;
|
||||
Entries.Clear();
|
||||
|
||||
var result = await entryRepository.GetTimeEntries(date);
|
||||
foreach (var entry in result) {
|
||||
Entries.Add(entry);
|
||||
}
|
||||
|
||||
UpdateCurrentType();
|
||||
}
|
||||
|
||||
private void UpdateCurrentType() {
|
||||
var last = Entries.LastOrDefault();
|
||||
|
||||
if (last is null) {
|
||||
CurrentType = EntryType.Login;
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentType = last.Type switch {
|
||||
EntryType.Login => EntryType.Logout,
|
||||
EntryType.LoginHome => EntryType.LogoutHome,
|
||||
EntryType.LoginTrip => EntryType.LogoutTrip,
|
||||
|
||||
EntryType.Logout => EntryType.Login,
|
||||
EntryType.LogoutHome => EntryType.LoginHome,
|
||||
EntryType.LogoutTrip => EntryType.LoginTrip,
|
||||
|
||||
_ => EntryType.Login
|
||||
};
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task OnAppearing() {
|
||||
await LoadDate(_currentDate);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task RegisterEntry(TimeEntry? entry = null) {
|
||||
entry ??= new TimeEntry {
|
||||
Timestamp = DateTime.Now,
|
||||
Type = CurrentType
|
||||
};
|
||||
|
||||
await entryRepository.AddTimeEntry(entry);
|
||||
await LoadDate(_currentDate);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task DeleteEntry(Guid entryId) {
|
||||
await entryRepository.DeleteTimeEntry(entryId);
|
||||
await LoadDate(_currentDate);
|
||||
}
|
||||
|
||||
}
|
||||
19
src/WorkTime.Mobile/Pages/Components/DateSelector.xaml
Normal file
19
src/WorkTime.Mobile/Pages/Components/DateSelector.xaml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:components="clr-namespace:WorkTime.Mobile.Pages.Components"
|
||||
x:Class="WorkTime.Mobile.Pages.Components.DateSelector"
|
||||
x:DataType="components:DateSelector"
|
||||
x:Name="Component">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<Label Grid.Column="0"
|
||||
Text="Tag"
|
||||
VerticalOptions="Center" />
|
||||
|
||||
<DatePicker Grid.Column="1"
|
||||
Date="{Binding CurrentDate, Source={x:Reference Component}}"
|
||||
MaximumDate="{Binding MaxDate, Source={x:Reference Component}}"
|
||||
DateSelected="OnDateSelected"/>
|
||||
</Grid>
|
||||
</ContentView>
|
||||
48
src/WorkTime.Mobile/Pages/Components/DateSelector.xaml.cs
Normal file
48
src/WorkTime.Mobile/Pages/Components/DateSelector.xaml.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace WorkTime.Mobile.Pages.Components;
|
||||
|
||||
public partial class DateSelector : ContentView {
|
||||
|
||||
public static readonly BindableProperty CurrentDateProperty = BindableProperty.Create(
|
||||
nameof(CurrentDate),
|
||||
typeof(DateTime),
|
||||
typeof(DateSelector),
|
||||
DateTime.Now);
|
||||
|
||||
public static readonly BindableProperty MaxDateProperty = BindableProperty.Create(
|
||||
nameof(MaxDate),
|
||||
typeof(DateTime),
|
||||
typeof(DateSelector),
|
||||
DateTime.Now);
|
||||
|
||||
public static readonly BindableProperty CommandProperty = BindableProperty.Create(
|
||||
nameof(Command),
|
||||
typeof(IRelayCommand<DateOnly>),
|
||||
typeof(DateSelector));
|
||||
|
||||
public DateTime CurrentDate {
|
||||
get => (DateTime)GetValue(CurrentDateProperty);
|
||||
set => SetValue(CurrentDateProperty, value);
|
||||
}
|
||||
|
||||
public DateTime MaxDate {
|
||||
get => (DateTime)GetValue(MaxDateProperty);
|
||||
set => SetValue(MaxDateProperty, value);
|
||||
}
|
||||
|
||||
public IRelayCommand<DateOnly>? Command {
|
||||
get => (IRelayCommand<DateOnly>)GetValue(CommandProperty);
|
||||
set => SetValue(CommandProperty, value);
|
||||
}
|
||||
|
||||
public DateSelector() {
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnDateSelected(object? sender, DateChangedEventArgs e) {
|
||||
var date = DateOnly.FromDateTime(CurrentDate);
|
||||
Command?.Execute(date);
|
||||
}
|
||||
|
||||
}
|
||||
24
src/WorkTime.Mobile/Pages/Components/SettingComponent.xaml
Normal file
24
src/WorkTime.Mobile/Pages/Components/SettingComponent.xaml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:components="clr-namespace:WorkTime.Mobile.Pages.Components"
|
||||
x:Class="WorkTime.Mobile.Pages.Components.SettingComponent"
|
||||
x:DataType="components:SettingComponent"
|
||||
x:Name="Component">
|
||||
<Grid ColumnDefinitions="*,Auto,80" ColumnSpacing="5">
|
||||
<Label Text="{Binding Title, Source={x:Reference Component}}"
|
||||
VerticalTextAlignment="Center"
|
||||
Grid.Column="0"/>
|
||||
|
||||
<Entry Placeholder="{Binding Placeholder, Source={x:Reference Component}}"
|
||||
Keyboard="Numeric"
|
||||
Grid.Column="1"
|
||||
TextChanged="OnValueChanged"
|
||||
x:Name="EntryField"/>
|
||||
|
||||
<Label Text="{Binding Unit, Source={x:Reference Component}}"
|
||||
VerticalTextAlignment="Center"
|
||||
Grid.Column="2"/>
|
||||
</Grid>
|
||||
</ContentView>
|
||||
@@ -0,0 +1,54 @@
|
||||
namespace WorkTime.Mobile.Pages.Components;
|
||||
|
||||
public partial class SettingComponent : ContentView {
|
||||
public static readonly BindableProperty TitleProperty =
|
||||
BindableProperty.Create(nameof(Title), typeof(string), typeof(SettingComponent), string.Empty);
|
||||
|
||||
public static readonly BindableProperty UnitProperty =
|
||||
BindableProperty.Create(nameof(Unit), typeof(string), typeof(SettingComponent), string.Empty);
|
||||
|
||||
public static readonly BindableProperty PlaceholderProperty =
|
||||
BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(SettingComponent), string.Empty);
|
||||
|
||||
public static readonly BindableProperty ValueProperty =
|
||||
BindableProperty.Create(nameof(Value), typeof(TimeSpan), typeof(SettingComponent), TimeSpan.Zero,
|
||||
BindingMode.TwoWay);
|
||||
|
||||
public string Title {
|
||||
get => (string)GetValue(TitleProperty);
|
||||
set => SetValue(TitleProperty, value);
|
||||
}
|
||||
|
||||
public string Unit {
|
||||
get => (string)GetValue(UnitProperty);
|
||||
set => SetValue(UnitProperty, value);
|
||||
}
|
||||
|
||||
public string Placeholder {
|
||||
get => (string)GetValue(PlaceholderProperty);
|
||||
set => SetValue(PlaceholderProperty, value);
|
||||
}
|
||||
|
||||
public TimeSpan Value {
|
||||
get => (TimeSpan)GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, value);
|
||||
}
|
||||
|
||||
public SettingComponent() {
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnValueChanged(object? sender, TextChangedEventArgs e) {
|
||||
if (!int.TryParse(e.NewTextValue, out var number)) return;
|
||||
|
||||
Value = Unit switch {
|
||||
"Stunden" or "Uhr" => TimeSpan.FromHours(number),
|
||||
"Minuten" => TimeSpan.FromMinutes(number),
|
||||
_ => Value
|
||||
};
|
||||
}
|
||||
|
||||
public void ClearInput() {
|
||||
Content.FindByName<Entry>(nameof(EntryField)).Text = string.Empty;
|
||||
}
|
||||
}
|
||||
97
src/WorkTime.Mobile/Pages/SettingsPage.xaml
Normal file
97
src/WorkTime.Mobile/Pages/SettingsPage.xaml
Normal file
@@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:components="clr-namespace:WorkTime.Mobile.Pages.Components"
|
||||
xmlns:pages="clr-namespace:WorkTime.Mobile.Pages"
|
||||
xmlns:icons="http://www.aathifmahir.com/dotnet/2022/maui/icons"
|
||||
x:Class="WorkTime.Mobile.Pages.SettingsPage"
|
||||
x:DataType="pages:SettingsPageModel">
|
||||
|
||||
<ContentPage.Content>
|
||||
<Grid Margin="20,10" RowDefinitions="*,Auto">
|
||||
<VerticalStackLayout Grid.Row="0" x:Name="SettingsStack">
|
||||
<HorizontalStackLayout Margin="0, 0, 0, 5" Spacing="15">
|
||||
<icons:MauiIcon Icon="{icons:Material Work}"
|
||||
IconSize="30"
|
||||
IconColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
|
||||
<Label Text="Zeiten"
|
||||
FontSize="20"
|
||||
HorizontalTextAlignment="Center"/>
|
||||
</HorizontalStackLayout>
|
||||
|
||||
<components:SettingComponent
|
||||
Title="Arbeitszeit"
|
||||
Unit="Stunden"
|
||||
Placeholder="{Binding Settings.WorkTime.TotalHours}"
|
||||
Value="{Binding Settings.WorkTime, Mode=OneWayToSource}"/>
|
||||
|
||||
|
||||
|
||||
<HorizontalStackLayout Margin="0, 10, 0, 5" Spacing="15">
|
||||
<icons:MauiIcon Icon="{icons:Material LocalPizza}"
|
||||
IconSize="30"
|
||||
IconColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
|
||||
<Label Text="Pause"
|
||||
FontSize="20"
|
||||
HorizontalTextAlignment="Center"/>
|
||||
</HorizontalStackLayout>
|
||||
|
||||
<components:SettingComponent
|
||||
Title="Nach 0 Stunden"
|
||||
Unit="Minuten"
|
||||
Placeholder="{Binding Settings.BreakAfter0.TotalMinutes}"
|
||||
Value="{Binding Settings.BreakAfter0, Mode=OneWayToSource}"/>
|
||||
|
||||
<components:SettingComponent
|
||||
Title="Nach 6 Stunden"
|
||||
Unit="Minuten"
|
||||
Placeholder="{Binding Settings.BreakAfter6.TotalMinutes}"
|
||||
Value="{Binding Settings.BreakAfter6, Mode=OneWayToSource}"/>
|
||||
|
||||
<components:SettingComponent
|
||||
Title="Nach 9 Stunden"
|
||||
Unit="Minuten"
|
||||
Placeholder="{Binding Settings.BreakAfter9.TotalMinutes}"
|
||||
Value="{Binding Settings.BreakAfter9, Mode=OneWayToSource}"/>
|
||||
|
||||
<components:SettingComponent
|
||||
Title="Nicht tracken nach"
|
||||
Unit="Uhr"
|
||||
Placeholder="{Binding Settings.DontTrackBreakAfter.TotalHours}"
|
||||
Value="{Binding Settings.DontTrackBreakAfter, Mode=OneWayToSource}"/>
|
||||
|
||||
|
||||
|
||||
<HorizontalStackLayout Margin="0, 10, 0, 5" Spacing="15">
|
||||
<icons:MauiIcon Icon="{icons:Material CreditCard}"
|
||||
IconSize="30"
|
||||
IconColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
||||
|
||||
<Label Text="Überstunden"
|
||||
FontSize="20"
|
||||
HorizontalTextAlignment="Center"/>
|
||||
</HorizontalStackLayout>
|
||||
|
||||
<components:SettingComponent
|
||||
Title="Optimal"
|
||||
Unit="Minuten"
|
||||
Placeholder="{Binding Settings.IdealOvertime.TotalMinutes}"
|
||||
Value="{Binding Settings.IdealOvertime, Mode=OneWayToSource}"/>
|
||||
|
||||
<components:SettingComponent
|
||||
Title="Maximal"
|
||||
Unit="Minuten"
|
||||
Placeholder="{Binding Settings.MaxOvertime.TotalMinutes}"
|
||||
Value="{Binding Settings.MaxOvertime, Mode=OneWayToSource}"/>
|
||||
</VerticalStackLayout>
|
||||
|
||||
<Button Grid.Row="1"
|
||||
Text="Speichern"
|
||||
HorizontalOptions="Center"
|
||||
Command="{Binding SaveSettingsCommand}"/>
|
||||
</Grid>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
49
src/WorkTime.Mobile/Pages/SettingsPage.xaml.cs
Normal file
49
src/WorkTime.Mobile/Pages/SettingsPage.xaml.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using CommunityToolkit.Maui.Alerts;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using WorkTime.Mobile.Pages.Components;
|
||||
using WorkTime.Models;
|
||||
using WorkTime.Models.Repositories;
|
||||
|
||||
namespace WorkTime.Mobile.Pages;
|
||||
|
||||
public partial class SettingsPage : ContentPage {
|
||||
private readonly SettingsPageModel _model;
|
||||
|
||||
public SettingsPage(SettingsPageModel model) {
|
||||
InitializeComponent();
|
||||
BindingContext = model;
|
||||
_model = model;
|
||||
}
|
||||
|
||||
protected override void OnAppearing() {
|
||||
base.OnAppearing();
|
||||
|
||||
if (_model.LoadSettingsCommand.CanExecute(null))
|
||||
_model.LoadSettingsCommand.Execute(null);
|
||||
|
||||
foreach (var child in Content.FindByName<VerticalStackLayout>(nameof(SettingsStack)).Children) {
|
||||
if (child is SettingComponent component)
|
||||
component.ClearInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class SettingsPageModel(ISettingsRepository settingsRepository) : ObservableObject {
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Settings Settings { get; set; }
|
||||
|
||||
[RelayCommand]
|
||||
public async Task LoadSettings() {
|
||||
Settings = await settingsRepository.LoadSettings();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task SaveSettings() {
|
||||
await settingsRepository.SaveSettings(Settings);
|
||||
|
||||
await Toast.Make("Einstellungen gespeichert!").Show();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user