using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace DeskCore; /// Einstellungen für Desktop-Seiten, das Aufziehen neuer Boxen und die Tönung der Desktop-Icons. public partial class MainWindow { public record PageRow(int Index, string Name, string Info, Brush Dot); private bool _loadingDesktopSettings; private void LoadDesktopSettings() { _loadingDesktopSettings = true; DrawFencesToggle.IsChecked = S.DrawFences; PageWheelBox.IsChecked = S.PageWheel; PageWheelBox.IsEnabled = S.Pages.Count > 1; var res = Application.Current.Resources; PageList.ItemsSource = S.Pages.Select((name, i) => { int boxes = S.Fences.Count(f => f.Page == i); var info = (boxes == 1 ? "1 Box" : $"{boxes} Boxen") + (i == S.CurrentPage ? " · wird gerade angezeigt" : ""); var o = S.PageOptions.GetValueOrDefault(name); if (o?.Scheduled == true) info += " · " + PageScheduler.Describe(o); if (string.Equals(S.PageFallback, name, StringComparison.OrdinalIgnoreCase)) info += " · sonst immer"; if (o?.Wallpaper is not null) info += " · eigenes Hintergrundbild"; return new PageRow(i, name, info, (Brush)res[i == S.CurrentPage ? "AccentBrush" : "ControlStrongStrokeBrush"]); }).ToList(); DesktopTintSwatches.Children.Clear(); void AddSwatch(string? hex, Brush brush, string tip) { var rb = new RadioButton { Style = (Style)res["SwatchRadio"], GroupName = "desktoptint", Background = brush, ToolTip = tip, IsChecked = S.DesktopTint == hex, }; rb.Checked += (_, _) => { if (_loadingDesktopSettings) return; S.DesktopTint = hex; S.Save(); DesktopTintStrength.IsEnabled = hex is not null; DesktopIcons.RefreshCache(); DesktopTint.Refresh(force: true); }; DesktopTintSwatches.Children.Add(rb); } AddSwatch(null, Brushes.Transparent, "Keine Tönung"); foreach (var (name, hex) in CategoryColors.All.Concat([("Weiß", "#F5F5F5")])) AddSwatch(hex, CategoryColors.Brush(hex)!, name); DesktopTintStrength.Value = Math.Round(S.DesktopTintStrength * 100); DesktopTintStrength.IsEnabled = S.DesktopTint is not null; _loadingDesktopSettings = false; } private void DrawFencesToggle_Click(object sender, RoutedEventArgs e) { S.DrawFences = DrawFencesToggle.IsChecked == true; S.Save(); DesktopToggle.Apply(); } private void PageWheel_Click(object sender, RoutedEventArgs e) { S.PageWheel = PageWheelBox.IsChecked == true; S.Save(); DesktopToggle.Apply(); } private void DesktopTintStrength_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { if (_loadingDesktopSettings || !IsLoaded) return; S.DesktopTintStrength = DesktopTintStrength.Value / 100; S.Save(); DesktopTint.Refresh(force: true); } // ---------- Seiten ---------- private static string? ValidatePageName(string t, int except) => t.Trim().Length == 0 ? "Bitte einen Namen eingeben." : S.Pages.Where((_, i) => i != except).Any(p => string.Equals(p, t.Trim(), StringComparison.OrdinalIgnoreCase)) ? "Diesen Namen gibt es schon." : null; private void AddPage_Click(object sender, RoutedEventArgs e) { var name = Dialog.Prompt(this, "Neue Desktop-Seite", "Name der Seite (z. B. „Arbeit“ oder „Freizeit“):", $"Seite {S.Pages.Count + 1}", "Hinzufügen", t => ValidatePageName(t, -1)); if (name is null) return; S.Pages.Add(name.Trim()); S.Save(); DesktopToggle.Apply(); LoadDesktopSettings(); ShowToast($"Seite „{name.Trim()}“ hinzugefügt", "Mit „Anzeigen“ wechselst du hin – neue Boxen landen immer auf der gerade angezeigten Seite."); } private void ShowPage_Click(object sender, RoutedEventArgs e) { if ((sender as FrameworkElement)?.Tag is int i) FenceManager.SwitchPage(i); LoadDesktopSettings(); } private void RenamePage_Click(object sender, RoutedEventArgs e) { if ((sender as FrameworkElement)?.Tag is not int i || i >= S.Pages.Count) return; var name = Dialog.Prompt(this, "Seite umbenennen", "Neuer Name:", S.Pages[i], "Umbenennen", t => ValidatePageName(t, i)); if (name is null) return; S.RenamePage(i, name.Trim()); S.Save(); LoadDesktopSettings(); } // ---------- Zeitplan & Hintergrundbild ---------- private void PageSchedule_Click(object sender, RoutedEventArgs e) { if ((sender as FrameworkElement)?.Tag is not int i || i >= S.Pages.Count) return; var page = S.Pages[i]; var o = S.PageOption(page); var res = Application.Current.Resources; var panel = new StackPanel(); TextBlock Label(string t, double top = 18) => new() { Text = t, Margin = new Thickness(0, top, 0, 8), FontWeight = FontWeights.SemiBold, FontSize = 13, }; TextBlock Hint(string t) => new() { Text = t, FontSize = 12, TextWrapping = TextWrapping.Wrap, Foreground = (Brush)res["TextSecondaryBrush"], Margin = new Thickness(0, 4, 0, 0), }; // Zeitplan var scheduled = new CheckBox { Content = "Diese Seite automatisch anzeigen", IsChecked = o.Scheduled }; panel.Children.Add(scheduled); var details = new StackPanel { Margin = new Thickness(28, 0, 0, 0) }; details.Children.Add(Label("An diesen Tagen", 12)); var days = new WrapPanel(); string[] dayNames = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]; var dayBoxes = new List(); for (int d = 0; d < 7; d++) { var cb = new CheckBox { Content = dayNames[d], IsChecked = (o.Days & (1 << d)) != 0, Margin = new Thickness(0, 0, 14, 4) }; dayBoxes.Add(cb); days.Children.Add(cb); } details.Children.Add(days); details.Children.Add(Label("Von – bis")); var from = new TextBox { Text = o.From, Width = 76, HorizontalContentAlignment = HorizontalAlignment.Center }; var to = new TextBox { Text = o.To, Width = 76, HorizontalContentAlignment = HorizontalAlignment.Center }; details.Children.Add(new StackPanel { Orientation = Orientation.Horizontal, Children = { from, new TextBlock { Text = "bis", Margin = new Thickness(12, 0, 12, 0), VerticalAlignment = VerticalAlignment.Center }, to, new TextBlock { Text = "Uhr", Margin = new Thickness(12, 0, 0, 0), VerticalAlignment = VerticalAlignment.Center }, }, }); details.Children.Add(Hint("Über Mitternacht geht auch, z. B. 22:00 bis 06:00.")); panel.Children.Add(details); void UpdateEnabled() => details.IsEnabled = scheduled.IsChecked == true; scheduled.Click += (_, _) => UpdateEnabled(); UpdateEnabled(); var fallback = new CheckBox { Content = "Zu allen anderen Zeiten diese Seite anzeigen", Margin = new Thickness(0, 18, 0, 0), IsChecked = string.Equals(S.PageFallback, page, StringComparison.OrdinalIgnoreCase), }; panel.Children.Add(fallback); panel.Children.Add(Hint("Beispiel: „Arbeit“ Mo–Fr 08:00–17:00 und bei „Freizeit“ diesen Haken setzen.")); // Hintergrundbild panel.Children.Add(Label("Hintergrundbild", 22)); string? wallpaper = o.Wallpaper; var wpText = new TextBlock { TextTrimming = TextTrimming.CharacterEllipsis, VerticalAlignment = VerticalAlignment.Center }; var wpRemove = new Button { Content = "Entfernen", Margin = new Thickness(8, 0, 0, 0) }; void UpdateWallpaper() { wpText.Text = wallpaper is null ? "Keins – der Hintergrund bleibt, wie er ist" : Path.GetFileName(wallpaper); wpText.ToolTip = wallpaper; wpRemove.IsEnabled = wallpaper is not null; } var wpPick = new Button { Content = "Bild wählen …" }; wpPick.Click += (_, _) => { var dlg = new Microsoft.Win32.OpenFileDialog { Title = $"Hintergrundbild für „{page}“", Filter = "Bilder|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.webp|Alle Dateien|*.*", }; if (wallpaper is not null) dlg.InitialDirectory = Path.GetDirectoryName(wallpaper); if (dlg.ShowDialog() == true) { wallpaper = dlg.FileName; UpdateWallpaper(); } }; wpRemove.Click += (_, _) => { wallpaper = null; UpdateWallpaper(); }; UpdateWallpaper(); var wpRow = new DockPanel(); var wpButtons = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(12, 0, 0, 0), Children = { wpPick, wpRemove } }; DockPanel.SetDock(wpButtons, Dock.Right); wpRow.Children.Add(wpButtons); wpRow.Children.Add(wpText); panel.Children.Add(wpRow); panel.Children.Add(Hint("Wechselst du auf eine Seite ohne eigenes Bild, kommt dein ursprünglicher Hintergrund zurück.")); string? Validate() { if (scheduled.IsChecked != true) return null; if (!TimeSpan.TryParse(from.Text.Trim(), out var f) || f.TotalHours >= 24 || !TimeSpan.TryParse(to.Text.Trim(), out var t) || t.TotalHours >= 24) return "Bitte die Uhrzeiten so eingeben: 08:00"; if (f == t) return "Start und Ende dürfen nicht gleich sein."; if (!dayBoxes.Any(b => b.IsChecked == true)) return "Bitte mindestens einen Tag auswählen."; return null; } if (!Dialog.Show(this, $"Seite „{page}“", panel, "Speichern", "Abbrechen", Validate)) return; o.Scheduled = scheduled.IsChecked == true; o.Days = dayBoxes.Select((b, d) => b.IsChecked == true ? 1 << d : 0).Sum(); if (TimeSpan.TryParse(from.Text.Trim(), out var ff)) o.From = ff.ToString(@"hh\:mm"); if (TimeSpan.TryParse(to.Text.Trim(), out var tt)) o.To = tt.ToString(@"hh\:mm"); if (fallback.IsChecked == true) S.PageFallback = page; else if (string.Equals(S.PageFallback, page, StringComparison.OrdinalIgnoreCase)) S.PageFallback = null; bool wallpaperChanged = !string.Equals(o.Wallpaper, wallpaper, StringComparison.OrdinalIgnoreCase); o.Wallpaper = wallpaper; S.Save(); if (wallpaperChanged && i == S.CurrentPage) PageScheduler.ApplyWallpaper(i); PageScheduler.Reset(); PageScheduler.Tick(); LoadDesktopSettings(); ShowToast($"Seite „{page}“ gespeichert", ""); } private void DeletePage_Click(object sender, RoutedEventArgs e) { if ((sender as FrameworkElement)?.Tag is not int i || i >= S.Pages.Count) return; if (S.Pages.Count < 2) { ShowToast("Die letzte Seite kann nicht gelöscht werden", "", info: true); return; } var name = S.Pages[i]; int boxes = S.Fences.Count(f => f.Page == i); if (boxes > 0 && !Dialog.Confirm(this, "Seite löschen", $"Auf „{name}“ liegen {boxes} Box(en). Sie wandern auf die Seite „{S.Pages[i == 0 ? 1 : i - 1]}“.", "Löschen")) return; FenceManager.DeletePage(i); S.ForgetPage(name); S.Save(); DesktopToggle.Apply(); Refresh(); LoadDesktopSettings(); ShowToast($"Seite „{name}“ gelöscht", ""); } }