Files
better-genshin-impact/BetterGenshinImpact/ViewModel/Pages/MapPathingViewModel.cs

468 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BetterGenshinImpact.Core.Config;
using BetterGenshinImpact.Core.Script;
using BetterGenshinImpact.Core.Script.Group;
using BetterGenshinImpact.Core.Script.Project;
using BetterGenshinImpact.GameTask.AutoPathing;
using BetterGenshinImpact.GameTask.AutoPathing.Model;
using BetterGenshinImpact.Helpers;
using BetterGenshinImpact.Helpers.Ui;
using BetterGenshinImpact.Model;
using BetterGenshinImpact.Service.Interface;
using BetterGenshinImpact.View.Controls.Drawer;
using BetterGenshinImpact.View.Controls.Webview;
using BetterGenshinImpact.View.Pages.View;
using BetterGenshinImpact.View.Windows;
using BetterGenshinImpact.ViewModel.Message;
using BetterGenshinImpact.ViewModel.Pages.View;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.Logging;
using Microsoft.Web.WebView2.Wpf;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using Wpf.Ui.Violeta.Controls;
using Wpf.Ui.Violeta.Win32;
namespace BetterGenshinImpact.ViewModel.Pages;
public partial class MapPathingViewModel : ViewModel
{
private readonly ILogger<MapPathingViewModel> _logger = App.GetLogger<MapPathingViewModel>();
public static readonly string PathJsonPath = Global.Absolute(@"User\AutoPathing");
[ObservableProperty] private ObservableCollection<FileTreeNode<PathingTask>> _treeList = [];
[ObservableProperty] private FileTreeNode<PathingTask>? _selectNode;
[ObservableProperty]
private bool _isRightClickSelection;
private MapPathingDevWindow? _mapPathingDevWindow;
private readonly IScriptService _scriptService;
public AllConfig Config { get; set; }
// 添加抽屉ViewModel
public DrawerViewModel DrawerVm { get; } = new DrawerViewModel();
/// <inheritdoc/>
public MapPathingViewModel(IScriptService scriptService, IConfigService configService)
{
_scriptService = scriptService;
Config = configService.Get();
WeakReferenceMessenger.Default.Register<RefreshDataMessage>(this, (r, m) => InitScriptListViewData());
IconManager.CacheExcludeExtensions = [".ico"];
}
private void InitScriptListViewData()
{
TreeList.Clear();
var root = FileTreeNodeHelper.LoadDirectory<PathingTask>(PathJsonPath);
// 循环写入 root.Children
foreach (var item in root.Children)
{
SetIconForNodeAndChildren(item);
TreeList.Add(item);
}
}
private void SetIconForNodeAndChildren(FileTreeNode<PathingTask> node)
{
if (!string.IsNullOrEmpty(node.FilePath) && File.Exists(Path.Combine(node.FilePath, "icon.ico")))
{
node.IconFilePath = Path.Combine(node.FilePath, "icon.ico");
}
else
{
node.IconFilePath = node.FilePath;
}
foreach (var child in node.Children)
{
SetIconForNodeAndChildren(child);
}
}
public override void OnNavigatedTo()
{
InitScriptListViewData();
}
[RelayCommand]
public void OnOpenScriptsFolder()
{
if (!Directory.Exists(PathJsonPath))
{
Directory.CreateDirectory(PathJsonPath);
}
Process.Start("explorer.exe", PathJsonPath);
}
[RelayCommand]
public void OnOpenScriptProjectFolder(ScriptProject? item)
{
if (item == null)
{
return;
}
Process.Start("explorer.exe", item.ProjectPath);
}
[RelayCommand]
public async Task OnStart(FileTreeNode<PathingTask>? item)
{
// 如果没有传入参数,使用选中的节点
if (item == null)
{
item = SelectNode;
}
if (item == null)
{
return;
}
if (item.IsDirectory)
{
Toast.Warning("执行多个地图追踪任务的时候,请使用调度器功能");
return;
}
if (string.IsNullOrEmpty(item.FilePath))
{
return;
}
var fileInfo = new FileInfo(item.FilePath);
var project = ScriptGroupProject.BuildPathingProject(fileInfo.Name, fileInfo.DirectoryName!);
await _scriptService.RunMulti([project]);
}
[RelayCommand]
public void OnOpenDevTools()
{
if (_mapPathingDevWindow == null || !_mapPathingDevWindow.IsVisible)
{
_mapPathingDevWindow = new MapPathingDevWindow();
_mapPathingDevWindow.Closed += (s, e) => _mapPathingDevWindow = null;
_mapPathingDevWindow.Show();
}
else
{
_mapPathingDevWindow.Activate();
}
}
[RelayCommand]
public async void OnOpenSettings()
{
// var uiMessageBox = new Wpf.Ui.Controls.MessageBox
// {
// Content = view,
// Title = "地图追踪配置",
// CloseButtonText = "关闭"
// };
//
// await uiMessageBox.ShowDialogAsync();
var vm = App.GetService<PathingConfigViewModel>();
var view = new PathingConfigView(vm);
view?.ShowDialog();
}
[RelayCommand]
public void OnGoToPathingUrl()
{
Process.Start(new ProcessStartInfo("https://bettergi.com/feats/autos/pathing.html") { UseShellExecute = true });
}
[RelayCommand]
public void OnRefresh()
{
InitScriptListViewData();
}
[RelayCommand]
public async Task OnDelete(FileTreeNode<PathingTask>? item)
{
// 如果没有传入参数,使用选中的节点
if (item == null)
{
item = SelectNode;
}
if (item == null)
{
return;
}
if (string.IsNullOrEmpty(item.FilePath))
{
Toast.Warning("无法删除:路径无效");
return;
}
// 确定删除的内容类型
string itemType = item.IsDirectory ? "文件夹" : "文件";
string itemName = item.FileName ?? "未知项目";
// 显示确认对话框
var messageBox = new Wpf.Ui.Controls.MessageBox
{
Title = "删除确认",
Content = $"确定要删除{itemType} \"{itemName}\" 吗?\n\n此操作将永久删除该{itemType}及其所有内容,无法恢复!",
PrimaryButtonText = "删除",
CloseButtonText = "取消",
Owner = Application.Current.MainWindow,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
};
var result = await messageBox.ShowDialogAsync();
if (result == Wpf.Ui.Controls.MessageBoxResult.Primary)
{
try
{
if (item.IsDirectory)
{
// 删除目录
if (Directory.Exists(item.FilePath))
{
Directory.Delete(item.FilePath, true);
Toast.Success($"已删除文件夹: {itemName}");
_logger.LogInformation("已删除地图追踪文件夹: {Name} ({Path})", itemName, item.FilePath);
}
else
{
Toast.Warning("文件夹不存在");
}
}
else
{
// 删除文件
if (File.Exists(item.FilePath))
{
File.Delete(item.FilePath);
Toast.Success($"已删除文件: {itemName}");
_logger.LogInformation("已删除地图追踪文件: {Name} ({Path})", itemName, item.FilePath);
}
else
{
Toast.Warning("文件不存在");
}
}
// 刷新列表
InitScriptListViewData();
}
catch (Exception ex)
{
Toast.Error($"删除失败: {ex.Message}");
_logger.LogError(ex, "删除地图追踪项失败");
}
}
}
[RelayCommand]
public void OnOpenLocalScriptRepo()
{
Config.ScriptConfig.ScriptRepoHintDotVisible = false;
ScriptRepoUpdater.Instance.OpenScriptRepoWindow();
}
[RelayCommand]
private void SetRightClickSelection(string isRightClick)
{
IsRightClickSelection = "True".Equals(isRightClick, StringComparison.OrdinalIgnoreCase);
}
[RelayCommand]
public void OnOpenPathingDetail()
{
var item = SelectNode;
// 如果是右键点击,不打开抽屉
if (item == null || IsRightClickSelection)
{
return;
}
// 如果是目录检查是否存在README.md
string? mdFilePath = null;
if (item.IsDirectory && !string.IsNullOrEmpty(item.FilePath))
{
mdFilePath = FindMdFilePath(item.FilePath);
}
// 设置抽屉位置和大小
DrawerVm.DrawerPosition = DrawerPosition.Right;
if (!string.IsNullOrEmpty(mdFilePath))
{
DrawerVm.DrawerWidth = 450;
}
else
{
DrawerVm.DrawerWidth = 350;
}
// 统一的抽屉事件处理
DrawerVm.SetDrawerClosingAction(_ => { });
DrawerVm.setDrawerOpenedAction(() => { SelectNode = null; });
// 创建要在抽屉中显示的内容
var content = CreatePathingDetailContent(item, mdFilePath);
// 打开抽屉
if (content != null)
{
DrawerVm.OpenDrawer(content);
}
}
private string? FindMdFilePath(string dirPath)
{
string[] possibleMdFiles = { "README.md", "readme.md" };
foreach (var mdFile in possibleMdFiles)
{
string fullPath = Path.Combine(dirPath, mdFile);
if (File.Exists(fullPath))
{
return fullPath;
}
}
return null;
}
private object? CreatePathingDetailContent(FileTreeNode<PathingTask> node, string? mdFilePath = null)
{
// 创建显示路径任务详情的控件
var border = new Border
{
//Background = new SolidColorBrush(Color.FromRgb(0x2B, 0x2B, 0x2B)),
Padding = new Thickness(20),
CornerRadius = new CornerRadius(8),
};
border.SetResourceReference(Border.BackgroundProperty, "ApplicationBackgroundBrush");
var mainGrid = new Grid();
mainGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); // 标题行
mainGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); // 内容行,占满剩余空间
border.Child = mainGrid;
// 添加标题
var titleTextBlock = new TextBlock
{
Text = node.FileName,
FontSize = 20,
FontWeight = FontWeights.Bold,
Margin = new Thickness(0, 0, 0, 10),
};
Grid.SetRow(titleTextBlock, 0);
mainGrid.Children.Add(titleTextBlock);
// 如果找到md文件使用RichTextBox显示
if (!string.IsNullOrEmpty(mdFilePath))
{
string markdown = File.ReadAllText(mdFilePath);
var flowDoc = MarkdownToFlowDocumentConverter.ConvertToFlowDocument(markdown);
var richTextBox = new RichTextBox
{
IsReadOnly = true,
IsDocumentEnabled = true,
BorderThickness = new Thickness(0),
VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
Document = flowDoc,
Background = Brushes.Transparent,
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
Margin = new Thickness(0, 10, 0, 0)
};
Grid.SetRow(richTextBox, 1);
mainGrid.Children.Add(richTextBox);
}
else if (!node.IsDirectory && !string.IsNullOrEmpty(node.FilePath))
{
// 如果是文件而不是目录,显示更多详情
try
{
if (string.IsNullOrEmpty(node.Value?.Info.Description))
{
return null;
}
var descriptionTextBlock = new TextBlock
{
Text = $"{node.Value?.Info.Description}",
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(0, 10, 0, 0),
VerticalAlignment = VerticalAlignment.Stretch
};
Grid.SetRow(descriptionTextBlock, 1);
mainGrid.Children.Add(descriptionTextBlock);
}
catch (Exception ex)
{
var errorTextBlock = new TextBlock
{
Text = $"读取文件信息时出错: {ex.Message}",
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(0, 10, 0, 0),
VerticalAlignment = VerticalAlignment.Stretch,
Foreground = Brushes.Orange
};
Grid.SetRow(errorTextBlock, 1);
mainGrid.Children.Add(errorTextBlock);
}
}
else
{
// 显示目录信息 - 使用StackPanel包装多个TextBlock
var contentPanel = new StackPanel
{
Margin = new Thickness(0, 10, 0, 0),
VerticalAlignment = VerticalAlignment.Top
};
contentPanel.Children.Add(new TextBlock
{
Text = "这是一个目录,包含多个地图追踪任务。",
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(0, 0, 0, 15)
});
// 添加子项信息
if (node.Children.Count > 0)
{
contentPanel.Children.Add(new TextBlock
{
Text = $"包含 {node.Children.Count} 个子项",
Margin = new Thickness(0, 0, 0, 5)
});
}
Grid.SetRow(contentPanel, 1);
mainGrid.Children.Add(contentPanel);
}
return border;
}
}