Upload via GUI (186 Dateien)

This commit is contained in:
2026-10-04 14:48:53 +00:00
parent c0b552ef39
commit 8efd5bc497
25 changed files with 2344 additions and 1015 deletions
+91 -10
View File
@@ -40,15 +40,45 @@ public class SortRule
[JsonIgnore] public string KindText => Kind == "Typ" ? "Dateityp ist" : "Name enthält";
}
/// <summary>Ein Tab einer Desktop-Box: eine Kategorie oder ein beliebiger Ordner ("Ordner-Portal").</summary>
/// <summary>Ein Tab einer Desktop-Box: eine Kategorie, ein beliebiger Ordner ("Ordner-Portal") oder "Zuletzt benutzt".</summary>
public class FenceTab
{
public const string CategoryKind = "Kategorie", FolderKind = "Ordner";
public const string CategoryKind = "Kategorie", FolderKind = "Ordner", RecentKind = "Zuletzt";
public string Kind { get; set; } = CategoryKind;
/// <summary>Kategoriename bzw. Ordnerpfad.</summary>
/// <summary>Kategoriename bzw. Ordnerpfad (bei "Zuletzt benutzt" leer).</summary>
public string Value { get; set; } = "";
/// <summary>Eigene Reihenfolge (Dateinamen), wenn die Box nach "Eigene" sortiert ist.</summary>
public List<string> Order { get; set; } = [];
[JsonIgnore] public bool IsFolder => Kind == FolderKind;
[JsonIgnore] public string Title => IsFolder ? Path.GetFileName(Value.TrimEnd('\\')) is { Length: > 0 } n ? n : Value : Value;
[JsonIgnore] public bool IsRecent => Kind == RecentKind;
[JsonIgnore] public bool IsCategory => Kind == CategoryKind;
[JsonIgnore] public string Title => IsRecent ? "Zuletzt benutzt"
: IsFolder ? Path.GetFileName(Value.TrimEnd('\\')) is { Length: > 0 } n ? n : Value : Value;
}
/// <summary>Zusatzeinstellungen einer Desktop-Seite: Zeitplan und Hintergrundbild.</summary>
public class PageOption
{
/// <summary>Seite automatisch zu bestimmten Zeiten anzeigen.</summary>
public bool Scheduled { get; set; }
/// <summary>Wochentage als Bits: Montag = 1, Dienstag = 2 … Sonntag = 64.</summary>
public int Days { get; set; } = 0b0011111; // Mo–Fr
public string From { get; set; } = "08:00";
public string To { get; set; } = "17:00";
/// <summary>Eigenes Hintergrundbild für diese Seite (null = nicht ändern).</summary>
public string? Wallpaper { get; set; }
public static int DayBit(DayOfWeek d) => 1 << (((int)d + 6) % 7); // Montag = Bit 0
/// <summary>Gilt der Zeitplan zu diesem Zeitpunkt? Zeiträume über Mitternacht (z. B. 22:00–06:00) gehen auch.</summary>
public bool Matches(DateTime now)
{
if (!Scheduled || !TimeSpan.TryParse(From, out var from) || !TimeSpan.TryParse(To, out var to)) return false;
var t = now.TimeOfDay;
if (from <= to) return (Days & DayBit(now.DayOfWeek)) != 0 && t >= from && t < to;
// über Mitternacht: der Tag zählt, an dem der Zeitraum beginnt
return t >= from ? (Days & DayBit(now.DayOfWeek)) != 0 : t < to && (Days & DayBit(now.AddDays(-1).DayOfWeek)) != 0;
}
}
/// <summary>Eine Desktop-Box mit Position, Tabs und Aussehen.</summary>
@@ -71,7 +101,7 @@ public class FenceDef
/// <summary>Milchglas-Effekt (Hintergrund verschwommen).</summary>
public bool Blur { get; set; }
public ViewMode IconSize { get; set; } = ViewMode.Medium;
/// <summary>"Name", "Typ" oder "Datum"</summary>
/// <summary>"Name", "Typ", "Datum", "Häufig" (meistgenutzt zuerst) oder "Eigene" (per Ziehen angeordnet)</summary>
public string Sort { get; set; } = "Name";
/// <summary>Icon-Tönung (#RRGGBB) oder null.</summary>
public string? Tint { get; set; }
@@ -128,6 +158,22 @@ public class AppSettings
public int CurrentPage { get; set; }
/// <summary>Mausrad über einer freien Desktop-Stelle wechselt die Seite.</summary>
public bool PageWheel { get; set; } = true;
/// <summary>Zeitplan und Hintergrundbild je Seite (Schlüssel = Seitenname).</summary>
public Dictionary<string, PageOption> PageOptions { get; set; } = new(StringComparer.OrdinalIgnoreCase);
/// <summary>Seite, die außerhalb aller Zeitpläne angezeigt wird (null = keine).</summary>
public string? PageFallback { get; set; }
/// <summary>Hintergrundbild, das vor dem ersten Seiten-Hintergrund eingestellt war (zum Zurückholen).</summary>
public string? SavedWallpaper { get; set; }
/// <summary>Schnellstart-Suche per Tastenkürzel.</summary>
public bool QuickSearchEnabled { get; set; } = true;
public int QuickSearchModifiers { get; set; } = Hotkey.ModAlt | Hotkey.ModShift;
public int QuickSearchKey { get; set; } = 0x20; // Leertaste
/// <summary>Programme aus dem Windows-Startmenü mit durchsuchen.</summary>
public bool QuickSearchStartMenu { get; set; } = true;
/// <summary>Sortierung im Hauptfenster: "Name" oder "Häufig".</summary>
public string MainSort { get; set; } = "Name";
/// <summary>Rechte Maustaste auf freier Desktop-Fläche ziehen → neue Box.</summary>
public bool DrawFences { get; set; } = true;
@@ -191,6 +237,8 @@ public class AppSettings
s.Fences ??= [];
s.Snapshots ??= [];
s.ScreenLayouts ??= [];
s.PageOptions = new(s.PageOptions ?? [], StringComparer.OrdinalIgnoreCase);
foreach (var t in s.Fences.SelectMany(f => f.Tabs)) t.Order ??= [];
if (s.Pages is null || s.Pages.Count == 0) s.Pages = ["Seite 1"];
s.CurrentPage = Math.Clamp(s.CurrentPage, 0, s.Pages.Count - 1);
@@ -257,11 +305,12 @@ public class AppSettings
g.Items[i] = newDir + g.Items[i][oldDir.Length..];
}
/// <summary>Wird diese Kategorie in irgendeiner Box angezeigt?</summary>
/// <summary>Liegt diese Kategorie auf der gerade angezeigten Desktop-Seite in einer Box?</summary>
public bool HasFence(string category) =>
Fences.Any(f => f.Tabs.Any(t => !t.IsFolder && string.Equals(t.Value, category, StringComparison.OrdinalIgnoreCase)));
Fences.Any(f => f.Page == CurrentPage &&
f.Tabs.Any(t => t.IsCategory && string.Equals(t.Value, category, StringComparison.OrdinalIgnoreCase)));
/// <summary>Kategorie als eigene Box anzeigen bzw. aus allen Boxen entfernen.</summary>
/// <summary>Kategorie auf der aktuellen Seite als eigene Box anzeigen bzw. von dieser Seite entfernen (andere Seiten bleiben).</summary>
public void SetFence(string category, bool on)
{
if (on)
@@ -271,8 +320,8 @@ public class AppSettings
}
else
{
foreach (var f in Fences)
f.Tabs.RemoveAll(t => !t.IsFolder && string.Equals(t.Value, category, StringComparison.OrdinalIgnoreCase));
foreach (var f in Fences.Where(f => f.Page == CurrentPage))
f.Tabs.RemoveAll(t => t.IsCategory && string.Equals(t.Value, category, StringComparison.OrdinalIgnoreCase));
Fences.RemoveAll(f => f.Tabs.Count == 0);
}
}
@@ -288,9 +337,41 @@ public class AppSettings
foreach (var g in LaunchGroups)
for (int i = 0; i < g.Items.Count; i++)
if (string.Equals(g.Items[i], oldPath, StringComparison.OrdinalIgnoreCase)) { g.Items[i] = newPath; changed = true; }
// Umbenannt im selben Ordner → Platz in der eigenen Box-Reihenfolge behalten
if (Storage.SamePath(Path.GetDirectoryName(oldPath), Path.GetDirectoryName(newPath)))
{
string oldName = Path.GetFileName(oldPath), newName = Path.GetFileName(newPath);
foreach (var t in Fences.SelectMany(f => f.Tabs))
for (int i = 0; i < t.Order.Count; i++)
if (string.Equals(t.Order[i], oldName, StringComparison.OrdinalIgnoreCase)) { t.Order[i] = newName; changed = true; }
}
Usage.Rename(oldPath, newPath);
if (changed) Save();
}
// ---------- Desktop-Seiten ----------
public PageOption PageOption(string page)
{
if (!PageOptions.TryGetValue(page, out var o)) PageOptions[page] = o = new PageOption();
return o;
}
public void RenamePage(int index, string newName)
{
var old = Pages[index];
Pages[index] = newName;
if (PageOptions.Remove(old, out var o)) PageOptions[newName] = o;
if (string.Equals(PageFallback, old, StringComparison.OrdinalIgnoreCase)) PageFallback = newName;
}
/// <summary>Aufräumen nach dem Löschen einer Seite (Boxen verschiebt der FenceManager).</summary>
public void ForgetPage(string name)
{
PageOptions.Remove(name);
if (string.Equals(PageFallback, name, StringComparison.OrdinalIgnoreCase)) PageFallback = null;
}
public void RemoveCategory(string name)
{
foreach (var f in Fences)