From 6f70ebc4c459c5337bdc8fe3c39fb6f49335026e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Mon, 8 Sep 2025 00:32:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BB=BB=E5=8A=A1=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E7=AA=97=E5=8F=A3=EF=BC=8C=E8=B0=83=E6=95=B4=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=B7=BB=E5=8A=A0=E9=80=BB=E8=BE=91=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=8D=95=E4=B8=AA=E4=BB=BB=E5=8A=A1=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=92=8C=E7=9B=AE=E5=BD=95=E7=BB=93=E6=9E=84=E4=BF=9D=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PathingTaskSelectionWindow.xaml.cs | 213 +++++++++--------- .../Pages/GearTaskListPageViewModel.cs | 9 +- .../GearTask/PathingTaskSelectionViewModel.cs | 142 ++++++------ 3 files changed, 183 insertions(+), 181 deletions(-) diff --git a/BetterGenshinImpact/View/Windows/GearTask/PathingTaskSelectionWindow.xaml.cs b/BetterGenshinImpact/View/Windows/GearTask/PathingTaskSelectionWindow.xaml.cs index 35cc5dde..6d80ed7e 100644 --- a/BetterGenshinImpact/View/Windows/GearTask/PathingTaskSelectionWindow.xaml.cs +++ b/BetterGenshinImpact/View/Windows/GearTask/PathingTaskSelectionWindow.xaml.cs @@ -32,17 +32,18 @@ public partial class PathingTaskSelectionWindow : FluentWindow /// 选中的任务 /// public PathingTaskInfo? SelectedTask { get; private set; } + + /// + /// 选中的任务 + /// + public GearTaskViewModel? SelectedGearTask { get; private set; } + /// /// 对话框结果 /// public bool DialogResult { get; private set; } - /// - /// 添加的任务列表 - /// - public List AddedTasks { get; private set; } = new(); - /// /// 目录到符号图标的转换器 /// @@ -64,10 +65,10 @@ public partial class PathingTaskSelectionWindow : FluentWindow /// /// 任务添加事件处理 /// - private void OnTaskAdded(List tasks) + private void OnTaskAdded(GearTaskViewModel? task) { - AddedTasks.AddRange(tasks); - + SelectedGearTask = task; + // 添加任务后自动关闭窗口 CloseWithResult(); } @@ -185,101 +186,101 @@ public class NullToVisibilityConverter : IValueConverter } } -/// -/// 字符串到ImageSource的转换器,处理空字符串情况,支持WebP格式 -/// -public class StringToImageSourceConverter : IValueConverter -{ - private static readonly HttpClient HttpClient = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is string url && !string.IsNullOrEmpty(url)) - { - try - { - // 检查是否为WebP格式或其他需要特殊处理的格式 - if (url.Contains(".webp", StringComparison.OrdinalIgnoreCase)) - { - return LoadWebPImage(url); - } - else - { - // 对于其他格式,使用原有的BitmapImage - return new BitmapImage(new Uri(url)); - } - } - catch (Exception e) - { - Debug.WriteLine(e); - return null; - } - } - return null; - } - - private static BitmapSource? LoadWebPImage(string url) - { - try - { - byte[] imageData; - - if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - // 从网络加载 - imageData = HttpClient.GetByteArrayAsync(url).Result; - } - else - { - // 从本地文件加载 - imageData = File.ReadAllBytes(url); - } - - using var image = Image.Load(imageData); - - // 转换为WPF可用的BitmapSource - var bitmap = new WriteableBitmap(image.Width, image.Height, 96, 96, PixelFormats.Bgra32, null); - - bitmap.Lock(); - try - { - var backBuffer = bitmap.BackBuffer; - var stride = bitmap.BackBufferStride; - - image.ProcessPixelRows(accessor => - { - for (int y = 0; y < accessor.Height; y++) - { - var pixelRow = accessor.GetRowSpan(y); - var targetPtr = backBuffer + y * stride; - - for (int x = 0; x < pixelRow.Length; x++) - { - var pixel = pixelRow[x]; - // 转换RGBA到BGRA - var bgra = (pixel.A << 24) | (pixel.R << 16) | (pixel.G << 8) | pixel.B; - System.Runtime.InteropServices.Marshal.WriteInt32(targetPtr + x * 4, bgra); - } - } - }); - } - finally - { - bitmap.AddDirtyRect(new Int32Rect(0, 0, image.Width, image.Height)); - bitmap.Unlock(); - } - - return bitmap; - } - catch (Exception e) - { - Debug.WriteLine($"Failed to load WebP image: {e}"); - return null; - } - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } -} \ No newline at end of file +// /// +// /// 字符串到ImageSource的转换器,处理空字符串情况,支持WebP格式 +// /// +// public class StringToImageSourceConverter : IValueConverter +// { +// private static readonly HttpClient HttpClient = new(); +// +// public object Convert(object value, Type targetType, object parameter, CultureInfo culture) +// { +// if (value is string url && !string.IsNullOrEmpty(url)) +// { +// try +// { +// // 检查是否为WebP格式或其他需要特殊处理的格式 +// if (url.Contains(".webp", StringComparison.OrdinalIgnoreCase)) +// { +// return LoadWebPImage(url); +// } +// else +// { +// // 对于其他格式,使用原有的BitmapImage +// return new BitmapImage(new Uri(url)); +// } +// } +// catch (Exception e) +// { +// Debug.WriteLine(e); +// return null; +// } +// } +// return null; +// } +// +// private static BitmapSource? LoadWebPImage(string url) +// { +// try +// { +// byte[] imageData; +// +// if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) +// { +// // 从网络加载 +// imageData = HttpClient.GetByteArrayAsync(url).Result; +// } +// else +// { +// // 从本地文件加载 +// imageData = File.ReadAllBytes(url); +// } +// +// using var image = Image.Load(imageData); +// +// // 转换为WPF可用的BitmapSource +// var bitmap = new WriteableBitmap(image.Width, image.Height, 96, 96, PixelFormats.Bgra32, null); +// +// bitmap.Lock(); +// try +// { +// var backBuffer = bitmap.BackBuffer; +// var stride = bitmap.BackBufferStride; +// +// image.ProcessPixelRows(accessor => +// { +// for (int y = 0; y < accessor.Height; y++) +// { +// var pixelRow = accessor.GetRowSpan(y); +// var targetPtr = backBuffer + y * stride; +// +// for (int x = 0; x < pixelRow.Length; x++) +// { +// var pixel = pixelRow[x]; +// // 转换RGBA到BGRA +// var bgra = (pixel.A << 24) | (pixel.R << 16) | (pixel.G << 8) | pixel.B; +// System.Runtime.InteropServices.Marshal.WriteInt32(targetPtr + x * 4, bgra); +// } +// } +// }); +// } +// finally +// { +// bitmap.AddDirtyRect(new Int32Rect(0, 0, image.Width, image.Height)); +// bitmap.Unlock(); +// } +// +// return bitmap; +// } +// catch (Exception e) +// { +// Debug.WriteLine($"Failed to load WebP image: {e}"); +// return null; +// } +// } +// +// public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) +// { +// throw new NotImplementedException(); +// } +// } \ No newline at end of file diff --git a/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs index 654e348a..0b307916 100644 --- a/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/GearTaskListPageViewModel.cs @@ -371,14 +371,9 @@ public partial class GearTaskListPageViewModel : ViewModel pathingSelectionWindow.ShowDialog(); - if (pathingSelectionWindow.DialogResult && pathingSelectionWindow.SelectedTask != null) + if (pathingSelectionWindow.DialogResult && pathingSelectionWindow.SelectedGearTask != null) { - var selectedTask = pathingSelectionWindow.SelectedTask; - newTask = new GearTaskViewModel(selectedTask.Name) - { - TaskType = "Pathing", - Path = selectedTask.RelativePath - }; + newTask = pathingSelectionWindow.SelectedGearTask; } else { diff --git a/BetterGenshinImpact/ViewModel/Windows/GearTask/PathingTaskSelectionViewModel.cs b/BetterGenshinImpact/ViewModel/Windows/GearTask/PathingTaskSelectionViewModel.cs index 539e7c65..868a8d6d 100644 --- a/BetterGenshinImpact/ViewModel/Windows/GearTask/PathingTaskSelectionViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Windows/GearTask/PathingTaskSelectionViewModel.cs @@ -71,7 +71,7 @@ public partial class PathingTaskSelectionViewModel : ViewModel LoadPathingTasks(); } - public Action>? OnTaskAdded { get; set; } + public Action? OnTaskAdded { get; set; } // /// // /// 加载图标字典 @@ -415,7 +415,7 @@ public partial class PathingTaskSelectionViewModel : ViewModel }; // 触发添加事件或通过其他方式返回给调用方 - OnTaskAdded?.Invoke([gearTaskViewModel]); + OnTaskAdded?.Invoke(gearTaskViewModel); } } @@ -427,8 +427,8 @@ public partial class PathingTaskSelectionViewModel : ViewModel { if (SelectedTask?.IsDirectory == true) { - var tasks = GetAllFolderTasksInDirectoryWithStructure(SelectedTask); - OnTaskAdded?.Invoke(tasks); + var task = GetAllFolderTasksInDirectoryWithStructure(SelectedTask); + OnTaskAdded?.Invoke(task); } } @@ -440,23 +440,29 @@ public partial class PathingTaskSelectionViewModel : ViewModel { if (SelectedTask?.IsDirectory == true) { + var rootGearTaskViewModel = new GearTaskViewModel + { + Name = SelectedTask.Name, + IsDirectory = true + }; + // 逐个添加:添加目录下所有JSON文件作为独立任务 var taskInfos = GetAllJsonFilesInDirectory(SelectedTask); - var tasks = new List(); foreach (var taskInfo in taskInfos) { var gearTaskViewModel = new GearTaskViewModel { Name = Path.GetFileNameWithoutExtension(taskInfo.Name), + TaskType = "Pathing", Path = @$"{{pathingRepoFolder}}\{taskInfo.RelativePath}\", IsDirectory = false }; - tasks.Add(gearTaskViewModel); + rootGearTaskViewModel.Children.Add(gearTaskViewModel); } - if (tasks.Count > 0) + if (rootGearTaskViewModel.Children.Count > 0) { - OnTaskAdded?.Invoke(tasks); + OnTaskAdded?.Invoke(rootGearTaskViewModel); } } } @@ -470,8 +476,8 @@ public partial class PathingTaskSelectionViewModel : ViewModel if (SelectedTask?.IsDirectory == true) { // 保持目录结构添加所有子任务 - var tasks = GetAllFileTasksInDirectoryWithStructure(SelectedTask); - OnTaskAdded?.Invoke(tasks); + var task = GetAllFileTasksInDirectoryWithStructure(SelectedTask); + OnTaskAdded?.Invoke(task); } } @@ -504,88 +510,88 @@ public partial class PathingTaskSelectionViewModel : ViewModel /// /// 获取目录下所有json文件任务并保持结构 /// - private List GetAllFileTasksInDirectoryWithStructure(PathingTaskInfo directory) + private GearTaskViewModel? GetAllFileTasksInDirectoryWithStructure(PathingTaskInfo node) { - var tasks = new List(); - - if (directory.Children is { Count: > 0 }) + if (node.IsDirectory) { - foreach (var child in directory.Children) + // 添加子目录作为组 + var groupTask = new GearTaskViewModel { - if (child.IsDirectory) - { - // 添加子目录作为组 - var groupTask = new GearTaskViewModel - { - Name = child.Name, - IsDirectory = true - }; - tasks.Add(groupTask); + Name = node.Name, + IsDirectory = true + }; - // 递归添加子任务 - tasks.AddRange(GetAllFileTasksInDirectoryWithStructure(child)); - } - else if (child.FullPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase)) + foreach (var pathingTaskInfo in node.Children) + { + var gearTask = GetAllFileTasksInDirectoryWithStructure(pathingTaskInfo); + if (gearTask != null) { - // 添加JSON文件作为任务 - var fileTask = new GearTaskViewModel - { - Name = Path.GetFileNameWithoutExtension(child.Name), - Path = @$"{{pathingRepoFolder}}\{child.RelativePath}\", - IsDirectory = false - }; - tasks.Add(fileTask); + groupTask.Children.Add(gearTask); } } + + return groupTask; + } + else if (node.FullPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase)) + { + // 添加JSON文件作为任务 + var fileTask = new GearTaskViewModel + { + Name = Path.GetFileNameWithoutExtension(node.Name), + TaskType = "Pathing", + Path = @$"{{pathingRepoFolder}}\{node.RelativePath}\", + IsDirectory = false + }; + return fileTask; } - return tasks; + return null; } /// /// 获取目录下所有文件夹任务并保持结构 /// - private List GetAllFolderTasksInDirectoryWithStructure(PathingTaskInfo directory) + private GearTaskViewModel? GetAllFolderTasksInDirectoryWithStructure(PathingTaskInfo directory) { - var tasks = new List(); - if (directory.Children is { Count: > 0 }) { - foreach (var child in directory.Children) + // 判断 directory 的子节点是否是文件 + var hasJsonFile = directory.Children.Any(grandChild => !grandChild.IsDirectory && grandChild.FullPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase)); + if (hasJsonFile) { - if (child.IsDirectory) + // 添加子目录作为任务 + var groupTask = new GearTaskViewModel { - // 判断 child 的子节点是否是文件 - var hasJsonFile = child.Children.Any(grandChild => !grandChild.IsDirectory && grandChild.FullPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase)); - if (hasJsonFile) + Name = directory.Name, + TaskType = "Pathing", + Path = @$"{{pathingRepoFolder}}\{directory.RelativePath}\", + IsDirectory = false + }; + return groupTask; + } + else + { + // 添加子目录作为组 + var groupTask = new GearTaskViewModel + { + Name = directory.Name, + IsDirectory = true + }; + foreach (var pathingTaskInfo in directory.Children) + { + var gearTask = GetAllFolderTasksInDirectoryWithStructure(pathingTaskInfo); + if (gearTask != null) { - // 添加子目录作为任务 - var groupTask = new GearTaskViewModel - { - Name = child.Name, - TaskType = "Pathing", - Path = @$"{{pathingRepoFolder}}\{child.RelativePath}\", - IsDirectory = false - }; - tasks.Add(groupTask); - } - else - { - // 添加子目录作为组 - var groupTask = new GearTaskViewModel - { - Name = child.Name, - IsDirectory = true - }; - tasks.Add(groupTask); - // 递归添加子任务 - tasks.AddRange(GetAllFolderTasksInDirectoryWithStructure(child)); + groupTask.Children.Add(gearTask); } } + return groupTask; } } - - return tasks; + else + { + return null; + } } } \ No newline at end of file