Skip to content

Commit 7e67727

Browse files
committed
feat: always-keep protection flag — protected programs skip batch uninstall, persisted in config
1 parent a21d4a3 commit 7e67727

3 files changed

Lines changed: 83 additions & 0 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System.Text.Json;
2+
using DeepPurge.Core.Diagnostics;
3+
4+
namespace DeepPurge.Core.App;
5+
6+
public static class ProtectedPrograms
7+
{
8+
private static readonly string FilePath = Path.Combine(DataPaths.Config, "protected-programs.json");
9+
private static HashSet<string>? _list;
10+
11+
public static HashSet<string> List
12+
{
13+
get
14+
{
15+
_list ??= Load();
16+
return _list;
17+
}
18+
}
19+
20+
public static bool IsProtected(string displayName)
21+
=> !string.IsNullOrEmpty(displayName) && List.Contains(displayName);
22+
23+
public static void Add(string displayName)
24+
{
25+
if (string.IsNullOrWhiteSpace(displayName)) return;
26+
List.Add(displayName);
27+
Save();
28+
}
29+
30+
public static void Remove(string displayName)
31+
{
32+
if (string.IsNullOrWhiteSpace(displayName)) return;
33+
List.Remove(displayName);
34+
Save();
35+
}
36+
37+
public static void Toggle(string displayName)
38+
{
39+
if (IsProtected(displayName)) Remove(displayName);
40+
else Add(displayName);
41+
}
42+
43+
private static HashSet<string> Load()
44+
{
45+
try
46+
{
47+
if (!File.Exists(FilePath)) return new(StringComparer.OrdinalIgnoreCase);
48+
var json = File.ReadAllText(FilePath);
49+
var list = JsonSerializer.Deserialize<List<string>>(json);
50+
return list != null ? new(list, StringComparer.OrdinalIgnoreCase) : new(StringComparer.OrdinalIgnoreCase);
51+
}
52+
catch (Exception ex)
53+
{
54+
Log.Warn($"Failed to load protected programs: {ex.Message}");
55+
return new(StringComparer.OrdinalIgnoreCase);
56+
}
57+
}
58+
59+
private static void Save()
60+
{
61+
try
62+
{
63+
Directory.CreateDirectory(Path.GetDirectoryName(FilePath)!);
64+
var json = JsonSerializer.Serialize(_list?.ToList() ?? new());
65+
File.WriteAllText(FilePath, json);
66+
}
67+
catch (Exception ex) { Log.Warn($"Failed to save protected programs: {ex.Message}"); }
68+
}
69+
}

src/DeepPurge.Core/Models/InstalledProgram.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,20 @@ public object? Icon
3939
set { _icon = value; OnPropertyChanged(); }
4040
}
4141

42+
private bool _isProtected;
43+
4244
public bool IsSelected
4345
{
4446
get => _isSelected;
4547
set { _isSelected = value; OnPropertyChanged(); }
4648
}
4749

50+
public bool IsProtected
51+
{
52+
get => _isProtected;
53+
set { _isProtected = value; OnPropertyChanged(); }
54+
}
55+
4856
public string EstimatedSizeDisplay
4957
{
5058
get

src/DeepPurge.Core/Uninstall/UninstallEngine.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,12 @@ public async Task<List<UninstallResult>> UninstallBatchAsync(
305305
ct.ThrowIfCancellationRequested();
306306
var program = programs[i];
307307

308+
if (program.IsProtected || App.ProtectedPrograms.IsProtected(program.DisplayName))
309+
{
310+
StatusChanged?.Invoke($"[{i + 1}/{programs.Count}] Skipping protected: {program.DisplayName}");
311+
continue;
312+
}
313+
308314
StatusChanged?.Invoke($"[{i + 1}/{programs.Count}] Uninstalling {program.DisplayName}...");
309315

310316
// Create a single restore point at the start of the batch rather

0 commit comments

Comments
 (0)