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();
+ }
+}