Upload via GUI (186 Dateien)
This commit is contained in:
+119
-21
@@ -55,7 +55,8 @@ public partial class FenceWindow : Window
|
||||
SourceInitialized += (_, _) => PinToDesktop();
|
||||
MouseEnter += (_, _) => OnHover(true);
|
||||
MouseLeave += (_, _) => OnHover(false);
|
||||
Closed += (_, _) => _portalWatcher?.Dispose();
|
||||
Usage.Changed += OnUsageChanged;
|
||||
Closed += (_, _) => { _portalWatcher?.Dispose(); Usage.Changed -= OnUsageChanged; };
|
||||
Refresh();
|
||||
}
|
||||
|
||||
@@ -215,29 +216,52 @@ public partial class FenceWindow : Window
|
||||
WatchPortal(portal ? folder : null);
|
||||
|
||||
List<IconItem> items = [];
|
||||
if (folder is not null && Directory.Exists(folder))
|
||||
if (tab?.IsRecent == true)
|
||||
items = Usage.Recent(RecentCount).Select(p => new IconItem { Path = p }).ToList();
|
||||
else if (folder is not null && Directory.Exists(folder))
|
||||
items = (portal ? PortalEntries(folder) : Storage.Entries(folder)).Select(p => new IconItem { Path = p }).ToList();
|
||||
items = Sort(items);
|
||||
items = Sort(items, tab);
|
||||
|
||||
int px = (int)Math.Round((double)Resources["FIcon"] * VisualTreeHelper.GetDpi(this).DpiScaleX);
|
||||
foreach (var i in items) IconLoader.Load(i, px);
|
||||
Items.ItemsSource = items;
|
||||
CountText.Text = items.Count.ToString();
|
||||
EmptyText.Text = folder is not null && !Directory.Exists(folder) ? "Ordner nicht gefunden" : "Leer – Icons hierher ziehen";
|
||||
EmptyText.Text = tab?.IsRecent == true ? "Noch nichts gestartet – was du über DeskCore öffnest, erscheint hier"
|
||||
: folder is not null && !Directory.Exists(folder) ? "Ordner nicht gefunden" : "Leer – Icons hierher ziehen";
|
||||
EmptyText.Visibility = items.Count == 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
/// <summary>Ordner-Portal zeigt alles außer versteckten/System-Dateien.</summary>
|
||||
private static IEnumerable<string> PortalEntries(string dir) => Storage.Entries(dir);
|
||||
|
||||
private List<IconItem> Sort(List<IconItem> items)
|
||||
/// <summary>Wie viele Einträge eine „Zuletzt benutzt“-Box zeigt.</summary>
|
||||
private const int RecentCount = 24;
|
||||
|
||||
private void OnUsageChanged()
|
||||
{
|
||||
// Zuletzt-Tab oder Sortierung nach Häufigkeit → neu ordnen (kurz verzögert, falls mehrere Starts kommen)
|
||||
if (Tab?.IsRecent == true || Def.Sort == "Häufig") Dispatcher.BeginInvoke(Refresh, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
private List<IconItem> Sort(List<IconItem> items, FenceTab? tab)
|
||||
{
|
||||
// Zuletzt benutzt: neueste zuerst – außer es ist ausdrücklich "Häufig" gewählt
|
||||
if (tab?.IsRecent == true)
|
||||
return Def.Sort == "Häufig" ? items.OrderByDescending(i => Usage.Score(i.Path)).ToList() : items;
|
||||
// Eigene Reihenfolge: wie gezogen; Neues hinten dran (alphabetisch)
|
||||
if (Def.Sort == "Eigene" && tab is not null)
|
||||
{
|
||||
var order = tab.Order;
|
||||
return items.OrderBy(i => order.FindIndex(n => string.Equals(n, Path.GetFileName(i.Path), StringComparison.OrdinalIgnoreCase)) is var k and >= 0 ? k : int.MaxValue)
|
||||
.ThenBy(i => i.Name, StringComparer.CurrentCultureIgnoreCase).ToList();
|
||||
}
|
||||
var folders = items.Where(i => Directory.Exists(i.Path));
|
||||
var files = items.Where(i => !Directory.Exists(i.Path));
|
||||
IEnumerable<IconItem> Order(IEnumerable<IconItem> x) => Def.Sort switch
|
||||
{
|
||||
"Typ" => x.OrderBy(i => Path.GetExtension(i.Path), StringComparer.OrdinalIgnoreCase).ThenBy(i => i.Name, StringComparer.CurrentCultureIgnoreCase),
|
||||
"Datum" => x.OrderByDescending(i => { try { return File.GetLastWriteTime(i.Path); } catch { return DateTime.MinValue; } }),
|
||||
"Häufig" => x.OrderByDescending(i => Usage.Score(i.Path)).ThenBy(i => i.Name, StringComparer.CurrentCultureIgnoreCase),
|
||||
_ => x.OrderBy(i => i.Name, StringComparer.CurrentCultureIgnoreCase),
|
||||
};
|
||||
return Order(folders).Concat(Order(files)).ToList();
|
||||
@@ -250,13 +274,13 @@ public partial class FenceWindow : Window
|
||||
{
|
||||
var t = Def.Tabs[i];
|
||||
bool active = i == Math.Clamp(Def.ActiveTab, 0, Def.Tabs.Count - 1);
|
||||
var meta = t.IsFolder ? null : S.Categories.GetValueOrDefault(t.Value);
|
||||
var meta = t.IsCategory ? S.Categories.GetValueOrDefault(t.Value) : null;
|
||||
var glyph = new TextBlock
|
||||
{
|
||||
Text = t.IsFolder ? "" : meta?.Glyph ?? "",
|
||||
Text = t.IsRecent ? "" : t.IsFolder ? "" : meta?.Glyph ?? "",
|
||||
FontFamily = (FontFamily)FindResource("IconFont"), FontSize = 13, VerticalAlignment = VerticalAlignment.Center,
|
||||
Margin = new Thickness(0, 0, 7, 0),
|
||||
Foreground = CategoryColors.Brush(meta?.Color) ?? (Brush)FindResource(t.IsFolder ? "AccentBrush" : "TextBrush"),
|
||||
Foreground = CategoryColors.Brush(meta?.Color) ?? (Brush)FindResource(t.IsCategory ? "TextBrush" : "AccentBrush"),
|
||||
};
|
||||
var label = new TextBlock
|
||||
{
|
||||
@@ -275,7 +299,7 @@ public partial class FenceWindow : Window
|
||||
{
|
||||
Style = (Style)FindResource("SubtleButton"), Padding = new Thickness(6, 4, 6, 4), MinHeight = 0, Tag = i,
|
||||
Content = new Grid { Children = { content, underline } }, Margin = new Thickness(0, 0, 2, 0),
|
||||
ToolTip = t.IsFolder ? t.Value : $"Kategorie „{t.Value}“",
|
||||
ToolTip = t.IsRecent ? "Was du zuletzt über DeskCore gestartet hast" : t.IsFolder ? t.Value : $"Kategorie „{t.Value}“",
|
||||
};
|
||||
WindowChrome.SetIsHitTestVisibleInChrome(btn, Def.Tabs.Count > 1); // bei nur einem Tab: Titel = Ziehfläche
|
||||
btn.Click += (_, _) => SwitchTab((int)btn.Tag);
|
||||
@@ -344,7 +368,7 @@ public partial class FenceWindow : Window
|
||||
Refresh();
|
||||
return;
|
||||
}
|
||||
try { Process.Start(new ProcessStartInfo(i.Path) { UseShellExecute = true }); }
|
||||
try { Usage.Start(i.Path); }
|
||||
catch { }
|
||||
}
|
||||
|
||||
@@ -383,7 +407,7 @@ public partial class FenceWindow : Window
|
||||
|
||||
bool inStorage = sel.All(i => Storage.IsInStorage(i.Path));
|
||||
var moveTo = MainWindow.MenuItem(inStorage ? "Verschieben nach" : "Sichern in", inStorage ? "" : "", null);
|
||||
var ownCategory = Tab is { IsFolder: false } t ? t.Value : null;
|
||||
var ownCategory = Tab is { IsCategory: true } t ? t.Value : null;
|
||||
foreach (var c in Storage.Categories().Where(c => !string.Equals(c, ownCategory, StringComparison.OrdinalIgnoreCase)))
|
||||
moveTo.Items.Add(MainWindow.MenuItem(c, S.Categories.GetValueOrDefault(c)?.Glyph ?? "",
|
||||
() => win.TransferAll(sel.Select(i => i.Path), Storage.CategoryPath(c))));
|
||||
@@ -423,18 +447,85 @@ public partial class FenceWindow : Window
|
||||
|
||||
private void Items_DragOver(object sender, DragEventArgs e)
|
||||
{
|
||||
e.Effects = e.Data.GetDataPresent(DataFormats.FileDrop) && !_dragging && CurrentFolder is not null
|
||||
? (e.AllowedEffects.HasFlag(DragDropEffects.Copy) ? DragDropEffects.Copy : DragDropEffects.Move)
|
||||
: DragDropEffects.None;
|
||||
if (_dragging)
|
||||
{
|
||||
// Innerhalb der eigenen Box: neu anordnen (nicht bei „Zuletzt benutzt“ – die ordnet sich selbst)
|
||||
e.Effects = Tab is { IsRecent: false } ? DragDropEffects.Copy : DragDropEffects.None;
|
||||
ShowDropMarker(e.Effects == DragDropEffects.None ? null : e.GetPosition(Items));
|
||||
}
|
||||
else
|
||||
e.Effects = e.Data.GetDataPresent(DataFormats.FileDrop) && CurrentFolder is not null
|
||||
? (e.AllowedEffects.HasFlag(DragDropEffects.Copy) ? DragDropEffects.Copy : DragDropEffects.Move)
|
||||
: DragDropEffects.None;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void Items_DragLeave(object sender, DragEventArgs e) => ShowDropMarker(null);
|
||||
|
||||
private void Items_Drop(object sender, DragEventArgs e)
|
||||
{
|
||||
if (!_dragging && CurrentFolder is { } folder && e.Data.GetData(DataFormats.FileDrop) is string[] files)
|
||||
ShowDropMarker(null);
|
||||
if (_dragging)
|
||||
{
|
||||
if (Tab is { IsRecent: false } t) Reorder(t, Selected, e.GetPosition(Items));
|
||||
return;
|
||||
}
|
||||
if (CurrentFolder is { } folder && e.Data.GetData(DataFormats.FileDrop) is string[] files)
|
||||
App.Win?.TransferAll(files, folder);
|
||||
}
|
||||
|
||||
// ---------- Eigene Reihenfolge ----------
|
||||
|
||||
/// <summary>Einfügestelle an der Mausposition: vor welchem Eintrag landet das Gezogene? (Count = ans Ende)</summary>
|
||||
private (int Index, Rect? Marker) InsertionAt(Point p)
|
||||
{
|
||||
var list = Items.ItemsSource as List<IconItem> ?? [];
|
||||
for (int k = 0; k < list.Count; k++)
|
||||
{
|
||||
if (Items.ItemContainerGenerator.ContainerFromIndex(k) is not ListBoxItem c || !c.IsVisible) continue;
|
||||
var r = new Rect(c.TranslatePoint(new Point(0, 0), Items), c.RenderSize);
|
||||
if (p.Y < r.Top) return (k, new Rect(r.Left - 2, r.Top, 3, r.Height)); // Zeile darüber, ganz links
|
||||
if (p.Y <= r.Bottom && p.X < r.Left + r.Width / 2) return (k, new Rect(r.Left - 2, r.Top, 3, r.Height));
|
||||
}
|
||||
if (list.Count > 0 && Items.ItemContainerGenerator.ContainerFromIndex(list.Count - 1) is ListBoxItem last)
|
||||
{
|
||||
var r = new Rect(last.TranslatePoint(new Point(0, 0), Items), last.RenderSize);
|
||||
return (list.Count, new Rect(r.Right - 1, r.Top, 3, r.Height));
|
||||
}
|
||||
return (list.Count, null);
|
||||
}
|
||||
|
||||
private void ShowDropMarker(Point? p)
|
||||
{
|
||||
if (p is { } pos && InsertionAt(pos).Marker is { } m)
|
||||
{
|
||||
DropMarker.Margin = new Thickness(m.Left, m.Top, 0, 0);
|
||||
DropMarker.Height = m.Height;
|
||||
DropMarker.Visibility = Visibility.Visible;
|
||||
}
|
||||
else DropMarker.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void Reorder(FenceTab tab, List<IconItem> moved, Point drop)
|
||||
{
|
||||
var list = Items.ItemsSource as List<IconItem> ?? [];
|
||||
if (moved.Count == 0) return;
|
||||
int index = InsertionAt(drop).Index;
|
||||
// Einfügestelle in der Liste ohne die gezogenen Einträge
|
||||
int before = list.Take(index).Count(i => moved.Contains(i));
|
||||
var rest = list.Where(i => !moved.Contains(i)).ToList();
|
||||
rest.InsertRange(Math.Clamp(index - before, 0, rest.Count), moved);
|
||||
|
||||
tab.Order = rest.Select(i => Path.GetFileName(i.Path)).ToList();
|
||||
bool switched = Def.Sort != "Eigene";
|
||||
Def.Sort = "Eigene";
|
||||
S.Save();
|
||||
Refresh();
|
||||
foreach (var i in (Items.ItemsSource as List<IconItem> ?? []).Where(i => moved.Any(m => m.Path == i.Path)))
|
||||
Items.SelectedItems.Add(i);
|
||||
if (switched) App.TrayIcon?.Notify("Eigene Reihenfolge", "Die Box ist jetzt so sortiert, wie du die Icons ziehst. Ändern unter „Aussehen …“.");
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// Menüs
|
||||
// =====================================================================
|
||||
@@ -448,15 +539,17 @@ public partial class FenceWindow : Window
|
||||
private void MenuButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FenceMenu.Items.Clear();
|
||||
if (Tab is { IsFolder: false } t)
|
||||
if (Tab is { IsCategory: true } t)
|
||||
FenceMenu.Items.Add(MainWindow.MenuItem("In DeskCore öffnen", "", () => App.Win?.ShowCategory(t.Value)));
|
||||
else if (Tab is { IsFolder: true } pt)
|
||||
FenceMenu.Items.Add(MainWindow.MenuItem("Im Explorer öffnen", "", () => Process.Start("explorer.exe", $"\"{CurrentFolder ?? pt.Value}\"")));
|
||||
|
||||
// Tabs
|
||||
var add = MainWindow.MenuItem("Tab hinzufügen", "", null);
|
||||
foreach (var c in Storage.Categories().Where(c => !Def.Tabs.Any(x => !x.IsFolder && string.Equals(x.Value, c, StringComparison.OrdinalIgnoreCase))))
|
||||
foreach (var c in Storage.Categories().Where(c => !Def.Tabs.Any(x => x.IsCategory && string.Equals(x.Value, c, StringComparison.OrdinalIgnoreCase))))
|
||||
add.Items.Add(MainWindow.MenuItem(c, S.Categories.GetValueOrDefault(c)?.Glyph ?? "", () => AddTab(new FenceTab { Value = c })));
|
||||
if (!Def.Tabs.Any(x => x.IsRecent))
|
||||
add.Items.Add(MainWindow.MenuItem("Zuletzt benutzt", "", () => AddTab(new FenceTab { Kind = FenceTab.RecentKind })));
|
||||
if (add.Items.Count > 0) add.Items.Add(new Separator());
|
||||
add.Items.Add(MainWindow.MenuItem("Ordner-Portal…", "", () =>
|
||||
{
|
||||
@@ -475,14 +568,19 @@ public partial class FenceWindow : Window
|
||||
if (S.Pages.Count > 1)
|
||||
{
|
||||
var move = MainWindow.MenuItem("Auf Seite verschieben", "\uE8AB", null);
|
||||
var copy = MainWindow.MenuItem("Auf Seite kopieren", "\uE8C8", null);
|
||||
for (int p = 0; p < S.Pages.Count; p++)
|
||||
{
|
||||
int page = p;
|
||||
var mi = MainWindow.MenuItem(S.Pages[p], "\uE8A1", () => FenceManager.MoveToPage(Def, page));
|
||||
mi.IsEnabled = page != Def.Page;
|
||||
move.Items.Add(mi);
|
||||
var ci = MainWindow.MenuItem(S.Pages[p], "\uE8A1", () => FenceManager.CopyToPage(Def, page));
|
||||
ci.IsEnabled = page != Def.Page;
|
||||
copy.Items.Add(ci);
|
||||
}
|
||||
FenceMenu.Items.Add(move);
|
||||
FenceMenu.Items.Add(copy);
|
||||
}
|
||||
FenceMenu.Items.Add(new Separator());
|
||||
FenceMenu.Items.Add(MainWindow.MenuItem("Box schließen", "", () => FenceManager.Remove(Def)));
|
||||
@@ -495,8 +593,8 @@ public partial class FenceWindow : Window
|
||||
if (index < 0 || index >= Def.Tabs.Count) return;
|
||||
var t = Def.Tabs[index];
|
||||
var menu = new ContextMenu();
|
||||
if (!t.IsFolder) menu.Items.Add(MainWindow.MenuItem("In DeskCore öffnen", "", () => App.Win?.ShowCategory(t.Value)));
|
||||
else menu.Items.Add(MainWindow.MenuItem("Im Explorer öffnen", "", () => Process.Start("explorer.exe", $"\"{t.Value}\"")));
|
||||
if (t.IsCategory) menu.Items.Add(MainWindow.MenuItem("In DeskCore öffnen", "", () => App.Win?.ShowCategory(t.Value)));
|
||||
else if (t.IsFolder) menu.Items.Add(MainWindow.MenuItem("Im Explorer öffnen", "", () => Process.Start("explorer.exe", $"\"{t.Value}\"")));
|
||||
if (Def.Tabs.Count > 1)
|
||||
{
|
||||
menu.Items.Add(MainWindow.MenuItem("Als eigene Box lösen", "", () => FenceManager.DetachTab(Def, index)));
|
||||
@@ -507,8 +605,8 @@ public partial class FenceWindow : Window
|
||||
|
||||
private void AddTab(FenceTab tab)
|
||||
{
|
||||
// Kategorie steckt schon in einer anderen Box? Dann dorthin verschieben statt doppelt anzeigen
|
||||
if (!tab.IsFolder) FenceManager.RemoveCategoryTab(tab.Value, except: Def);
|
||||
// Kategorie steckt auf dieser Seite schon in einer anderen Box? Dann hierher holen statt doppelt anzeigen
|
||||
if (tab.IsCategory) FenceManager.RemoveCategoryTab(tab.Value, except: Def, Def.Page);
|
||||
Def.Tabs.Add(tab);
|
||||
Def.ActiveTab = Def.Tabs.Count - 1;
|
||||
_portalSub = null;
|
||||
|
||||
Reference in New Issue
Block a user