Skip to content

Commit 2e1c35e

Browse files
committed
重构 CommandHelper 和 KitopiaExplorerCommand,简化路径解析逻辑并固定配置路径至 AppData
1 parent fa80fbc commit 2e1c35e

File tree

9 files changed

+76
-236
lines changed

9 files changed

+76
-236
lines changed

ContextMenu.Avalonia/ViewModels/MainWindowViewModel.cs

Lines changed: 29 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,15 @@
44
using System.IO;
55
using System.Text.Json;
66
using System.Threading.Tasks;
7-
using Avalonia;
8-
using Avalonia.Controls.ApplicationLifetimes;
9-
using Avalonia.Platform.Storage;
107
using CommunityToolkit.Mvvm.ComponentModel;
118
using CommunityToolkit.Mvvm.Input;
12-
using Microsoft.Win32;
139
using Windows.Storage;
1410

1511
namespace ContextMenu.Avalonia.ViewModels;
1612

1713
public partial class MainWindowViewModel : ViewModelBase
1814
{
15+
private const string AppName = "Kitopia";
1916
private const string SettingsFileName = "ContextMenuSettings.json";
2017
private const string ConfigFileName = "KitopiaContextMenu.json";
2118

@@ -38,39 +35,19 @@ private async Task LoadDataAsync()
3835
{
3936
try
4037
{
41-
// 0. Check for Saved Manual Path
38+
// 0. Resolve install path
4239
var settings = LoadSettings();
43-
string? installPath = null;
44-
45-
if (!string.IsNullOrEmpty(settings.ExternalConfigPath))
46-
{
47-
// Try to infer install path from config path (..\configs\file.json)
48-
var configDir = Path.GetDirectoryName(settings.ExternalConfigPath);
49-
if (configDir != null)
50-
{
51-
var inferredPath = Path.GetDirectoryName(configDir); // Parent of configs
52-
if (inferredPath != null && Directory.Exists(inferredPath))
53-
{
54-
installPath = inferredPath;
55-
}
56-
}
57-
}
40+
KitopiaPath = GetAppRootPath();
5841

59-
// 1. If no manual path, Find Kitopia Path from Registry
60-
if (string.IsNullOrEmpty(installPath))
61-
{
62-
installPath = FindKitopiaInstallPath();
63-
}
64-
65-
if (string.IsNullOrEmpty(installPath))
42+
if (string.IsNullOrWhiteSpace(KitopiaPath))
6643
{
6744
StatusMessage = "未找到 Kitopia 安装位置,请手动设置。";
6845
return;
6946
}
70-
KitopiaPath = installPath;
47+
// install path search is removed; config path is fixed under AppData
7148

7249
// 2. Locate Config
73-
var configPath = Path.Combine(installPath, "configs", ConfigFileName);
50+
var configPath = GetConfigPath();
7451
if (!File.Exists(configPath))
7552
{
7653
StatusMessage = $"未找到配置文件: {configPath}";
@@ -123,100 +100,9 @@ private async Task LoadDataAsync()
123100
}
124101

125102
[RelayCommand]
126-
private async Task BrowsePath()
103+
private void BrowsePath()
127104
{
128-
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
129-
{
130-
var folders = await desktop.MainWindow.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
131-
{
132-
Title = "选择 Kitopia 安装文件夹",
133-
AllowMultiple = false
134-
});
135-
136-
if (folders.Count > 0)
137-
{
138-
var path = folders[0].Path.LocalPath;
139-
140-
// Verify it looks like Kitopia (check for executable or configs folder)
141-
if (File.Exists(Path.Combine(path, "Kitopia.StoreCompanion.exe")) ||
142-
File.Exists(Path.Combine(path, "KitopiaAvalonia.exe")) ||
143-
Directory.Exists(Path.Combine(path, "configs")))
144-
{
145-
KitopiaPath = path;
146-
147-
// Update settings with new config path
148-
var settings = LoadSettings();
149-
settings.ExternalConfigPath = Path.Combine(KitopiaPath, "configs", ConfigFileName);
150-
SaveSettings(settings);
151-
152-
// Reload
153-
await LoadDataAsync();
154-
}
155-
else
156-
{
157-
StatusMessage = "选择的文件夹似乎不是有效的 Kitopia 安装目录。";
158-
}
159-
}
160-
}
161-
}
162-
163-
private string? FindKitopiaInstallPath()
164-
{
165-
try
166-
{
167-
// Check HKLM and HKCU Uninstall keys
168-
string[] roots = {
169-
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
170-
@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
171-
};
172-
173-
foreach (var root in roots)
174-
{
175-
using var key = Registry.LocalMachine.OpenSubKey(root);
176-
if (key != null)
177-
{
178-
SearchRegistryKey(key, out var path);
179-
if (!string.IsNullOrEmpty(path)) return path;
180-
}
181-
}
182-
183-
// Try HKCU
184-
using var cuKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
185-
if (cuKey != null)
186-
{
187-
SearchRegistryKey(cuKey, out var path);
188-
if (!string.IsNullOrEmpty(path)) return path;
189-
}
190-
191-
}
192-
catch { }
193-
return null;
194-
195-
void SearchRegistryKey(RegistryKey root, out string? foundPath)
196-
{
197-
foundPath = null;
198-
foreach (var subKeyName in root.GetSubKeyNames())
199-
{
200-
using var subKey = root.OpenSubKey(subKeyName);
201-
if (subKey == null) continue;
202-
203-
var displayName = subKey.GetValue("DisplayName") as string;
204-
if (displayName != null && displayName.Contains("Kitopia") && !displayName.Contains("Packing"))
205-
{
206-
var installLocation = subKey.GetValue("InstallLocation") as string;
207-
if (string.IsNullOrEmpty(installLocation))
208-
{
209-
installLocation = subKey.GetValue("Path") as string; // ModernInstaller uses "Path"
210-
}
211-
212-
if (!string.IsNullOrEmpty(installLocation) && Directory.Exists(installLocation))
213-
{
214-
foundPath = installLocation;
215-
return;
216-
}
217-
}
218-
}
219-
}
105+
StatusMessage = $"配置路径已固定: {GetConfigPath()}";
220106
}
221107

222108
private ContextMenuSettings LoadSettings()
@@ -242,7 +128,7 @@ private void SaveSettings(ContextMenuSettings? settings = null)
242128
{
243129
settings = new ContextMenuSettings
244130
{
245-
ExternalConfigPath = Path.Combine(KitopiaPath, "configs", ConfigFileName)
131+
ExternalConfigPath = GetConfigPath()
246132
};
247133
foreach (var item in Items)
248134
{
@@ -263,6 +149,26 @@ private void SaveSettings(ContextMenuSettings? settings = null)
263149
}
264150
}
265151

152+
private static string GetConfigPath()
153+
{
154+
var configsDirectory = Path.Combine(GetAppRootPath(), "configs");
155+
Directory.CreateDirectory(configsDirectory);
156+
return Path.Combine(configsDirectory, ConfigFileName);
157+
}
158+
159+
private static string GetAppRootPath()
160+
{
161+
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
162+
if (string.IsNullOrWhiteSpace(localAppData))
163+
{
164+
localAppData = AppDomain.CurrentDomain.BaseDirectory;
165+
}
166+
167+
var root = Path.Combine(localAppData, AppName);
168+
Directory.CreateDirectory(root);
169+
return root;
170+
}
171+
266172
private string GetSettingsPath()
267173
{
268174
// Try Package LocalState first

ContextMenuDll/CommandHelper.cs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,17 @@ namespace ContextMenuDll;
55

66
public static class CommandHelper
77
{
8-
public static string ResolvePath(string path, string? kitopiaPath)
8+
public static string ResolvePath(string path)
99
{
1010
if (string.IsNullOrEmpty(path)) return path;
1111

1212
// If absolute, return as is
1313
if (Path.IsPathRooted(path)) return path;
1414

15-
// If we have kitopia path, combine
16-
if (!string.IsNullOrEmpty(kitopiaPath))
17-
{
18-
return Path.Combine(kitopiaPath, path);
19-
}
20-
2115
return path;
2216
}
2317

24-
public static void ExecuteCommand(ContextMenuItem item, List<string> paths, string? kitopiaPath, Action<string> logAction)
18+
public static void ExecuteCommand(ContextMenuItem item, List<string> paths, Action<string> logAction)
2519
{
2620
if (string.IsNullOrEmpty(item.Command)) return;
2721

@@ -31,7 +25,7 @@ public static void ExecuteCommand(ContextMenuItem item, List<string> paths, stri
3125
{
3226
// Simple replacement logic
3327
string args = item.Arguments ?? string.Empty;
34-
string command = ResolvePath(item.Command, kitopiaPath);
28+
string command = ResolvePath(item.Command);
3529

3630
// Case 1: Multi-file placeholder {all} or %*
3731
if (args.Contains("{all}") || args.Contains("%*"))
@@ -97,7 +91,7 @@ public static void ExecuteCommand(ContextMenuItem item, List<string> paths, stri
9791
else
9892
{
9993
// No files selected (background click?), just run command
100-
string command = ResolvePath(item.Command, kitopiaPath);
94+
string command = ResolvePath(item.Command);
10195
logAction($"Executing (No files): {command} Args: {item.Arguments}");
10296

10397
Process.Start(new ProcessStartInfo

ContextMenuDll/KitopiaExplorerCommand.Legacy.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Runtime.InteropServices;
1+
using System.Runtime.InteropServices;
22
using System.Text;
33
using ContextMenuDll.Interop;
44

@@ -158,7 +158,7 @@ public int InvokeCommand(IntPtr pici)
158158
{
159159
var item = _cmdIdMap[id];
160160
Log($"InvokeCommand: {item.Title}");
161-
CommandHelper.ExecuteCommand(item, _legacySelectedPaths, _kitopiaPath, Log);
161+
CommandHelper.ExecuteCommand(item, _legacySelectedPaths, Log);
162162
}
163163
}
164164
}

0 commit comments

Comments
 (0)