// // MaaWpfGui - A part of the MaaCoreArknights project // Copyright (C) 2021 MistEO and Contributors // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License v3.0 only as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY // using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Management; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Threading; using System.Threading.Tasks; using System.Windows; using HandyControl.Controls; using HandyControl.Data; using MaaWpfGui.Configuration; using MaaWpfGui.Constants; using MaaWpfGui.Extensions; using MaaWpfGui.Helper; using MaaWpfGui.Main; using MaaWpfGui.Models; using MaaWpfGui.Services; using MaaWpfGui.Services.HotKeys; using MaaWpfGui.Services.Notification; using MaaWpfGui.Services.RemoteControl; using MaaWpfGui.States; using MaaWpfGui.Utilities; using MaaWpfGui.Utilities.ValueType; using MaaWpfGui.WineCompat; using Microsoft.Win32; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Serilog; using Stylet; using ComboBox = System.Windows.Controls.ComboBox; using DarkModeType = MaaWpfGui.Configuration.GUI.DarkModeType; using Timer = System.Timers.Timer; namespace MaaWpfGui.ViewModels.UI { /// /// The view model of settings. /// public class SettingsViewModel : Screen { private readonly RunningState _runningState; private static readonly ILogger _logger = Log.ForContext(); [DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); private const int SWMINIMIZE = 6; [DllImport("user32.dll")] private static extern bool IsIconic(IntPtr hWnd); /// /// The Pallas language key. /// public const string PallasLangKey = "pallas"; /// /// Gets the visibility of task setting views. /// public TaskSettingVisibilityInfo TaskSettingVisibilities { get; } = TaskSettingVisibilityInfo.Current; /// /// Initializes a new instance of the class. /// public SettingsViewModel() { DisplayName = LocalizationHelper.GetString("Settings"); Init(); HangoverEnd(); _runningState = RunningState.Instance; } #region Init private List _listTitle = [ LocalizationHelper.GetString("SwitchConfiguration"), LocalizationHelper.GetString("ScheduleSettings"), LocalizationHelper.GetString("PerformanceSettings"), LocalizationHelper.GetString("GameSettings"), LocalizationHelper.GetString("ConnectionSettings"), LocalizationHelper.GetString("StartupSettings"), LocalizationHelper.GetString("RemoteControlSettings"), LocalizationHelper.GetString("UiSettings"), LocalizationHelper.GetString("ExternalNotificationSettings"), LocalizationHelper.GetString("HotKeySettings"), LocalizationHelper.GetString("UpdateSettings")+LocalizationHelper.GetString("UpdateSettings"), LocalizationHelper.GetString("AboutUs"), ]; /// /// Gets or sets the list title. /// public List ListTitle { get => _listTitle; set => SetAndNotify(ref _listTitle, value); } private bool _idle; /// /// Gets or sets a value indicating whether it is idle. /// public bool Idle { get => _idle; set => SetAndNotify(ref _idle, value); } private void Init() { InitInfrast(); InitRoguelike(); InitConfiguration(); InitUiSettings(); InitConnectConfig(); } private void InitInfrast() { var facilityList = new[] { "Mfg", "Trade", "Control", "Power", "Reception", "Office", "Dorm", "Processing", "Training", }; var tempOrderList = new List(new DragItemViewModel[facilityList.Length]); for (int i = 0; i != facilityList.Length; ++i) { var facility = facilityList[i]; bool parsed = int.TryParse(ConfigurationHelper.GetFacilityOrder(facility, "-1"), out int order); if (!parsed || order < 0) { tempOrderList[i] = new DragItemViewModel(LocalizationHelper.GetString(facility), facility, "Infrast."); } else { tempOrderList[order] = new DragItemViewModel(LocalizationHelper.GetString(facility), facility, "Infrast."); } } InfrastItemViewModels = new ObservableCollection(tempOrderList); _dormThresholdLabel = LocalizationHelper.GetString("DormThreshold") + ": " + _dormThreshold + "%"; } private void InitRoguelike() { UpdateRoguelikeModeList(); UpdateRoguelikeSquadList(); UpdateRoguelikeCoreCharList(); } private void InitConfiguration() { var configurations = new ObservableCollection(); foreach (var conf in ConfigurationHelper.GetConfigurationList()) { configurations.Add(new CombinedData { Display = conf, Value = conf }); } ConfigurationList = configurations; } private void InitUiSettings() { var languageList = (from pair in LocalizationHelper.SupportedLanguages where pair.Key != PallasLangKey || Cheers select new CombinedData { Display = pair.Value, Value = pair.Key }) .ToList(); LanguageList = languageList; SwitchDarkMode(); } private void InitConnectConfig() { var addressListJson = ConfigurationHelper.GetValue(ConfigurationKeys.AddressHistory, string.Empty); if (!string.IsNullOrEmpty(addressListJson)) { ConnectAddressHistory = JsonConvert.DeserializeObject>(addressListJson) ?? []; } } #endregion Init #region EasterEggs private bool _cheers = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.Cheers, bool.FalseString)); /// /// Gets or sets a value indicating whether to cheer. /// public bool Cheers { get => _cheers; set { if (_cheers == value) { return; } SetAndNotify(ref _cheers, value); ConfigurationHelper.SetValue(ConfigurationKeys.Cheers, value.ToString()); if (_cheers) { ConfigurationHelper.SetValue(ConfigurationKeys.Localization, PallasLangKey); } } } private bool _hangover = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.Hangover, bool.FalseString)); /// /// Gets or sets a value indicating whether to hangover. /// public bool Hangover { get => _hangover; set { SetAndNotify(ref _hangover, value); ConfigurationHelper.SetValue(ConfigurationKeys.Hangover, value.ToString()); } } private string _lastBuyWineTime = ConfigurationHelper.GetGlobalValue(ConfigurationKeys.LastBuyWineTime, DateTime.UtcNow.ToYjDate().AddDays(-1).ToFormattedString()); public string LastBuyWineTime { get => _lastBuyWineTime; set { SetAndNotify(ref _lastBuyWineTime, value); ConfigurationHelper.SetGlobalValue(ConfigurationKeys.LastBuyWineTime, value); } } public void HangoverEnd() { if (!Hangover) { return; } Hangover = false; MessageBoxHelper.Show( LocalizationHelper.GetString("Hangover"), LocalizationHelper.GetString("Burping"), iconKey: "HangoverGeometry", iconBrushKey: "PallasBrush"); Bootstrapper.ShutdownAndRestartWithoutArgs(); } public void Sober() { if (!Cheers || Language != PallasLangKey) { return; } ConfigurationHelper.SetValue(ConfigurationKeys.Localization, SoberLanguage); Hangover = true; Cheers = false; } private string _soberLanguage = ConfigurationHelper.GetValue(ConfigurationKeys.SoberLanguage, LocalizationHelper.DefaultLanguage); public string SoberLanguage { get => _soberLanguage; set { SetAndNotify(ref _soberLanguage, value); ConfigurationHelper.SetValue(ConfigurationKeys.SoberLanguage, value); } } /// /// Did you buy wine? /// /// The answer. public bool DidYouBuyWine() { var now = DateTime.UtcNow.ToYjDate(); if (now == DateTime.ParseExact(LastBuyWineTime.Replace('-', '/'), "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture)) { return false; } if (now.IsAprilFoolsDay()) { return true; } string[] wineList = ["酒", "liquor", "drink", "wine", "beer", "술", "🍷", "🍸", "🍺", "🍻", "🥃", "🍶"]; return wineList.Any(CreditFirstList.Contains); } #endregion EasterEggs #region Remote Control // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public async void RemoteControlConnectionTest() { await RemoteControlService.ConnectionTest(); } // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void RemoteControlRegenerateDeviceIdentity() { RemoteControlService.RegenerateDeviceIdentity(); } private string _remoteControlGetTaskEndpointUri = ConfigurationHelper.GetValue(ConfigurationKeys.RemoteControlGetTaskEndpointUri, string.Empty); public string RemoteControlGetTaskEndpointUri { get => _remoteControlGetTaskEndpointUri; set { SetAndNotify(ref _remoteControlGetTaskEndpointUri, value); ConfigurationHelper.SetValue(ConfigurationKeys.RemoteControlGetTaskEndpointUri, value); } } private string _remoteControlReportStatusUri = ConfigurationHelper.GetValue(ConfigurationKeys.RemoteControlReportStatusUri, string.Empty); public string RemoteControlReportStatusUri { get => _remoteControlReportStatusUri; set { SetAndNotify(ref _remoteControlReportStatusUri, value); ConfigurationHelper.SetValue(ConfigurationKeys.RemoteControlReportStatusUri, value); } } private string _remoteControlUserIdentity = ConfigurationHelper.GetValue(ConfigurationKeys.RemoteControlUserIdentity, string.Empty); public string RemoteControlUserIdentity { get => _remoteControlUserIdentity; set { SetAndNotify(ref _remoteControlUserIdentity, value); ConfigurationHelper.SetValue(ConfigurationKeys.RemoteControlUserIdentity, value); } } private string _remoteControlDeviceIdentity = ConfigurationHelper.GetValue(ConfigurationKeys.RemoteControlDeviceIdentity, string.Empty); public string RemoteControlDeviceIdentity { get => _remoteControlDeviceIdentity; set { SetAndNotify(ref _remoteControlDeviceIdentity, value); ConfigurationHelper.SetValue(ConfigurationKeys.RemoteControlDeviceIdentity, value); } } #endregion Remote Control #region External Notifications // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void ExternalNotificationSendTest() { ExternalNotificationService.Send( LocalizationHelper.GetString("ExternalNotificationSendTestTitle"), LocalizationHelper.GetString("ExternalNotificationSendTestContent"), true); } public static List ExternalNotificationProviders => [ new CombinedData { Display = LocalizationHelper.GetString("Off"), Value = "Off" }, new CombinedData { Display = "Server Chan", Value = "ServerChan" }, new CombinedData { Display = "Telegram", Value = "Telegram" }, new CombinedData { Display = "Discord", Value = "Discord" }, new CombinedData { Display = "SMTP", Value = "SMTP" }, new CombinedData { Display = "Bark", Value = "Bark" } ]; private string _enabledExternalNotificationProvider = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationEnabled, "Off"); public string EnabledExternalNotificationProvider { get => _enabledExternalNotificationProvider; set { SetAndNotify(ref _enabledExternalNotificationProvider, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationEnabled, value); } } private string _serverChanSendKey = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationServerChanSendKey, string.Empty); public string ServerChanSendKey { get => _serverChanSendKey; set { SetAndNotify(ref _serverChanSendKey, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationServerChanSendKey, value); } } public string BarkSendKey { get => _barkSendKey; set { SetAndNotify(ref _barkSendKey, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationBarkSendKey, value); } } private string _barkSendKey = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationBarkSendKey, string.Empty); public string BarkServer { get => _barkServer; set { SetAndNotify(ref _barkServer, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationBarkServer, value); } } private string _barkServer = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationBarkServer, "https://api.day.app"); private string _smtpServer = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationSmtpServer, string.Empty); public string SmtpServer { get => _smtpServer; set { SetAndNotify(ref _smtpServer, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationSmtpServer, value); } } private string _smtpPort = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationSmtpPort, string.Empty); public string SmtpPort { get => _smtpPort; set { SetAndNotify(ref _smtpPort, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationSmtpPort, value); } } private string _smtpUser = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationSmtpUser, string.Empty); public string SmtpUser { get => _smtpUser; set { SetAndNotify(ref _smtpUser, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationSmtpUser, value); } } private string _smtpPassword = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationSmtpPassword, string.Empty); public string SmtpPassword { get => _smtpPassword; set { SetAndNotify(ref _smtpPassword, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationSmtpPassword, value); } } private string _smtpFrom = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationSmtpFrom, string.Empty); public string SmtpFrom { get => _smtpFrom; set { SetAndNotify(ref _smtpFrom, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationSmtpFrom, value); } } private string _smtpTo = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationSmtpTo, string.Empty); public string SmtpTo { get => _smtpTo; set { SetAndNotify(ref _smtpTo, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationSmtpTo, value); } } private bool _smtpUseSsl = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationSmtpUseSsl, "false")); public bool SmtpUseSsl { get => _smtpUseSsl; set { SetAndNotify(ref _smtpUseSsl, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationSmtpUseSsl, value.ToString()); } } private bool _smtpRequireAuthentication = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationSmtpRequiresAuthentication, "false")); public bool SmtpRequireAuthentication { get => _smtpRequireAuthentication; set { SetAndNotify(ref _smtpRequireAuthentication, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationSmtpRequiresAuthentication, value.ToString()); } } private string _discordBotToken = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationDiscordBotToken, string.Empty); public string DiscordBotToken { get => _discordBotToken; set { SetAndNotify(ref _discordBotToken, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationDiscordBotToken, value); } } private string _discordUserId = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationDiscordUserId, string.Empty); public string DiscordUserId { get => _discordUserId; set { SetAndNotify(ref _discordUserId, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationDiscordUserId, value); } } private string _telegramBotToken = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationTelegramBotToken, string.Empty); public string TelegramBotToken { get => _telegramBotToken; set { SetAndNotify(ref _telegramBotToken, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationTelegramBotToken, value); } } private string _telegramChatId = ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationTelegramChatId, string.Empty); public string TelegramChatId { get => _telegramChatId; set { SetAndNotify(ref _telegramChatId, value); ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationTelegramChatId, value); } } #endregion External Notifications #region Performance public List GpuOptions => GpuOption.GetGpuOptions(); public GpuOption ActiveGpuOption { get => GpuOption.GetCurrent(); set { GpuOption.SetCurrent(value); AskRestartToApplySettings(); } } #endregion Performance #region 启动设置 private bool _startSelf = AutoStart.CheckStart(); /// /// Gets or sets a value indicating whether to start itself. /// public bool StartSelf { get => _startSelf; set { if (!AutoStart.SetStart(value, out var error)) { _logger.Error("Failed to set startup."); MessageBoxHelper.Show(error); return; } SetAndNotify(ref _startSelf, value); } } private bool _runDirectly = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RunDirectly, bool.FalseString)); /// /// Gets or sets a value indicating whether to run directly. /// public bool RunDirectly { get => _runDirectly; set { SetAndNotify(ref _runDirectly, value); ConfigurationHelper.SetValue(ConfigurationKeys.RunDirectly, value.ToString()); } } private bool _minimizeDirectly = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.MinimizeDirectly, bool.FalseString)); /// /// Gets or sets a value indicating whether to minimize directly. /// public bool MinimizeDirectly { get => _minimizeDirectly; set { SetAndNotify(ref _minimizeDirectly, value); ConfigurationHelper.SetValue(ConfigurationKeys.MinimizeDirectly, value.ToString()); } } private bool _startEmulator = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.StartEmulator, bool.FalseString)); /// /// Gets or sets a value indicating whether to start emulator. /// public bool StartEmulator { get => _startEmulator; set { SetAndNotify(ref _startEmulator, value); ConfigurationHelper.SetValue(ConfigurationKeys.StartEmulator, value.ToString()); if (ClientType == string.Empty && _runningState.GetIdle()) { ClientType = "Official"; } } } private string _accountName = ConfigurationHelper.GetValue(ConfigurationKeys.AccountName, string.Empty); public string AccountName { get => _accountName; set { SetAndNotify(ref _accountName, value); ConfigurationHelper.SetValue(ConfigurationKeys.AccountName, value); } } // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void AccountSwitchManualRun() { Instances.TaskQueueViewModel.QuickSwitchAccount(); } private bool _minimizingStartup = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.MinimizingStartup, bool.FalseString)); /// /// Gets or sets a value indicating whether to minimally start the emulator /// public bool MinimizingStartup { get => _minimizingStartup; set { SetAndNotify(ref _minimizingStartup, value); ConfigurationHelper.SetValue(ConfigurationKeys.MinimizingStartup, value.ToString()); } } private string _emulatorPath = ConfigurationHelper.GetValue(ConfigurationKeys.EmulatorPath, string.Empty); /// /// Gets or sets the emulator path. /// public string EmulatorPath { get => _emulatorPath; set { SetAndNotify(ref _emulatorPath, value); ConfigurationHelper.SetValue(ConfigurationKeys.EmulatorPath, value); } } private string _emulatorAddCommand = ConfigurationHelper.GetValue(ConfigurationKeys.EmulatorAddCommand, string.Empty); /// /// Gets or sets the command to append after the emulator command. /// public string EmulatorAddCommand { get => _emulatorAddCommand; set { SetAndNotify(ref _emulatorAddCommand, value); ConfigurationHelper.SetValue(ConfigurationKeys.EmulatorAddCommand, value); } } private string _emulatorWaitSeconds = ConfigurationHelper.GetValue(ConfigurationKeys.EmulatorWaitSeconds, "60"); /// /// Gets or sets the seconds to wait for the emulator. /// public string EmulatorWaitSeconds { get => _emulatorWaitSeconds; set { SetAndNotify(ref _emulatorWaitSeconds, value); ConfigurationHelper.SetValue(ConfigurationKeys.EmulatorWaitSeconds, value); } } private string _startsWithScript = ConfigurationHelper.GetValue(ConfigurationKeys.StartsWithScript, string.Empty); public string StartsWithScript { get => _startsWithScript; set { SetAndNotify(ref _startsWithScript, value); ConfigurationHelper.SetValue(ConfigurationKeys.StartsWithScript, value); } } private string _endsWithScript = ConfigurationHelper.GetValue(ConfigurationKeys.EndsWithScript, string.Empty); public string EndsWithScript { get => _endsWithScript; set { SetAndNotify(ref _endsWithScript, value); ConfigurationHelper.SetValue(ConfigurationKeys.EndsWithScript, value); } } private bool _copilotWithScript = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.CopilotWithScript, bool.FalseString)); public bool CopilotWithScript { get => _copilotWithScript; set { SetAndNotify(ref _copilotWithScript, value); ConfigurationHelper.SetValue(ConfigurationKeys.CopilotWithScript, value.ToString()); } } private bool _manualStopWithScript = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ManualStopWithScript, bool.FalseString)); public bool ManualStopWithScript { get => _manualStopWithScript; set { SetAndNotify(ref _manualStopWithScript, value); ConfigurationHelper.SetValue(ConfigurationKeys.ManualStopWithScript, value.ToString()); } } private bool _blockSleep = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.BlockSleep, bool.FalseString)); public bool BlockSleep { get => _blockSleep; set { SetAndNotify(ref _blockSleep, value); ConfigurationHelper.SetValue(ConfigurationKeys.BlockSleep, value.ToString()); } } private bool _blockSleepWithScreenOn = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.BlockSleepWithScreenOn, bool.TrueString)); public bool BlockSleepWithScreenOn { get => _blockSleepWithScreenOn; set { SetAndNotify(ref _blockSleepWithScreenOn, value); ConfigurationHelper.SetValue(ConfigurationKeys.BlockSleepWithScreenOn, value.ToString()); } } private string _screencapCost = string.Format(LocalizationHelper.GetString("ScreencapCost"), "---", "---", "---", "---"); public string ScreencapCost { get => _screencapCost; set => SetAndNotify(ref _screencapCost, value); } public void RunScript(string str, bool showLog = true) { bool enable = str switch { "StartsWithScript" => !string.IsNullOrWhiteSpace(StartsWithScript), "EndsWithScript" => !string.IsNullOrWhiteSpace(EndsWithScript), _ => false, }; if (!enable) { return; } Func func = str switch { "StartsWithScript" => RunStartCommand, "EndsWithScript" => RunEndCommand, _ => () => false, }; if (!showLog) { if (!func()) { _logger.Warning("Failed to execute the script."); } return; } Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("StartTask") + LocalizationHelper.GetString(str)); if (func()) { Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("CompleteTask") + LocalizationHelper.GetString(str)); } else { Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("TaskError") + LocalizationHelper.GetString(str), UiLogColor.Warning); } } private bool RunStartCommand() { try { var process = new Process { StartInfo = new ProcessStartInfo { FileName = StartsWithScript, WindowStyle = ProcessWindowStyle.Minimized, UseShellExecute = true, // FileName = "cmd.exe", // Arguments = $"/c {StartsWithScript}", }, }; process.Start(); process.WaitForExit(); return true; } catch (Exception) { return false; } } private bool RunEndCommand() { try { var process = new Process { StartInfo = new ProcessStartInfo { FileName = EndsWithScript, WindowStyle = ProcessWindowStyle.Minimized, UseShellExecute = true, // FileName = "cmd.exe", // Arguments = $"/c {EndsWithScript}", }, }; process.Start(); process.WaitForExit(); return true; } catch (Exception) { return false; } } /// /// Tries to start the emulator. /// /// Whether to start manually. public void TryToStartEmulator(bool manual = false) { if (EmulatorPath.Length == 0 || !File.Exists(EmulatorPath) || (!StartEmulator && !manual)) { return; } if (!int.TryParse(EmulatorWaitSeconds, out int delay)) { delay = 60; } try { string fileName = string.Empty; string arguments = string.Empty; if (Path.GetExtension(EmulatorPath).Equals(".lnk", StringComparison.CurrentCultureIgnoreCase)) { // ReSharper disable once SuspiciousTypeConversion.Global var link = (IShellLink)new ShellLink(); // ReSharper disable once SuspiciousTypeConversion.Global var file = (IPersistFile)link; file.Load(EmulatorPath, 0); // STGM_READ link.Resolve(IntPtr.Zero, 1); // SLR_NO_UI var buf = new char[32768]; unsafe { fixed (char* ptr = buf) { link.GetPath(ptr, 260, IntPtr.Zero, 0); // MAX_PATH var len = Array.IndexOf(buf, '\0'); if (len != -1) { fileName = new string(buf, 0, len); } link.GetArguments(ptr, 32768); len = Array.IndexOf(buf, '\0'); if (len != -1) { arguments = new string(buf, 0, len); } } } } else { fileName = EmulatorPath; arguments = EmulatorAddCommand; } var startInfo = arguments.Length != 0 ? new ProcessStartInfo(fileName, arguments) : new ProcessStartInfo(fileName); startInfo.UseShellExecute = false; Process process = new Process { StartInfo = startInfo, }; _logger.Information("Try to start emulator: \nfileName: " + fileName + "\narguments: " + arguments); process.Start(); try { // 如果之前就启动了模拟器,这一步有几率会抛出异常 process.WaitForInputIdle(); if (MinimizingStartup) { _logger.Information("Try minimizing the emulator"); int i; for (i = 0; !IsIconic(process.MainWindowHandle) && i < 100; ++i) { ShowWindow(process.MainWindowHandle, SWMINIMIZE); Thread.Sleep(10); if (process.HasExited) { throw new Exception(); } } if (i >= 100) { _logger.Information("Attempts to exceed the limit"); throw new Exception(); } } } catch (Exception) { _logger.Information("The emulator was already start"); // 如果之前就启动了模拟器,如果开启了最小化启动,就把所有模拟器最小化 // TODO:只最小化需要开启的模拟器 string processName = Path.GetFileNameWithoutExtension(fileName); Process[] processes = Process.GetProcessesByName(processName); if (processes.Length > 0) { if (MinimizingStartup) { _logger.Information("Try minimizing the emulator by processName: " + processName); foreach (Process p in processes) { int i; for (i = 0; !IsIconic(p.MainWindowHandle) && !p.HasExited && i < 100; ++i) { ShowWindow(p.MainWindowHandle, SWMINIMIZE); Thread.Sleep(10); } if (i >= 100) { _logger.Warning("The emulator minimization failure"); } } } } } } catch (Exception) { _logger.Information("Start emulator error, try to start using the default: \n" + "EmulatorPath: " + EmulatorPath + "\n" + "EmulatorAddCommand: " + EmulatorAddCommand); try { if (EmulatorAddCommand.Length != 0) { Process.Start(EmulatorPath); } else { Process.Start(EmulatorPath, EmulatorAddCommand); } } catch (Exception e) { if (e is Win32Exception { NativeErrorCode: 740 }) { Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("EmulatorStartFailed"), UiLogColor.Warning); _logger.Warning( "Insufficient permissions to start the emulator:\n" + "EmulatorPath: " + EmulatorPath + "\n"); } else { _logger.Warning("Emulator start failed with error: " + e.Message); } } } // 储存按钮状态,以便后续重置 bool idle = _runningState.GetIdle(); // 让按钮变成停止按钮,可手动停止等待 _runningState.SetIdle(false); for (var i = 0; i < delay; ++i) { if (Instances.TaskQueueViewModel.Stopping) { _logger.Information("Stop waiting for the emulator to start"); return; } if (i % 10 == 0) { Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("WaitForEmulator") + ": " + (delay - i) + "s"); _logger.Information("Waiting for the emulator to start: " + (delay - i) + "s"); } Thread.Sleep(1000); } Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("WaitForEmulatorFinish")); _logger.Information("The wait is over"); // 重置按钮状态,不影响后续判断 _runningState.SetIdle(idle); } /// /// Restarts the ADB (Android Debug Bridge). /// public void RestartAdb() { if (!AllowAdbRestart) { return; } string adbPath = AdbPath; if (string.IsNullOrEmpty(adbPath)) { return; } ProcessStartInfo processStartInfo = new ProcessStartInfo { FileName = "cmd.exe", RedirectStandardInput = true, RedirectStandardOutput = true, CreateNoWindow = true, UseShellExecute = false, }; Process process = new Process { StartInfo = processStartInfo, }; process.Start(); process.StandardInput.WriteLine($"{adbPath} kill-server"); process.StandardInput.WriteLine($"{adbPath} start-server"); process.StandardInput.WriteLine("exit"); process.WaitForExit(); } /// /// Reconnect by ADB (Android Debug Bridge). /// public void ReconnectByAdb() { string adbPath = AdbPath; string address = ConnectAddress; if (string.IsNullOrEmpty(adbPath)) { return; } ProcessStartInfo processStartInfo = new ProcessStartInfo { FileName = "cmd.exe", RedirectStandardInput = true, RedirectStandardOutput = true, CreateNoWindow = true, UseShellExecute = false, }; Process process = new Process { StartInfo = processStartInfo, }; process.Start(); process.StandardInput.WriteLine($"{adbPath} disconnect {address}"); process.StandardInput.WriteLine("exit"); process.WaitForExit(); } /// /// Kill and restart the ADB (Android Debug Bridge) process. /// public void HardRestartAdb() { if (!AllowAdbHardRestart) { return; } string adbPath = AdbPath; if (string.IsNullOrEmpty(adbPath)) { return; } // This allows for SQL injection, but since it is not on a real database nothing horrible would happen. // The following query string does what I want, but WMI does not accept it. // var wmiQueryString = string.Format("SELECT ProcessId, CommandLine FROM Win32_Process WHERE ExecutablePath='{0}'", adbPath); const string WmiQueryString = "SELECT ProcessId, ExecutablePath, CommandLine FROM Win32_Process"; using var searcher = new ManagementObjectSearcher(WmiQueryString); using var results = searcher.Get(); var query = from p in Process.GetProcesses() join mo in results.Cast() on p.Id equals (int)(uint)mo["ProcessId"] select new { Process = p, Path = (string)mo["ExecutablePath"], }; foreach (var item in query) { if (item.Path != adbPath) { continue; } // Some emulators start their ADB with administrator privilege. // Not sure if this is necessary try { item.Process.Kill(); item.Process.WaitForExit(); } catch { // ignored } } } /// /// Selects the emulator to execute. /// // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void SelectEmulatorExec() { var dialog = new OpenFileDialog { Filter = LocalizationHelper.GetString("Executable") + "|*.exe;*.bat;*.lnk", }; if (dialog.ShowDialog() == true) { EmulatorPath = dialog.FileName; } } private string _clientType = ConfigurationHelper.GetValue(ConfigurationKeys.ClientType, "Official"); /// /// Gets or sets the client type. /// public string ClientType { get => _clientType; set { SetAndNotify(ref _clientType, value); ConfigurationHelper.SetValue(ConfigurationKeys.ClientType, value); ResourceVersion = GetResourceVersionByClientType(_clientType); UpdateWindowTitle(); // 每次修改客户端时更新WindowTitle Instances.TaskQueueViewModel.UpdateStageList(true); Instances.TaskQueueViewModel.UpdateDatePrompt(); Instances.AsstProxy.LoadResource(); if (_clientType is "YoStarEN") { AskRestartToApplySettingsYoStarEN(); } else { AskRestartToApplySettings(); } } } /// /// Gets the client type. /// public string ClientName { get { foreach (var item in ClientTypeList.Where(item => item.Value == ClientType)) { return item.Display; } return "Unknown Client"; } } private readonly Dictionary _serverMapping = new() { { string.Empty, "CN" }, { "Official", "CN" }, { "Bilibili", "CN" }, { "YoStarEN", "US" }, { "YoStarJP", "JP" }, { "YoStarKR", "KR" }, { "txwy", "ZH_TW" }, }; private bool _autoRestartOnDrop = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.AutoRestartOnDrop, "True")); public bool AutoRestartOnDrop { get => _autoRestartOnDrop; set { SetAndNotify(ref _autoRestartOnDrop, value); ConfigurationHelper.SetValue(ConfigurationKeys.AutoRestartOnDrop, value.ToString()); } } /// /// Gets the server type. /// public string ServerType => _serverMapping[ClientType]; #endregion #region 基建设置 /// /// Gets or sets the infrast item view models. /// public ObservableCollection InfrastItemViewModels { get; set; } /// /// Gets the list of uses of drones. /// public List UsesOfDronesList { get; } = [ new() { Display = LocalizationHelper.GetString("DronesNotUse"), Value = "_NotUse" }, new() { Display = LocalizationHelper.GetString("Money"), Value = "Money" }, new() { Display = LocalizationHelper.GetString("SyntheticJade"), Value = "SyntheticJade" }, new() { Display = LocalizationHelper.GetString("CombatRecord"), Value = "CombatRecord" }, new() { Display = LocalizationHelper.GetString("PureGold"), Value = "PureGold" }, new() { Display = LocalizationHelper.GetString("OriginStone"), Value = "OriginStone" }, new() { Display = LocalizationHelper.GetString("Chip"), Value = "Chip" }, ]; /// /// Gets the list of uses of default infrast. /// public List DefaultInfrastList { get; } = [ new() { Display = LocalizationHelper.GetString("UserDefined"), Value = UserDefined }, new() { Display = LocalizationHelper.GetString("153Time3"), Value = "153_layout_3_times_a_day.json" }, new() { Display = LocalizationHelper.GetString("243Time3"), Value = "243_layout_3_times_a_day.json" }, new() { Display = LocalizationHelper.GetString("243Time4"), Value = "243_layout_4_times_a_day.json" }, new() { Display = LocalizationHelper.GetString("252Time3"), Value = "252_layout_3_times_a_day.json" }, new() { Display = LocalizationHelper.GetString("333Time3"), Value = "333_layout_for_Orundum_3_times_a_day.json" }, ]; private int _dormThreshold = Convert.ToInt32(ConfigurationHelper.GetValue(ConfigurationKeys.DormThreshold, "30")); /// /// Gets or sets the threshold to enter dormitory. /// public int DormThreshold { get => _dormThreshold; set { SetAndNotify(ref _dormThreshold, value); DormThresholdLabel = LocalizationHelper.GetString("DormThreshold") + ": " + _dormThreshold + "%"; ConfigurationHelper.SetValue(ConfigurationKeys.DormThreshold, value.ToString()); } } private string _dormThresholdLabel; /// /// Gets or sets the label of dormitory threshold. /// public string DormThresholdLabel { get => _dormThresholdLabel; set => SetAndNotify(ref _dormThresholdLabel, value); } /// /// Gets infrast order list. /// /// The infrast order list. public List GetInfrastOrderList() { return (from item in InfrastItemViewModels where item.IsChecked select item.OriginalName).ToList(); } /// /// 实时更新基建换班顺序 /// public void InfrastOrderSelectionChanged() { int index = 0; foreach (var item in InfrastItemViewModels) { ConfigurationHelper.SetFacilityOrder(item.OriginalName, index.ToString()); ++index; } } public static TaskQueueViewModel CustomInfrastPlanDataContext { get => Instances.TaskQueueViewModel; } private string _usesOfDrones = ConfigurationHelper.GetValue(ConfigurationKeys.UsesOfDrones, "Money"); /// /// Gets or sets the uses of drones. /// public string UsesOfDrones { get => _usesOfDrones; set { SetAndNotify(ref _usesOfDrones, value); ConfigurationHelper.SetValue(ConfigurationKeys.UsesOfDrones, value); } } private bool _continueTraining = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ContinueTraining, bool.FalseString)); /// /// Gets or sets a value indicating whether to continue training after current training completed. /// public bool ContinueTraining { get => _continueTraining; set { SetAndNotify(ref _continueTraining, value); ConfigurationHelper.SetValue(ConfigurationKeys.ContinueTraining, value.ToString()); } } private string _defaultInfrast = ConfigurationHelper.GetValue(ConfigurationKeys.DefaultInfrast, UserDefined); private const string UserDefined = "user_defined"; /// /// Gets or sets the uses of drones. /// public string DefaultInfrast { get => _defaultInfrast; set { SetAndNotify(ref _defaultInfrast, value); if (_defaultInfrast != UserDefined) { CustomInfrastFile = @"resource\custom_infrast\" + value; IsCustomInfrastFileReadOnly = true; } else { IsCustomInfrastFileReadOnly = false; } ConfigurationHelper.SetValue(ConfigurationKeys.DefaultInfrast, value); } } private bool _isCustomInfrastFileReadOnly = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.IsCustomInfrastFileReadOnly, bool.FalseString)); /// /// Gets or sets a value indicating whether CustomInfrastFile is read-only /// public bool IsCustomInfrastFileReadOnly { get => _isCustomInfrastFileReadOnly; set { SetAndNotify(ref _isCustomInfrastFileReadOnly, value); ConfigurationHelper.SetValue(ConfigurationKeys.IsCustomInfrastFileReadOnly, value.ToString()); } } private bool _dormFilterNotStationedEnabled = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.DormFilterNotStationedEnabled, bool.TrueString)); /// /// Gets or sets a value indicating whether the not stationed filter in dorm is enabled. /// public bool DormFilterNotStationedEnabled { get => _dormFilterNotStationedEnabled; set { SetAndNotify(ref _dormFilterNotStationedEnabled, value); ConfigurationHelper.SetValue(ConfigurationKeys.DormFilterNotStationedEnabled, value.ToString()); } } private bool _dormTrustEnabled = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.DormTrustEnabled, bool.FalseString)); /// /// Gets or sets a value indicating whether trust in dorm is enabled. /// public bool DormTrustEnabled { get => _dormTrustEnabled; set { SetAndNotify(ref _dormTrustEnabled, value); ConfigurationHelper.SetValue(ConfigurationKeys.DormTrustEnabled, value.ToString()); } } private bool _originiumShardAutoReplenishment = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.OriginiumShardAutoReplenishment, bool.TrueString)); /// /// Gets or sets a value indicating whether Originium shard auto replenishment is enabled. /// public bool OriginiumShardAutoReplenishment { get => _originiumShardAutoReplenishment; set { SetAndNotify(ref _originiumShardAutoReplenishment, value); ConfigurationHelper.SetValue(ConfigurationKeys.OriginiumShardAutoReplenishment, value.ToString()); } } private bool _customInfrastEnabled = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.CustomInfrastEnabled, bool.FalseString)); public bool CustomInfrastEnabled { get => _customInfrastEnabled; set { SetAndNotify(ref _customInfrastEnabled, value); ConfigurationHelper.SetValue(ConfigurationKeys.CustomInfrastEnabled, value.ToString()); Instances.TaskQueueViewModel.CustomInfrastEnabled = value; } } /// /// Selects infrast config file. /// // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void SelectCustomInfrastFile() { var dialog = new OpenFileDialog { Filter = LocalizationHelper.GetString("CustomInfrastFile") + "|*.json", }; if (dialog.ShowDialog() == true) { CustomInfrastFile = dialog.FileName; } DefaultInfrast = UserDefined; } private string _customInfrastFile = ConfigurationHelper.GetValue(ConfigurationKeys.CustomInfrastFile, string.Empty); public string CustomInfrastFile { get => _customInfrastFile; set { SetAndNotify(ref _customInfrastFile, value); ConfigurationHelper.SetValue(ConfigurationKeys.CustomInfrastFile, value); Instances.TaskQueueViewModel.RefreshCustomInfrastPlan(); // SetAndNotify 在值没有变化时不会触发 PropertyChanged 事件,所以这里手动触发一下 var index = Instances.TaskQueueViewModel.CustomInfrastPlanIndex; var count = Instances.TaskQueueViewModel.CustomInfrastPlanList.Count; Instances.TaskQueueViewModel.NeedAddCustomInfrastPlanInfo = false; { Instances.TaskQueueViewModel.CustomInfrastPlanIndex = (index + 1) % count; Instances.TaskQueueViewModel.CustomInfrastPlanIndex = index; } Instances.TaskQueueViewModel.NeedAddCustomInfrastPlanInfo = true; } } #region 设置页面列表和滚动视图联动绑定 private enum NotifyType { None, SelectedIndex, ScrollOffset, } private NotifyType _notifySource = NotifyType.None; private Timer _resetNotifyTimer; private void ResetNotifySource() { if (_resetNotifyTimer != null) { _resetNotifyTimer.Stop(); _resetNotifyTimer.Close(); } _resetNotifyTimer = new Timer(20); _resetNotifyTimer.Elapsed += (_, _) => { _notifySource = NotifyType.None; }; _resetNotifyTimer.AutoReset = false; _resetNotifyTimer.Enabled = true; _resetNotifyTimer.Start(); } /// /// Gets or sets the height of scroll viewport. /// public double ScrollViewportHeight { get; set; } /// /// Gets or sets the extent height of scroll. /// public double ScrollExtentHeight { get; set; } /// /// Gets or sets the list of divider vertical offset. /// public List DividerVerticalOffsetList { get; set; } = new(); private int _selectedIndex; /// /// Gets or sets the index selected. /// public int SelectedIndex { get => _selectedIndex; set { switch (_notifySource) { case NotifyType.None: _notifySource = NotifyType.SelectedIndex; SetAndNotify(ref _selectedIndex, value); if (DividerVerticalOffsetList?.Count > 0 && value < DividerVerticalOffsetList.Count) { ScrollOffset = DividerVerticalOffsetList[value]; } ResetNotifySource(); break; case NotifyType.ScrollOffset: SetAndNotify(ref _selectedIndex, value); break; case NotifyType.SelectedIndex: break; default: throw new ArgumentOutOfRangeException(); } } } private double _scrollOffset; /// /// Gets or sets the scroll offset. /// public double ScrollOffset { get => _scrollOffset; set { switch (_notifySource) { case NotifyType.None: _notifySource = NotifyType.ScrollOffset; SetAndNotify(ref _scrollOffset, value); // 设置 ListBox SelectedIndex 为当前 ScrollOffset 索引 if (DividerVerticalOffsetList?.Count > 0) { // 滚动条滚动到底部,返回最后一个 Divider 索引 if (value + ScrollViewportHeight >= ScrollExtentHeight) { SelectedIndex = DividerVerticalOffsetList.Count - 1; ResetNotifySource(); break; } // 根据出当前 ScrollOffset 选出最后一个在可视范围的 Divider 索引 var dividerSelect = DividerVerticalOffsetList.Select((n, i) => ( dividerAppeared: value >= n, index: i)); var index = dividerSelect.LastOrDefault(n => n.dividerAppeared).index; SelectedIndex = index; } ResetNotifySource(); break; case NotifyType.SelectedIndex: SetAndNotify(ref _scrollOffset, value); break; case NotifyType.ScrollOffset: break; default: throw new ArgumentOutOfRangeException(); } } } #endregion 设置页面列表和滚动视图联动绑定 #endregion #region 肉鸽设置 private void UpdateRoguelikeModeList() { var roguelikeMode = RoguelikeMode; RoguelikeModeList = [ new() { Display = LocalizationHelper.GetString("RoguelikeStrategyExp"), Value = "0" }, new() { Display = LocalizationHelper.GetString("RoguelikeStrategyGold"), Value = "1" }, // new CombData { Display = "两者兼顾,投资过后退出", Value = "2" } // 弃用 // new CombData { Display = Localization.GetString("3"), Value = "3" }, // 开发中 new() { Display = LocalizationHelper.GetString("RoguelikeStrategyLastReward"), Value = "4" }, ]; switch (RoguelikeTheme) { case "Sami": RoguelikeModeList.Add(new() { Display = LocalizationHelper.GetString("RoguelikeStrategyCollapse"), Value = "5" }); break; } RoguelikeMode = RoguelikeModeList.Any(x => x.Value == roguelikeMode) ? roguelikeMode : "0"; } private void UpdateRoguelikeSquadList() { var roguelikeSquad = RoguelikeSquad; RoguelikeSquadList = [ new() { Display = LocalizationHelper.GetString("DefaultSquad"), Value = string.Empty }, ]; switch (RoguelikeTheme) { case "Phantom": foreach (var item in new ObservableCollection { new() { Display = LocalizationHelper.GetString("ResearchSquad"), Value = "研究分队" }, }) { RoguelikeSquadList.Add(item); } break; case "Mizuki": foreach (var item in new ObservableCollection { new() { Display = LocalizationHelper.GetString("IS2NewSquad1"), Value = "心胜于物分队" }, new() { Display = LocalizationHelper.GetString("IS2NewSquad2"), Value = "物尽其用分队" }, new() { Display = LocalizationHelper.GetString("IS2NewSquad3"), Value = "以人为本分队" }, new() { Display = LocalizationHelper.GetString("ResearchSquad"), Value = "研究分队" }, }) { RoguelikeSquadList.Add(item); } break; case "Sami": foreach (var item in new ObservableCollection { new() { Display = LocalizationHelper.GetString("IS3NewSquad1"), Value = "永恒狩猎分队" }, new() { Display = LocalizationHelper.GetString("IS3NewSquad2"), Value = "生活至上分队" }, new() { Display = LocalizationHelper.GetString("IS3NewSquad3"), Value = "科学主义分队" }, new() { Display = LocalizationHelper.GetString("IS3NewSquad4"), Value = "特训分队" }, }) { RoguelikeSquadList.Add(item); } break; } // 通用分队 foreach (var item in new ObservableCollection { new() { Display = LocalizationHelper.GetString("LeaderSquad"), Value = "指挥分队" }, new() { Display = LocalizationHelper.GetString("GatheringSquad"), Value = "集群分队" }, new() { Display = LocalizationHelper.GetString("SupportSquad"), Value = "后勤分队" }, new() { Display = LocalizationHelper.GetString("SpearheadSquad"), Value = "矛头分队" }, new() { Display = LocalizationHelper.GetString("TacticalAssaultOperative"), Value = "突击战术分队" }, new() { Display = LocalizationHelper.GetString("TacticalFortificationOperative"), Value = "堡垒战术分队" }, new() { Display = LocalizationHelper.GetString("TacticalRangedOperative"), Value = "远程战术分队" }, new() { Display = LocalizationHelper.GetString("TacticalDestructionOperative"), Value = "破坏战术分队" }, new() { Display = LocalizationHelper.GetString("First-ClassSquad"), Value = "高规格分队" }, }) { RoguelikeSquadList.Add(item); } RoguelikeSquad = RoguelikeSquadList.Any(x => x.Value == roguelikeSquad) ? roguelikeSquad : string.Empty; } private void UpdateRoguelikeCoreCharList() { var filePath = $"resource/roguelike/{RoguelikeTheme}/recruitment.json"; if (!File.Exists(filePath)) { RoguelikeCoreCharList.Clear(); return; } var jsonStr = File.ReadAllText(filePath); var json = (JObject)JsonConvert.DeserializeObject(jsonStr); var roguelikeCoreCharList = new ObservableCollection(); if (json?["priority"] is JArray priorityArray) { foreach (var priorityItem in priorityArray) { if (priorityItem?["opers"] is not JArray opersArray) { continue; } foreach (var operItem in opersArray) { var isStart = (bool?)operItem["is_start"] ?? false; if (!isStart) { continue; } var name = (string)operItem["name"]; if (string.IsNullOrEmpty(name)) { continue; } var localizedName = DataHelper.GetLocalizedCharacterName(name, _language); if (!string.IsNullOrEmpty(localizedName) && !(_clientType.Contains("YoStar") && DataHelper.GetLocalizedCharacterName(name, "en-us") == DataHelper.GetLocalizedCharacterName(name, "zh-cn"))) { roguelikeCoreCharList.Add(localizedName); } } } } RoguelikeCoreCharList = roguelikeCoreCharList; } /// /// Gets the list of roguelike lists. /// public List RoguelikeThemeList { get; } = [ new() { Display = LocalizationHelper.GetString("RoguelikeThemePhantom"), Value = "Phantom" }, new() { Display = LocalizationHelper.GetString("RoguelikeThemeMizuki"), Value = "Mizuki" }, new() { Display = LocalizationHelper.GetString("RoguelikeThemeSami"), Value = "Sami" }, ]; private ObservableCollection _roguelikeModeList = new(); /// /// Gets the list of roguelike modes. /// public ObservableCollection RoguelikeModeList { get => _roguelikeModeList; set => SetAndNotify(ref _roguelikeModeList, value); } private ObservableCollection _roguelikeSquadList = new(); /// /// Gets or sets the list of roguelike squad. /// public ObservableCollection RoguelikeSquadList { get => _roguelikeSquadList; set => SetAndNotify(ref _roguelikeSquadList, value); } /// /// Gets the list of roguelike roles. /// public List RoguelikeRolesList { get; } = [ new() { Display = LocalizationHelper.GetString("DefaultRoles"), Value = string.Empty }, new() { Display = LocalizationHelper.GetString("FirstMoveAdvantage"), Value = "先手必胜" }, new() { Display = LocalizationHelper.GetString("SlowAndSteadyWinsTheRace"), Value = "稳扎稳打" }, new() { Display = LocalizationHelper.GetString("OvercomingYourWeaknesses"), Value = "取长补短" }, new() { Display = LocalizationHelper.GetString("AsYourHeartDesires"), Value = "随心所欲" }, ]; // public List RoguelikeCoreCharList { get; set; } private string _roguelikeTheme = ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeTheme, "Sami"); /// /// Gets or sets the Roguelike theme. /// public string RoguelikeTheme { get => _roguelikeTheme; set { SetAndNotify(ref _roguelikeTheme, value); UpdateRoguelikeModeList(); UpdateRoguelikeSquadList(); UpdateRoguelikeCoreCharList(); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeTheme, value); } } private string _roguelikeMode = ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeMode, "0"); /// /// Gets or sets 策略,往后打 / 刷一层就退 / 烧热水 /// public string RoguelikeMode { get => _roguelikeMode; set { if (value == "1") { RoguelikeInvestmentEnabled = true; } SetAndNotify(ref _roguelikeMode, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeMode, value); } } private string _roguelikeSquad = ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeSquad, string.Empty); /// /// Gets or sets the roguelike squad. /// public string RoguelikeSquad { get => _roguelikeSquad; set { SetAndNotify(ref _roguelikeSquad, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeSquad, value); } } public bool RoguelikeSquadIsProfessional => RoguelikeMode == "4" && RoguelikeTheme != "Phantom" && RoguelikeSquad is "突击战术分队" or "堡垒战术分队" or "远程战术分队" or "破坏战术分队"; public bool RoguelikeSquadIsFoldartal => RoguelikeMode == "4" && RoguelikeTheme == "Sami" && RoguelikeSquad == "生活至上分队"; private string _roguelikeRoles = ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeRoles, string.Empty); /// /// Gets or sets the roguelike roles. /// public string RoguelikeRoles { get => _roguelikeRoles; set { SetAndNotify(ref _roguelikeRoles, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeRoles, value); } } private string _roguelikeCoreChar = ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeCoreChar, string.Empty); /// /// Gets or sets the roguelike core character. /// public string RoguelikeCoreChar { get => _roguelikeCoreChar; set { if (_roguelikeCoreChar == (value ??= string.Empty)) { return; } SetAndNotify(ref _roguelikeCoreChar, value); Instances.TaskQueueViewModel.AddLog(value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeCoreChar, value); } } private ObservableCollection _roguelikeCoreCharList = []; /// /// Gets the roguelike core character. /// public ObservableCollection RoguelikeCoreCharList { get => _roguelikeCoreCharList; private set { if (!string.IsNullOrEmpty(RoguelikeCoreChar) && !value.Contains(RoguelikeCoreChar)) { value.Add(RoguelikeCoreChar); } SetAndNotify(ref _roguelikeCoreCharList, value); } } private bool _roguelikeStartWithEliteTwo = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeStartWithEliteTwo, bool.FalseString)); /// /// Gets or sets a value indicating whether core char need start with elite two. /// public bool RoguelikeStartWithEliteTwoRaw { get => _roguelikeStartWithEliteTwo; set { switch (value) { case true when RoguelikeUseSupportUnit: RoguelikeUseSupportUnit = false; break; case false when RoguelikeOnlyStartWithEliteTwoRaw: RoguelikeOnlyStartWithEliteTwoRaw = false; break; } SetAndNotify(ref _roguelikeStartWithEliteTwo, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeStartWithEliteTwo, value.ToString()); } } /// /// Gets a value indicating whether core char need start with elite two. /// public bool RoguelikeStartWithEliteTwo => _roguelikeStartWithEliteTwo && RoguelikeSquadIsProfessional; private bool _roguelikeOnlyStartWithEliteTwo = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeOnlyStartWithEliteTwo, bool.FalseString)); /// /// Gets or sets a value indicating whether only need with elite two's core char. /// public bool RoguelikeOnlyStartWithEliteTwoRaw { get => _roguelikeOnlyStartWithEliteTwo; set { SetAndNotify(ref _roguelikeOnlyStartWithEliteTwo, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeOnlyStartWithEliteTwo, value.ToString()); } } /// /// Gets a value indicating whether only need with elite two's core char. /// public bool RoguelikeOnlyStartWithEliteTwo => _roguelikeOnlyStartWithEliteTwo && RoguelikeStartWithEliteTwo; private bool _roguelike3FirstFloorFoldartal = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.Roguelike3FirstFloorFoldartal, bool.FalseString)); /// /// Gets or sets a value indicating whether core char need start with elite two. /// public bool Roguelike3FirstFloorFoldartalRaw { get => _roguelike3FirstFloorFoldartal; set { SetAndNotify(ref _roguelike3FirstFloorFoldartal, value); ConfigurationHelper.SetValue(ConfigurationKeys.Roguelike3FirstFloorFoldartal, value.ToString()); } } /// /// Gets a value indicating whether core char need start with elite two. /// public bool Roguelike3FirstFloorFoldartal => _roguelike3FirstFloorFoldartal && RoguelikeMode == "4" && RoguelikeTheme == "Sami"; private string _roguelike3StartFloorFoldartal = ConfigurationHelper.GetValue(ConfigurationKeys.Roguelike3StartFloorFoldartal, string.Empty); public string Roguelike3StartFloorFoldartal { get => _roguelike3StartFloorFoldartal; set { SetAndNotify(ref _roguelike3StartFloorFoldartal, value); ConfigurationHelper.SetValue(ConfigurationKeys.Roguelike3StartFloorFoldartal, value); } } private bool _roguelike3NewSquad2StartingFoldartal = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.Roguelike3NewSquad2StartingFoldartal, bool.FalseString)); /// /// Gets or sets a value indicating whether core char need start with elite two. /// public bool Roguelike3NewSquad2StartingFoldartalRaw { get => _roguelike3NewSquad2StartingFoldartal; set { SetAndNotify(ref _roguelike3NewSquad2StartingFoldartal, value); ConfigurationHelper.SetValue(ConfigurationKeys.Roguelike3NewSquad2StartingFoldartal, value.ToString()); } } /// /// Gets a value indicating whether core char need start with elite two. /// public bool Roguelike3NewSquad2StartingFoldartal => _roguelike3NewSquad2StartingFoldartal && RoguelikeSquadIsFoldartal; private string _roguelike3NewSquad2StartingFoldartals = ConfigurationHelper.GetValue(ConfigurationKeys.Roguelike3NewSquad2StartingFoldartals, string.Empty); public string Roguelike3NewSquad2StartingFoldartals { get => _roguelike3NewSquad2StartingFoldartals; set { SetAndNotify(ref _roguelike3NewSquad2StartingFoldartals, value); ConfigurationHelper.SetValue(ConfigurationKeys.Roguelike3NewSquad2StartingFoldartals, value); } } private bool _roguelikeUseSupportUnit = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeUseSupportUnit, bool.FalseString)); /// /// Gets or sets a value indicating whether to use support unit. /// public bool RoguelikeUseSupportUnit { get => _roguelikeUseSupportUnit; set { if (value && RoguelikeStartWithEliteTwo) { RoguelikeStartWithEliteTwoRaw = false; } SetAndNotify(ref _roguelikeUseSupportUnit, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeUseSupportUnit, value.ToString()); } } private bool _roguelikeEnableNonfriendSupport = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeEnableNonfriendSupport, bool.FalseString)); /// /// Gets or sets a value indicating whether can roguelike support unit belong to nonfriend /// public bool RoguelikeEnableNonfriendSupport { get => _roguelikeEnableNonfriendSupport; set { SetAndNotify(ref _roguelikeEnableNonfriendSupport, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeEnableNonfriendSupport, value.ToString()); } } private bool _roguelikeDelayAbortUntilCombatComplete = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeDelayAbortUntilCombatComplete, bool.FalseString)); /// /// Gets or sets a value indicating whether delay abort until battle complete /// public bool RoguelikeDelayAbortUntilCombatComplete { get => _roguelikeDelayAbortUntilCombatComplete; set { SetAndNotify(ref _roguelikeDelayAbortUntilCombatComplete, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeDelayAbortUntilCombatComplete, value.ToString()); } } private string _roguelikeStartsCount = ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeStartsCount, "9999999"); /// /// Gets or sets the start count of roguelike. /// public int RoguelikeStartsCount { get => int.Parse(_roguelikeStartsCount); set { SetAndNotify(ref _roguelikeStartsCount, value.ToString()); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeStartsCount, value.ToString()); } } private bool _roguelikeInvestmentEnabled = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeInvestmentEnabled, bool.TrueString)); /// /// Gets or sets a value indicating whether investment is enabled. /// public bool RoguelikeInvestmentEnabled { get => _roguelikeInvestmentEnabled; set { SetAndNotify(ref _roguelikeInvestmentEnabled, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeInvestmentEnabled, value.ToString()); } } private bool _roguelikeInvestmentWithMoreScore = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeInvestmentEnterSecondFloor, bool.FalseString)); /// /// Gets or sets a value indicating whether investment is enabled. /// public bool RoguelikeInvestmentWithMoreScoreRaw { get => _roguelikeInvestmentWithMoreScore; set { SetAndNotify(ref _roguelikeInvestmentWithMoreScore, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeInvestmentEnterSecondFloor, value.ToString()); } } /// /// Gets a value indicating whether investment is enabled. /// public bool RoguelikeInvestmentWithMoreScore => _roguelikeInvestmentWithMoreScore && RoguelikeMode == "1"; private bool _roguelikeRefreshTraderWithDice = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeRefreshTraderWithDice, bool.FalseString)); public bool RoguelikeRefreshTraderWithDiceRaw { get => _roguelikeRefreshTraderWithDice; set { SetAndNotify(ref _roguelikeRefreshTraderWithDice, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeRefreshTraderWithDice, value.ToString()); } } public bool RoguelikeRefreshTraderWithDice { get => _roguelikeRefreshTraderWithDice && RoguelikeTheme == "Mizuki"; set { SetAndNotify(ref _roguelikeRefreshTraderWithDice, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeRefreshTraderWithDice, value.ToString()); } } private string _roguelikeInvestsCount = ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeInvestsCount, "9999999"); /// /// Gets or sets the invests count of roguelike. /// public int RoguelikeInvestsCount { get => int.Parse(_roguelikeInvestsCount); set { SetAndNotify(ref _roguelikeInvestsCount, value.ToString()); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeInvestsCount, value.ToString()); } } private bool _roguelikeStopWhenInvestmentFull = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeStopWhenInvestmentFull, bool.FalseString)); /// /// Gets or sets a value indicating whether to stop when investment is full. /// public bool RoguelikeStopWhenInvestmentFull { get => _roguelikeStopWhenInvestmentFull; set { SetAndNotify(ref _roguelikeStopWhenInvestmentFull, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeStopWhenInvestmentFull, value.ToString()); } } #endregion #region 生息演算设置 private bool _reclamation2ExEnable = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.Reclamation2ExEnable, bool.FalseString)); public bool Reclamation2ExEnable { get => _reclamation2ExEnable; set { SetAndNotify(ref _reclamation2ExEnable, value); ConfigurationHelper.SetValue(ConfigurationKeys.Reclamation2ExEnable, value.ToString()); } } private string _reclamation2ExProduct = ConfigurationHelper.GetValue(ConfigurationKeys.Reclamation2ExProduct, string.Empty); public string Reclamation2ExProduct { get => _reclamation2ExProduct; set { SetAndNotify(ref _reclamation2ExProduct, value); ConfigurationHelper.SetValue(ConfigurationKeys.Reclamation2ExProduct, value); } } #endregion #region 信用相关设置 private string _lastCreditFightTaskTime = ConfigurationHelper.GetValue(ConfigurationKeys.LastCreditFightTaskTime, DateTime.UtcNow.ToYjDate().AddDays(-1).ToFormattedString()); public string LastCreditFightTaskTime { get => _lastCreditFightTaskTime; set { SetAndNotify(ref _lastCreditFightTaskTime, value); ConfigurationHelper.SetValue(ConfigurationKeys.LastCreditFightTaskTime, value); } } private bool _creditFightTaskEnabled = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.CreditFightTaskEnabled, bool.FalseString)); /// /// Gets or sets a value indicating whether credit fight task is enabled. /// public bool CreditFightTaskEnabled { get { try { if (DateTime.UtcNow.ToYjDate() > DateTime.ParseExact(_lastCreditFightTaskTime.Replace('-', '/'), "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture)) { return _creditFightTaskEnabled; } } catch { return _creditFightTaskEnabled; } return false; } set { SetAndNotify(ref _creditFightTaskEnabled, value); ConfigurationHelper.SetValue(ConfigurationKeys.CreditFightTaskEnabled, value.ToString()); } } public bool CreditFightTaskEnabledDisplay { get { return _creditFightTaskEnabled; } set { SetAndNotify(ref _creditFightTaskEnabled, value); ConfigurationHelper.SetValue(ConfigurationKeys.CreditFightTaskEnabled, value.ToString()); } } /// /// Gets 设置选择的编队 /// // ReSharper disable once MemberCanBePrivate.Global public List FormationSelectList { get; } = [ new() { Display = LocalizationHelper.GetString("Current"), Value = "0" }, new() { Display = "1", Value = "1" }, new() { Display = "2", Value = "2" }, new() { Display = "3", Value = "3" }, new() { Display = "4", Value = "4" }, ]; private bool _creditVisitFriends = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.CreditVisitFriends, bool.TrueString)); /// /// Gets or sets a value indicating whether visiting is enabled or disabled. /// public bool CreditVisitFriends { get => _creditVisitFriends; set { SetAndNotify(ref _creditVisitFriends, value); ConfigurationHelper.SetValue(ConfigurationKeys.CreditVisitFriends, value.ToString()); } } private int _creditFightSelectFormation = Convert.ToInt32(ConfigurationHelper.GetValue(ConfigurationKeys.CreditFightSelectFormation, "0")); /// /// Gets or sets a value indicating which formation will be select in credit fight. /// public int CreditFightSelectFormation { get => _creditFightSelectFormation; set { SetAndNotify(ref _creditFightSelectFormation, value); ConfigurationHelper.SetValue(ConfigurationKeys.CreditFightSelectFormation, value.ToString()); } } private bool _creditShopping = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.CreditShopping, bool.TrueString)); /// /// Gets or sets a value indicating whether to shop with credit. /// public bool CreditShopping { get => _creditShopping; set { SetAndNotify(ref _creditShopping, value); ConfigurationHelper.SetValue(ConfigurationKeys.CreditShopping, value.ToString()); } } private string _creditFirstList = ConfigurationHelper.GetValue(ConfigurationKeys.CreditFirstListNew, LocalizationHelper.GetString("HighPriorityDefault")); /// /// Gets or sets the priority item list of credit shop. /// public string CreditFirstList { get => _creditFirstList; set { SetAndNotify(ref _creditFirstList, value); ConfigurationHelper.SetValue(ConfigurationKeys.CreditFirstListNew, value); } } private string _creditBlackList = ConfigurationHelper.GetValue(ConfigurationKeys.CreditBlackListNew, LocalizationHelper.GetString("BlacklistDefault")); /// /// Gets or sets the blacklist of credit shop. /// public string CreditBlackList { get => _creditBlackList; set { SetAndNotify(ref _creditBlackList, value); ConfigurationHelper.SetValue(ConfigurationKeys.CreditBlackListNew, value); } } private bool _creditForceShoppingIfCreditFull = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.CreditForceShoppingIfCreditFull, bool.FalseString)); /// /// Gets or sets a value indicating whether save credit is enabled. /// public bool CreditForceShoppingIfCreditFull { get => _creditForceShoppingIfCreditFull; set { SetAndNotify(ref _creditForceShoppingIfCreditFull, value); ConfigurationHelper.SetValue(ConfigurationKeys.CreditForceShoppingIfCreditFull, value.ToString()); } } private bool _creditOnlyBuyDiscount = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.CreditOnlyBuyDiscount, bool.FalseString)); /// /// Gets or sets a value indicating whether only buy discount is enabled. /// public bool CreditOnlyBuyDiscount { get => _creditOnlyBuyDiscount; set { SetAndNotify(ref _creditOnlyBuyDiscount, value); ConfigurationHelper.SetValue(ConfigurationKeys.CreditOnlyBuyDiscount, value.ToString()); } } private bool _creditReserveMaxCredit = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.CreditReserveMaxCredit, bool.FalseString)); /// /// Gets or sets a value indicating whether reserve max credit is enabled. /// public bool CreditReserveMaxCredit { get => _creditReserveMaxCredit; set { SetAndNotify(ref _creditReserveMaxCredit, value); ConfigurationHelper.SetValue(ConfigurationKeys.CreditReserveMaxCredit, value.ToString()); } } #endregion #region 领取奖励设置 private bool _receiveAward = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ReceiveAward, bool.TrueString)); /// /// Gets or sets a value indicating whether receive award is enabled. /// public bool ReceiveAward { get => _receiveAward; set { SetAndNotify(ref _receiveAward, value); ConfigurationHelper.SetValue(ConfigurationKeys.ReceiveAward, value.ToString()); } } private bool _receiveMail = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ReceiveMail, bool.FalseString)); /// /// Gets or sets a value indicating whether receive mail is enabled. /// public bool ReceiveMail { get => _receiveMail; set { SetAndNotify(ref _receiveMail, value); ConfigurationHelper.SetValue(ConfigurationKeys.ReceiveMail, value.ToString()); } } private bool _receiveFreeRecruit = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ReceiveFreeRecruit, bool.FalseString)); /// /// Gets or sets a value indicating whether receive mail is enabled. /// public bool ReceiveFreeRecruit { get => _receiveFreeRecruit; set { if (value) { var result = MessageBoxHelper.Show( LocalizationHelper.GetString("GachaWarning"), LocalizationHelper.GetString("Warning"), MessageBoxButton.YesNo, MessageBoxImage.Warning, no: LocalizationHelper.GetString("Confirm"), yes: LocalizationHelper.GetString("Cancel"), iconBrushKey: "DangerBrush"); if (result != MessageBoxResult.No) { return; } } SetAndNotify(ref _receiveFreeRecruit, value); ConfigurationHelper.SetValue(ConfigurationKeys.ReceiveFreeRecruit, value.ToString()); } } private bool _receiveOrundum = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ReceiveOrundum, bool.FalseString)); /// /// Gets or sets a value indicating whether receive orundum is enabled. /// public bool ReceiveOrundum { get => _receiveOrundum; set { SetAndNotify(ref _receiveOrundum, value); ConfigurationHelper.SetValue(ConfigurationKeys.ReceiveOrundum, value.ToString()); } } private bool _receiveMining = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ReceiveMining, bool.FalseString)); /// /// Gets or sets a value indicating whether receive mining is enabled. /// public bool ReceiveMining { get => _receiveMining; set { SetAndNotify(ref _receiveMining, value); ConfigurationHelper.SetValue(ConfigurationKeys.ReceiveMining, value.ToString()); } } private bool _receiveReceiveSpecialAccess = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ReceiveSpecialAccess, bool.FalseString)); /// /// Gets or sets a value indicating whether to collect special access rewards. /// public bool ReceiveSpecialAccess { get => _receiveReceiveSpecialAccess; set { SetAndNotify(ref _receiveReceiveSpecialAccess, value); ConfigurationHelper.SetValue(ConfigurationKeys.ReceiveSpecialAccess, value.ToString()); } } #endregion #region 定时设置 public class TimerModel { public class TimerProperties : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public TimerProperties(int timeId, bool isOn, int hour, int min, string timerConfig) { TimerId = timeId; _isOn = isOn; _hour = hour; _min = min; if (timerConfig == null || !ConfigurationHelper.GetConfigurationList().Contains(timerConfig)) { _timerConfig = ConfigurationHelper.GetCurrentConfiguration(); } else { _timerConfig = timerConfig; } } protected void OnPropertyChanged([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } public int TimerId { get; set; } private readonly string _timerName = LocalizationHelper.GetString("Timer"); public string TimerName { get => $"{_timerName} {TimerId + 1}"; } private bool _isOn; /// /// Gets or sets a value indicating whether the timer is set. /// public bool IsOn { get => _isOn; set { _isOn = value; OnPropertyChanged(); ConfigurationHelper.SetTimer(TimerId, value.ToString()); } } private int _hour; /// /// Gets or sets the hour of the timer. /// public int Hour { get => _hour; set { _hour = value is >= 0 and <= 23 ? value : _hour; OnPropertyChanged(); ConfigurationHelper.SetTimerHour(TimerId, _hour.ToString()); } } private int _min; /// /// Gets or sets the minute of the timer. /// public int Min { get => _min; set { _min = value is >= 0 and <= 59 ? value : _min; OnPropertyChanged(); ConfigurationHelper.SetTimerMin(TimerId, _min.ToString()); } } private string _timerConfig; /// /// Gets or sets the config of the timer. /// public string TimerConfig { get => _timerConfig; set { _timerConfig = value ?? ConfigurationHelper.GetCurrentConfiguration(); OnPropertyChanged(); ConfigurationHelper.SetTimerConfig(TimerId, _timerConfig); } } public TimerProperties() { PropertyChanged += (_, _) => { }; } } public TimerProperties[] Timers { get; set; } = new TimerProperties[8]; public TimerModel() { for (int i = 0; i < 8; i++) { Timers[i] = new TimerProperties( i, ConfigurationHelper.GetTimer(i, bool.FalseString) == bool.TrueString, int.Parse(ConfigurationHelper.GetTimerHour(i, $"{i * 3}")), int.Parse(ConfigurationHelper.GetTimerMin(i, "0")), ConfigurationHelper.GetTimerConfig(i, ConfigurationHelper.GetCurrentConfiguration())); } } } public TimerModel TimerModels { get; set; } = new(); private bool _forceScheduledStart = Convert.ToBoolean(ConfigurationHelper.GetGlobalValue(ConfigurationKeys.ForceScheduledStart, bool.FalseString)); /// /// Gets or sets a value indicating whether to force scheduled start. /// public bool ForceScheduledStart { get => _forceScheduledStart; set { SetAndNotify(ref _forceScheduledStart, value); ConfigurationHelper.SetGlobalValue(ConfigurationKeys.ForceScheduledStart, value.ToString()); } } private bool _showWindowBeforeForceScheduledStart = Convert.ToBoolean(ConfigurationHelper.GetGlobalValue(ConfigurationKeys.ShowWindowBeforeForceScheduledStart, bool.FalseString)); /// /// Gets or sets a value indicating whether show window before force scheduled start. /// public bool ShowWindowBeforeForceScheduledStart { get => _showWindowBeforeForceScheduledStart; set { SetAndNotify(ref _showWindowBeforeForceScheduledStart, value); ConfigurationHelper.SetGlobalValue(ConfigurationKeys.ShowWindowBeforeForceScheduledStart, value.ToString()); } } private bool _customConfig = Convert.ToBoolean(ConfigurationHelper.GetGlobalValue(ConfigurationKeys.CustomConfig, bool.FalseString)); /// /// Gets or sets a value indicating whether to use custom config. /// public bool CustomConfig { get => _customConfig; set { SetAndNotify(ref _customConfig, value); ConfigurationHelper.SetGlobalValue(ConfigurationKeys.CustomConfig, value.ToString()); } } #endregion #region 刷理智设置 private string _penguinId = ConfigurationHelper.GetValue(ConfigurationKeys.PenguinId, string.Empty); /// /// Gets or sets the id of PenguinStats. /// public string PenguinId { get => _penguinId; set { SetAndNotify(ref _penguinId, value); ConfigurationHelper.SetValue(ConfigurationKeys.PenguinId, value); } } private bool _enablePenguin = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.EnablePenguin, bool.TrueString)); /// /// Gets or sets a value indicating whether to enable penguin upload. /// public bool EnablePenguin { get => _enablePenguin; set { SetAndNotify(ref _enablePenguin, value); ConfigurationHelper.SetValue(ConfigurationKeys.EnablePenguin, value.ToString()); } } private bool _enableYituliu = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.EnableYituliu, bool.TrueString)); /// /// Gets or sets a value indicating whether to enable yituliu upload. /// public bool EnableYituliu { get => _enableYituliu; set { SetAndNotify(ref _enableYituliu, value); ConfigurationHelper.SetValue(ConfigurationKeys.EnableYituliu, value.ToString()); } } private bool _isDrGrandet = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.IsDrGrandet, bool.FalseString)); /// /// Gets or sets a value indicating whether to use DrGrandet mode. /// public bool IsDrGrandet { get => _isDrGrandet; set { SetAndNotify(ref _isDrGrandet, value); ConfigurationHelper.SetValue(ConfigurationKeys.IsDrGrandet, value.ToString()); } } private bool _useAlternateStage = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.UseAlternateStage, bool.FalseString)); /// /// Gets or sets a value indicating whether to use alternate stage. /// public bool UseAlternateStage { get => _useAlternateStage; set { SetAndNotify(ref _useAlternateStage, value); Instances.TaskQueueViewModel.UseAlternateStage = value; ConfigurationHelper.SetValue(ConfigurationKeys.UseAlternateStage, value.ToString()); if (value) { HideUnavailableStage = false; } } } private bool _useRemainingSanityStage = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.UseRemainingSanityStage, bool.TrueString)); public bool UseRemainingSanityStage { get => _useRemainingSanityStage; set { SetAndNotify(ref _useRemainingSanityStage, value); Instances.TaskQueueViewModel.UseRemainingSanityStage = value; ConfigurationHelper.SetValue(ConfigurationKeys.UseRemainingSanityStage, value.ToString()); } } private bool _useExpiringMedicine = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.UseExpiringMedicine, bool.FalseString)); public bool UseExpiringMedicine { get => _useExpiringMedicine; set { SetAndNotify(ref _useExpiringMedicine, value); ConfigurationHelper.SetValue(ConfigurationKeys.UseExpiringMedicine, value.ToString()); Instances.TaskQueueViewModel.SetFightParams(); } } private bool _hideUnavailableStage = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.HideUnavailableStage, bool.TrueString)); /// /// Gets or sets a value indicating whether to hide unavailable stages. /// public bool HideUnavailableStage { get => _hideUnavailableStage; set { SetAndNotify(ref _hideUnavailableStage, value); ConfigurationHelper.SetValue(ConfigurationKeys.HideUnavailableStage, value.ToString()); if (value) { UseAlternateStage = false; } Instances.TaskQueueViewModel.UpdateStageList(true); } } private bool _hideSeries = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.HideSeries, bool.FalseString)); /// /// Gets or sets a value indicating whether to hide series. /// public bool HideSeries { get => _hideSeries; set { SetAndNotify(ref _hideSeries, value); Instances.TaskQueueViewModel.HideSeries = value; ConfigurationHelper.SetValue(ConfigurationKeys.HideSeries, value.ToString()); } } private bool _customStageCode = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.CustomStageCode, bool.FalseString)); /// /// Gets or sets a value indicating whether to use custom stage code. /// public bool CustomStageCode { get => _customStageCode; set { SetAndNotify(ref _customStageCode, value); ConfigurationHelper.SetValue(ConfigurationKeys.CustomStageCode, value.ToString()); Instances.TaskQueueViewModel.CustomStageCode = value; } } #endregion #region 自动公招设置 /// /// Gets the list of auto recruit selecting extra tags. /// public List AutoRecruitSelectExtraTagsList { get; } = [ new() { Display = LocalizationHelper.GetString("DefaultNoExtraTags"), Value = "0" }, new() { Display = LocalizationHelper.GetString("SelectExtraTags"), Value = "1" }, new() { Display = LocalizationHelper.GetString("SelectExtraOnlyRareTags"), Value = "2" }, ]; private string _autoRecruitFirstList = ConfigurationHelper.GetValue(ConfigurationKeys.AutoRecruitFirstList, string.Empty); /// /// Gets or sets the priority tag list of level-3 tags. /// public string AutoRecruitFirstList { get => _autoRecruitFirstList; set { SetAndNotify(ref _autoRecruitFirstList, value); ConfigurationHelper.SetValue(ConfigurationKeys.AutoRecruitFirstList, value); } } private string _recruitMaxTimes = ConfigurationHelper.GetValue(ConfigurationKeys.RecruitMaxTimes, "4"); /// /// Gets or sets the maximum times of recruit. /// public string RecruitMaxTimes { get => _recruitMaxTimes; set { SetAndNotify(ref _recruitMaxTimes, value); ConfigurationHelper.SetValue(ConfigurationKeys.RecruitMaxTimes, value); } } private bool _refreshLevel3 = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RefreshLevel3, bool.TrueString)); /// /// Gets or sets a value indicating whether to refresh level 3. /// public bool RefreshLevel3 { get => _refreshLevel3; set { SetAndNotify(ref _refreshLevel3, value); ConfigurationHelper.SetValue(ConfigurationKeys.RefreshLevel3, value.ToString()); } } private bool _forceRefresh = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ForceRefresh, bool.TrueString)); /// /// Gets or Sets a value indicating whether to refresh when recruit permit ran out. /// public bool ForceRefresh { get => _forceRefresh; set { SetAndNotify(ref _forceRefresh, value); ConfigurationHelper.SetValue(ConfigurationKeys.ForceRefresh, value.ToString()); } } private bool _useExpedited; /// /// Gets or sets a value indicating whether to use expedited. /// public bool UseExpedited { get => _useExpedited; set => SetAndNotify(ref _useExpedited, value); } private string _selectExtraTags = ConfigurationHelper.GetValue(ConfigurationKeys.SelectExtraTags, "0"); /// /// Gets or sets a value indicating three tags are always selected or select only rare tags as many as possible . /// public string SelectExtraTags { get { if (int.TryParse(_selectExtraTags, out _)) { return _selectExtraTags; } var value = "0"; if (bool.TryParse(_selectExtraTags, out bool boolValue)) { value = boolValue ? "1" : "0"; } SetAndNotify(ref _selectExtraTags, value); ConfigurationHelper.SetValue(ConfigurationKeys.SelectExtraTags, value); return value; } set { SetAndNotify(ref _selectExtraTags, value); ConfigurationHelper.SetValue(ConfigurationKeys.SelectExtraTags, value); } } private bool _isLevel3UseShortTime = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.IsLevel3UseShortTime, bool.FalseString)); /// /// Gets or sets a value indicating whether to shorten the time for level 3. /// public bool IsLevel3UseShortTime { get => _isLevel3UseShortTime; set { if (value) { IsLevel3UseShortTime2 = false; } SetAndNotify(ref _isLevel3UseShortTime, value); ConfigurationHelper.SetValue(ConfigurationKeys.IsLevel3UseShortTime, value.ToString()); } } private bool _isLevel3UseShortTime2 = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.IsLevel3UseShortTime2, bool.FalseString)); /// /// Gets or sets a value indicating whether to shorten the time for level 3. /// public bool IsLevel3UseShortTime2 { get => _isLevel3UseShortTime2; set { if (value) { IsLevel3UseShortTime = false; } SetAndNotify(ref _isLevel3UseShortTime2, value); ConfigurationHelper.SetValue(ConfigurationKeys.IsLevel3UseShortTime2, value.ToString()); } } private bool _notChooseLevel1 = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.NotChooseLevel1, bool.TrueString)); /// /// Gets or sets a value indicating whether not to choose level 1. /// public bool NotChooseLevel1 { get => _notChooseLevel1; set { SetAndNotify(ref _notChooseLevel1, value); ConfigurationHelper.SetValue(ConfigurationKeys.NotChooseLevel1, value.ToString()); } } private bool _chooseLevel3 = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RecruitChooseLevel3, bool.TrueString)); /// /// Gets or sets a value indicating whether to choose level 3. /// public bool ChooseLevel3 { get => _chooseLevel3; set { SetAndNotify(ref _chooseLevel3, value); ConfigurationHelper.SetValue(ConfigurationKeys.RecruitChooseLevel3, value.ToString()); } } private bool _chooseLevel4 = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RecruitChooseLevel4, bool.TrueString)); /// /// Gets or sets a value indicating whether to choose level 4. /// public bool ChooseLevel4 { get => _chooseLevel4; set { SetAndNotify(ref _chooseLevel4, value); ConfigurationHelper.SetValue(ConfigurationKeys.RecruitChooseLevel4, value.ToString()); } } private bool _chooseLevel5 = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RecruitChooseLevel5, bool.FalseString)); /// /// Gets or sets a value indicating whether to choose level 5. /// public bool ChooseLevel5 { get => _chooseLevel5; set { SetAndNotify(ref _chooseLevel5, value); ConfigurationHelper.SetValue(ConfigurationKeys.RecruitChooseLevel5, value.ToString()); } } #endregion #region 软件更新设置 public enum UpdateVersionType { /// /// 测试版 /// Nightly, /// /// 开发版 /// Beta, /// /// 稳定版 /// Stable, } /// /// Gets the core version. /// public static string CoreVersion { get; } = Marshal.PtrToStringAnsi(MaaService.AsstGetVersion()) ?? "0.0.1"; private static readonly string _uiVersion = Assembly.GetExecutingAssembly().GetCustomAttribute()?.InformationalVersion.Split('+')[0] ?? "0.0.1"; /// /// Gets the UI version. /// public static string UiVersion { get; } = _uiVersion == "0.0.1" ? "DEBUG VERSION" : _uiVersion; private static string _resourceVersion = GetResourceVersionByClientType(ConfigurationHelper.GetValue(ConfigurationKeys.ClientType, "Official")); /// /// Gets or sets the resource version. /// public string ResourceVersion { get => _resourceVersion; set => SetAndNotify(ref _resourceVersion, value); } private static string GetResourceVersionByClientType(string clientType) { const string OfficialClientType = "Official"; const string BilibiliClientType = "Bilibili"; string jsonPath = "resource/version.json"; if (clientType is not ("" or OfficialClientType or BilibiliClientType)) { jsonPath = $"resource/global/{clientType}/resource/version.json"; } string versionName = string.Empty; if (!File.Exists(jsonPath)) { return versionName; } JObject versionJson = (JObject)JsonConvert.DeserializeObject(File.ReadAllText(jsonPath)); var currentTime = (ulong)DateTimeOffset.UtcNow.ToUnixTimeSeconds(); var poolTime = (ulong?)versionJson?["gacha"]?["time"]; // 卡池的开始时间 var activityTime = (ulong?)versionJson?["activity"]?["time"]; // 活动的开始时间 if ((currentTime < poolTime) && (currentTime < activityTime)) { versionName = string.Empty; } else if ((currentTime >= poolTime) && (currentTime < activityTime)) { versionName = versionJson?["gacha"]?["pool"]?.ToString() ?? string.Empty; } else if ((currentTime < poolTime) && (currentTime >= activityTime)) { versionName = versionJson?["activity"]?["name"]?.ToString() ?? string.Empty; } else if (poolTime > activityTime) { versionName = versionJson?["gacha"]?["pool"]?.ToString() ?? string.Empty; } else { versionName = versionJson?["activity"]?["name"]?.ToString() ?? string.Empty; } return versionName; } private UpdateVersionType _versionType = (UpdateVersionType)Enum.Parse( typeof(UpdateVersionType), ConfigurationHelper.GetGlobalValue(ConfigurationKeys.VersionType, UpdateVersionType.Stable.ToString())); /// /// Gets or sets the type of version to update. /// public UpdateVersionType VersionType { get { if (_versionType == UpdateVersionType.Nightly && !_allowNightlyUpdates) { SetAndNotify(ref _versionType, UpdateVersionType.Beta); ConfigurationHelper.SetGlobalValue(ConfigurationKeys.VersionType, UpdateVersionType.Beta.ToString()); } return _versionType; } set { SetAndNotify(ref _versionType, value); ConfigurationHelper.SetGlobalValue(ConfigurationKeys.VersionType, value.ToString()); } } /// /// Gets the list of the version type. /// public List> AllVersionTypeList { get; } = [ new() { Display = LocalizationHelper.GetString("UpdateCheckNightly"), Value = UpdateVersionType.Nightly }, new() { Display = LocalizationHelper.GetString("UpdateCheckBeta"), Value = UpdateVersionType.Beta }, new() { Display = LocalizationHelper.GetString("UpdateCheckStable"), Value = UpdateVersionType.Stable }, ]; public List> VersionTypeList { get => AllVersionTypeList.Where(v => _allowNightlyUpdates || v.Value != UpdateVersionType.Nightly).ToList(); } private readonly bool _allowNightlyUpdates = Convert.ToBoolean(ConfigurationHelper.GetGlobalValue(ConfigurationKeys.AllowNightlyUpdates, bool.FalseString)); /// /// Gets a value indicating whether to update nightly. /// public bool UpdateNightly { get => _versionType == UpdateVersionType.Nightly; } /// /// Gets a value indicating whether to update beta version. /// public bool UpdateBeta { get => _versionType == UpdateVersionType.Beta; } private bool _updateCheck = Convert.ToBoolean(ConfigurationHelper.GetGlobalValue(ConfigurationKeys.UpdateCheck, bool.TrueString)); /// /// Gets or sets a value indicating whether to check update. /// public bool UpdateCheck { get => _updateCheck; set { SetAndNotify(ref _updateCheck, value); ConfigurationHelper.SetGlobalValue(ConfigurationKeys.UpdateCheck, value.ToString()); } } private bool _updateAutoCheck = Convert.ToBoolean(ConfigurationHelper.GetGlobalValue(ConfigurationKeys.UpdateAutoCheck, bool.FalseString)); /// /// Gets or sets a value indicating whether to check update. /// public bool UpdateAutoCheck { get => _updateAutoCheck; set { SetAndNotify(ref _updateAutoCheck, value); ConfigurationHelper.SetGlobalValue(ConfigurationKeys.UpdateAutoCheck, value.ToString()); } } private string _proxy = ConfigurationHelper.GetGlobalValue(ConfigurationKeys.UpdateProxy, string.Empty); /// /// Gets or sets the proxy settings. /// public string Proxy { get => _proxy; set { SetAndNotify(ref _proxy, value); ConfigurationHelper.SetGlobalValue(ConfigurationKeys.UpdateProxy, value); } } private bool _isCheckingForUpdates; /// /// Gets or sets a value indicating whether the update is being checked. /// public bool IsCheckingForUpdates { get => _isCheckingForUpdates; set { SetAndNotify(ref _isCheckingForUpdates, value); } } private bool _autoDownloadUpdatePackage = Convert.ToBoolean(ConfigurationHelper.GetGlobalValue(ConfigurationKeys.AutoDownloadUpdatePackage, bool.TrueString)); /// /// Gets or sets a value indicating whether to auto download update package. /// public bool AutoDownloadUpdatePackage { get => _autoDownloadUpdatePackage; set { SetAndNotify(ref _autoDownloadUpdatePackage, value); ConfigurationHelper.SetGlobalValue(ConfigurationKeys.AutoDownloadUpdatePackage, value.ToString()); } } private bool _autoInstallUpdatePackage = Convert.ToBoolean(ConfigurationHelper.GetGlobalValue(ConfigurationKeys.AutoInstallUpdatePackage, bool.FalseString)); /// /// Gets or sets a value indicating whether to auto install update package. /// public bool AutoInstallUpdatePackage { get => _autoInstallUpdatePackage; set { SetAndNotify(ref _autoInstallUpdatePackage, value); ConfigurationHelper.SetGlobalValue(ConfigurationKeys.AutoInstallUpdatePackage, value.ToString()); } } /// /// Updates manually. /// /// A representing the asynchronous operation. public async Task ManualUpdate() { var ret = await Instances.VersionUpdateViewModel.CheckAndDownloadUpdate(); string toastMessage = null; switch (ret) { case VersionUpdateViewModel.CheckUpdateRetT.NoNeedToUpdate: break; case VersionUpdateViewModel.CheckUpdateRetT.NoNeedToUpdateDebugVersion: toastMessage = LocalizationHelper.GetString("NoNeedToUpdateDebugVersion"); break; case VersionUpdateViewModel.CheckUpdateRetT.AlreadyLatest: toastMessage = LocalizationHelper.GetString("AlreadyLatest"); break; case VersionUpdateViewModel.CheckUpdateRetT.UnknownError: toastMessage = LocalizationHelper.GetString("NewVersionDetectFailedTitle"); break; case VersionUpdateViewModel.CheckUpdateRetT.NetworkError: toastMessage = LocalizationHelper.GetString("CheckNetworking"); break; case VersionUpdateViewModel.CheckUpdateRetT.FailedToGetInfo: toastMessage = LocalizationHelper.GetString("GetReleaseNoteFailed"); break; case VersionUpdateViewModel.CheckUpdateRetT.OK: Instances.VersionUpdateViewModel.AskToRestart(); break; case VersionUpdateViewModel.CheckUpdateRetT.NewVersionIsBeingBuilt: toastMessage = LocalizationHelper.GetString("NewVersionIsBeingBuilt"); break; case VersionUpdateViewModel.CheckUpdateRetT.OnlyGameResourceUpdated: toastMessage = LocalizationHelper.GetString("GameResourceUpdated"); break; default: throw new ArgumentOutOfRangeException(); } if (toastMessage != null) { _ = Execute.OnUIThreadAsync(() => { using var toast = new ToastNotification(toastMessage); toast.Show(); }); } } // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void ShowChangelog() { Instances.WindowManager.ShowWindow(Instances.VersionUpdateViewModel); } #endregion #region 连接设置 /// /// Gets the list of the configuration of connection. /// public List ConnectConfigList { get; } = [ new() { Display = LocalizationHelper.GetString("General"), Value = "General" }, new() { Display = LocalizationHelper.GetString("BlueStacks"), Value = "BlueStacks" }, new() { Display = LocalizationHelper.GetString("MuMuEmulator12"), Value = "MuMuEmulator12" }, new() { Display = LocalizationHelper.GetString("LDPlayer"), Value = "LDPlayer" }, new() { Display = LocalizationHelper.GetString("Nox"), Value = "Nox" }, new() { Display = LocalizationHelper.GetString("XYAZ"), Value = "XYAZ" }, new() { Display = LocalizationHelper.GetString("WSA"), Value = "WSA" }, new() { Display = LocalizationHelper.GetString("Compatible"), Value = "Compatible" }, new() { Display = LocalizationHelper.GetString("SecondResolution"), Value = "SecondResolution" }, new() { Display = LocalizationHelper.GetString("GeneralWithoutScreencapErr"), Value = "GeneralWithoutScreencapErr" }, ]; /// /// Gets the list of touch modes /// public List TouchModeList { get; } = [ new() { Display = LocalizationHelper.GetString("MiniTouchMode"), Value = "minitouch" }, new() { Display = LocalizationHelper.GetString("MaaTouchMode"), Value = "maatouch" }, new() { Display = LocalizationHelper.GetString("AdbTouchMode"), Value = "adb" }, ]; /// /// Gets the list of the client types. /// public List ClientTypeList { get; } = [ new() { Display = LocalizationHelper.GetString("NotSelected"), Value = string.Empty }, new() { Display = LocalizationHelper.GetString("Official"), Value = "Official" }, new() { Display = LocalizationHelper.GetString("Bilibili"), Value = "Bilibili" }, new() { Display = LocalizationHelper.GetString("YoStarEN"), Value = "YoStarEN" }, new() { Display = LocalizationHelper.GetString("YoStarJP"), Value = "YoStarJP" }, new() { Display = LocalizationHelper.GetString("YoStarKR"), Value = "YoStarKR" }, new() { Display = LocalizationHelper.GetString("Txwy"), Value = "txwy" }, ]; private bool _autoDetectConnection = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.AutoDetect, bool.TrueString)); public bool AutoDetectConnection { get => _autoDetectConnection; set { SetAndNotify(ref _autoDetectConnection, value); ConfigurationHelper.SetValue(ConfigurationKeys.AutoDetect, value.ToString()); } } private bool _alwaysAutoDetectConnection = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.AlwaysAutoDetect, bool.FalseString)); public bool AlwaysAutoDetectConnection { get => _alwaysAutoDetectConnection; set { SetAndNotify(ref _alwaysAutoDetectConnection, value); ConfigurationHelper.SetValue(ConfigurationKeys.AlwaysAutoDetect, value.ToString()); } } private ObservableCollection _connectAddressHistory = []; public ObservableCollection ConnectAddressHistory { get => _connectAddressHistory; set => SetAndNotify(ref _connectAddressHistory, value); } private string _connectAddress = ConfigurationHelper.GetValue(ConfigurationKeys.ConnectAddress, string.Empty); /// /// Gets or sets the connection address. /// public string ConnectAddress { get => _connectAddress; set { if (ConnectAddress == value || string.IsNullOrEmpty(value)) { return; } UpdateConnectionHistory(value); SetAndNotify(ref _connectAddress, value); ConfigurationHelper.SetValue(ConfigurationKeys.AddressHistory, JsonConvert.SerializeObject(ConnectAddressHistory)); ConfigurationHelper.SetValue(ConfigurationKeys.ConnectAddress, value); UpdateWindowTitle(); // 每次修改客户端时更新WindowTitle } } private void UpdateConnectionHistory(string address) { var history = ConnectAddressHistory.ToList(); if (history.Remove(address)) { history.Insert(0, address); } else { history.Insert(0, address); const int MaxHistoryCount = 5; if (history.Count > MaxHistoryCount) { history.RemoveRange(MaxHistoryCount, history.Count - MaxHistoryCount); } } ConnectAddressHistory = new ObservableCollection(history); } // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void RemoveAddressClick(string address) { ConnectAddressHistory.Remove(address); ConfigurationHelper.SetValue(ConfigurationKeys.AddressHistory, JsonConvert.SerializeObject(ConnectAddressHistory)); } private string _adbPath = ConfigurationHelper.GetValue(ConfigurationKeys.AdbPath, string.Empty); /// /// Gets or sets the ADB path. /// public string AdbPath { get => _adbPath; set { if (!Path.GetFileName(value).ToLower().Contains("adb")) { int count = 3; while (count-- > 0) { var result = MessageBoxHelper.Show( LocalizationHelper.GetString("AdbPathFileSelectionErrorPrompt"), LocalizationHelper.GetString("Tip"), MessageBoxButton.OKCancel, MessageBoxImage.Warning, ok: LocalizationHelper.GetString("AdbPathFileSelectionErrorImSure") + $"({count + 1})", cancel: LocalizationHelper.GetString("AdbPathFileSelectionErrorSelectAgain")); if (result == MessageBoxResult.Cancel) { return; } } } SetAndNotify(ref _adbPath, value); ConfigurationHelper.SetValue(ConfigurationKeys.AdbPath, value); } } private string _connectConfig = ConfigurationHelper.GetValue(ConfigurationKeys.ConnectConfig, "General"); /// /// Gets or sets the connection config. /// public string ConnectConfig { get => _connectConfig; set { SetAndNotify(ref _connectConfig, value); ConfigurationHelper.SetValue(ConfigurationKeys.ConnectConfig, value); UpdateWindowTitle(); // 每次修改客户端时更新WindowTitle } } public class MuMuEmulator12ConnectionExtras : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } private bool _enable = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.MuMu12ExtrasEnabled, bool.FalseString)); public bool Enable { get => _enable; set { if (_enable == value) { return; } _enable = value; if (value) { MessageBoxHelper.Show(LocalizationHelper.GetString("MuMu12ExtrasEnabledTip")); } Instances.AsstProxy.Connected = false; OnPropertyChanged(); ConfigurationHelper.SetValue(ConfigurationKeys.MuMu12ExtrasEnabled, value.ToString()); } } private static readonly string _configuredPath = ConfigurationHelper.GetValue(ConfigurationKeys.MuMu12EmulatorPath, @"C:\Program Files\Netease\MuMuPlayer-12.0"); private string _emulatorPath = Directory.Exists(_configuredPath) ? _configuredPath : string.Empty; /// /// Gets or sets a value indicating the path of the emulator. /// public string EmulatorPath { get => _emulatorPath; set { if (!Directory.Exists(value)) { MessageBoxHelper.Show("MuMu Emulator 12 Path Not Found"); value = string.Empty; } _emulatorPath = value; Instances.AsstProxy.Connected = false; OnPropertyChanged(); ConfigurationHelper.SetValue(ConfigurationKeys.MuMu12EmulatorPath, value); } } private string _index = ConfigurationHelper.GetValue(ConfigurationKeys.MuMu12Index, "0"); /// /// Gets or sets the index of the emulator. /// public string Index { get => _index; set { _index = value; Instances.AsstProxy.Connected = false; OnPropertyChanged(); ConfigurationHelper.SetValue(ConfigurationKeys.MuMu12Index, value); } } private string _display = ConfigurationHelper.GetValue(ConfigurationKeys.MuMu12Display, "0"); /// /// Gets or sets the display of the emulator. /// public string Display { get => _display; set { _display = value; Instances.AsstProxy.Connected = false; OnPropertyChanged(); ConfigurationHelper.SetValue(ConfigurationKeys.MuMu12Display, _display); } } public string Config { get { if (!Enable) { return JsonConvert.SerializeObject(new JObject()); } var configObject = new JObject { ["path"] = EmulatorPath, ["index"] = int.TryParse(Index, out var indexParse) ? indexParse : 0, ["display"] = int.TryParse(Display, out var displayParse) ? displayParse : 0, }; return JsonConvert.SerializeObject(configObject); } } public MuMuEmulator12ConnectionExtras() { PropertyChanged += (_, _) => { }; } } public MuMuEmulator12ConnectionExtras MuMuEmulator12Extras { get; set; } = new(); private bool _retryOnDisconnected = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RetryOnAdbDisconnected, bool.FalseString)); /// /// Gets or sets a value indicating whether to retry task after ADB disconnected. /// public bool RetryOnDisconnected { get => _retryOnDisconnected; set { if (string.IsNullOrEmpty(EmulatorPath)) { MessageBoxHelper.Show( LocalizationHelper.GetString("RetryOnDisconnectedEmulatorPathEmptyError"), LocalizationHelper.GetString("Tip"), MessageBoxButton.OK, MessageBoxImage.Warning); value = false; } SetAndNotify(ref _retryOnDisconnected, value); ConfigurationHelper.SetValue(ConfigurationKeys.RetryOnAdbDisconnected, value.ToString()); } } private bool _allowAdbRestart = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.AllowAdbRestart, bool.TrueString)); /// /// Gets or sets a value indicating whether to retry task after ADB disconnected. /// public bool AllowAdbRestart { get => _allowAdbRestart; set { SetAndNotify(ref _allowAdbRestart, value); ConfigurationHelper.SetValue(ConfigurationKeys.AllowAdbRestart, value.ToString()); } } private bool _allowAdbHardRestart = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.AllowAdbHardRestart, bool.TrueString)); /// /// Gets or sets a value indicating whether to allow for killing ADB process. /// public bool AllowAdbHardRestart { get => _allowAdbHardRestart; set { SetAndNotify(ref _allowAdbHardRestart, value); ConfigurationHelper.SetValue(ConfigurationKeys.AllowAdbHardRestart, value.ToString()); } } private bool _deploymentWithPause = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeDeploymentWithPause, bool.FalseString)); public bool DeploymentWithPause { get => _deploymentWithPause; set { SetAndNotify(ref _deploymentWithPause, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeDeploymentWithPause, value.ToString()); UpdateInstanceSettings(); } } private bool _adbLiteEnabled = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.AdbLiteEnabled, bool.FalseString)); public bool AdbLiteEnabled { get => _adbLiteEnabled; set { SetAndNotify(ref _adbLiteEnabled, value); ConfigurationHelper.SetValue(ConfigurationKeys.AdbLiteEnabled, value.ToString()); UpdateInstanceSettings(); } } private bool _killAdbOnExit = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.KillAdbOnExit, bool.FalseString)); public bool KillAdbOnExit { get => _killAdbOnExit; set { SetAndNotify(ref _killAdbOnExit, value); ConfigurationHelper.SetValue(ConfigurationKeys.KillAdbOnExit, value.ToString()); UpdateInstanceSettings(); } } /// /// Gets the default addresses. /// public Dictionary> DefaultAddress { get; } = new() { { "General", [string.Empty] }, { "BlueStacks", ["127.0.0.1:5555", "127.0.0.1:5556", "127.0.0.1:5565", "127.0.0.1:5575", "127.0.0.1:5585", "127.0.0.1:5595", "127.0.0.1:5554"] }, { "MuMuEmulator12", ["127.0.0.1:16384", "127.0.0.1:16416", "127.0.0.1:16448", "127.0.0.1:16480", "127.0.0.1:16512", "127.0.0.1:16544", "127.0.0.1:16576"] }, { "LDPlayer", ["emulator-5554", "emulator-5556", "emulator-5558", "emulator-5560", "127.0.0.1:5555", "127.0.0.1:5556", "127.0.0.1:5554"] }, { "Nox", ["127.0.0.1:62001", "127.0.0.1:59865"] }, { "XYAZ", ["127.0.0.1:21503"] }, { "WSA", ["127.0.0.1:58526"] }, }; /// /// RegisterKey of Bluestacks_Nxt /// private const string BluestacksNxtRegistryKey = @"SOFTWARE\BlueStacks_nxt"; private const string BluestacksNxtValueName = "UserDefinedDir"; /// /// Refreshes ADB config. /// /// Errors when doing this operation. /// Whether the operation is successful. public bool DetectAdbConfig(ref string error) { var adapter = new WinAdapter(); List emulators; try { emulators = adapter.RefreshEmulatorsInfo(); } catch (Exception e) { _logger.Information(e.Message); error = LocalizationHelper.GetString("EmulatorException"); return false; } switch (emulators.Count) { case 0: error = LocalizationHelper.GetString("EmulatorNotFound"); return false; case > 1: error = LocalizationHelper.GetString("EmulatorTooMany"); break; } ConnectConfig = emulators.First(); AdbPath = adapter.GetAdbPathByEmulatorName(ConnectConfig) ?? AdbPath; if (string.IsNullOrEmpty(AdbPath)) { error = LocalizationHelper.GetString("AdbException"); return false; } var addresses = adapter.GetAdbAddresses(AdbPath); switch (addresses.Count) { case 1: ConnectAddress = addresses.First(); break; case > 1: { foreach (var address in addresses.Where(address => address != "emulator-5554")) { ConnectAddress = address; break; } break; } } if (ConnectAddress.Length == 0) { ConnectAddress = DefaultAddress[ConnectConfig][0]; } return true; } /// /// Get the path of bluestacks.conf /// /// path private static string GetBluestacksConfig() { var conf = ConfigurationHelper.GetValue(ConfigurationKeys.BluestacksConfigPath, string.Empty); if (!string.IsNullOrEmpty(conf)) { return conf; } using RegistryKey key = Registry.LocalMachine.OpenSubKey(BluestacksNxtRegistryKey); object value = key?.GetValue(BluestacksNxtValueName); if (value != null) { return (string)value + @"\bluestacks.conf"; } return null; } /// /// Selects ADB program file. /// // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void SelectFile() { var dialog = new OpenFileDialog(); if (MaaWineBridge.Availability == WineBridgeAvailability.NotAvailable) { dialog.Filter = LocalizationHelper.GetString("AdbProgram") + "|*.exe"; } if (dialog.ShowDialog() == true) { AdbPath = dialog.FileName; } } /// /// 标题栏显示模拟器名称和IP端口。 /// public void UpdateWindowTitle() { var rvm = (RootViewModel)this.Parent; string prefix = ConfigurationHelper.GetValue(ConfigurationKeys.WindowTitlePrefix, string.Empty); if (!string.IsNullOrEmpty(prefix)) { prefix += " - "; } List windowTitleSelectShowList = _windowTitleSelectShowList .Where(x => _windowTitleAllShowDict.ContainsKey(x?.ToString() ?? string.Empty)) .Select(x => _windowTitleAllShowDict[x?.ToString() ?? string.Empty]).ToList(); string currentConfiguration = string.Empty; string connectConfigName = string.Empty; string connectAddress = string.Empty; string clientName = string.Empty; foreach (var select in windowTitleSelectShowList) { switch (select) { case "1": // 配置名 currentConfiguration = $" ({CurrentConfiguration})"; break; case "2": // 连接模式 foreach (var data in ConnectConfigList.Where(data => data.Value == ConnectConfig)) { connectConfigName = $" - {data.Display}"; } break; case "3": // 端口地址 connectAddress = $" ({ConnectAddress})"; break; case "4": // 客户端类型 clientName = $" - {ClientName}"; break; } } string resourceVersion = !string.IsNullOrEmpty(ResourceVersion) ? $" - {ResourceVersion}" : string.Empty; rvm.WindowTitle = $"{prefix}MAA{currentConfiguration} - {CoreVersion}{resourceVersion}{connectConfigName}{connectAddress}{clientName}"; } private readonly string _bluestacksConfig = GetBluestacksConfig(); private string _bluestacksKeyWord = ConfigurationHelper.GetValue(ConfigurationKeys.BluestacksConfigKeyword, string.Empty); /// /// Tries to set BlueStack Hyper V address. /// /// success public string TryToSetBlueStacksHyperVAddress() { if (string.IsNullOrEmpty(_bluestacksConfig)) { return null; } if (!File.Exists(_bluestacksConfig)) { ConfigurationHelper.SetValue(ConfigurationKeys.BluestacksConfigError, "File not exists"); return null; } var allLines = File.ReadAllLines(_bluestacksConfig); // ReSharper disable once InvertIf if (string.IsNullOrEmpty(_bluestacksKeyWord)) { foreach (var line in allLines) { if (!line.StartsWith("bst.installed_images")) { continue; } var images = line.Split('"')[1].Split(','); _bluestacksKeyWord = "bst.instance." + images[0] + ".status.adb_port"; break; } } return (from line in allLines where line.StartsWith(_bluestacksKeyWord) select line.Split('"') into sp select "127.0.0.1:" + sp[1]) .FirstOrDefault(); } public bool IsAdbTouchMode() { return TouchMode == "adb"; } private string _touchMode = ConfigurationHelper.GetValue(ConfigurationKeys.TouchMode, "minitouch"); public string TouchMode { get => _touchMode; set { SetAndNotify(ref _touchMode, value); UpdateInstanceSettings(); ConfigurationHelper.SetValue(ConfigurationKeys.TouchMode, value); AskRestartToApplySettings(); } } public void UpdateInstanceSettings() { Instances.AsstProxy.AsstSetInstanceOption(InstanceOptionKey.TouchMode, TouchMode); Instances.AsstProxy.AsstSetInstanceOption(InstanceOptionKey.DeploymentWithPause, DeploymentWithPause ? "1" : "0"); Instances.AsstProxy.AsstSetInstanceOption(InstanceOptionKey.AdbLiteEnabled, AdbLiteEnabled ? "1" : "0"); Instances.AsstProxy.AsstSetInstanceOption(InstanceOptionKey.KillAdbOnExit, KillAdbOnExit ? "1" : "0"); } // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public async void ReplaceAdb() { if (string.IsNullOrEmpty(AdbPath)) { _ = Execute.OnUIThreadAsync(() => { using var toast = new ToastNotification(LocalizationHelper.GetString("NoAdbPathSpecifiedMessage")); toast.Show(); }); return; } if (!File.Exists(MaaUrls.GoogleAdbFilename)) { var downloadResult = await Instances.HttpService.DownloadFileAsync(new Uri(MaaUrls.GoogleAdbDownloadUrl), MaaUrls.GoogleAdbFilename); if (!downloadResult) { downloadResult = await Instances.HttpService.DownloadFileAsync(new Uri(MaaUrls.AdbMaaMirrorDownloadUrl), MaaUrls.GoogleAdbFilename); } if (!downloadResult) { _ = Execute.OnUIThreadAsync(() => { using var toast = new ToastNotification(LocalizationHelper.GetString("AdbDownloadFailedTitle")); toast.AppendContentText(LocalizationHelper.GetString("AdbDownloadFailedDesc")).Show(); }); return; } } const string UnzipDir = "adb"; const string NewAdb = UnzipDir + "/platform-tools/adb.exe"; try { if (Directory.Exists(UnzipDir)) { Directory.Delete(UnzipDir, true); } } catch (Exception ex) { _logger.Error($"An error occurred while deleting directory: {ex.GetType()}: {ex.Message}"); _ = Execute.OnUIThreadAsync(() => { using var toast = new ToastNotification(LocalizationHelper.GetString("AdbDeletionFailedMessage")); toast.Show(); }); return; } try { ZipFile.ExtractToDirectory(MaaUrls.GoogleAdbFilename, UnzipDir); } catch (Exception ex) { _logger.Error(ex.ToString()); _ = Execute.OnUIThreadAsync(() => { using var toast = new ToastNotification(LocalizationHelper.GetString("UnzipFailedMessage")); toast.Show(); }); return; } bool replaced = false; if (AdbPath != NewAdb && File.Exists(AdbPath)) { try { foreach (var process in Process.GetProcessesByName(Path.GetFileName(AdbPath))) { process.Kill(); process.WaitForExit(5000); } string adbBack = AdbPath + ".bak"; if (!File.Exists(adbBack)) { File.Copy(AdbPath, adbBack, true); } File.Copy(NewAdb, AdbPath, true); replaced = true; } catch (Exception ex) { _logger.Error(ex.ToString()); replaced = false; } } if (replaced) { AdbReplaced = true; ConfigurationHelper.SetValue(ConfigurationKeys.AdbReplaced, bool.TrueString); _ = Execute.OnUIThreadAsync(() => { using var toast = new ToastNotification(LocalizationHelper.GetString("SuccessfullyReplacedAdb")); toast.Show(); }); } else { AdbPath = NewAdb; _ = Execute.OnUIThreadAsync(() => { using var toast = new ToastNotification(LocalizationHelper.GetString("FailedToReplaceAdbAndUseLocal")); toast.AppendContentText(LocalizationHelper.GetString("FailedToReplaceAdbAndUseLocalDesc")).Show(); }); } } public bool AdbReplaced { get; set; } = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.AdbReplaced, bool.FalseString)); #endregion #region 界面设置 /// /// Gets or sets the language list. /// public List LanguageList { get; set; } /// /// Gets the list of dark mode. /// public List> DarkModeList { get; } = [ new() { Display = LocalizationHelper.GetString("Light"), Value = DarkModeType.Light }, new() { Display = LocalizationHelper.GetString("Dark"), Value = DarkModeType.Dark }, new() { Display = LocalizationHelper.GetString("SyncWithOs"), Value = DarkModeType.SyncWithOs }, ]; /// /// Gets the list of inverse clear modes. /// public List InverseClearModeList { get; } = [ new() { Display = LocalizationHelper.GetString("Clear"), Value = "Clear" }, new() { Display = LocalizationHelper.GetString("Inverse"), Value = "Inverse" }, new() { Display = LocalizationHelper.GetString("Switchable"), Value = "ClearInverse" }, ]; /* /// /// Gets a value indicating whether to use tray icon. /// public bool UseTray => true; */ private bool _minimizeToTray = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.MinimizeToTray, bool.FalseString)); /// /// Gets or sets a value indicating whether to minimize to tray. /// public bool MinimizeToTray { get => _minimizeToTray; set { SetAndNotify(ref _minimizeToTray, value); ConfigurationHelper.SetValue(ConfigurationKeys.MinimizeToTray, value.ToString()); Instances.MainWindowManager.SetMinimizeToTaskBar(value); } } private bool _windowTitleScrollable = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.WindowTitleScrollable, bool.FalseString)); /// /// Gets or sets a value indicating whether to make window title scrollable. /// public bool WindowTitleScrollable { get => _windowTitleScrollable; set { SetAndNotify(ref _windowTitleScrollable, value); ConfigurationHelper.SetValue(ConfigurationKeys.WindowTitleScrollable, value.ToString()); var rvm = (RootViewModel)this.Parent; rvm.WindowTitleScrollable = value; } } private bool _hideCloseButton = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.HideCloseButton, bool.FalseString)); /// /// Gets or sets a value indicating whether to hide close button. /// public bool HideCloseButton { get => _hideCloseButton; set { SetAndNotify(ref _hideCloseButton, value); ConfigurationHelper.SetValue(ConfigurationKeys.HideCloseButton, value.ToString()); var rvm = (RootViewModel)this.Parent; rvm.ShowCloseButton = !value; } } /// /// Gets or sets a value indicating whether to use notification. /// public bool UseNotify { get => ConfigFactory.CurrentConfig.GUI.UseNotify; set { ConfigFactory.CurrentConfig.GUI.UseNotify = value; NotifyOfPropertyChange(); if (value) { Execute.OnUIThreadAsync(() => { using var toast = new ToastNotification("Test test"); toast.Show(); }); } } } private bool _useLogItemDateFormat = true; // Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.UseLogItemDateFormat, bool.FalseString)); public bool UseLogItemDateFormat { get => _useLogItemDateFormat; set { SetAndNotify(ref _useLogItemDateFormat, value); ConfigurationHelper.SetValue(ConfigurationKeys.UseLogItemDateFormat, value.ToString()); } } public List LogItemDateFormatStringList { get; } = [ "HH:mm:ss", "MM-dd HH:mm:ss", "MM/dd HH:mm:ss", "MM.dd HH:mm:ss", "dd-MM HH:mm:ss", "dd/MM HH:mm:ss", "dd.MM HH:mm:ss", ]; private string _logItemDateFormatString = ConfigurationHelper.GetValue(ConfigurationKeys.LogItemDateFormat, "HH:mm:ss"); public string LogItemDateFormatString { get => _logItemDateFormatString; set { SetAndNotify(ref _logItemDateFormatString, value); ConfigurationHelper.SetValue(ConfigurationKeys.LogItemDateFormat, value); } } /// /// Gets or sets the dark mode. /// public DarkModeType DarkMode { get => ConfigFactory.CurrentConfig.GUI.DarkMode; set { ConfigFactory.CurrentConfig.GUI.DarkMode = value; NotifyOfPropertyChange(); SwitchDarkMode(); /* AskToRestartToApplySettings(); */ } } public void SwitchDarkMode() { DarkModeType darkModeType = ConfigFactory.CurrentConfig.GUI.DarkMode; switch (darkModeType) { case DarkModeType.Light: ThemeHelper.SwitchToLightMode(); break; case DarkModeType.Dark: ThemeHelper.SwitchToDarkMode(); break; case DarkModeType.SyncWithOs: ThemeHelper.SwitchToSyncWithOsMode(); break; default: throw new ArgumentOutOfRangeException(); } } private enum InverseClearType { Clear, Inverse, ClearInverse, } private InverseClearType _inverseClearMode = Enum.TryParse(ConfigurationHelper.GetValue(ConfigurationKeys.InverseClearMode, InverseClearType.Clear.ToString()), out InverseClearType temp) ? temp : InverseClearType.Clear; /// /// Gets or sets the inverse clear mode. /// public string InverseClearMode { get => _inverseClearMode.ToString(); set { if (!Enum.TryParse(value, out InverseClearType tempEnumValue)) { return; } SetAndNotify(ref _inverseClearMode, tempEnumValue); ConfigurationHelper.SetValue(ConfigurationKeys.InverseClearMode, value); switch (tempEnumValue) { case InverseClearType.Clear: Instances.TaskQueueViewModel.InverseMode = false; Instances.TaskQueueViewModel.ShowInverse = false; Instances.TaskQueueViewModel.SelectedAllWidth = 90; break; case InverseClearType.Inverse: Instances.TaskQueueViewModel.InverseMode = true; Instances.TaskQueueViewModel.ShowInverse = false; Instances.TaskQueueViewModel.SelectedAllWidth = 90; break; case InverseClearType.ClearInverse: Instances.TaskQueueViewModel.ShowInverse = true; Instances.TaskQueueViewModel.SelectedAllWidth = TaskQueueViewModel.SelectedAllWidthWhenBoth; break; default: throw new ArgumentOutOfRangeException(); } } } private static readonly Dictionary _windowTitleAllShowDict = new() { { LocalizationHelper.GetString("ConfigurationName"), "1" }, { LocalizationHelper.GetString("ConnectionPreset"), "2" }, { LocalizationHelper.GetString("ConnectionAddress"), "3" }, { LocalizationHelper.GetString("ClientType"), "4" }, }; private List _windowTitleAllShowList = [.. _windowTitleAllShowDict.Keys]; public List WindowTitleAllShowList { get => _windowTitleAllShowList; set => SetAndNotify(ref _windowTitleAllShowList, value); } private object[] _windowTitleSelectShowList = ConfigurationHelper.GetValue(ConfigurationKeys.WindowTitleSelectShowList, "1 2 3 4").Split(' ').Select(s => _windowTitleAllShowDict.FirstOrDefault(pair => pair.Value == s).Key).ToArray(); public object[] WindowTitleSelectShowList { get => _windowTitleSelectShowList; set { SetAndNotify(ref _windowTitleSelectShowList, value); UpdateWindowTitle(); var config = string.Join(' ', _windowTitleSelectShowList.Cast().Select(s => _windowTitleAllShowDict[s])); ConfigurationHelper.SetValue(ConfigurationKeys.WindowTitleSelectShowList, config); } } private string _language = ConfigurationHelper.GetValue(ConfigurationKeys.Localization, LocalizationHelper.DefaultLanguage); /// /// Gets or sets the language. /// public string Language { get => _language; set { if (value == _language) { return; } if (_language == PallasLangKey) { Hangover = true; Cheers = false; } if (value != PallasLangKey) { SoberLanguage = value; } // var backup = _language; ConfigurationHelper.SetValue(ConfigurationKeys.Localization, value); var mainWindow = Application.Current.MainWindow; if (mainWindow != null) { mainWindow.Show(); mainWindow.WindowState = mainWindow.WindowState = WindowState.Normal; mainWindow.Activate(); } var result = MessageBoxHelper.Show( FormatText("{0}\n{1}", "LanguageChangedTip"), FormatText("{0}({1})", "Tip"), MessageBoxButton.OKCancel, MessageBoxImage.Question, ok: FormatText("{0}({1})", "Ok"), cancel: FormatText("{0}({1})", "ManualRestart")); if (result == MessageBoxResult.OK) { Bootstrapper.ShutdownAndRestartWithoutArgs(); } SetAndNotify(ref _language, value); return; string FormatText(string text, string key) => string.Format(text, LocalizationHelper.GetString(key, value), LocalizationHelper.GetString(key, _language)); } } /// /// Gets the language info. /// public string LanguageInfo { get { var language = (string)Application.Current.Resources["Language"]; return language == "Language" ? language : language + " / Language"; } } #endregion #region HotKey /// /// Gets or sets the hotkey: ShowGui. /// public static MaaHotKey HotKeyShowGui { get => Instances.MaaHotKeyManager.GetOrNull(MaaHotKeyAction.ShowGui); set => SetHotKey(MaaHotKeyAction.ShowGui, value); } /// /// Gets or sets the hotkey: LinkStart. /// public static MaaHotKey HotKeyLinkStart { get => Instances.MaaHotKeyManager.GetOrNull(MaaHotKeyAction.LinkStart); set => SetHotKey(MaaHotKeyAction.LinkStart, value); } private static void SetHotKey(MaaHotKeyAction action, MaaHotKey value) { if (value != null) { Instances.MaaHotKeyManager.TryRegister(action, value); } else { Instances.MaaHotKeyManager.UnRegister(action); } } #endregion #region 配置 public ObservableCollection ConfigurationList { get; set; } private string _currentConfiguration = ConfigurationHelper.GetCurrentConfiguration(); public string CurrentConfiguration { get => _currentConfiguration; set { SetAndNotify(ref _currentConfiguration, value); ConfigurationHelper.SwitchConfiguration(value); Bootstrapper.ShutdownAndRestartWithoutArgs(); } } private string _newConfigurationName; public string NewConfigurationName { get => _newConfigurationName; set => SetAndNotify(ref _newConfigurationName, value); } // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void AddConfiguration() { if (string.IsNullOrEmpty(NewConfigurationName)) { NewConfigurationName = DateTime.Now.ToString("yy/MM/dd HH:mm:ss"); } if (ConfigurationHelper.AddConfiguration(NewConfigurationName, CurrentConfiguration)) { ConfigurationList.Add(new CombinedData { Display = NewConfigurationName, Value = NewConfigurationName }); var growlInfo = new GrowlInfo { IsCustom = true, Message = string.Format(LocalizationHelper.GetString("AddConfigSuccess"), NewConfigurationName), IconKey = "HangoverGeometry", IconBrushKey = "PallasBrush", }; Growl.Info(growlInfo); } else { var growlInfo = new GrowlInfo { IsCustom = true, Message = string.Format(LocalizationHelper.GetString("ConfigExists"), NewConfigurationName), IconKey = "HangoverGeometry", IconBrushKey = "PallasBrush", }; Growl.Info(growlInfo); } } // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void DeleteConfiguration(CombinedData delete) { if (ConfigurationHelper.DeleteConfiguration(delete.Display)) { ConfigurationList.Remove(delete); } } #endregion #region SettingsGuide // 目前共4步,再多塞不下了,后续可以整个新功能展示( public const int GuideMaxStep = 4; private int _guideStepIndex = Convert.ToInt32(ConfigurationHelper.GetValue(ConfigurationKeys.GuideStepIndex, "0")); public int GuideStepIndex { get => _guideStepIndex; set { SetAndNotify(ref _guideStepIndex, value); if (value == GuideMaxStep) { ConfigurationHelper.SetValue(ConfigurationKeys.GuideStepIndex, value.ToString()); } } } private string _guideTransitionMode = "Bottom2Top"; public string GuideTransitionMode { get => _guideTransitionMode; set => SetAndNotify(ref _guideTransitionMode, value); } // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void NextGuide(StepBar stepBar) { GuideTransitionMode = "Bottom2Top"; stepBar.Next(); } // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void PrevGuide(StepBar stepBar) { GuideTransitionMode = "Top2Bottom"; stepBar.Prev(); } // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public void DoneGuide() { TaskSettingVisibilities.Guide = false; GuideStepIndex = GuideMaxStep; } #endregion SettingsGuide /// /// 要求用户重启以应用设置 /// private void AskRestartToApplySettings() { var result = MessageBoxHelper.Show( LocalizationHelper.GetString("PromptRestartForSettingsChange"), LocalizationHelper.GetString("Tip"), MessageBoxButton.OKCancel, MessageBoxImage.Question); if (result == MessageBoxResult.OK) { Bootstrapper.ShutdownAndRestartWithoutArgs(); } } /// /// Remembers the user to set 1920x1080 for YoStarEN. /// private static void AskRestartToApplySettingsYoStarEN() { var result = MessageBoxHelper.Show( LocalizationHelper.GetString("PromptRestartForSettingsChange") + "\n" + LocalizationHelper.GetString("SwitchResolutionTip"), LocalizationHelper.GetString("Tip"), MessageBoxButton.OKCancel, MessageBoxImage.Question); if (result == MessageBoxResult.OK) { Bootstrapper.ShutdownAndRestartWithoutArgs(); } } /// /// Make comboBox searchable /// /// Event sender /// Event args // UI 绑定的方法 // EventArgs 不能省略,否则会报错 // ReSharper disable once UnusedMember.Global // ReSharper disable once UnusedParameter.Global public void MakeComboBoxSearchable(object sender, EventArgs e) { (sender as ComboBox)?.MakeComboBoxSearchable(); } // UI 绑定的方法 // ReSharper disable once UnusedMember.Global public async Task CheckAndDownloadAnnouncement() { await Instances.AnnouncementViewModel.CheckAndDownloadAnnouncement(); _ = Execute.OnUIThreadAsync(() => Instances.WindowManager.ShowWindow(Instances.AnnouncementViewModel)); } public void SetupSleepManagement() { if (!BlockSleep) { return; } SleepManagement.BlockSleep(BlockSleepWithScreenOn); _logger.Information("Blocking sleep."); } } }