Upload via GUI (180 Dateien)
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace DeskCore;
|
||||
|
||||
/// <summary>Verknüpfungen zu deinstallierten Programmen automatisch aus den Kategorien entfernen.</summary>
|
||||
public partial class MainWindow
|
||||
{
|
||||
private DispatcherTimer? _deadScanTimer;
|
||||
private DispatcherTimer? _deadScanPeriodic;
|
||||
private bool _deadScanRunning;
|
||||
private DispatcherTimer? _deadConfirmTimer;
|
||||
private readonly Dictionary<string, DateTime> _deadSince = new(StringComparer.OrdinalIgnoreCase);
|
||||
private static readonly TimeSpan ConfirmAfter = TimeSpan.FromSeconds(60);
|
||||
|
||||
/// <summary>Zweite Prüfung kurz nach Ablauf der Wartezeit.</summary>
|
||||
private void ScheduleConfirmScan()
|
||||
{
|
||||
if (_deadConfirmTimer is null)
|
||||
{
|
||||
_deadConfirmTimer = new DispatcherTimer { Interval = ConfirmAfter + TimeSpan.FromSeconds(5) };
|
||||
_deadConfirmTimer.Tick += (_, _) => { _deadConfirmTimer.Stop(); CleanupDeadShortcuts(); };
|
||||
}
|
||||
if (!_deadConfirmTimer.IsEnabled) _deadConfirmTimer.Start();
|
||||
}
|
||||
|
||||
/// <summary>Einmal beim Start einrichten: Prüfung kurz nach dem Start und danach alle 10 Minuten.</summary>
|
||||
public void StartDeadShortcutWatch()
|
||||
{
|
||||
_deadScanTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(4) };
|
||||
_deadScanTimer.Tick += (_, _) => { _deadScanTimer.Stop(); CleanupDeadShortcuts(); };
|
||||
// Deinstallationen über die Windows-Einstellungen ändern unsere Ordner nicht → zusätzlich regelmäßig prüfen
|
||||
_deadScanPeriodic = new DispatcherTimer { Interval = TimeSpan.FromMinutes(10) };
|
||||
_deadScanPeriodic.Tick += (_, _) => CleanupDeadShortcuts();
|
||||
_deadScanPeriodic.Start();
|
||||
ScheduleDeadShortcutScan();
|
||||
}
|
||||
|
||||
/// <summary>Nach Änderungen (z. B. Deinstallation entfernt die Desktop-Verknüpfung) gebündelt prüfen.</summary>
|
||||
public void ScheduleDeadShortcutScan()
|
||||
{
|
||||
if (_deadScanTimer is null) return;
|
||||
_deadScanTimer.Stop();
|
||||
_deadScanTimer.Start();
|
||||
}
|
||||
|
||||
private async void CleanupDeadShortcuts()
|
||||
{
|
||||
if (!S.RemoveDeadShortcuts || _deadScanRunning || IsBusy) return;
|
||||
_deadScanRunning = true;
|
||||
try
|
||||
{
|
||||
var keep = S.KeptShortcuts.ToList();
|
||||
var found = await Task.Run(() => Storage.FindDeadShortcuts(keep));
|
||||
|
||||
// Updates ersetzen ihre Programmdatei manchmal kurz → erst entfernen, wenn sie mindestens
|
||||
// eine Minute lang fehlt (zweite Prüfung), sonst würde ein laufendes Update fälschlich aufgeräumt
|
||||
var now = DateTime.UtcNow;
|
||||
foreach (var p in _deadSince.Keys.Where(k => !found.Contains(k, StringComparer.OrdinalIgnoreCase)).ToList())
|
||||
_deadSince.Remove(p);
|
||||
foreach (var p in found) _deadSince.TryAdd(p, now);
|
||||
var dead = found.Where(p => now - _deadSince[p] >= ConfirmAfter).ToList();
|
||||
if (dead.Count < found.Count) ScheduleConfirmScan();
|
||||
if (dead.Count == 0) return;
|
||||
foreach (var p in dead) _deadSince.Remove(p);
|
||||
|
||||
var entry = new UndoEntry(dead.Count == 1
|
||||
? $"„{Storage.DisplayName(dead[0])}“ entfernen (Programm deinstalliert)"
|
||||
: $"{dead.Count} Verknüpfungen deinstallierter Programme entfernen");
|
||||
var removed = new List<string>();
|
||||
foreach (var p in dead)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Reihenfolge beim Rückgängigmachen: erst zurückholen, dann merken, dass sie bleiben soll
|
||||
var path = p;
|
||||
entry.Add(() =>
|
||||
{
|
||||
if (!S.KeptShortcuts.Contains(path, StringComparer.OrdinalIgnoreCase)) S.KeptShortcuts.Add(path);
|
||||
S.Save();
|
||||
return null;
|
||||
});
|
||||
entry.AddDelete(p, Storage.Delete(p));
|
||||
removed.Add(p);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
if (removed.Count == 0) return;
|
||||
Undo.Push(entry);
|
||||
Refresh();
|
||||
FenceManager.RefreshAll();
|
||||
|
||||
var text = removed.Count == 1
|
||||
? $"„{Storage.DisplayName(removed[0])}“ entfernt – das Programm ist nicht mehr installiert"
|
||||
: $"{removed.Count} Verknüpfungen entfernt – die Programme sind nicht mehr installiert";
|
||||
if (IsVisible && IsActive) ShowToast(text, "", undoable: true);
|
||||
else App.TrayIcon?.Notify("Aufgeräumt", text);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_deadScanRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void DeadShortcutsToggle_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
S.RemoveDeadShortcuts = DeadShortcutsToggle.IsChecked == true;
|
||||
// beim Einschalten: früher behaltene Verknüpfungen wieder prüfen lassen
|
||||
if (S.RemoveDeadShortcuts) S.KeptShortcuts.RemoveAll(p => !File.Exists(p));
|
||||
S.Save();
|
||||
if (S.RemoveDeadShortcuts) ScheduleDeadShortcutScan();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user