diff --git a/resource/item_index.json b/resource/item_index.json index fb42ff0d53..0253f29b89 100644 --- a/resource/item_index.json +++ b/resource/item_index.json @@ -1679,6 +1679,38 @@ "sortId": 30001, "usage": "一份椒盐果仁的糖皮月饼,可用于恢复理智。" }, + "ap_supply_lt_120_2023_1": { + "classifyType": "CONSUME", + "description": "可口凉爽的冰皮月饼,记得冷藏保存哦!", + "icon": "ap_supply_lt_120_2023_1.png", + "name": "“满庭光”", + "sortId": 30001, + "usage": "一份芒果椰蓉馅的冰皮月饼,可用于恢复理智。" + }, + "ap_supply_lt_120_2023_2": { + "classifyType": "CONSUME", + "description": "可口凉爽的冰皮月饼,记得冷藏保存哦!", + "icon": "ap_supply_lt_120_2023_2.png", + "name": "“良宵晴”", + "sortId": 30001, + "usage": "一份肉松馅的冰皮月饼,可用于恢复理智。" + }, + "ap_supply_lt_120_2023_3": { + "classifyType": "CONSUME", + "description": "香甜脆爽的糖皮月饼,食用前记得加热哦!", + "icon": "ap_supply_lt_120_2023_3.png", + "name": "“飘桂香”", + "sortId": 30001, + "usage": "一份豆沙桂花馅的糖皮月饼,可用于恢复理智。" + }, + "ap_supply_lt_120_2023_4": { + "classifyType": "CONSUME", + "description": "香甜脆爽的糖皮月饼,食用前记得加热哦!", + "icon": "ap_supply_lt_120_2023_4.png", + "name": "“藏金波“", + "sortId": 30001, + "usage": "一份咸蛋黄馅的糖皮月饼,可用于恢复理智。" + }, "ap_supply_lt_60": { "classifyType": "CONSUME", "description": "虽然暴饮暴食可以缓解战场带来的焦虑与压力,但总归不利于博士的身体健康。本品含有一定糖分,故而外包装采取特制结构,较难拆解,请借此消耗掉多余的卡路里。", diff --git a/src/MaaWpfGui/Constants/ConfigurationKeys.cs b/src/MaaWpfGui/Constants/ConfigurationKeys.cs index c9bcebab6c..10cdd34490 100644 --- a/src/MaaWpfGui/Constants/ConfigurationKeys.cs +++ b/src/MaaWpfGui/Constants/ConfigurationKeys.cs @@ -163,6 +163,11 @@ namespace MaaWpfGui.Constants public const string DropsItemName = "MainFunction.Drops.ItemName"; public const string DropsQuantity = "MainFunction.Drops.Quantity"; + public const string RemoteControlGetTaskEndpointUri = "RemoteControl.RemoteControlGetTaskEndpointUri"; + public const string RemoteControlReportStatusUri = "RemoteControl.RemoteControlReportStatusUri"; + public const string RemoteControlUserIdentity = "RemoteControl.RemoteControlUserIdentity"; + public const string RemoteControlDeviceIdentity = "RemoteControl.RemoteControlDeviceIdentity"; + public const string ExternalNotificationEnabled = "ExternalNotification.Enabled"; public const string ExternalNotificationSmtpServer = "ExternalNotification.Smtp.Server"; public const string ExternalNotificationSmtpPort = "ExternalNotification.Smtp.Port"; diff --git a/src/MaaWpfGui/Helper/Instances.cs b/src/MaaWpfGui/Helper/Instances.cs index 132eae623d..56b067c322 100644 --- a/src/MaaWpfGui/Helper/Instances.cs +++ b/src/MaaWpfGui/Helper/Instances.cs @@ -16,6 +16,7 @@ using MaaWpfGui.Main; using MaaWpfGui.Services; using MaaWpfGui.Services.HotKeys; using MaaWpfGui.Services.Managers; +using MaaWpfGui.Services.RemoteControl; using MaaWpfGui.Services.Web; using MaaWpfGui.ViewModels.UI; using Stylet; @@ -50,6 +51,8 @@ namespace MaaWpfGui.Helper public static IMaaHotKeyActionHandler MaaHotKeyActionHandler { get; private set; } + public static RemoteControlService RemoteControlService { get; private set; } + public static IMainWindowManager MainWindowManager { get; private set; } public static IHttpService HttpService { get; private set; } @@ -71,6 +74,8 @@ namespace MaaWpfGui.Helper HttpService = container.Get(); MaaApiService = container.Get(); + RemoteControlService = container.Get(); + HotKeyManager = container.Get(); MaaHotKeyManager = container.Get(); MaaHotKeyActionHandler = container.Get(); diff --git a/src/MaaWpfGui/Main/Bootstrapper.cs b/src/MaaWpfGui/Main/Bootstrapper.cs index 4e91392e56..52886096f8 100644 --- a/src/MaaWpfGui/Main/Bootstrapper.cs +++ b/src/MaaWpfGui/Main/Bootstrapper.cs @@ -23,6 +23,7 @@ using MaaWpfGui.Helper; using MaaWpfGui.Services; using MaaWpfGui.Services.HotKeys; using MaaWpfGui.Services.Managers; +using MaaWpfGui.Services.RemoteControl; using MaaWpfGui.Services.Web; using MaaWpfGui.ViewModels.UI; using MaaWpfGui.Views.UI; @@ -171,6 +172,8 @@ namespace MaaWpfGui.Main builder.Bind().To().InSingletonScope(); builder.Bind().To().InSingletonScope(); + builder.Bind().To().InSingletonScope(); + builder.Bind().To().InSingletonScope(); builder.Bind().To().InSingletonScope(); diff --git a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml index e2117f6a33..bc7434ce82 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml @@ -234,6 +234,13 @@ 附加命令 开始前脚本 结束后脚本 + 远程控制 + 设备标识符(只读) + 测试连接 + 重新生成 + 用户标识符 + 获取任务端点 + 汇报任务端点 肉鸽主题 傀影 水月 @@ -663,6 +670,12 @@ 游戏资源已更新,请重启 MAA 游戏资源正在更新,请勿关闭 MAA + + 连接测试成功! + 连接测试失败。 + 收到远端任务{0},任务Id:{1}。 + 完成远端任务{0},任务Id:{1}。 + 博士,有新的通知哦! 您会收到此邮件,是因为您在 MAA 中设置了 SMTP 服务器并开启了邮件通知服务。 diff --git a/src/MaaWpfGui/Services/RemoteControl/RemoteControlService.cs b/src/MaaWpfGui/Services/RemoteControl/RemoteControlService.cs new file mode 100644 index 0000000000..da451edc96 --- /dev/null +++ b/src/MaaWpfGui/Services/RemoteControl/RemoteControlService.cs @@ -0,0 +1,496 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; +using System.Windows.Threading; +using MaaWpfGui.Constants; +using MaaWpfGui.Helper; +using MaaWpfGui.States; +using MaaWpfGui.ViewModels.UI; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Serilog; +using static System.Windows.Forms.VisualStyles.VisualStyleElement; + +namespace MaaWpfGui.Services.RemoteControl +{ + public class RemoteControlService + { + private readonly Task _pollJobTask = Task.CompletedTask; + private readonly Task _executeJobTask = Task.CompletedTask; + private readonly List _executedTaskIds = new List(); + private readonly ConcurrentQueue _taskQueue = new ConcurrentQueue(); + private readonly RunningState _runningState; + + public RemoteControlService() + { + _pollJobTask = _pollJobTask.ContinueWith(async (_) => + { + while (true) + { + await Task.Delay(1000); + try + { + await PollJobTaskLoop(); + } + catch (Exception ex) + { + Log.Logger.Error(ex, "RemoteControl service raises unknown error."); + } + } + + // ReSharper disable once FunctionNeverReturns + }); + + _executeJobTask = _executeJobTask.ContinueWith(async (_) => + { + while (true) + { + await Task.Delay(1000); + try + { + await ExecuteJobLoop(); + } + catch (Exception ex) + { + Log.Logger.Error(ex, "RemoteControl service raises unknown error."); + } + } + + // ReSharper disable once FunctionNeverReturns + }); + + _runningState = RunningState.Instance; + } + + #region Private Method Invoker + + private static void InvokeInstanceMethod(object instance, string methodName) + { + if (instance == null) + { + throw new ArgumentNullException(nameof(instance)); + } + + if (string.IsNullOrEmpty(methodName)) + { + throw new ArgumentNullException(nameof(methodName)); + } + + Type type = instance.GetType(); + MethodInfo methodInfo = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); + + if (methodInfo == null) + { + throw new ArgumentException($"Method '{methodName}' not found in type '{type.FullName}'."); + } + + methodInfo.Invoke(instance, null); + } + + private static T InvokeInstanceFunction(object instance, string methodName) + { + if (instance == null) + { + throw new ArgumentNullException(nameof(instance)); + } + + if (string.IsNullOrEmpty(methodName)) + { + throw new ArgumentNullException(nameof(methodName)); + } + + Type type = instance.GetType(); + MethodInfo methodInfo = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); + + if (methodInfo == null) + { + throw new ArgumentException($"Method '{methodName}' not found in type '{type.FullName}'."); + } + + if (!typeof(T).IsAssignableFrom(methodInfo.ReturnType)) + { + throw new ArgumentException($"Method '{methodName}' is not {typeof(T)}."); + } + + return (T)methodInfo.Invoke(instance, null); + } + + private static async Task InvokeInstanceAsyncFunction(object instance, string methodName) + { + if (instance == null) { throw new ArgumentNullException(nameof(instance)); } + if (string.IsNullOrEmpty(methodName)) { throw new ArgumentNullException(nameof(methodName)); } + + Type type = instance.GetType(); + MethodInfo methodInfo = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); + + if (methodInfo == null) + { + throw new ArgumentException($"Method '{methodName}' not found in type '{type.FullName}'."); + } + + // 检查方法是否是异步方法 (返回Task或Task) + if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType)) + { + throw new ArgumentException($"Method '{methodName}' is not asynchronous."); + } + + return await (Task)methodInfo.Invoke(instance, null); + } + + private static TResult InvokeStaticFunction(Type staticType, string methodName) + { + if (staticType == null) { throw new ArgumentNullException(nameof(staticType)); } + + if (string.IsNullOrEmpty(methodName)) { throw new ArgumentNullException(nameof(methodName)); } + + MethodInfo methodInfo = staticType.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static); + + if (methodInfo == null) + { + throw new ArgumentException($"Method '{methodName}' not found in type '{staticType.FullName}'."); + } + + return (TResult)methodInfo.Invoke(null, null); + } + + #endregion + + private async Task PollJobTaskLoop() + { + var endpoint = Instances.SettingsViewModel.RemoteControlGetTaskEndpointUri; + var uid = Instances.SettingsViewModel.RemoteControlUserIdentity; + var did = Instances.SettingsViewModel.RemoteControlDeviceIdentity; + var response = await Instances.HttpService.PostAsJsonAsync(new Uri(endpoint), new { user=uid, device = did}); + if (response == null) + { + Log.Logger.Error("RemoteControlService endpoint failed."); + return; + } + + var jsonObject = JsonConvert.DeserializeObject(response); + + // A list of task + if (jsonObject?.GetValue("tasks") is JArray tasks) + { + foreach (var task in tasks.OfType()) + { + var type = task.GetValue("type")?.Value(); + if (!string.IsNullOrWhiteSpace(type)) + { + // It is a valid task + var id = task.GetValue("id")?.Value(); + if (!_executedTaskIds.Contains(id)) + { + _executedTaskIds.Add(id); + + _taskQueue.Enqueue(task); + } + } + } + } + } + + private async Task ExecuteJobLoop() + { + if (_taskQueue.TryDequeue(out var task)) + { + var type = task.GetValue("type")?.Value(); + var id = task.GetValue("id")?.Value(); + var data = task.GetValue("params")?.Value(); + var payload = string.Empty; + var status = "SUCCESS"; + + switch (type) + { + case "LinkStart": + { + // 一键长草特殊任务 + await _runningState.UntilIdleAsync(); + var startLogStr = string.Format(LocalizationHelper.GetString("RemoteControlReceivedTask"), type, id); + + Application.Current.Dispatcher.Invoke(() => + { + Instances.TaskQueueViewModel.AddLog(startLogStr); + Instances.TaskQueueViewModel.LinkStart(); + }); + await _runningState.UntilIdleAsync(); + + var stopLogStr = string.Format(LocalizationHelper.GetString("RemoteControlCompletedTask"), type, id); + Application.Current.Dispatcher.Invoke(() => + { + Instances.TaskQueueViewModel.AddLog(stopLogStr); + }); + break; + } + + case "LinkStart-Base": + case "LinkStart-WakeUp": + case "LinkStart-Combat": + case "LinkStart-Recruiting": + case "LinkStart-Mall": + case "LinkStart-Mission": + case "LinkStart-AutoRoguelike": + case "LinkStart-ReclamationAlgorithm": + { + await LinkStart(new[] { type.Split('-')[1] }); + break; + } + + case "Toolbox-GachaOnce": + { + await _runningState.UntilIdleAsync(); + Instances.RecognizerViewModel.GachaOnce(); + while (!Instances.RecognizerViewModel.GachaDone) + { + await Task.Delay(100); // 暂停100毫秒以避免密集循环 + } + + break; + } + + case "Toolbox-GachaTenTimes": + { + await _runningState.UntilIdleAsync(); + Instances.RecognizerViewModel.GachaTenTimes(); + while (!Instances.RecognizerViewModel.GachaDone) + { + await Task.Delay(100); // 暂停100毫秒以避免密集循环 + } + + break; + } + + case "CaptureImage": + { + string errMsg = string.Empty; + bool connected = await Task.Run(() => Instances.AsstProxy.AsstConnect(ref errMsg)); + if (connected) + { + var image = Instances.AsstProxy.AsstGetImage(); + if (image == null) + { + status = "FAILED"; + break; + } + + byte[] bytes; + using (MemoryStream stream = new MemoryStream()) + { + PngBitmapEncoder encoder = new PngBitmapEncoder(); + encoder.Frames.Add(BitmapFrame.Create(image)); + encoder.Save(stream); + bytes = stream.ToArray(); + } + + payload = Convert.ToBase64String(bytes); + break; + } + else + { + status = "FAILED"; + break; + } + } + + case "Settings-ConnectAddress": + // ConfigurationHelper.SetValue(type.Split('-')[1], data); + Application.Current.Dispatcher.Invoke(() => + { + Instances.SettingsViewModel.ConnectAddress = data; + }); + + break; + + default: + // 未知的Type统一直接发给MAACore + // No! 未知的任务一概不处理 + break; + } + + var endpoint = Instances.SettingsViewModel.RemoteControlReportStatusUri; + var uid = Instances.SettingsViewModel.RemoteControlUserIdentity; + var did = Instances.SettingsViewModel.RemoteControlDeviceIdentity; + var response = await Instances.HttpService.PostAsJsonAsync(new Uri(endpoint), new + { + user = uid, + device = did, + status = status, + task = id, + payload = payload, + }); + if (response == null) + { + Log.Logger.Error("RemoteControlService report task failed."); + } + } + } + + /// + /// 根据"一键长草"功能进行修改的方法。 + /// + /// + /// 注意以下特点: + /// - 可以在非UI线程执行。 + /// - 不调用StartScript。 + /// - 不使用Model里的列表。 + /// - 在结尾添加对RunningStatus的等待。 + /// 若"一键长草"功能在未来有更新,此方法也应进行相应的同步更新,但需确保上述特点保持不变。 + /// + /// 指定的任务列表。 + /// 异步任务,无返回结果。 + public async Task LinkStart(IEnumerable originalNames) + { + await _runningState.UntilIdleAsync(); + + _runningState.SetIdle(false); + + await Application.Current.Dispatcher.Invoke(async () => + { + + // 虽然更改时已经保存过了,不过保险起见还是在点击开始之后再保存一次任务及基建列表 + Instances.TaskQueueViewModel.TaskItemSelectionChanged(); + Instances.SettingsViewModel.InfrastOrderSelectionChanged(); + + InvokeInstanceMethod(Instances.TaskQueueViewModel, "ClearLog"); + + /*await Task.Run(() => Instances.SettingsViewModel.RunScript("StartsWithScript"));*/ + + Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("ConnectingToEmulator")); + if (!Instances.SettingsViewModel.AdbReplaced && !Instances.SettingsViewModel.IsAdbTouchMode()) + { + Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("AdbReplacementTips"), UiLogColor.Info); + } + + // 一般是点了“停止”按钮了 + if (Instances.TaskQueueViewModel.Stopping) + { + Instances.TaskQueueViewModel.SetStopped(); + return; + } + + if (!await InvokeInstanceAsyncFunction(Instances.TaskQueueViewModel, "ConnectToEmulator")) + { + return; + } + + // 一般是点了“停止”按钮了 + if (Instances.TaskQueueViewModel.Stopping) + { + Instances.TaskQueueViewModel.SetStopped(); + return; + } + + bool taskRet = true; + + // 直接遍历TaskItemViewModels里面的内容,是排序后的 + int count = 0; + foreach (var item in originalNames) + { + ++count; + switch (item) + { + case "Base": + taskRet &= InvokeInstanceFunction(Instances.TaskQueueViewModel, "AppendInfrast"); + break; + + case "WakeUp": + taskRet &= InvokeStaticFunction(Instances.TaskQueueViewModel.GetType(), "AppendStart"); + break; + + case "Combat": + taskRet &= InvokeInstanceFunction(Instances.TaskQueueViewModel, "AppendFight"); + break; + + case "Recruiting": + taskRet &= InvokeStaticFunction(Instances.TaskQueueViewModel.GetType(), "AppendRecruit"); + break; + + case "Mall": + taskRet &= InvokeInstanceFunction(Instances.TaskQueueViewModel, "AppendMall"); + break; + + case "Mission": + taskRet &= InvokeInstanceFunction(Instances.TaskQueueViewModel, "AppendAward"); + break; + + case "AutoRoguelike": + taskRet &= InvokeStaticFunction(Instances.TaskQueueViewModel.GetType(), "AppendRoguelike"); + break; + + case "ReclamationAlgorithm": + taskRet &= InvokeStaticFunction(Instances.TaskQueueViewModel.GetType(), "AppendReclamation"); + break; + + default: + --count; + + // Instances.TaskQueueViewModel._logger.Error("Unknown task: " + item); + break; + } + + if (taskRet) + { + continue; + } + + Instances.TaskQueueViewModel.AddLog(item + "Error", UiLogColor.Error); + taskRet = true; + --count; + } + + if (count == 0) + { + Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("UnselectedTask")); + _runningState.SetIdle(true); + Instances.TaskQueueViewModel.SetStopped(); + return; + } + + taskRet &= Instances.AsstProxy.AsstStart(); + + if (taskRet) + { + Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("Running")); + } + else + { + Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("UnknownErrorOccurs")); + await Instances.TaskQueueViewModel.Stop(); + Instances.TaskQueueViewModel.SetStopped(); + } + }); + + await _runningState.UntilIdleAsync(); + } + + public static async Task ConnectionTest() + { + var endpoint = Instances.SettingsViewModel.RemoteControlGetTaskEndpointUri; + var uid = Instances.SettingsViewModel.RemoteControlUserIdentity; + var did = Instances.SettingsViewModel.RemoteControlDeviceIdentity; + var response = await Instances.HttpService.PostAsJsonAsync(new Uri(endpoint), new { user = uid, device = did }); + + using var toast = new ToastNotification( + LocalizationHelper.GetString( + response != null ? "RemoteControlConnectionTestSuccess" : "RemoteControlConnectionTestFail")); + + // if (response != null) + // { + // toast.AppendContentText(response); + // } + toast.Show(); + + } + + public static void RegenerateDeviceIdentity() + { + Instances.SettingsViewModel.RemoteControlDeviceIdentity = Guid.NewGuid().ToString("N"); + } + } +} diff --git a/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs b/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs index 412ac2faf4..5e08ca1e8d 100644 --- a/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/SettingsViewModel.cs @@ -36,6 +36,7 @@ using MaaWpfGui.Main; using MaaWpfGui.Models; using MaaWpfGui.Services.HotKeys; using MaaWpfGui.Services.Notification; +using MaaWpfGui.Services.RemoteControl; using MaaWpfGui.States; using MaaWpfGui.Utilities; using MaaWpfGui.Utilities.ValueType; @@ -106,6 +107,7 @@ namespace MaaWpfGui.ViewModels.UI _listTitle.Add(LocalizationHelper.GetString("ConnectionSettings")); _listTitle.Add(LocalizationHelper.GetString("StartupSettings")); _listTitle.Add(LocalizationHelper.GetString("UISettings")); + _listTitle.Add(LocalizationHelper.GetString("RemoteControlSettings")); _listTitle.Add(LocalizationHelper.GetString("ExternalNotificationSettings")); _listTitle.Add(LocalizationHelper.GetString("HotKeySettings")); _listTitle.Add(LocalizationHelper.GetString("UpdateSettings")); @@ -150,6 +152,69 @@ namespace MaaWpfGui.ViewModels.UI } } + #region Remote Control + + public async void RemoteControlConnectionTest() + { + await RemoteControlService.ConnectionTest(); + } + + 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 + #region External Notifications public void ExternalNotificationSendTest() @@ -406,6 +471,14 @@ namespace MaaWpfGui.ViewModels.UI new CombinedData { Display = LocalizationHelper.GetString("RoguelikeThemeSami"), Value = "Sami" }, }; + RemoteControlList = new List + { + new CombinedData { Display = LocalizationHelper.GetString("RemoteControlHandshakeUri"), Value = "Phantom" }, + new CombinedData { Display = LocalizationHelper.GetString("RemoteControlEndpointUri"), Value = "Mizuki" }, + new CombinedData { Display = LocalizationHelper.GetString("RemoteControlUserIdentity"), Value = "Sami" }, + new CombinedData { Display = LocalizationHelper.GetString("RemoteControlUserIdentity"), Value = "Sami" }, + }; + UpdateRoguelikeSquadList(); UpdateRoguelikeCoreCharList(); @@ -1206,6 +1279,11 @@ namespace MaaWpfGui.ViewModels.UI /// public List TouchModeList { get; set; } + /// + /// Gets or sets the list of touch modes + /// + public List RemoteControlList { get; set; } + /// /// Gets or sets the list of dark mode. /// diff --git a/src/MaaWpfGui/Views/UI/SettingsView.xaml b/src/MaaWpfGui/Views/UI/SettingsView.xaml index 022d22d02b..e748d6a38b 100644 --- a/src/MaaWpfGui/Views/UI/SettingsView.xaml +++ b/src/MaaWpfGui/Views/UI/SettingsView.xaml @@ -69,15 +69,18 @@ - + - + - + + + + diff --git a/src/MaaWpfGui/Views/UserControl/RemoteControlUserControl.xaml b/src/MaaWpfGui/Views/UserControl/RemoteControlUserControl.xaml new file mode 100644 index 0000000000..142df54942 --- /dev/null +++ b/src/MaaWpfGui/Views/UserControl/RemoteControlUserControl.xaml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + +