using System.Diagnostics; using System.IO; using System.Text.Json; using System.Windows.Threading; namespace DeskCore; public class UsageEntry { public int Count { get; set; } public DateTime Last { get; set; } } /// /// Merkt sich, was wie oft und wann zuletzt über DeskCore gestartet wurde (für „Meistgenutzt“, „Zuletzt benutzt“ /// und die Schnellstart-Suche). Liegt getrennt von den Einstellungen in usage.json, weil es sich ständig ändert. /// public static class Usage { /// Schlüssel-Präfix für Start-Gruppen (die keinen Dateipfad haben). public const string GroupPrefix = "gruppe:"; private static readonly string FilePath = Path.Combine(AppSettings.Folder, "usage.json"); private static readonly Dictionary _data = Load(); private static DispatcherTimer? _saveTimer; /// Etwas wurde gestartet (z. B. damit „Zuletzt benutzt“-Boxen sich aktualisieren). public static event Action? Changed; private static Dictionary Load() { try { if (File.Exists(FilePath) && JsonSerializer.Deserialize>(File.ReadAllText(FilePath)) is { } d) return new(d, StringComparer.OrdinalIgnoreCase); } catch { } return new(StringComparer.OrdinalIgnoreCase); } /// Programm/Datei starten und den Start mitzählen. Wirft bei Fehlern wie Process.Start. public static void Start(string path) { Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); Record(path); } public static void Record(string key) { if (!_data.TryGetValue(key, out var e)) _data[key] = e = new UsageEntry(); e.Count++; e.Last = DateTime.Now; ScheduleSave(); Changed?.Invoke(); } public static int Count(string key) => _data.TryGetValue(key, out var e) ? e.Count : 0; /// /// Wie „beliebt“ etwas ist: Anzahl der Starts, mit der Zeit abnehmend gewichtet – /// was du früher oft, aber seit Wochen nicht mehr benutzt hast, rutscht langsam nach hinten. /// public static double Score(string key) { if (!_data.TryGetValue(key, out var e)) return 0; double days = Math.Max(0, (DateTime.Now - e.Last).TotalDays); return e.Count / (1 + days / 30); } /// Zuletzt gestartete Dateien, die es noch gibt (neueste zuerst). public static List Recent(int max) => _data .Where(kv => !kv.Key.StartsWith(GroupPrefix) && (File.Exists(kv.Key) || Directory.Exists(kv.Key))) .OrderByDescending(kv => kv.Value.Last) .Take(max) .Select(kv => kv.Key) .ToList(); /// Datei wurde umbenannt/verschoben → Zählung mitnehmen. public static void Rename(string oldKey, string newKey) { if (!_data.Remove(oldKey, out var e)) return; if (_data.TryGetValue(newKey, out var existing)) { existing.Count += e.Count; if (e.Last > existing.Last) existing.Last = e.Last; } else _data[newKey] = e; ScheduleSave(); } public static void Forget(string key) { if (_data.Remove(key)) { ScheduleSave(); Changed?.Invoke(); } } private static void ScheduleSave() { _saveTimer ??= new DispatcherTimer(TimeSpan.FromSeconds(2), DispatcherPriority.Background, (_, _) => Flush(), Dispatcher.CurrentDispatcher); _saveTimer.Stop(); _saveTimer.Start(); } /// Sofort speichern (z. B. beim Beenden). public static void Flush() { _saveTimer?.Stop(); try { // Nicht mehr vorhandene Einträge, die lange nicht benutzt wurden, aufräumen foreach (var key in _data.Where(kv => kv.Value.Last < DateTime.Now.AddDays(-180) && !kv.Key.StartsWith(GroupPrefix) && !File.Exists(kv.Key) && !Directory.Exists(kv.Key)).Select(kv => kv.Key).ToList()) _data.Remove(key); Directory.CreateDirectory(AppSettings.Folder); File.WriteAllText(FilePath, JsonSerializer.Serialize(_data)); } catch { } } }