diff --git a/Elwig/App.xaml.cs b/Elwig/App.xaml.cs index e526761..55b130f 100644 --- a/Elwig/App.xaml.cs +++ b/Elwig/App.xaml.cs @@ -292,6 +292,10 @@ namespace Elwig { return w; } + public static DeliveryScheduleAdminWindow FocusDeliverySchedule() { + return FocusWindow(() => new()); + } + public static PaymentVariantsWindow FocusPaymentVariants(int year) { return FocusWindow(() => new(year), w => w.Year == year); } diff --git a/Elwig/Controls/CheckComboBox.cs b/Elwig/Controls/CheckComboBox.cs index 06208b2..e108505 100644 --- a/Elwig/Controls/CheckComboBox.cs +++ b/Elwig/Controls/CheckComboBox.cs @@ -20,6 +20,12 @@ namespace Elwig.Controls { set => SetValue(DelimiterProperty, value); } + public static readonly DependencyProperty ListDisplayMemberPathProperty = DependencyProperty.Register(nameof(ListDisplayMemberPath), typeof(string), typeof(CheckComboBox), new FrameworkPropertyMetadata(null)); + public string ListDisplayMemberPath { + get => (string)GetValue(ListDisplayMemberPathProperty); + set => SetValue(ListDisplayMemberPathProperty, value); + } + public static readonly DependencyProperty AllItemsSelectedContentProperty = DependencyProperty.Register(nameof(AllItemsSelectedContent), typeof(string), typeof(CheckComboBox), new FrameworkPropertyMetadata("All")); public string AllItemsSelectedContent { get => (string)GetValue(AllItemsSelectedContentProperty); @@ -116,7 +122,7 @@ namespace Elwig.Controls { private void OnSelectionChanged(object sender, SelectionChangedEventArgs evt) { SelectItemsReverse(); - var dmp = DisplayMemberPath != null && DisplayMemberPath != "" ? DisplayMemberPath : null; + var dmp = !string.IsNullOrEmpty(ListDisplayMemberPath) ? ListDisplayMemberPath : !string.IsNullOrEmpty(DisplayMemberPath) ? DisplayMemberPath : null; if (SelectedItems.Count == ItemsSource.Cast().Count() && AllItemsSelectedContent != null) { _textBox.Text = AllItemsSelectedContent; AllItemsSelected = true; diff --git a/Elwig/Helpers/AppDbContext.cs b/Elwig/Helpers/AppDbContext.cs index e1c9847..1749688 100644 --- a/Elwig/Helpers/AppDbContext.cs +++ b/Elwig/Helpers/AppDbContext.cs @@ -239,6 +239,13 @@ namespace Elwig.Helpers { return c + 1; } + public async Task NextDsNr(int year) { + int c = 0; + (await DeliverySchedules.Where(s => s.Year == year).Select(s => s.DsNr).ToListAsync()) + .ForEach(a => { if (a <= c + 100) c = a; }); + return c + 1; + } + public async Task GetWineQualityLevel(double kmw) { return await WineQualityLevels .Where(q => !q.IsPredicate && (q.MinKmw == null || q.MinKmw <= kmw)) @@ -269,6 +276,31 @@ namespace Elwig.Helpers { } } + public void UpdateDeliveryScheduleWineVarieties(DeliverySchedule schedule, IEnumerable<(WineVar, int)> oldVarieties, IEnumerable<(WineVar, int)> newVarieties) { + foreach (var v in WineVarieties) { + var e = new DeliveryScheduleWineVar { + Year = schedule.Year, + DsNr = schedule.DsNr, + SortId = v.SortId, + Priority = 1, + }; + var o = oldVarieties.Where(x => x.Item1.SortId == e.SortId).Select(x => x.Item2).FirstOrDefault(-1); + var n = newVarieties.Where(x => x.Item1.SortId == e.SortId).Select(x => x.Item2).FirstOrDefault(-1); + if (n != -1) { + e.Priority = n; + if (o == -1) { + Add(e); + } else { + Update(e); + } + } else { + if (o != -1) { + Remove(e); + } + } + } + } + private async Task FetchMemberAreaCommitmentBuckets(int year, SqliteConnection? cnx = null) { var ownCnx = cnx == null; cnx ??= await ConnectAsync(); diff --git a/Elwig/Services/DeliveryScheduleService.cs b/Elwig/Services/DeliveryScheduleService.cs new file mode 100644 index 0000000..28d8d67 --- /dev/null +++ b/Elwig/Services/DeliveryScheduleService.cs @@ -0,0 +1,183 @@ +using Elwig.Helpers; +using Elwig.Models.Entities; +using Elwig.ViewModels; +using LinqKit; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Elwig.Services { + public static class DeliveryScheduleService { + + public static void InitInputs(this DeliveryScheduleAdminViewModel vm) { + if (vm.BranchSource.Count() == 1) + vm.Branch = vm.BranchSource.First(); + vm.AncmtFromTimeString = "00:00"; + vm.AncmtToTimeString = "23:59"; + } + + public static void ClearInputs(this DeliveryScheduleAdminViewModel vm) { + } + + public static async Task FillInputs(this DeliveryScheduleAdminViewModel vm, DeliverySchedule s) { + vm.Date = s.Date; + vm.Branch = (Branch?)ControlUtils.GetItemFromSourceWithPk(vm.BranchSource, s.ZwstId); + vm.Description = s.Description; + vm.MaxWeight = s.MaxWeight; + vm.MainVarieties.Clear(); + foreach (var v in s.Varieties.Where(v => v.Priority == 1)) { + vm.MainVarieties.Add((WineVar)ControlUtils.GetItemFromSourceWithPk(vm.MainVarietiesSource, v.SortId)!); + } + vm.OtherVarieties.Clear(); + foreach (var v in s.Varieties.Where(v => v.Priority != 1)) { + vm.OtherVarieties.Add((WineVar)ControlUtils.GetItemFromSourceWithPk(vm.OtherVarietiesSource, v.SortId)!); + } + vm.AncmtFrom = s.AncmtFrom; + vm.AncmtTo = s.AncmtTo?.AddSeconds(-1); + } + + public static async Task<(List, IQueryable, List)> GetFilters(this DeliveryScheduleAdminViewModel vm, AppDbContext ctx) { + List filterNames = []; + IQueryable deliveryScheduleQuery = ctx.DeliverySchedules; + if (vm.FilterSeason != null) { + deliveryScheduleQuery = deliveryScheduleQuery.Where(s => s.Year == vm.FilterSeason); + filterNames.Add($"{vm.FilterSeason}"); + } + if (vm.FilterOnlyUpcoming) { + deliveryScheduleQuery = deliveryScheduleQuery.Where(s => s.DateString.CompareTo(Utils.Today.ToString("yyyy-MM-dd")) >= 0); + filterNames.Add($"ab {Utils.Today:dd.MM.yyyy}"); + } + + var filterVar = new List(); + var filterNotVar = new List(); + var filterZwst = new List(); + var filterDate = new List<(string?, string?)>(); + + var filter = vm.TextFilter; + if (filter.Count > 0) { + var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); + var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b); + + for (int i = 0; i < filter.Count; i++) { + var e = filter[i]; + if (e.ToLower() is "r" or "rot") { + filterVar.AddRange(var.Values.Where(v => v.IsRed).Select(v => v.SortId)); + filter.RemoveAt(i--); + filterNames.Add("Rotweinsorten"); + } else if (e.ToLower() is "w" or "weiß" or "weiss") { + filterVar.AddRange(var.Values.Where(v => v.IsWhite).Select(v => v.SortId)); + filter.RemoveAt(i--); + filterNames.Add("Weißweinsorten"); + } else if (e.Length == 2 && var.ContainsKey(e.ToUpper())) { + filterVar.Add(e.ToUpper()); + filter.RemoveAt(i--); + filterNames.Add(var[e.ToUpper()].Name); + } else if (e.Length == 3 && e[0] == '!' && var.ContainsKey(e[1..].ToUpper())) { + filterNotVar.Add(e[1..].ToUpper()); + filter.RemoveAt(i--); + filterNames.Add("außer " + var[e[1..].ToUpper()].Name); + } else if (zwst.ContainsKey(e.ToLower())) { + var b = zwst[e.ToLower()]; + filterZwst.Add(b.ZwstId); + filter.RemoveAt(i--); + filterNames.Add($"Zweigstelle {b.Name}"); + } else if (DateOnly.TryParse(e, out var date)) { + var s = date.ToString("yyyy-MM-dd"); + filterDate.Add((s, s)); + filter.RemoveAt(i--); + if (filterNames.Contains($"{vm.FilterSeason}") && vm.FilterSeason == date.Year) + filterNames.Remove($"{vm.FilterSeason}"); + filterNames.Add(date.ToString("dd.MM.yyyy")); + } else if (Utils.DateFromToRegex.IsMatch(e)) { + var parts = e.Split("-"); + if (parts.Length == 1) { + // single date + var dParts = parts[0].Split('.'); + var s = $"{dParts[2]}-{dParts[1].PadLeft(2, '0')}-{dParts[0].PadLeft(2, '0')}"; + filterDate.Add((s, s)); + filter.RemoveAt(i--); + var n = string.Join('.', s.Split('-').Reverse()); + if (dParts[2] == "") { + filterNames.Remove($"{vm.FilterSeason}"); + filterNames.Add(n + $"{vm.FilterSeason}"); + } else { + if ($"{vm.FilterSeason}" == dParts[2]) + filterNames.Remove($"{vm.FilterSeason}"); + filterNames.Add(n); + } + } else if (parts.Length == 2) { + // from/to date + var d1Parts = parts[0].Split('.'); + var d2Parts = parts[1].Split('.'); + var s1 = d1Parts.Length < 2 ? null : $"{d1Parts.ElementAtOrDefault(2)}-{d1Parts[1].PadLeft(2, '0')}-{d1Parts[0].PadLeft(2, '0')}"; + var s2 = d2Parts.Length < 2 ? null : $"{d2Parts.ElementAtOrDefault(2)}-{d2Parts[1].PadLeft(2, '0')}-{d2Parts[0].PadLeft(2, '0')}"; + filterDate.Add((s1, s2)); + filter.RemoveAt(i--); + var n1 = s1 == null ? null : string.Join('.', s1.Split('-').Reverse()); + var n2 = s2 == null ? null : string.Join('.', s2.Split('-').Reverse()); + if (n1 != null && n2 != null) { + filterNames.Add($"{n1}–{n2}"); + } else if (n1 != null) { + filterNames.Add($"ab dem {n1}"); + } else if (n2 != null) { + filterNames.Add($"bis zum {n2}"); + } + } + } else if (e.Length > 2 && e.StartsWith('"') && e.EndsWith('"')) { + filter[i] = e[1..^1]; + } else if (e.Length <= 2) { + filter.RemoveAt(i--); + } + } + + if (filterDate.Count > 0) { + var pr = PredicateBuilder.New(false); + foreach (var (d1, d2) in filterDate) + pr.Or(p => (d1 == null || d1.CompareTo(p.DateString.Substring(10 - d1.Length)) <= 0) && (d2 == null || d2.CompareTo(p.DateString.Substring(10 - d2.Length)) >= 0)); + deliveryScheduleQuery = deliveryScheduleQuery.Where(pr); + } + if (filterVar.Count > 0) deliveryScheduleQuery = deliveryScheduleQuery.Where(s => s.Varieties.Any(v => filterVar.Contains(v.SortId))); + if (filterNotVar.Count > 0) deliveryScheduleQuery = deliveryScheduleQuery.Where(s => s.Varieties.All(v => !filterNotVar.Contains(v.SortId))); + if (filterZwst.Count > 0) deliveryScheduleQuery = deliveryScheduleQuery.Where(s => filterZwst.Contains(s.Branch.ZwstId)); + } + + return (filterNames, deliveryScheduleQuery, filter); + } + + public static async Task UpdateDeliverySchedule(this DeliveryScheduleAdminViewModel vm, int? oldYear, int? oldDsNr) { + int year = vm.Date!.Value.Year; + + using (var ctx = new AppDbContext()) { + var s = new DeliverySchedule { + Year = oldYear ?? year, + DsNr = oldDsNr ?? await ctx.NextDsNr(year), + DateString = $"{vm.Date:yyyy-MM-dd}", + ZwstId = vm.Branch!.ZwstId, + Description = vm.Description, + MaxWeight = vm.MaxWeight, + AncmtFrom = vm.AncmtFrom, + AncmtTo = vm.AncmtTo?.AddMinutes(1), + }; + + if (oldDsNr != null) { + ctx.Update(s); + } else { + ctx.Add(s); + } + + ctx.UpdateDeliveryScheduleWineVarieties(s, (await ctx.DeliveryScheduleWineVarieties + .Where(v => v.Year == s.Year && v.DsNr == s.DsNr) + .Select(v => new { v.Variety, v.Priority }) + .ToListAsync()) + .Select(v => (v.Variety, v.Priority)) + .ToList(), vm.MainVarieties.Select(v => (v, 1)).Union(vm.OtherVarieties.Select(v => (v, 2))).ToList()); + + await ctx.SaveChangesAsync(); + } + + await App.HintContextChange(); + } + } +} diff --git a/Elwig/ViewModels/DeliveryScheduleAdminViewModel.cs b/Elwig/ViewModels/DeliveryScheduleAdminViewModel.cs new file mode 100644 index 0000000..ee5a39f --- /dev/null +++ b/Elwig/ViewModels/DeliveryScheduleAdminViewModel.cs @@ -0,0 +1,101 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using Elwig.Models.Entities; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Windows; + +namespace Elwig.ViewModels { + public partial class DeliveryScheduleAdminViewModel : ObservableObject { + + [ObservableProperty] + private string? _searchQuery = ""; + public List TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0)]; + + [ObservableProperty] + private bool _filterOnlyUpcoming; + [ObservableProperty] + private string? _filterSeasonString; + public int? FilterSeason { + get => int.TryParse(FilterSeasonString, out var year) ? year : null; + set => FilterSeasonString = $"{value}"; + } + + [ObservableProperty] + private DeliverySchedule? _selectedDeliverySchedule; + [ObservableProperty] + private IEnumerable _deliverySchedules = []; + [ObservableProperty] + private bool _enableSearchInputs = true; + + [ObservableProperty] + private string _dateString = ""; + public DateOnly? Date { + get => DateOnly.TryParseExact(DateString, "dd.MM.yyyy", out var d) ? d : null; + set => DateString = $"{value:dd.MM.yyyy}"; + } + [ObservableProperty] + private Branch? _branch; + [ObservableProperty] + private IEnumerable _branchSource = []; + [ObservableProperty] + private string _description = ""; + [ObservableProperty] + private string? _maxWeightString = ""; + public int? MaxWeight { + get => int.TryParse(MaxWeightString, out var w) ? w : null; + set => MaxWeightString = $"{value}"; + } + public ObservableCollection MainVarieties { get; set; } = []; + [ObservableProperty] + private IEnumerable _mainVarietiesSource = []; + public ObservableCollection OtherVarieties { get; set; } = []; + [ObservableProperty] + private IEnumerable _otherVarietiesSource = []; + + [ObservableProperty] + private string _ancmtFromDateString = ""; + public DateOnly? AncmtFromDate { + get => DateOnly.TryParseExact(AncmtFromDateString, "dd.MM.yyyy", out var d) ? d : null; + set => AncmtFromDateString = $"{value:dd.MM.yyyy}"; + } + [ObservableProperty] + private string _ancmtFromTimeString = ""; + public TimeOnly? AncmtFromTime { + get => TimeOnly.TryParseExact(AncmtFromTimeString, "HH:mm", out var t) ? t : null; + set => AncmtFromTimeString = $"{value:HH:mm}"; + } + public DateTime? AncmtFrom { + get => AncmtFromDate != null && AncmtFromTime != null ? AncmtFromDate.Value.ToDateTime(AncmtFromTime.Value) : null; + set { + AncmtFromDateString = $"{value:dd.MM.yyyy}"; + AncmtFromTimeString = $"{value:HH:mm}"; + } + } + [ObservableProperty] + private string _ancmtToDateString = ""; + public DateOnly? AncmtToDate { + get => DateOnly.TryParseExact(AncmtToDateString, "dd.MM.yyyy", out var d) ? d : null; + set => AncmtToDateString = $"{value:dd.MM.yyyy}"; + } + [ObservableProperty] + private string _ancmtToTimeString = ""; + public TimeOnly? AncmtToTime { + get => TimeOnly.TryParseExact(AncmtToTimeString, "HH:mm", out var t) ? t : null; + set => AncmtToTimeString = $"{value:HH:mm}"; + } + public DateTime? AncmtTo { + get => AncmtToDate != null && AncmtToTime != null ? AncmtToDate.Value.ToDateTime(AncmtToTime.Value) : null; + set { + AncmtToDateString = $"{value:dd.MM.yyyy}"; + AncmtToTimeString = $"{value:HH:mm}"; + } + } + + [ObservableProperty] + private Visibility _controlButtonsVisibility = Visibility.Visible; + [ObservableProperty] + private Visibility _editingButtonsVisibility = Visibility.Hidden; + } +} diff --git a/Elwig/Windows/DeliveryScheduleAdminWindow.xaml b/Elwig/Windows/DeliveryScheduleAdminWindow.xaml new file mode 100644 index 0000000..67780f9 --- /dev/null +++ b/Elwig/Windows/DeliveryScheduleAdminWindow.xaml @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Strg+F + Lesepläne filtern und durchsuchen. Die Filter sind beliebig kombinierbar. + Groß- und Kleinschreibung ist in den meisten Fällen egal. + + Filtern nach: + Sorte: z.B. GV, ZW, rr, sa, !gv (ausgenommen GV), ... + Rot/Weiß: z.B. r, Rot, w, weiß, ... + Zweigstelle: z.B. musterort, ... + Datum: z.B. 1.9., 15.9.-10.10., -15.10.2020, ... + Beschreibung: z.B. Bio, ... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Elwig/Windows/DeliveryScheduleAdminWindow.xaml.cs b/Elwig/Windows/DeliveryScheduleAdminWindow.xaml.cs new file mode 100644 index 0000000..5836f06 --- /dev/null +++ b/Elwig/Windows/DeliveryScheduleAdminWindow.xaml.cs @@ -0,0 +1,311 @@ +using Elwig.Helpers; +using Elwig.Models.Entities; +using Elwig.Services; +using Elwig.ViewModels; +using Microsoft.EntityFrameworkCore; +using System; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; + +namespace Elwig.Windows { + public partial class DeliveryScheduleAdminWindow : AdministrationWindow { + + public DeliveryScheduleAdminViewModel ViewModel => (DeliveryScheduleAdminViewModel)DataContext; + + private readonly RoutedCommand CtrlF = new("CtrlF", typeof(DeliveryScheduleAdminWindow), [new KeyGesture(Key.F, ModifierKeys.Control)]); + + public DeliveryScheduleAdminWindow() { + InitializeComponent(); + CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput)); + ExemptInputs = [ + SearchInput, SeasonInput, OnlyUpcomingInput, DeliveryScheduleList, + ]; + RequiredInputs = [ + DateInput, BranchInput, DescriptionInput, MainWineVarietiesInput, + ]; + + InitializeDelayTimer(SearchInput, SearchInput_TextChanged); + SearchInput.TextChanged -= SearchInput_TextChanged; + ViewModel.FilterSeason = Utils.CurrentLastSeason; + } + + private void Window_Loaded(object sender, RoutedEventArgs evt) { + ViewModel.FilterOnlyUpcoming = true; + LockInputs(); + } + + private async Task RefreshList(bool updateSort = false) { + using var ctx = new AppDbContext(); + var (_, deliveryScheduleQuery, filter) = await ViewModel.GetFilters(ctx); + var deliverySchedules = await deliveryScheduleQuery + .Include(s => s.Varieties) + .Include(s => s.Branch) + .AsSplitQuery() + .ToListAsync(); + + if (filter.Count > 0 && deliverySchedules.Count > 0) { + var dict = deliverySchedules.AsParallel() + .ToDictionary(s => s, s => s.SearchScore(filter)) + .OrderByDescending(a => a.Value) + .ThenBy(a => a.Key.DateString) + .ThenBy(a => a.Key.Branch.Name) + .ThenBy(a => a.Key.Description); + var threshold = dict.Select(a => a.Value).Max() * 3 / 4; + deliverySchedules = dict + .Where(a => a.Value > threshold) + .Select(a => a.Key) + .ToList(); + } else { + deliverySchedules = deliverySchedules + .OrderBy(s => s.DateString) + .ThenBy(s => s.Branch.Name) + .ThenBy(s => s.Description) + .ToList(); + } + + ControlUtils.RenewItemsSource(DeliveryScheduleList, deliverySchedules, + DeliveryScheduleList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); + if (updateSort && DeliveryScheduleList.SelectedItem != null) + DeliveryScheduleList.ScrollIntoView(DeliveryScheduleList.SelectedItem); + } + + private async Task RefreshInputs(bool validate = false) { + ClearInputStates(); + if (ViewModel.SelectedDeliverySchedule is DeliverySchedule s) { + EditDeliveryScheduleButton.IsEnabled = true; + DeleteDeliveryScheduleButton.IsEnabled = true; + await FillInputs(s); + } else { + EditDeliveryScheduleButton.IsEnabled = false; + DeleteDeliveryScheduleButton.IsEnabled = false; + ClearOriginalValues(); + ClearDefaultValues(); + ClearInputs(validate); + ClearInputStates(); + } + GC.Collect(); + } + + private void InitInputs() { + ClearOriginalValues(); + ClearDefaultValues(); + ViewModel.InitInputs(); + ValidateRequiredInputs(); + } + + protected override async Task OnRenewContext(AppDbContext ctx) { + await base.OnRenewContext(ctx); + + ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync()); + var varieties = await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync(); + ControlUtils.RenewItemsSource(MainWineVarietiesInput, varieties); + ControlUtils.RenewItemsSource(OtherWineVarietiesInput, varieties); + + await RefreshList(); + } + + private async void DeliveryScheduleList_SelectionChanged(object sender, RoutedEventArgs evt) { + await RefreshInputs(); + } + + private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) { + await RefreshList(); + } + + private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) { + await RefreshList(true); + } + + private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) { + if (ViewModel.FilterSeason == null) return; + ViewModel.FilterOnlyUpcoming = false; + await RefreshList(); + } + + protected override void ShortcutNew() { + if (!NewDeliveryScheduleButton.IsEnabled || NewDeliveryScheduleButton.Visibility != Visibility.Visible) + return; + NewDeliveryScheduleButton_Click(null, null); + } + + private void NewDeliveryScheduleButton_Click(object? sender, RoutedEventArgs? evt) { + IsCreating = true; + DeliveryScheduleList.IsEnabled = false; + ViewModel.SelectedDeliverySchedule = null; + HideNewEditDeleteButtons(); + ShowSaveResetCancelButtons(); + UnlockInputs(); + InitInputs(); + ViewModel.EnableSearchInputs = false; + } + + protected override void ShortcutEdit() { + if (!EditDeliveryScheduleButton.IsEnabled || EditDeliveryScheduleButton.Visibility != Visibility.Visible) + return; + EditDeliveryScheduleButton_Click(null, null); + } + + private void EditDeliveryScheduleButton_Click(object? sender, RoutedEventArgs? evt) { + if (ViewModel.SelectedDeliverySchedule == null) return; + IsEditing = true; + DeliveryScheduleList.IsEnabled = false; + HideNewEditDeleteButtons(); + ShowSaveResetCancelButtons(); + UnlockInputs(); + ViewModel.EnableSearchInputs = false; + } + + protected override void ShortcutDelete() { + if (!DeleteDeliveryScheduleButton.IsEnabled || DeleteDeliveryScheduleButton.Visibility != Visibility.Visible) + return; + DeleteDeliveryScheduleButton_Click(null, null); + } + + private async void DeleteDeliveryScheduleButton_Click(object? sender, RoutedEventArgs? evt) { + if (ViewModel.SelectedDeliverySchedule is not DeliverySchedule s) + return; + var r = MessageBox.Show( + $"Soll der Leseplan \"{s.Description}\" vom {s.Date:dd.MM.yyyy} wirklich unwiderruflich gelöscht werden?", + "Leseplan löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel); + if (r == MessageBoxResult.OK) { + Mouse.OverrideCursor = Cursors.AppStarting; + try { + using (var ctx = new AppDbContext()) { + ctx.Remove(s); + await ctx.SaveChangesAsync(); + } + await App.HintContextChange(); + } catch (Exception exc) { + var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; + if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message; + MessageBox.Show(str, "Leseplan löschen", MessageBoxButton.OK, MessageBoxImage.Error); + } + Mouse.OverrideCursor = null; + } + } + + protected override void ShortcutSave() { + if (!SaveButton.IsEnabled || SaveButton.Visibility != Visibility.Visible) + return; + SaveButton_Click(null, null); + } + + private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) { + Mouse.OverrideCursor = Cursors.AppStarting; + try { + await ViewModel.UpdateDeliverySchedule(ViewModel.SelectedDeliverySchedule?.Year, ViewModel.SelectedDeliverySchedule?.DsNr); + } catch (Exception exc) { + var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; + if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message; + MessageBox.Show(str, "Leseplan aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error); + } + Mouse.OverrideCursor = null; + IsEditing = false; + IsCreating = false; + DeliveryScheduleList.IsEnabled = true; + HideSaveResetCancelButtons(); + ShowNewEditDeleteButtons(); + LockInputs(); + ViewModel.EnableSearchInputs = true; + FinishInputFilling(); + await RefreshList(); + await RefreshInputs(); + ViewModel.SearchQuery = ""; + } + + protected override void ShortcutReset() { + if (!ResetButton.IsEnabled || ResetButton.Visibility != Visibility.Visible) + return; + ResetButton_Click(null, null); + } + + private async void ResetButton_Click(object? sender, RoutedEventArgs? evt) { + if (IsEditing) { + await RefreshInputs(); + } else if (IsCreating) { + ClearInputs(); + InitInputs(); + } + UpdateButtons(); + } + + private async void CancelButton_Click(object? sender, RoutedEventArgs? evt) { + IsEditing = false; + IsCreating = false; + DeliveryScheduleList.IsEnabled = true; + HideSaveResetCancelButtons(); + ShowNewEditDeleteButtons(); + await RefreshInputs(); + LockInputs(); + ViewModel.EnableSearchInputs = true; + } + + private async Task FillInputs(DeliverySchedule s) { + ClearOriginalValues(); + ClearDefaultValues(); + await ViewModel.FillInputs(s); + FinishInputFilling(); + } + + new protected void ClearInputs(bool validate = false) { + ViewModel.ClearInputs(); + base.ClearInputs(validate); + } + + protected override void UpdateButtons() { + if (!IsEditing && !IsCreating) return; + bool ch = HasChanged, v = IsValid; + ResetButton.IsEnabled = ch; + SaveButton.IsEnabled = v && ch; + } + + private void FocusSearchInput(object sender, RoutedEventArgs evt) { + if (!IsEditing && !IsCreating) { + SearchInput.Focus(); + SearchInput.SelectAll(); + } + } + + private void ShowSaveResetCancelButtons() { + SaveButton.IsEnabled = false; + ResetButton.IsEnabled = false; + CancelButton.IsEnabled = true; + ViewModel.EditingButtonsVisibility = Visibility.Visible; + } + + private void HideSaveResetCancelButtons() { + SaveButton.IsEnabled = false; + ResetButton.IsEnabled = false; + CancelButton.IsEnabled = false; + ViewModel.EditingButtonsVisibility = Visibility.Hidden; + } + + private void ShowNewEditDeleteButtons() { + NewDeliveryScheduleButton.IsEnabled = true; + EditDeliveryScheduleButton.IsEnabled = ViewModel.SelectedDeliverySchedule != null; + DeleteDeliveryScheduleButton.IsEnabled = ViewModel.SelectedDeliverySchedule != null; + ViewModel.ControlButtonsVisibility = Visibility.Visible; + } + + private void HideNewEditDeleteButtons() { + NewDeliveryScheduleButton.IsEnabled = false; + EditDeliveryScheduleButton.IsEnabled = false; + DeleteDeliveryScheduleButton.IsEnabled = false; + ViewModel.ControlButtonsVisibility = Visibility.Hidden; + } + + private new void DateInput_TextChanged(object sender, TextChangedEventArgs evt) { + base.DateInput_TextChanged(sender, evt); + if (ViewModel.Date is DateOnly date) { + ViewModel.AncmtToDate = date.AddDays(-2); + } + } + + private void MaxWeightInput_TextChanged(object sender, TextChangedEventArgs evt) { + InputTextChanged((TextBox)sender, Validator.CheckInteger((TextBox)sender, false, 6)); + } + } +} diff --git a/Elwig/Windows/MainWindow.xaml b/Elwig/Windows/MainWindow.xaml index 6273cad..4c3ddb7 100644 --- a/Elwig/Windows/MainWindow.xaml +++ b/Elwig/Windows/MainWindow.xaml @@ -64,7 +64,7 @@ Margin="205,210,0,0"/>