265 lines
12 KiB
C#
265 lines
12 KiB
C#
using System.IO;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Media;
|
||
|
||
namespace DeskCore;
|
||
|
||
/// <summary>Einstellungen für Desktop-Seiten, das Aufziehen neuer Boxen und die Tönung der Desktop-Icons.</summary>
|
||
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<double> 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<CheckBox>();
|
||
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", "");
|
||
}
|
||
}
|