From d2c2989f4e67dc1872287028db6140abc2bbff52 Mon Sep 17 00:00:00 2001 From: uye <99072975+ABA2396@users.noreply.github.com> Date: Fri, 20 Mar 2026 02:10:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=BB=BB=E5=8A=A1=20(#16026)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 增加更新数据任务 * chore: 仅在立即启动时更新提示 * perf: 只解析一次 json * feat: 按完成度优先级显示状态 Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix: typo * rft: 多taskId支持 part.1 * rft: 多taskId支持 part.2 * rft: 多taskId支持 part.2.5 * rft: 多taskId支持 part.3 * fix: 错误设置标签状态 * feat: 统一命名 * chore: 注释 --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: status102 <102887808+status102@users.noreply.github.com> --- .../Configuration/Single/MaaTask/BaseTask.cs | 1 + .../Single/MaaTask/UserDataUpdateTask.cs | 35 +++ .../Constants/Enums/TaskItemStatus.cs | 42 ++++ .../Enums/UserDataUpdateTriggerInterval.cs | 21 ++ src/MaaWpfGui/Main/AsstProxy.cs | 49 +++-- .../Models/TaskSettingVisibilityInfo.cs | 10 +- src/MaaWpfGui/Res/Localizations/en-us.xaml | 7 +- src/MaaWpfGui/Res/Localizations/ja-jp.xaml | 7 +- src/MaaWpfGui/Res/Localizations/ko-kr.xaml | 7 +- src/MaaWpfGui/Res/Localizations/zh-cn.xaml | 7 +- src/MaaWpfGui/Res/Localizations/zh-tw.xaml | 7 +- src/MaaWpfGui/Res/Themes/Dark.xaml | 6 +- src/MaaWpfGui/Res/Themes/Light.xaml | 6 +- src/MaaWpfGui/ViewModels/TaskItemViewModel.cs | 65 +++++- .../ViewModels/TaskSettingsViewModel.cs | 7 +- .../ViewModels/UI/TaskQueueViewModel.cs | 31 +-- .../ViewModels/UI/ToolboxViewModel.cs | 202 ++++++++++++++---- .../AwardSettingsUserControlModel.cs | 13 +- .../CustomSettingsUserControlModel.cs | 13 +- .../FightSettingsUserControlModel.cs | 20 +- .../InfrastSettingsUserControlModel.cs | 12 +- .../TaskQueue/MallSettingsUserControlModel.cs | 12 +- .../ReclamationSettingsUserControlModel.cs | 12 +- .../RecruitSettingsUserControlModel.cs | 12 +- .../RoguelikeSettingsUserControlModel.cs | 12 +- .../StartUpSettingsUserControlModel.cs | 13 +- .../UserDataUpdateSettingsUserControlModel.cs | 150 +++++++++++++ src/MaaWpfGui/Views/UI/TaskQueueView.xaml | 30 ++- src/MaaWpfGui/Views/UI/ToolboxView.xaml | 19 +- .../UserDataUpdateSettingsUserControl.xaml | 63 ++++++ .../UserDataUpdateSettingsUserControl.xaml.cs | 28 +++ 31 files changed, 750 insertions(+), 169 deletions(-) create mode 100644 src/MaaWpfGui/Configuration/Single/MaaTask/UserDataUpdateTask.cs create mode 100644 src/MaaWpfGui/Constants/Enums/TaskItemStatus.cs create mode 100644 src/MaaWpfGui/Constants/Enums/UserDataUpdateTriggerInterval.cs create mode 100644 src/MaaWpfGui/ViewModels/UserControl/TaskQueue/UserDataUpdateSettingsUserControlModel.cs create mode 100644 src/MaaWpfGui/Views/UserControl/TaskQueue/UserDataUpdateSettingsUserControl.xaml create mode 100644 src/MaaWpfGui/Views/UserControl/TaskQueue/UserDataUpdateSettingsUserControl.xaml.cs diff --git a/src/MaaWpfGui/Configuration/Single/MaaTask/BaseTask.cs b/src/MaaWpfGui/Configuration/Single/MaaTask/BaseTask.cs index cbce076ece..cc88f53e01 100644 --- a/src/MaaWpfGui/Configuration/Single/MaaTask/BaseTask.cs +++ b/src/MaaWpfGui/Configuration/Single/MaaTask/BaseTask.cs @@ -33,6 +33,7 @@ namespace MaaWpfGui.Configuration.Single.MaaTask; [JsonDerivedType(typeof(SingleStepTask), typeDiscriminator: nameof(SingleStepTask))] [JsonDerivedType(typeof(DepotTask), typeDiscriminator: nameof(DepotTask))] [JsonDerivedType(typeof(OperBoxTask), typeDiscriminator: nameof(OperBoxTask))] +[JsonDerivedType(typeof(UserDataUpdateTask), typeDiscriminator: nameof(UserDataUpdateTask))] [JsonDerivedType(typeof(ReclamationTask), typeDiscriminator: nameof(ReclamationTask))] [JsonDerivedType(typeof(CustomTask), typeDiscriminator: nameof(CustomTask))] public class BaseTask : INotifyPropertyChanged diff --git a/src/MaaWpfGui/Configuration/Single/MaaTask/UserDataUpdateTask.cs b/src/MaaWpfGui/Configuration/Single/MaaTask/UserDataUpdateTask.cs new file mode 100644 index 0000000000..b29c292759 --- /dev/null +++ b/src/MaaWpfGui/Configuration/Single/MaaTask/UserDataUpdateTask.cs @@ -0,0 +1,35 @@ +// +// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team) +// Copyright (C) 2021-2025 MaaAssistantArknights 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 +// + +#nullable enable + +using MaaWpfGui.Constants.Enums; +using static MaaWpfGui.Main.AsstProxy; + +namespace MaaWpfGui.Configuration.Single.MaaTask; + +/// +/// 更新用户数据任务。 +/// +public class UserDataUpdateTask : BaseTask +{ + public UserDataUpdateTask() => TaskType = TaskType.UserDataUpdate; + + public bool UpdateOperBox { get; set; } = true; + + public bool UpdateDepot { get; set; } = true; + + public UserDataUpdateTriggerInterval TriggerInterval { get; set; } = UserDataUpdateTriggerInterval.EveryTime; + + public bool IsTriggered => UpdateOperBox || UpdateDepot; +} diff --git a/src/MaaWpfGui/Constants/Enums/TaskItemStatus.cs b/src/MaaWpfGui/Constants/Enums/TaskItemStatus.cs new file mode 100644 index 0000000000..a18cdbeb6e --- /dev/null +++ b/src/MaaWpfGui/Constants/Enums/TaskItemStatus.cs @@ -0,0 +1,42 @@ +// +// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team) +// Copyright (C) 2021-2025 MaaAssistantArknights 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 +// + +namespace MaaWpfGui.Constants.Enums; + +public enum TaskItemStatus +{ + /// + /// 未开始 + /// + Idle = 0, + + /// + /// 进行中 + /// + InProgress = 1, + + /// + /// 已完成 + /// + Completed = 2, + + /// + /// 错误终止 + /// + Error = 3, + + /// + /// 跳过 + /// + Skipped = 4, +} diff --git a/src/MaaWpfGui/Constants/Enums/UserDataUpdateTriggerInterval.cs b/src/MaaWpfGui/Constants/Enums/UserDataUpdateTriggerInterval.cs new file mode 100644 index 0000000000..fec3c7adec --- /dev/null +++ b/src/MaaWpfGui/Constants/Enums/UserDataUpdateTriggerInterval.cs @@ -0,0 +1,21 @@ +// +// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team) +// Copyright (C) 2021-2025 MaaAssistantArknights 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 +// + +namespace MaaWpfGui.Constants.Enums; + +public enum UserDataUpdateTriggerInterval +{ + EveryTime, + Daily, + Weekly, +} diff --git a/src/MaaWpfGui/Main/AsstProxy.cs b/src/MaaWpfGui/Main/AsstProxy.cs index 03806c61e4..4a1376a1d1 100644 --- a/src/MaaWpfGui/Main/AsstProxy.cs +++ b/src/MaaWpfGui/Main/AsstProxy.cs @@ -441,6 +441,10 @@ public class AsstProxy if (args.Action == NotifyCollectionChangedAction.Reset) { TaskSettingVisibilityInfo.Instance.NotifyOfTaskStatus(); + foreach (var i in Instances.TaskQueueViewModel.TaskItemViewModels) + { + i.SetTaskIds([]); + } } }; @@ -1038,11 +1042,8 @@ public class AsstProxy { case AsstMsg.TaskChainStopped: Instances.TaskQueueViewModel.SetStopped(); - UpdateTaskStatus(taskId, TaskStatus.Completed); - foreach (var i in Instances.TaskQueueViewModel.TaskItemViewModels) - { - i.TaskId = 0; - } + + // UpdateTaskStatus(taskId, TaskStatus.Completed); _tasksStatus.Clear(); break; @@ -1071,7 +1072,7 @@ public class AsstProxy case AsstMsg.TaskChainStart: { - var taskIndex = Instances.TaskQueueViewModel.TaskItemViewModels.FirstOrDefault(t => t.TaskId == taskId)?.Index ?? -1; + var taskIndex = Instances.TaskQueueViewModel.TaskItemViewModels.FirstOrDefault(i => i.TaskIds.Contains(taskId))?.Index ?? -1; var task = taskIndex >= 0 && taskIndex < ConfigFactory.CurrentConfig.TaskQueue.Count ? ConfigFactory.CurrentConfig.TaskQueue[taskIndex] : null; @@ -1100,7 +1101,7 @@ public class AsstProxy } } - var taskIndex = Instances.TaskQueueViewModel.TaskItemViewModels.FirstOrDefault(t => t.TaskId == taskId)?.Index ?? -1; + var taskIndex = Instances.TaskQueueViewModel.TaskItemViewModels.FirstOrDefault(i => i.TaskIds.Contains(taskId))?.Index ?? -1; var task = taskIndex >= 0 && taskIndex < ConfigFactory.CurrentConfig.TaskQueue.Count ? ConfigFactory.CurrentConfig.TaskQueue[taskIndex] : null; @@ -1188,10 +1189,6 @@ public class AsstProxy } bool buyWine = _tasksStatus.Any(t => t.Value.Type == TaskType.Mall) && Instances.SettingsViewModel.DidYouBuyWine(); - foreach (var i in Instances.TaskQueueViewModel.TaskItemViewModels) - { - i.TaskId = 0; - } _tasksStatus.Clear(); Instances.TaskQueueViewModel.ResetAllTemporaryVariable(); @@ -1437,7 +1434,7 @@ public class AsstProxy // 剿灭放弃上传企鹅物流的特殊处理 Instances.AsstProxy.TasksStatus.TryGetValue(taskId, out var value); if (value is { Type: TaskType.Fight } - && (Instances.TaskQueueViewModel.TaskItemViewModels.FirstOrDefault(t => t.TaskId == taskId)?.Index ?? -1) is int index and > -1 + && Instances.TaskQueueViewModel.TaskItemViewModels.FirstOrDefault(i => i.TaskIds.Contains(taskId))?.Index is int index and > -1 && index <= ConfigFactory.CurrentConfig.TaskQueue.Count && ConfigFactory.CurrentConfig.TaskQueue[index] is Configuration.Single.MaaTask.FightTask fight && FightSettingsUserControlModel.GetFightStage(fight.StagePlan) == FightSettingsUserControlModel.AnnihilationName) @@ -1744,7 +1741,7 @@ public class AsstProxy { case "EndOfActionThenStop": { - var index = Instances.TaskQueueViewModel.TaskItemViewModels.FirstOrDefault(t => t.TaskId == taskId)?.Index ?? -1; + var index = Instances.TaskQueueViewModel.TaskItemViewModels.FirstOrDefault(i => i.TaskIds.Contains(taskId))?.Index ?? -1; if (index >= 0 && index < ConfigFactory.CurrentConfig.TaskQueue.Count && ConfigFactory.CurrentConfig.TaskQueue[index] is MallTask mall) { mall.CreditFightLastTime = DateTime.UtcNow.ToYjDate().ToFormattedString(); @@ -1756,7 +1753,7 @@ public class AsstProxy case "VisitLimited" or "VisitNextBlack": { - var index = Instances.TaskQueueViewModel.TaskItemViewModels.FirstOrDefault(t => t.TaskId == taskId)?.Index ?? -1; + var index = Instances.TaskQueueViewModel.TaskItemViewModels.FirstOrDefault(i => i.TaskIds.Contains(taskId))?.Index ?? -1; if (index >= 0 && index < ConfigFactory.CurrentConfig.TaskQueue.Count && ConfigFactory.CurrentConfig.TaskQueue[index] is MallTask mall) { mall.VisitFriendsLastTime = DateTime.UtcNow.ToYjDate().ToFormattedString(); @@ -1798,7 +1795,7 @@ public class AsstProxy break; case "OperBox": - Instances.ToolboxViewModel.OperBoxParse((JObject?)subTaskDetails); + Instances.ToolboxViewModel.OperBoxParse((JObject?)subTaskDetails, updateSyncTime: true); break; } @@ -2802,6 +2799,9 @@ public class AsstProxy /// 生息演算 Reclamation, + /// 更新用户数据 + UserDataUpdate, + /// 小游戏 MiniGame, @@ -2819,12 +2819,17 @@ public class AsstProxy TaskType.Award, TaskType.Roguelike, TaskType.Reclamation, + TaskType.UserDataUpdate, ]; private readonly ObservableDictionary _tasksStatus = []; public IReadOnlyDictionary TasksStatus => new Dictionary(_tasksStatus); + public delegate void TaskItemStatusDelegate(int taskId, TaskItemStatus status); + + public event TaskItemStatusDelegate? OnTaskItemStatusChanged; + private bool UpdateTaskStatus(AsstTaskId id, TaskStatus status) { if (id <= 0) @@ -2844,7 +2849,7 @@ public class AsstProxy } _tasksStatus[id] = (value.Type, status); - Instances.TaskQueueViewModel.TaskItemViewModels.FirstOrDefault(item => item.TaskId == id)?.Status = (int)status; + OnTaskItemStatusChanged?.Invoke(id, (TaskItemStatus)status); if (status == TaskStatus.InProgress) { TaskSettingVisibilityInfo.Instance.NotifyOfTaskStatus(); @@ -2882,19 +2887,23 @@ public class AsstProxy /// /// 仓库识别。 /// + /// 是否立刻启动。 /// 是否成功。 - public bool AsstStartDepot() + public bool AsstStartDepot(bool startImmediately = true) { - return AsstAppendTaskWithEncoding(TaskType.Depot, AsstTaskType.Depot) && AsstStart(); + return AsstAppendTaskWithEncoding(TaskType.Depot, AsstTaskType.Depot) && + (!startImmediately || AsstStart()); } /// /// 干员识别。 /// + /// 是否立刻启动。 /// 是否成功。 - public bool AsstStartOperBox() + public bool AsstStartOperBox(bool startImmediately = true) { - return AsstAppendTaskWithEncoding(TaskType.OperBox, AsstTaskType.OperBox) && AsstStart(); + return AsstAppendTaskWithEncoding(TaskType.OperBox, AsstTaskType.OperBox) && + (!startImmediately || AsstStart()); } /// diff --git a/src/MaaWpfGui/Models/TaskSettingVisibilityInfo.cs b/src/MaaWpfGui/Models/TaskSettingVisibilityInfo.cs index 69918d14b8..dc7e880d71 100644 --- a/src/MaaWpfGui/Models/TaskSettingVisibilityInfo.cs +++ b/src/MaaWpfGui/Models/TaskSettingVisibilityInfo.cs @@ -12,6 +12,7 @@ // #nullable enable using System; +using System.Linq; using MaaWpfGui.Configuration.Factory; using MaaWpfGui.Configuration.Single.MaaTask; using MaaWpfGui.Constants; @@ -51,6 +52,8 @@ public class TaskSettingVisibilityInfo : PropertyChangedBase public bool Reclamation { get => field; set => SetAndNotify(ref field, value); } + public bool UserDataUpdate { get => field; set => SetAndNotify(ref field, value); } + public bool Custom { get => field; set => SetAndNotify(ref field, value); } public bool PostAction { get => field; set => SetAndNotify(ref field, value); } @@ -79,8 +82,9 @@ public class TaskSettingVisibilityInfo : PropertyChangedBase public bool IsCurrentTaskRunning => ConfigFactory.CurrentConfig.TaskQueue.Count > CurrentIndex && CurrentIndex >= 0 && - Instances.AsstProxy.TasksStatus.TryGetValue(Instances.TaskQueueViewModel.TaskItemViewModels[CurrentIndex].TaskId, out var status) && - status.Status == TaskStatus.InProgress; + Instances.TaskQueueViewModel.TaskItemViewModels[CurrentIndex].TaskIds.Any(taskId => + Instances.AsstProxy.TasksStatus.TryGetValue(taskId, out var status) && + status.Status == TaskStatus.InProgress); public static BaseTask? CurrentTask => ConfigFactory.CurrentConfig.TaskQueue.Count > Instance.CurrentIndex && @@ -143,6 +147,7 @@ public class TaskSettingVisibilityInfo : PropertyChangedBase AwardTask => Award = enable, RoguelikeTask => Roguelike = enable, ReclamationTask => Reclamation = enable, + UserDataUpdateTask => UserDataUpdate = enable, CustomTask => Custom = enable, _ => throw new NotImplementedException(), }; @@ -160,6 +165,7 @@ public class TaskSettingVisibilityInfo : PropertyChangedBase Award = false; Roguelike = false; Reclamation = false; + UserDataUpdate = false; Custom = false; } diff --git a/src/MaaWpfGui/Res/Localizations/en-us.xaml b/src/MaaWpfGui/Res/Localizations/en-us.xaml index 70f386868e..e1d58ddef1 100644 --- a/src/MaaWpfGui/Res/Localizations/en-us.xaml +++ b/src/MaaWpfGui/Res/Localizations/en-us.xaml @@ -690,6 +690,7 @@ If the game is launched in portrait mode and then switched to landscape, it may Auto I.S. {key=AutoRoguelike} Reclamation Algorithm + Update User Data Mini-Games Custom Task Single-Step Task @@ -848,7 +849,7 @@ Right Click: Select Target Process Depot {key=DepotRecognition} - Last Sync Time + Last Sync Time This function is still in testing. If you encounter any unexpected results, please zip the 「debug/depot」 folder in the installation path and submit an issue on GitHub Start to Identify Export to Arkplanner @@ -1222,6 +1223,10 @@ Right-click to clear inactive jobs Stage recognition error Use formation Current + Every Time + Daily + Weekly + Trigger Interval Start formation Formation parse failed Selected:  diff --git a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml index e43a18f13b..9dda1276ff 100644 --- a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml +++ b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml @@ -691,6 +691,7 @@ C:\\leidian\\LDPlayer9 自動ローグ {key=AutoRoguelike} 生息演算 + ユーザーデータ更新 ミニゲーム カスタムタスク 単一ステップタスク @@ -849,7 +850,7 @@ C:\\leidian\\LDPlayer9 倉庫アイテム認識 {key=DepotRecognition} - 前回同期時間 + 前回同期時間 この機能はまだテスト版です。エラーが発生/統計情報に問題があれば、debug/depotフォルダを圧縮し、issueを提出してください~ 認識開始 Arkplannerへ出力 @@ -1223,6 +1224,10 @@ C:\\leidian\\LDPlayer9 ステージ認識エラー 使用編成 現在 + 毎回 + 毎日 + 毎週 + 実行間隔 編成開始 フォーメーション解析に失敗しました {key=Operator}を選択: diff --git a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml index 38f1b60308..65b9c63e23 100644 --- a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml +++ b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml @@ -692,6 +692,7 @@ C:\\leidian\\LDPlayer9 통합 전략 {key=AutoRoguelike} 생존 연산 + 사용자 데이터 업데이트 미니게임 커스텀 작업 단일 단계 작업 @@ -850,7 +851,7 @@ C:\\leidian\\LDPlayer9 창고 인식 {key=DepotRecognition} - 마지막 동기화 시간 + 마지막 동기화 시간 이 기능은 현재 테스트 중입니다. 내보내기 전 인식 결과가 맞는지 확인 후 사용하세요\n만약 오류가 있다면 MAA 경로 내 debug 폴더 안의 depot 폴더 전체를 압축해서 Github의 issue로 올려주세요 인식 시작 Arkplanner로 내보내기 @@ -1224,6 +1225,10 @@ C:\\leidian\\LDPlayer9 스테이지 인식 오류 편성 사용 현재 + 매번 + 매일 + 매주 + 실행 간격 편성 시작 편성 분석에 실패했습니다 {key=Operator}를 선택: diff --git a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml index 9277f294dd..b04c0c2be4 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml @@ -691,6 +691,7 @@ C:\\leidian\\LDPlayer9。\n 自动肉鸽 {key=AutoRoguelike} 生息演算 + 更新数据 小游戏 自定任务 单步任务 @@ -849,7 +850,7 @@ C:\\leidian\\LDPlayer9。\n 仓库识别 {key=DepotRecognition} - 上次同步时间 + 上次同步时间 该功能尚处于测试阶段,请检查结果是否准确再行使用。若有误,欢迎打包 debug/depot 文件夹后向我们提交 issue ~ 开始识别 导出至企鹅物流刷图规划 @@ -1223,6 +1224,10 @@ C:\\leidian\\LDPlayer9。\n 关卡识别错误 使用编队 当前 + 每次 + 每天 + 每周 + 触发间隔 开始编队 编队解析失败 选择{key=Operator}: diff --git a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml index c6bb632907..b117c1e89b 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml @@ -691,6 +691,7 @@ C:\\leidian\\LDPlayer9\n 自動肉鴿 {key=AutoRoguelike} 生息演算 + 更新使用者資料 小遊戲 自定義任務 單步任務 @@ -849,7 +850,7 @@ C:\\leidian\\LDPlayer9\n 倉庫辨識 {key=DepotRecognition} - 上次同步時間 + 上次同步時間 該功能尚處於測試階段,請檢查結果是否準確再行使用。若有誤,歡迎打包 debug/depot 資料夾後向我們提交 issue ~ 開始辨識 匯出到企鵝物流刷圖規劃 @@ -1223,6 +1224,10 @@ C:\\leidian\\LDPlayer9\n 關卡辨識錯誤 使用編隊 目前 + 每次 + 每天 + 每週 + 觸發間隔 開始編隊 編隊解析失敗 選擇{key=Operator}: diff --git a/src/MaaWpfGui/Res/Themes/Dark.xaml b/src/MaaWpfGui/Res/Themes/Dark.xaml index cf0961a8ef..5783892e53 100644 --- a/src/MaaWpfGui/Res/Themes/Dark.xaml +++ b/src/MaaWpfGui/Res/Themes/Dark.xaml @@ -80,9 +80,9 @@ - - - + + + diff --git a/src/MaaWpfGui/Res/Themes/Light.xaml b/src/MaaWpfGui/Res/Themes/Light.xaml index fa5051cc11..47ffd64f0a 100644 --- a/src/MaaWpfGui/Res/Themes/Light.xaml +++ b/src/MaaWpfGui/Res/Themes/Light.xaml @@ -62,9 +62,9 @@ - - - + + + diff --git a/src/MaaWpfGui/ViewModels/TaskItemViewModel.cs b/src/MaaWpfGui/ViewModels/TaskItemViewModel.cs index 099ee9a31e..3294c764d5 100644 --- a/src/MaaWpfGui/ViewModels/TaskItemViewModel.cs +++ b/src/MaaWpfGui/ViewModels/TaskItemViewModel.cs @@ -11,18 +11,24 @@ // but WITHOUT ANY WARRANTY // #nullable enable +using System; +using System.Collections.Generic; +using System.Linq; using MaaWpfGui.Configuration.Factory; +using MaaWpfGui.Constants.Enums; +using MaaWpfGui.Helper; using MaaWpfGui.Models; using Stylet; namespace MaaWpfGui.ViewModels; -public class TaskItemViewModel : PropertyChangedBase +public class TaskItemViewModel : PropertyChangedBase, IDisposable { public TaskItemViewModel(string name, bool? isCheckedWithNull = true) { _name = name; _isEnable = isCheckedWithNull; + Instances.AsstProxy.OnTaskItemStatusChanged += OnTaskStatusChanged; } private string _name; @@ -48,7 +54,7 @@ public class TaskItemViewModel : PropertyChangedBase } ConfigFactory.CurrentConfig.TaskQueue[Index].IsEnable = value; - Status = 0; + StatusDisplay = TaskItemStatus.Idle; } } @@ -67,9 +73,58 @@ public class TaskItemViewModel : PropertyChangedBase } /// - /// Gets or sets 任务id,默认为0,添加后任务id应 > 0;执行后应置为0 + /// Gets or sets 任务id,默认为[],添加后任务id应 > 0;执行后应置为[] /// - public int TaskId { get; set; } + private List _taskIds = []; - public int Status { get => field; set => SetAndNotify(ref field, value); } + public IReadOnlyList TaskIds => _taskIds; + + public void SetTaskIds(IEnumerable taskIds) + { + _taskIds = [.. taskIds]; + StatusList = [.. Enumerable.Repeat(TaskItemStatus.Idle, TaskIds.Count)]; + } + + private List StatusList { get; set; } = []; + + /// + /// Gets or sets 上次状态, 可能和当前不一致 + /// + public TaskItemStatus StatusDisplay { get => field; set => SetAndNotify(ref field, value); } + + private void OnTaskStatusChanged(int taskId, TaskItemStatus status) + { + if (taskId < 0) + { + return; + } + int index = _taskIds.IndexOf(taskId); + if (index < 0) + { + return; + } + StatusList[index] = status; + if (StatusList.Any(s => s == TaskItemStatus.Error)) + { + StatusDisplay = TaskItemStatus.Error; + } + else if (StatusList.Any(s => s == TaskItemStatus.InProgress)) + { + StatusDisplay = TaskItemStatus.InProgress; + } + else if (StatusList.All(s => s == TaskItemStatus.Completed)) + { + StatusDisplay = TaskItemStatus.Completed; + } + else if (StatusList.Any(s => s == TaskItemStatus.Skipped)) + { + StatusDisplay = TaskItemStatus.Skipped; + } + else + { + StatusDisplay = TaskItemStatus.Idle; + } + } + + void IDisposable.Dispose() => Instances.AsstProxy.OnTaskItemStatusChanged -= OnTaskStatusChanged; } diff --git a/src/MaaWpfGui/ViewModels/TaskSettingsViewModel.cs b/src/MaaWpfGui/ViewModels/TaskSettingsViewModel.cs index 4fd2ee0497..ee1d8ad060 100644 --- a/src/MaaWpfGui/ViewModels/TaskSettingsViewModel.cs +++ b/src/MaaWpfGui/ViewModels/TaskSettingsViewModel.cs @@ -13,6 +13,7 @@ #nullable enable using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; using MaaWpfGui.Configuration.Factory; using MaaWpfGui.Configuration.Single.MaaTask; @@ -77,11 +78,13 @@ public abstract class TaskSettingsViewModel : PropertyChangedBase /// 存储的任务 /// 任务id, null时追加任务, 非null为设置任务参数 /// null为未序列化, false失败, true成功 - public abstract (bool? IsSuccess, int TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null); + public abstract (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null); } public interface ITaskQueueModelSerialize { /// - public abstract (bool? IsSuccess, int TaskId) Serialize(BaseTask? baseTask, int? taskId); + public abstract (bool? IsSuccess, IEnumerable TaskId) Serialize(BaseTask? baseTask, int? taskId); + + protected static (bool? IsSuccess, IEnumerable TaskId) FromSingle((bool? IsSuccess, int TaskId) result) => (result.IsSuccess, result.TaskId > 0 ? [result.TaskId] : []); } diff --git a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs index 4e52353f7b..edb757785b 100644 --- a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs @@ -31,6 +31,7 @@ using JetBrains.Annotations; using MaaWpfGui.Configuration.Factory; using MaaWpfGui.Configuration.Single.MaaTask; using MaaWpfGui.Constants; +using MaaWpfGui.Constants.Enums; using MaaWpfGui.Extensions; using MaaWpfGui.Helper; using MaaWpfGui.Main; @@ -123,6 +124,11 @@ public class TaskQueueViewModel : Screen /// public static ReclamationSettingsUserControlModel ReclamationTask => ReclamationSettingsUserControlModel.Instance; + /// + /// Gets 更新用户数据任务Model + /// + public static UserDataUpdateSettingsUserControlModel UserDataUpdateTask => UserDataUpdateSettingsUserControlModel.Instance; + /// /// Gets 生稀盐酸任务Model /// @@ -1277,6 +1283,7 @@ public class TaskQueueViewModel : Screen new GenericCombinedData { Display = LocalizationHelper.GetString("Award"), Value = typeof(AwardTask) }, new GenericCombinedData { Display = LocalizationHelper.GetString("Roguelike"), Value = typeof(RoguelikeTask) }, new GenericCombinedData { Display = LocalizationHelper.GetString("Reclamation"), Value = typeof(ReclamationTask) }, + new GenericCombinedData { Display = LocalizationHelper.GetString("UserDataUpdate"), Value = typeof(UserDataUpdateTask) }, new GenericCombinedData { Display = LocalizationHelper.GetString("Custom"), Value = typeof(CustomTask) }, ]); @@ -1737,27 +1744,28 @@ public class TaskQueueViewModel : Screen item.IsEnable); if (!IsTaskEnable(item)) { - SetTaskStatus(index, 4); + SetTaskStatus(index, TaskItemStatus.Skipped); continue; } try { - var (isSuccess, taskId) = SerializeTask(item); + var (isSuccess, taskIds) = SerializeTask(item); switch (isSuccess) { case true: ++count; - Instances.TaskQueueViewModel.TaskItemViewModels.ElementAtOrDefault(index)?.TaskId = taskId; + Instances.TaskQueueViewModel.TaskItemViewModels[index].SetTaskIds(taskIds); + // Instances.TaskQueueViewModel.TaskItemViewModels.ElementAtOrDefault(index)?.TaskId = taskId; break; case false: taskRet = false; AddLog(LocalizationHelper.GetStringFormat("TaskAppend.Error", LocalizationHelper.GetString(item.TaskType.ToString()), item.Name), UiLogColor.Error); - SetTaskStatus(index, (int)Main.TaskStatus.Error); + SetTaskStatus(index, TaskItemStatus.Error); break; case null: AddLog(LocalizationHelper.GetStringFormat("TaskAppend.Skip", LocalizationHelper.GetString(item.TaskType.ToString()), item.Name), UiLogColor.Info); - SetTaskStatus(index, 4); + SetTaskStatus(index, TaskItemStatus.Skipped); break; } } @@ -1796,17 +1804,14 @@ public class TaskQueueViewModel : Screen AchievementTrackerHelper.Instance.MissionStartCountAdd(); AchievementTrackerHelper.Instance.UseDailyAdd(); - void SetTaskStatus(int index, int status) + static void SetTaskStatus(int index, TaskItemStatus status) { if (index < 0 || index >= Instances.TaskQueueViewModel.TaskItemViewModels.Count) { return; } - foreach (var item in Instances.TaskQueueViewModel.TaskItemViewModels) - { - item.Status = status; - } + Instances.TaskQueueViewModel.TaskItemViewModels[index].StatusDisplay = status; } } @@ -1814,7 +1819,7 @@ public class TaskQueueViewModel : Screen { foreach (var item in TaskItemViewModels) { - item.Status = (int)Main.TaskStatus.Idle; + item.StatusDisplay = TaskItemStatus.Idle; } } @@ -2065,10 +2070,10 @@ public class TaskQueueViewModel : Screen /// 存储的任务 /// 任务id, null时追加任务, 非null为设置任务参数 /// null为未序列化, false失败, true成功 - private static (bool? IsSuccess, int TaskId) SerializeTask(BaseTask task, int? taskId = null) + private static (bool? IsSuccess, IEnumerable TaskIds) SerializeTask(BaseTask task, int? taskId = null) { bool? ret = null; - int id = 0; + IEnumerable id = []; foreach (var instance in _taskViewModelTypes) { if (ret is null) diff --git a/src/MaaWpfGui/ViewModels/UI/ToolboxViewModel.cs b/src/MaaWpfGui/ViewModels/UI/ToolboxViewModel.cs index 0f74e65f89..17fc67f6fe 100644 --- a/src/MaaWpfGui/ViewModels/UI/ToolboxViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/ToolboxViewModel.cs @@ -931,6 +931,30 @@ public class ToolboxViewModel : Screen } } + /// + /// 重置仓库识别状态。 + /// + public void ResetDepotRecognitionState() + { + DepotClear(); + } + + /// + /// 追加或启动仓库识别任务。 + /// + /// 是否立刻启动。 + /// 是否成功。 + public bool StartDepotRecognitionTask(bool startImmediately = true) + { + bool ret = Instances.AsstProxy.AsstStartDepot(startImmediately); + if (ret && startImmediately) + { + DepotInfo = LocalizationHelper.GetString("Identifying"); + } + + return ret; + } + /// /// Starts depot recognition. /// UI 绑定的方法 @@ -950,16 +974,42 @@ public class ToolboxViewModel : Screen return; } - DepotInfo = LocalizationHelper.GetString("Identifying"); - DepotClear(); - - Instances.AsstProxy.AsstStartDepot(); + ResetDepotRecognitionState(); + StartDepotRecognitionTask(); } #endregion Depot #region OperBox + private DateTime? _lastOperBoxSyncTime; + + /// + /// Gets or sets 上次干员同步时间(UTC 时间) + /// + public DateTime? LastOperBoxSyncTime + { + get => _lastOperBoxSyncTime; + set => SetAndNotify(ref _lastOperBoxSyncTime, value); + } + + /// + /// Gets 上次干员同步时间的显示文本(本地时间) + /// + [PropertyDependsOn(nameof(LastOperBoxSyncTime))] + public string LastOperBoxSyncTimeText + { + get { + if (LastOperBoxSyncTime == null) + { + return string.Empty; + } + + var localTime = LastOperBoxSyncTime.Value.ToLocalTime(); + return localTime.ToString(); + } + } + private int _operBoxSelectedIndex = 0; public int OperBoxSelectedIndex @@ -1030,7 +1080,7 @@ public class ToolboxViewModel : Screen public int IdNumber { get; } = ExtractIdNumber(id); - public string RarityStars => IsPallas ? LocalizationHelper.GetPallasString(6, 6) : new('★', Rarity); + public string RarityStars => (IsPallas && Level > 0) ? LocalizationHelper.GetPallasString(6, 6) : new('★', Rarity); /// /// Gets the path to the Elite icon image @@ -1047,7 +1097,7 @@ public class ToolboxViewModel : Screen /// /// Gets the resource key based on rarity /// - public string RarityColorResourceKey => IsPallas ? "AchievementBrush.Rare.LinearGradientBrush" : $"Star{Rarity}OperatorLogBrush"; + public string RarityColorResourceKey => (IsPallas && Level > 0) ? "AchievementBrush.Rare.LinearGradientBrush" : $"Star{Rarity}OperatorLogBrush"; public bool Equals(Operator? other) => other != null && Name == other.Name && Rarity == other.Rarity; @@ -1105,11 +1155,19 @@ public class ToolboxViewModel : Screen set => SetAndNotify(ref _operBoxNotHaveList, value); } - private static void SaveOperBoxDetails(List details) + private void SaveOperBoxDetails(List details) { - // var json = details.ToString(Formatting.None); - // ConfigurationHelper.SetValue(ConfigurationKeys.OperBoxData, json); - JsonDataHelper.Set(JsonDataKey.OperBoxData, JArray.FromObject(details)); + var data = new JObject { + ["done"] = true, + ["own_opers"] = JArray.FromObject(details), + }; + + if (LastOperBoxSyncTime.HasValue) + { + data["syncTime"] = LastOperBoxSyncTime.Value.ToString("o"); + } + + JsonDataHelper.Set(JsonDataKey.OperBoxData, data); } private void SortOperBoxLists() @@ -1126,7 +1184,7 @@ public class ToolboxViewModel : Screen } return [.. list - .OrderByDescending(x => x.IsPallas) + .OrderByDescending(x => x.IsPallas && x.Level > 0) .ThenByDescending(x => x.Rarity) .ThenByDescending(x => x.Elite) .ThenByDescending(x => x.Level) @@ -1147,40 +1205,58 @@ public class ToolboxViewModel : Screen try { - var ownOpers = JsonConvert.DeserializeObject>(json)?.Where(i => !string.IsNullOrEmpty(i.Id)).ToList(); - if (ownOpers is null) + var token = JToken.Parse(json); + if (token is JArray oldArray) { + var ownOpers = oldArray + .ToObject>()? + .Where(i => !string.IsNullOrEmpty(i.Id)) + .ToList(); + if (ownOpers is null) + { + return; + } + LoadOperBoxList(ownOpers); return; } - - var operDataMap = ownOpers.ToDictionary(o => o.Id); - foreach (var (id, oper) in DataHelper.Operators) + else if (token is JObject details) { - if (DataHelper.IsCharacterAvailableInClient(oper, SettingsViewModel.GameSettings.ClientType)) - { - var name = DataHelper.GetLocalizedCharacterName(oper) ?? "???"; - if (operDataMap.TryGetValue(id, out var operData)) - { - OperBoxHaveList.Add(new Operator(id, name, oper.Rarity, operData.Elite, operData.Level, operData.Potential)); - - if (id == "char_485_pallas") - { - AchievementTrackerHelper.Instance.Unlock(AchievementIds.WarehouseKeeper); - } - } - else - { - OperBoxNotHaveList.Add(new Operator(id, name, oper.Rarity)); - } - } + OperBoxParse(details, updateSyncTime: false); } - - SortOperBoxLists(); } catch { // 兼容老数据或异常时忽略 } + + void LoadOperBoxList(List ownOpers) + { + var operDataMap = ownOpers.ToDictionary(o => o.Id); + foreach (var (id, oper) in DataHelper.Operators) + { + if (!DataHelper.IsCharacterAvailableInClient(oper, SettingsViewModel.GameSettings.ClientType)) + { + continue; + } + + var name = DataHelper.GetLocalizedCharacterName(oper) ?? "???"; + if (operDataMap.TryGetValue(id, out var operData)) + { + OperBoxHaveList.Add(new Operator(id, name, oper.Rarity, operData.Elite, operData.Level, operData.Potential)); + + if (id == "char_485_pallas") + { + AchievementTrackerHelper.Instance.Unlock(AchievementIds.WarehouseKeeper); + } + } + else + { + OperBoxNotHaveList.Add(new Operator(id, name, oper.Rarity)); + } + } + + SortOperBoxLists(); + } } /// @@ -1188,7 +1264,7 @@ public class ToolboxViewModel : Screen /// private HashSet _tempOperHaveSet = []; - public bool OperBoxParse(JObject? details) + public bool OperBoxParse(JObject? details, bool updateSyncTime = true) { if (details == null) { @@ -1236,12 +1312,54 @@ public class ToolboxViewModel : Screen OperBoxSelectedIndex = 0; } + if (updateSyncTime) + { + LastOperBoxSyncTime = DateTime.UtcNow; + } + else + { + var syncTimeStr = details["syncTime"]?.ToString(Formatting.None)?.Trim('"'); + if (!string.IsNullOrEmpty(syncTimeStr) && + DateTime.TryParseExact(syncTimeStr, "O", null, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var lastOperBoxSyncTime)) + { + LastOperBoxSyncTime = lastOperBoxSyncTime; + } + } + OperBoxInfo = $"{LocalizationHelper.GetString("IdentificationCompleted")}\n{LocalizationHelper.GetString("OperBoxRecognitionTip")}"; SaveOperBoxDetails(ownOpers); _tempOperHaveSet = []; return true; } + /// + /// 重置干员识别状态。 + /// + public void ResetOperBoxRecognitionState() + { + OperBoxSelectedIndex = 1; + _operBoxPotential = null; + _tempOperHaveSet = []; + OperBoxHaveList = []; + OperBoxNotHaveList = []; + } + + /// + /// 追加或启动干员识别任务。 + /// + /// 是否立刻启动。 + /// 是否成功。 + public bool StartOperBoxRecognitionTask(bool startImmediately = true) + { + bool ret = Instances.AsstProxy.AsstStartOperBox(startImmediately); + if (ret && startImmediately) + { + OperBoxInfo = LocalizationHelper.GetString("Identifying"); + } + + return ret; + } + /// /// 开始识别干员 /// UI 绑定的方法 @@ -1250,13 +1368,8 @@ public class ToolboxViewModel : Screen [UsedImplicitly] public async Task StartOperBox() { - OperBoxSelectedIndex = 1; - _operBoxPotential = null; - _tempOperHaveSet = []; - OperBoxHaveList = []; - OperBoxNotHaveList = []; + ResetOperBoxRecognitionState(); _runningState.SetIdle(false); - string errMsg = string.Empty; OperBoxInfo = LocalizationHelper.GetString("ConnectingToEmulator"); bool caught = await Task.Run(() => Instances.AsstProxy.AsstConnect(ref errMsg)); @@ -1267,10 +1380,7 @@ public class ToolboxViewModel : Screen return; } - if (Instances.AsstProxy.AsstStartOperBox()) - { - OperBoxInfo = LocalizationHelper.GetString("Identifying"); - } + StartOperBoxRecognitionTask(); } // UI 绑定的方法 diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/AwardSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/AwardSettingsUserControlModel.cs index 1d2101692c..d5be093ca5 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/AwardSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/AwardSettingsUserControlModel.cs @@ -12,6 +12,7 @@ // #nullable enable +using System.Collections.Generic; using System.Windows; using MaaWpfGui.Configuration.Single.MaaTask; using MaaWpfGui.Helper; @@ -109,15 +110,15 @@ public class AwardSettingsUserControlModel : TaskSettingsViewModel, AwardSetting } } - public override (bool? IsSuccess, int TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize)?.Serialize(baseTask, taskId) ?? (null, 0); + public override (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); private interface ISerialize : ITaskQueueModelSerialize { - (bool? IsSuccess, int TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) + (bool? IsSuccess, IEnumerable TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) { if (baseTask is not AwardTask award) { - return (null, 0); + return (null, []); } var task = new AsstAwardTask() { @@ -129,9 +130,9 @@ public class AwardSettingsUserControlModel : TaskSettingsViewModel, AwardSetting SpecialAccess = award.SpecialAccess, }; return taskId switch { - int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), id), - null => Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Award, task), - _ => (null, 0), + int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), [id]), + null => FromSingle(Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Award, task)), + _ => (null, []), }; } } diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/CustomSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/CustomSettingsUserControlModel.cs index 09d32f6ba7..c9a95ddd4d 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/CustomSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/CustomSettingsUserControlModel.cs @@ -13,6 +13,7 @@ #nullable enable using System; +using System.Collections.Generic; using System.Linq; using MaaWpfGui.Configuration.Single.MaaTask; using MaaWpfGui.Helper; @@ -70,24 +71,24 @@ public class CustomSettingsUserControlModel : TaskSettingsViewModel, CustomSetti } } - public override (bool? IsSuccess, int TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize)?.Serialize(baseTask, taskId) ?? (null, 0); + public override (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); private interface ISerialize : ITaskQueueModelSerialize { - (bool? IsSuccess, int TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) + (bool? IsSuccess, IEnumerable TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) { if (baseTask is not CustomTask custom) { - return (null, 0); + return (null, []); } var task = new AsstCustomTask() { CustomTasks = [.. custom.CustomTaskName.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(task => task.Trim())], }; return taskId switch { - int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), id), - null => Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Custom, task), - _ => (null, 0), + int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), [id]), + null => FromSingle(Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Custom, task)), + _ => (null, []), }; } } diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/FightSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/FightSettingsUserControlModel.cs index af0c4c4647..2fa1c7f895 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/FightSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/FightSettingsUserControlModel.cs @@ -695,14 +695,14 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel, FightSetting return null; } - if (ConfigFactory.CurrentConfig.TaskQueue.IndexOf(fight) is int index && index > -1 && Instances.TaskQueueViewModel.TaskItemViewModels[index].TaskId > 0) + if (ConfigFactory.CurrentConfig.TaskQueue.IndexOf(fight) is int index && index > -1 && Instances.TaskQueueViewModel.TaskItemViewModels[index].TaskIds.Count > 0) { - return SerializeTask(fight, Instances.TaskQueueViewModel.TaskItemViewModels[index].TaskId).IsSuccess; + return SerializeTask(fight, Instances.TaskQueueViewModel.TaskItemViewModels[index].TaskIds[0]).IsSuccess; } return null; } - public override (bool? IsSuccess, int TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); + public override (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); #region 关卡列表更新 @@ -912,23 +912,23 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel, FightSetting private interface ISerialize : ITaskQueueModelSerialize { - (bool? IsSuccess, int TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) + (bool? IsSuccess, IEnumerable TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) { if (baseTask is not FightTask fight || taskId is int and <= 0) { - return (null, 0); + return (null, []); } if (fight.UseWeeklySchedule && fight.WeeklySchedule.TryGetValue(Instances.TaskQueueViewModel.CurDayOfWeek, out var isEnabled) && !isEnabled) { - return (null, 0); + return (null, []); } using var scope = _lock.EnterScope(); var stage = FightSettingsUserControlModel.GetFightStage(fight.StagePlan); if (stage is null) { - return (null, 0); + return (null, []); } var task = new AsstFightTask() { Stage = stage, @@ -962,9 +962,9 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel, FightSetting } return taskId switch { - int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), id), - null => Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Fight, task), - _ => (null, 0), + int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), [id]), + null => FromSingle(Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Fight, task)), + _ => (null, []), }; } } diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/InfrastSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/InfrastSettingsUserControlModel.cs index 4e6c332e48..c97b457e6b 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/InfrastSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/InfrastSettingsUserControlModel.cs @@ -541,15 +541,15 @@ public class InfrastSettingsUserControlModel : TaskSettingsViewModel, InfrastSet } } - public override (bool? IsSuccess, int TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize)?.Serialize(baseTask, taskId) ?? (null, 0); + public override (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); private interface ISerialize : ITaskQueueModelSerialize { - (bool? IsSuccess, int TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) + (bool? IsSuccess, IEnumerable TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) { if (baseTask is not InfrastTask infrast) { - return (null, 0); + return (null, []); } var task = new AsstInfrastTask { @@ -594,9 +594,9 @@ public class InfrastSettingsUserControlModel : TaskSettingsViewModel, InfrastSet } return taskId switch { - int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), id), - null => Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Infrast, task), - _ => (null, 0), + int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), [id]), + null => FromSingle(Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Infrast, task)), + _ => (null, []), }; } } diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/MallSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/MallSettingsUserControlModel.cs index cb07e605fa..9af8e4f29a 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/MallSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/MallSettingsUserControlModel.cs @@ -187,15 +187,15 @@ public class MallSettingsUserControlModel : TaskSettingsViewModel, MallSettingsU } } - public override (bool? IsSuccess, int TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize)?.Serialize(baseTask, taskId) ?? (null, 0); + public override (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); private interface ISerialize : ITaskQueueModelSerialize { - (bool? IsSuccess, int TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) + (bool? IsSuccess, IEnumerable TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) { if (baseTask is not MallTask mall) { - return (null, 0); + return (null, []); } var fightStageEmpty = false; @@ -240,9 +240,9 @@ public class MallSettingsUserControlModel : TaskSettingsViewModel, MallSettingsU }; return taskId switch { - int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), id), - null => Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Mall, task), - _ => (null, 0), + int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), [id]), + null => FromSingle(Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Mall, task)), + _ => (null, []), }; string? GetStageForDayOfWeek(FightTask fightTask, DayOfWeek day) diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/ReclamationSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/ReclamationSettingsUserControlModel.cs index 8b2ed28743..fffed1bc2f 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/ReclamationSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/ReclamationSettingsUserControlModel.cs @@ -137,15 +137,15 @@ public class ReclamationSettingsUserControlModel : TaskSettingsViewModel, Reclam } } - public override (bool? IsSuccess, int TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize)?.Serialize(baseTask, taskId) ?? (null, 0); + public override (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); private interface ISerialize : ITaskQueueModelSerialize { - (bool? IsSuccess, int TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) + (bool? IsSuccess, IEnumerable TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) { if (baseTask is not ReclamationTask reclamation) { - return (null, 0); + return (null, []); } var toolToCraft = !string.IsNullOrEmpty(reclamation.ToolToCraft) ? reclamation.ToolToCraft : LocalizationHelper.GetString("ReclamationToolToCraftPlaceholder", DataHelper.ClientLanguageMapper[SettingsViewModel.GameSettings.ClientType]); @@ -159,9 +159,9 @@ public class ReclamationSettingsUserControlModel : TaskSettingsViewModel, Reclam }; return taskId switch { - int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), id), - null => Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Reclamation, task), - _ => (null, 0), + int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), [id]), + null => FromSingle(Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Reclamation, task)), + _ => (null, []), }; } } diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RecruitSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RecruitSettingsUserControlModel.cs index beee55fb8b..981e54270a 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RecruitSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RecruitSettingsUserControlModel.cs @@ -254,15 +254,15 @@ public class RecruitSettingsUserControlModel : TaskSettingsViewModel, RecruitSet } } - public override (bool? IsSuccess, int TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize)?.Serialize(baseTask, taskId) ?? (null, 0); + public override (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); private interface ISerialize : ITaskQueueModelSerialize { - (bool? IsSuccess, int TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) + (bool? IsSuccess, IEnumerable TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) { if (baseTask is not RecruitTask recruit) { - return (null, 0); + return (null, []); } var task = new AsstRecruitTask() { @@ -309,9 +309,9 @@ public class RecruitSettingsUserControlModel : TaskSettingsViewModel, RecruitSet } return taskId switch { - int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), id), - null => Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Recruit, task), - _ => (null, 0), + int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), [id]), + null => FromSingle(Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Recruit, task)), + _ => (null, []), }; } } diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RoguelikeSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RoguelikeSettingsUserControlModel.cs index d4e8743c66..dd8803917f 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RoguelikeSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RoguelikeSettingsUserControlModel.cs @@ -1052,15 +1052,15 @@ public class RoguelikeSettingsUserControlModel : TaskSettingsViewModel, Roguelik } } - public override (bool? IsSuccess, int TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize)?.Serialize(baseTask, taskId) ?? (null, 0); + public override (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); private interface ISerialize : ITaskQueueModelSerialize { - (bool? IsSuccess, int TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) + (bool? IsSuccess, IEnumerable TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) { if (baseTask is not RoguelikeTask roguelike) { - return (null, 0); + return (null, []); } bool roguelikeSquadIsProfessional = roguelike.Mode == Mode.Collectible && roguelike.Theme != Theme.Phantom && roguelike.Squad is "突击战术分队" or "堡垒战术分队" or "远程战术分队" or "破坏战术分队"; @@ -1136,9 +1136,9 @@ public class RoguelikeSettingsUserControlModel : TaskSettingsViewModel, Roguelik } return taskId switch { - int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), id), - null => Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Roguelike, task), - _ => (null, 0), + int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), [id]), + null => FromSingle(Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Roguelike, task)), + _ => (null, []), }; } } diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/StartUpSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/StartUpSettingsUserControlModel.cs index a45653aa9b..d1bc35ec1f 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/StartUpSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/StartUpSettingsUserControlModel.cs @@ -12,6 +12,7 @@ // #nullable enable +using System.Collections.Generic; using JetBrains.Annotations; using MaaWpfGui.Configuration.Single.MaaTask; using MaaWpfGui.Constants; @@ -73,15 +74,15 @@ public class StartUpSettingsUserControlModel : TaskSettingsViewModel, StartUpSet } } - public override (bool? IsSuccess, int TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize)?.Serialize(baseTask, taskId) ?? (null, 0); + public override (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); private interface ISerialize : ITaskQueueModelSerialize { - (bool? IsSuccess, int TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) + (bool? IsSuccess, IEnumerable TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) { if (baseTask is not StartUpTask startUp) { - return (null, 0); + return (null, []); } var clientType = SettingsViewModel.GameSettings.ClientType; @@ -97,9 +98,9 @@ public class StartUpSettingsUserControlModel : TaskSettingsViewModel, StartUpSet }; return taskId switch { - int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), id), - null => Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.StartUp, task), - _ => (null, 0), + int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), [id]), + null => FromSingle(Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.StartUp, task)), + _ => (null, []), }; } } diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/UserDataUpdateSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/UserDataUpdateSettingsUserControlModel.cs new file mode 100644 index 0000000000..8a801ccef6 --- /dev/null +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/UserDataUpdateSettingsUserControlModel.cs @@ -0,0 +1,150 @@ +// +// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team) +// Copyright (C) 2021-2025 MaaAssistantArknights 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 +// + +#nullable enable + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using MaaWpfGui.Configuration.Single.MaaTask; +using MaaWpfGui.Constants; +using MaaWpfGui.Constants.Enums; +using MaaWpfGui.Extensions; +using MaaWpfGui.Helper; +using MaaWpfGui.Utilities.ValueType; + +namespace MaaWpfGui.ViewModels.UserControl.TaskQueue; + +public class UserDataUpdateSettingsUserControlModel : TaskSettingsViewModel, UserDataUpdateSettingsUserControlModel.ISerialize +{ + static UserDataUpdateSettingsUserControlModel() + { + Instance = new(); + } + + public static UserDataUpdateSettingsUserControlModel Instance { get; } + + public bool UpdateOperBox + { + get => GetTaskConfig().UpdateOperBox; + set => SetTaskConfig(t => t.UpdateOperBox == value, t => t.UpdateOperBox = value); + } + + public bool UpdateDepot + { + get => GetTaskConfig().UpdateDepot; + set => SetTaskConfig(t => t.UpdateDepot == value, t => t.UpdateDepot = value); + } + + public UserDataUpdateTriggerInterval TriggerInterval + { + get => GetTaskConfig().TriggerInterval; + set => SetTaskConfig(t => t.TriggerInterval == value, t => t.TriggerInterval = value); + } + + public List> TriggerIntervalList { get; } = + [ + new() { Display = LocalizationHelper.GetString("EveryTime"), Value = UserDataUpdateTriggerInterval.EveryTime }, + new() { Display = LocalizationHelper.GetString("Daily"), Value = UserDataUpdateTriggerInterval.Daily }, + new() { Display = LocalizationHelper.GetString("Weekly"), Value = UserDataUpdateTriggerInterval.Weekly }, + ]; + + public override void RefreshUI(BaseTask baseTask) + { + if (baseTask is UserDataUpdateTask) + { + Refresh(); + } + } + + public override (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); + + private interface ISerialize : ITaskQueueModelSerialize + { + (bool? IsSuccess, IEnumerable TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) + { + if (baseTask is not UserDataUpdateTask updateTask) + { + return (null, []); + } + + if (taskId is int id && id > 0) + { + Instances.TaskQueueViewModel.AddLog("Unable to modify existing UserDataUpdateTask.", UiLogColor.Error); + return (null, []); + } + + if (!updateTask.IsTriggered) + { + return (null, []); + } + + bool operBoxTriggerDue = updateTask.UpdateOperBox && IsTriggerDue(Instances.ToolboxViewModel.LastOperBoxSyncTime, updateTask.TriggerInterval); + bool depotTriggerDue = updateTask.UpdateDepot && IsTriggerDue(Instances.ToolboxViewModel.LastDepotSyncTime, updateTask.TriggerInterval); + + if (!operBoxTriggerDue && !depotTriggerDue) + { + return (null, []); + } + + List ids = []; + bool ret = false; + if (operBoxTriggerDue) + { + Instances.ToolboxViewModel.ResetOperBoxRecognitionState(); + ret = Instances.ToolboxViewModel.StartOperBoxRecognitionTask(startImmediately: false); + if (!ret) + { + return (false, []); + } + ids.Add(Instances.AsstProxy.TasksStatus.Last().Key); + } + + if (depotTriggerDue) + { + Instances.ToolboxViewModel.ResetDepotRecognitionState(); + ret = Instances.ToolboxViewModel.StartDepotRecognitionTask(false); + if (!ret) + { + return (false, []); + } + ids.Add(Instances.AsstProxy.TasksStatus.Last().Key); + } + + return ret ? (true, ids) : (null, []); + } + + private static bool IsTriggerDue(DateTime? lastSyncTime, UserDataUpdateTriggerInterval triggerInterval) + { + if (triggerInterval == UserDataUpdateTriggerInterval.EveryTime) + { + return true; + } + + if (!lastSyncTime.HasValue) + { + return true; + } + + var now = DateTime.UtcNow.ToYjDate(); + var lastDate = lastSyncTime.Value.ToYjDate(); + + return triggerInterval switch { + UserDataUpdateTriggerInterval.Daily => now > lastDate, + UserDataUpdateTriggerInterval.Weekly => ISOWeek.GetYear(now) != ISOWeek.GetYear(lastDate) || ISOWeek.GetWeekOfYear(now) != ISOWeek.GetWeekOfYear(lastDate), + _ => true, + }; + } + } +} diff --git a/src/MaaWpfGui/Views/UI/TaskQueueView.xaml b/src/MaaWpfGui/Views/UI/TaskQueueView.xaml index b9bd15310a..62d6e1fe10 100644 --- a/src/MaaWpfGui/Views/UI/TaskQueueView.xaml +++ b/src/MaaWpfGui/Views/UI/TaskQueueView.xaml @@ -9,6 +9,7 @@ xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:helper="clr-namespace:MaaWpfGui.Helper" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:enums="clr-namespace:MaaWpfGui.Constants.Enums" xmlns:properties="clr-namespace:MaaWpfGui.Styles.Properties" xmlns:s="https://github.com/canton7/Stylet" xmlns:taskQueue="clr-namespace:MaaWpfGui.Views.UserControl.TaskQueue" @@ -78,19 +79,19 @@ - - + + - - + + - - + + - + @@ -289,7 +290,12 @@ Padding="0,3" Command="{s:Action AddTaskQueueTask}" CommandParameter="{Binding TaskTypeList[8].Value}" - Header="{Binding TaskTypeList[8].Display}" + Header="{Binding TaskTypeList[8].Display}" /> + @@ -494,6 +500,12 @@ AncestorType={x:Type UserControl}}}" /> + @@ -540,7 +552,7 @@ - + diff --git a/src/MaaWpfGui/Views/UI/ToolboxView.xaml b/src/MaaWpfGui/Views/UI/ToolboxView.xaml index dc14c9fbee..857e49e624 100644 --- a/src/MaaWpfGui/Views/UI/ToolboxView.xaml +++ b/src/MaaWpfGui/Views/UI/ToolboxView.xaml @@ -210,6 +210,7 @@ + @@ -217,6 +218,18 @@ + + + + + + + + - + diff --git a/src/MaaWpfGui/Views/UserControl/TaskQueue/UserDataUpdateSettingsUserControl.xaml b/src/MaaWpfGui/Views/UserControl/TaskQueue/UserDataUpdateSettingsUserControl.xaml new file mode 100644 index 0000000000..f018703549 --- /dev/null +++ b/src/MaaWpfGui/Views/UserControl/TaskQueue/UserDataUpdateSettingsUserControl.xaml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/MaaWpfGui/Views/UserControl/TaskQueue/UserDataUpdateSettingsUserControl.xaml.cs b/src/MaaWpfGui/Views/UserControl/TaskQueue/UserDataUpdateSettingsUserControl.xaml.cs new file mode 100644 index 0000000000..64ba04e22b --- /dev/null +++ b/src/MaaWpfGui/Views/UserControl/TaskQueue/UserDataUpdateSettingsUserControl.xaml.cs @@ -0,0 +1,28 @@ +// +// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team) +// Copyright (C) 2021-2025 MaaAssistantArknights 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 +// + +namespace MaaWpfGui.Views.UserControl.TaskQueue; + +/// +/// UserDataUpdateSettingsUserControl.xaml 的交互逻辑 +/// +public partial class UserDataUpdateSettingsUserControl : System.Windows.Controls.UserControl +{ + /// + /// Initializes a new instance of the class. + /// + public UserDataUpdateSettingsUserControl() + { + InitializeComponent(); + } +}