Files
better-genshin-impact/BetterGenshinImpact/ViewModel/Pages/ScriptControlViewModel.cs
2024-09-10 23:27:04 +08:00

568 lines
17 KiB
C#

using BetterGenshinImpact.Core.Config;
using BetterGenshinImpact.Core.Script.Group;
using BetterGenshinImpact.Core.Script.Project;
using BetterGenshinImpact.Service.Interface;
using BetterGenshinImpact.View.Windows;
using BetterGenshinImpact.View.Windows.Editable;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Wpf.Ui;
using Wpf.Ui.Controls;
using Wpf.Ui.Violeta.Controls;
using StackPanel = Wpf.Ui.Controls.StackPanel;
namespace BetterGenshinImpact.ViewModel.Pages;
public partial class ScriptControlViewModel : ObservableObject, INavigationAware, IViewModel
{
private readonly ISnackbarService _snackbarService;
private readonly ILogger<ScriptControlViewModel> _logger = App.GetLogger<ScriptControlViewModel>();
private readonly HomePageViewModel _homePageViewModel;
private readonly IScriptService _scriptService;
/// <summary>
/// 配置组配置
/// </summary>
[ObservableProperty]
private ObservableCollection<ScriptGroup> _scriptGroups = [];
/// <summary>
/// 当前选中的配置组
/// </summary>
[ObservableProperty]
private ScriptGroup? _selectedScriptGroup;
public readonly string ScriptGroupPath = Global.Absolute(@"User\ScriptGroup");
public void OnNavigatedFrom()
{
}
public void OnNavigatedTo()
{
ReadScriptGroup();
}
public ScriptControlViewModel(ISnackbarService snackbarService, IScriptService scriptService, HomePageViewModel homePageViewModel)
{
_snackbarService = snackbarService;
_scriptService = scriptService;
_homePageViewModel = homePageViewModel;
ScriptGroups.CollectionChanged += ScriptGroupsCollectionChanged;
}
[RelayCommand]
private void OnAddScriptGroup()
{
var str = PromptDialog.Prompt("请输入配置组名称", "新增配置组");
if (!string.IsNullOrEmpty(str))
{
// 检查是否已存在
if (ScriptGroups.Any(x => x.Name == str))
{
_snackbarService.Show(
"配置组已存在",
$"配置组 {str} 已经存在,请勿重复添加",
ControlAppearance.Caution,
null,
TimeSpan.FromSeconds(2)
);
}
else
{
ScriptGroups.Add(new ScriptGroup { Name = str });
}
}
}
[RelayCommand]
public void OnDeleteScriptGroup(ScriptGroup? item)
{
if (item == null)
{
return;
}
try
{
ScriptGroups.Remove(item);
File.Delete(Path.Combine(ScriptGroupPath, $"{item.Name}.json"));
_snackbarService.Show(
"配置组删除成功",
$"配置组 {item.Name} 已经被删除",
ControlAppearance.Success,
null,
TimeSpan.FromSeconds(2)
);
}
catch (Exception e)
{
_logger.LogDebug(e, "删除配置组配置时失败");
_snackbarService.Show(
"删除配置组配置失败",
$"配置组 {item.Name} 删除失败!",
ControlAppearance.Danger,
null,
TimeSpan.FromSeconds(3)
);
}
}
[RelayCommand]
private void OnAddJsScript()
{
var list = LoadAllJsScriptProjects();
var combobox = new ComboBox();
foreach (var scriptProject in list)
{
combobox.Items.Add(scriptProject.FolderName + " - " + scriptProject.Manifest.Name);
}
var str = PromptDialog.Prompt("请选择需要添加的JS脚本", "请选择需要添加的JS脚本", combobox);
if (!string.IsNullOrEmpty(str))
{
var folderName = str.Split(" - ")[0];
SelectedScriptGroup?.Projects.Add(new ScriptGroupProject(new ScriptProject(folderName)));
}
}
[RelayCommand]
private void OnAddKmScript()
{
var list = LoadAllKmScripts();
var combobox = new ComboBox();
foreach (var fileInfo in list)
{
combobox.Items.Add(fileInfo.Name);
}
var str = PromptDialog.Prompt("请选择需要添加的键鼠脚本", "请选择需要添加的键鼠脚本", combobox);
if (!string.IsNullOrEmpty(str))
{
SelectedScriptGroup?.Projects.Add(ScriptGroupProject.BuildKeyMouseProject(str));
}
}
[RelayCommand]
private void OnAddPathing()
{
var directories = LoadAllPathingScripts();
var stackPanel = CreatePathingScriptSelectionPanel(directories);
var result = PromptDialog.Prompt("请选择需要添加的路径追踪任务", "请选择需要添加的路径追踪任务", stackPanel, new Size(500, 600));
if (!string.IsNullOrEmpty(result))
{
AddSelectedPathingScripts((StackPanel)stackPanel.Content);
}
}
private ScrollViewer CreatePathingScriptSelectionPanel(Dictionary<string, List<FileInfo>> directories)
{
var stackPanel = new StackPanel();
foreach (var directory in directories)
{
var parentCheckBox = new CheckBox
{
Content = directory.Key,
Tag = directory.Value
};
var childStackPanel = new StackPanel();
foreach (var fileInfo in directory.Value)
{
var childCheckBox = new CheckBox
{
Content = fileInfo.Name,
Tag = fileInfo,
Margin = new Thickness(30, 0, 0, 0)
};
childStackPanel.Children.Add(childCheckBox);
}
parentCheckBox.Checked += (s, e) => SetChildCheckBoxesState(childStackPanel, true);
parentCheckBox.Unchecked += (s, e) => SetChildCheckBoxesState(childStackPanel, false);
stackPanel.Children.Add(parentCheckBox);
stackPanel.Children.Add(childStackPanel);
}
var scrollViewer = new ScrollViewer
{
Content = stackPanel,
VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
Height = 435 // 固定高度
};
return scrollViewer;
}
private void SetChildCheckBoxesState(StackPanel childStackPanel, bool state)
{
foreach (CheckBox child in childStackPanel.Children)
{
child.IsChecked = state;
}
}
private void AddSelectedPathingScripts(StackPanel stackPanel)
{
foreach (var child in stackPanel.Children)
{
if (child is StackPanel childStackPanel)
{
foreach (var grandChild in childStackPanel.Children)
{
if (grandChild is CheckBox checkBox && checkBox.IsChecked == true)
{
var fileInfo = (FileInfo)checkBox.Tag;
SelectedScriptGroup?.Projects.Add(ScriptGroupProject.BuildPathingProject(fileInfo.Name, fileInfo.DirectoryName));
}
}
}
}
}
private Dictionary<string, List<FileInfo>> LoadAllPathingScripts()
{
var folder = Global.Absolute(@"User\AutoPathing");
var directories = Directory.GetDirectories(folder);
var result = new Dictionary<string, List<FileInfo>>();
foreach (var directory in directories)
{
var dirInfo = new DirectoryInfo(directory);
var files = dirInfo.GetFiles("*.*", SearchOption.TopDirectoryOnly).ToList();
result.Add(dirInfo.Name, files);
}
return result;
}
private List<ScriptProject> LoadAllJsScriptProjects()
{
var path = Global.ScriptPath();
// 获取所有脚本项目
var projects = Directory.GetDirectories(path)
.Select(x => new ScriptProject(Path.GetFileName(x)))
.ToList();
return projects;
}
private List<FileInfo> LoadAllKmScripts()
{
var folder = Global.Absolute(@"User\KeyMouseScript");
// 获取所有脚本项目
var files = Directory.GetFiles(folder, "*.*",
SearchOption.AllDirectories);
return files.Select(file => new FileInfo(file)).ToList();
}
[RelayCommand]
public void OnEditScriptCommon(ScriptGroupProject? item)
{
if (item == null)
{
return;
}
ShowEditWindow(item);
// foreach (var group in ScriptGroups)
// {
// WriteScriptGroup(group);
// }
}
public static void ShowEditWindow(object viewModel)
{
var uiMessageBox = new Wpf.Ui.Controls.MessageBox
{
Title = "修改通用设置",
Content = new ScriptGroupProjectEditor { DataContext = viewModel },
CloseButtonText = "关闭",
Owner = Application.Current.MainWindow,
};
uiMessageBox.ShowDialogAsync();
}
[RelayCommand]
public void OnEditJsScriptSettings(ScriptGroupProject? item)
{
if (item == null)
{
return;
}
if (item.Project == null)
{
item.BuildScriptProjectRelation();
}
if (item.Project == null)
{
return;
}
if (item.Type == "Javascript")
{
if (item.JsScriptSettingsObject == null)
{
item.JsScriptSettingsObject = new ExpandoObject();
}
var ui = item.Project.LoadSettingUi(item.JsScriptSettingsObject);
if (ui == null)
{
Toast.Warning("此脚本未提供自定义配置");
return;
}
var uiMessageBox = new Wpf.Ui.Controls.MessageBox
{
Title = "修改JS脚本自定义设置 ",
Content = ui,
CloseButtonText = "关闭",
Owner = Application.Current.MainWindow,
};
uiMessageBox.ShowDialogAsync();
// foreach (var group in ScriptGroups)
// {
// WriteScriptGroup(group);
// }
}
else
{
Toast.Warning("只有JS脚本才有自定义配置");
}
}
[RelayCommand]
public void OnDeleteScript(ScriptGroupProject? item)
{
if (item == null)
{
return;
}
SelectedScriptGroup?.Projects.Remove(item);
_snackbarService.Show(
"脚本配置移除成功",
$"{item.Name} 的关联配置已经移除",
ControlAppearance.Success,
null,
TimeSpan.FromSeconds(2)
);
}
private void ScriptGroupsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (ScriptGroup newItem in e.NewItems)
{
newItem.Projects.CollectionChanged += ScriptProjectsCollectionChanged;
foreach (var project in newItem.Projects)
{
project.PropertyChanged += ScriptProjectsPChanged;
}
}
}
if (e.OldItems != null)
{
foreach (ScriptGroup oldItem in e.OldItems)
{
foreach (var project in oldItem.Projects)
{
project.PropertyChanged -= ScriptProjectsPChanged;
}
oldItem.Projects.CollectionChanged -= ScriptProjectsCollectionChanged;
}
}
// 补充排序字段
var i = 1;
foreach (var group in ScriptGroups)
{
group.Index = i++;
}
// 保存配置组配置
foreach (var group in ScriptGroups)
{
WriteScriptGroup(group);
}
}
private void ScriptProjectsPChanged(object? sender, PropertyChangedEventArgs e)
{
foreach (var group in ScriptGroups)
{
WriteScriptGroup(group);
}
}
private void ScriptProjectsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
// 补充排序字段
if (SelectedScriptGroup is { Projects.Count: > 0 })
{
var i = 1;
foreach (var project in SelectedScriptGroup.Projects)
{
project.Index = i++;
}
}
// 保存配置组配置
if (SelectedScriptGroup != null)
{
WriteScriptGroup(SelectedScriptGroup);
}
}
private void WriteScriptGroup(ScriptGroup scriptGroup)
{
try
{
if (!Directory.Exists(ScriptGroupPath))
{
Directory.CreateDirectory(ScriptGroupPath);
}
var file = Path.Combine(ScriptGroupPath, $"{scriptGroup.Name}.json");
File.WriteAllText(file, scriptGroup.ToJson());
}
catch (Exception e)
{
_logger.LogDebug(e, "保存配置组配置时失败");
_snackbarService.Show(
"保存配置组配置失败",
$"{scriptGroup.Name} 保存失败!",
ControlAppearance.Danger,
null,
TimeSpan.FromSeconds(3)
);
}
}
private void ReadScriptGroup()
{
try
{
if (!Directory.Exists(ScriptGroupPath))
{
Directory.CreateDirectory(ScriptGroupPath);
}
ScriptGroups.Clear();
var files = Directory.GetFiles(ScriptGroupPath, "*.json");
List<ScriptGroup> groups = [];
foreach (var file in files)
{
try
{
var json = File.ReadAllText(file);
var group = ScriptGroup.FromJson(json);
groups.Add(group);
}
catch (Exception e)
{
_logger.LogDebug(e, "读取单个配置组配置时失败");
_snackbarService.Show(
"读取配置组配置失败",
"读取配置组配置失败:" + e.Message,
ControlAppearance.Danger,
null,
TimeSpan.FromSeconds(3)
);
}
}
// 按index排序
groups.Sort((a, b) => a.Index.CompareTo(b.Index));
foreach (var group in groups)
{
ScriptGroups.Add(group);
}
}
catch (Exception e)
{
_logger.LogDebug(e, "读取配置组配置时失败");
_snackbarService.Show(
"读取配置组配置失败",
"读取配置组配置失败!",
ControlAppearance.Danger,
null,
TimeSpan.FromSeconds(3)
);
}
}
[RelayCommand]
public void OnGoToScriptGroupUrl()
{
Process.Start(new ProcessStartInfo("https://bgi.huiyadan.com/autos/dispatcher.html") { UseShellExecute = true });
}
[RelayCommand]
public void OnImportScriptGroup(string scriptGroupExample)
{
ScriptGroup group = new();
if ("AutoCrystalflyExampleGroup" == scriptGroupExample)
{
group.Name = "晶蝶示例组";
group.Projects.Add(new ScriptGroupProject(new ScriptProject("AutoCrystalfly")));
}
if (ScriptGroups.Any(x => x.Name == group.Name))
{
_snackbarService.Show(
"配置组已存在",
$"配置组 {group.Name} 已经存在,请勿重复添加",
ControlAppearance.Caution,
null,
TimeSpan.FromSeconds(2)
);
return;
}
ScriptGroups.Add(group);
}
[RelayCommand]
public async Task OnStartScriptGroupAsync()
{
if (SelectedScriptGroup == null)
{
_snackbarService.Show(
"未选择配置组",
"请先选择一个配置组",
ControlAppearance.Caution,
null,
TimeSpan.FromSeconds(2)
);
return;
}
await _scriptService.RunMulti(SelectedScriptGroup.Projects, SelectedScriptGroup.Name);
}
}