diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fad10a1d1..e22e911b07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## v6.10.0-beta.3 + +### 新增 | New + +* 点击成就横幅跳转至成就设置,自动打开成就列表并筛选对应成就 (#16537) @H2O-MERO @ABA2396 +* 任务日志输出停滞时发送通知, 替换 任务超时通知 (#16511) @H2O-MERO + +### 其他 | Other + +* 放宽对 RA-1 关卡名的检查 @ABA2396 +* 添加拆除设施的描述 @ABA2396 +* 删除辅助建设模式的描述 @ABA2396 + ## v6.10.0-beta.2 ### 新增 | New diff --git a/resource/tasks/RA/Reclamation3.json b/resource/tasks/RA/Reclamation3.json index b323a8cd68..b1029f29d0 100644 --- a/resource/tasks/RA/Reclamation3.json +++ b/resource/tasks/RA/Reclamation3.json @@ -8,7 +8,7 @@ "doc": "步骤 1(任务起点):OCR 识别 RA-1 并点击;右下角出现 <开启建设> 时进入步骤 2", "algorithm": "OcrDetect", "action": "ClickSelf", - "text": ["RA-1"], + "text": ["RA", "-1"], "withoutDet": true, "useRaw": false, "binThreshold": [200, 255], diff --git a/src/MAAUnified b/src/MAAUnified index 1ee09448b3..ee18d23329 160000 --- a/src/MAAUnified +++ b/src/MAAUnified @@ -1 +1 @@ -Subproject commit 1ee09448b3eb2f12e20f5ad186eaa322ce62aa9c +Subproject commit ee18d23329e9c20917363f8851cb07fa40d43054 diff --git a/src/MaaWpfGui/Constants/ConfigurationKeys.cs b/src/MaaWpfGui/Constants/ConfigurationKeys.cs index 7e2b822bd6..23a0619897 100644 --- a/src/MaaWpfGui/Constants/ConfigurationKeys.cs +++ b/src/MaaWpfGui/Constants/ConfigurationKeys.cs @@ -258,6 +258,7 @@ public static class ConfigurationKeys public const string TaskTimeoutMinutes = "TimeOut.Timer.TaskTimeoutMinutes"; public const string ReminderIntervalMinutes = "TimeOut.Timer.ReminderIntervalMinutes"; + public const string StallTimeoutMinutes = "TimeOut.Timer.StallTimeoutMinutes"; public const string BluestacksConfigPath = "Bluestacks.Config.Path"; public const string BluestacksConfigKeyword = "Bluestacks.Config.Keyword"; @@ -293,7 +294,7 @@ public static class ConfigurationKeys public const string ExternalNotificationSendWhenComplete = "ExternalNotification.SendWhenComplete"; public const string ExternalNotificationEnableDetails = "ExternalNotification.EnableDetails"; public const string ExternalNotificationSendWhenError = "ExternalNotification.SendWhenError"; - public const string ExternalNotificationSendWhenTimeout = "ExternalNotification.SendWhenTimeout"; + public const string ExternalNotificationSendWhenStalled = "ExternalNotification.SendWhenStalled"; public const string ExternalNotificationSmtpServer = "ExternalNotification.Smtp.Server"; public const string ExternalNotificationSmtpPort = "ExternalNotification.Smtp.Port"; public const string ExternalNotificationSmtpUser = "ExternalNotification.Smtp.User"; diff --git a/src/MaaWpfGui/Helper/AchievementTrackerHelper.cs b/src/MaaWpfGui/Helper/AchievementTrackerHelper.cs index 88e2d964d2..e4b306bca5 100644 --- a/src/MaaWpfGui/Helper/AchievementTrackerHelper.cs +++ b/src/MaaWpfGui/Helper/AchievementTrackerHelper.cs @@ -16,6 +16,10 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Threading; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; @@ -103,9 +107,28 @@ public class AchievementTrackerHelper : PropertyChangedBase public ICommand SearchCmd { get; } + private string _searchText = string.Empty; + + public string SearchText + { + get => _searchText; + set => SetAndNotify(ref _searchText, value ?? string.Empty); + } + + public void SearchAndSyncText(string text = "") + { + SearchText = text.Trim(); + Search(SearchText); + } + public void Search(string text = "") { text = text.Trim(); + if (!string.Equals(SearchText, text, StringComparison.Ordinal)) + { + SearchText = text; + } + if (string.IsNullOrWhiteSpace(text)) { foreach (var achievement in Achievements) @@ -115,9 +138,14 @@ public class AchievementTrackerHelper : PropertyChangedBase } else { - foreach (var (_, value) in Achievements) + foreach (var (key, value) in Achievements) { - value.IsVisibleInSearch = value.Title.Contains(text) || value.Description.Contains(text) || value.Conditions.Contains(text) || value.ReleasePhaseTag.Contains(text); + value.IsVisibleInSearch = + key == text || + value.Title.Contains(text) || + value.Description.Contains(text) || + value.Conditions.Contains(text) || + value.ReleasePhaseTag.Contains(text); } } @@ -223,6 +251,7 @@ public class AchievementTrackerHelper : PropertyChangedBase IconKey = "HangoverGeometry", IconBrushKey = achievement.MedalBrushKey, }; + _growlAchievementMap[growlInfo] = id; ShowInfo(growlInfo, forceStayOpen: forceStayOpen); } @@ -276,6 +305,8 @@ public class AchievementTrackerHelper : PropertyChangedBase Save(); } + private static readonly Dictionary _growlAchievementMap = []; + private static readonly List _pending = []; public static void ShowInfo(GrowlInfo info, bool forceStayOpen = false) @@ -294,16 +325,132 @@ public class AchievementTrackerHelper : PropertyChangedBase return; } + var previousItems = Growl.GrowlPanel?.Children.OfType().ToHashSet() ?? []; Growl.Info(info); + AttachGrowlClickHandler(info, previousItems); }); } + private static void AttachGrowlClickHandler(GrowlInfo info, HashSet previousItems) + { + if (!_growlAchievementMap.TryGetValue(info, out var id)) + { + return; + } + + bool TryAttachToNewItems() + { + if (Growl.GrowlPanel is not { } panel) + { + return false; + } + + bool attached = false; + foreach (var growlItem in panel.Children.OfType().Where(item => !previousItems.Contains(item))) + { + growlItem.RemoveHandler(UIElement.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(OnGrowlItemMouseDown)); + growlItem.AddHandler( + UIElement.PreviewMouseLeftButtonDownEvent, + new MouseButtonEventHandler(OnGrowlItemMouseDown), + handledEventsToo: true); + + if (growlItem is FrameworkElement element) + { + element.Tag = id; + element.Unloaded -= OnGrowlItemUnloaded; + element.Unloaded += OnGrowlItemUnloaded; + } + + attached = true; + } + + if (attached) + { + _growlAchievementMap.Remove(info); + } + + return attached; + } + + if (!TryAttachToNewItems()) + { + Application.Current.Dispatcher.BeginInvoke( + DispatcherPriority.Loaded, + new Action(() => TryAttachToNewItems())); + } + } + + private static void OnGrowlItemUnloaded(object sender, RoutedEventArgs e) + { + if (sender is UIElement growlItem) + { + growlItem.RemoveHandler(UIElement.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(OnGrowlItemMouseDown)); + } + + if (sender is FrameworkElement element) + { + element.Tag = null; + element.Unloaded -= OnGrowlItemUnloaded; + } + } + + private static void OnGrowlItemMouseDown(object sender, MouseButtonEventArgs e) + { + if (sender is not UIElement growlItem) + { + return; + } + + var source = e.OriginalSource as DependencyObject; + while (source != null && source != growlItem) + { + if (source is Button) + { + return; + } + + source = VisualTreeHelper.GetParent(source); + } + + if (sender is FrameworkElement { Tag: string id } && !string.IsNullOrWhiteSpace(id)) + { + NavigateToAchievement(id); + } + } + + public static void NavigateToAchievement(string id) + { + if (Instances.SettingsViewModel.Parent is IHaveActiveItem conductor) + { + conductor.ActiveItem = Instances.SettingsViewModel; + } + + Application.Current.Dispatcher.BeginInvoke( + DispatcherPriority.Loaded, + new Action(() => + { + var settings = Instances.SettingsViewModel.Settings; + for (int i = 0; i < settings.Count; i++) + { + if (settings[i].Key == "AchievementSettings") + { + Instances.SettingsViewModel.SelectedIndex = i; + break; + } + } + + AchievementSettingsUserControlModel.Instance.OnShowAchievementsClick(id); + })); + } + public static void TryShowPendingGrowls() { Execute.OnUIThread(() => { foreach (var info in _pending) { + var previousItems = Growl.GrowlPanel?.Children.OfType().ToHashSet() ?? []; Growl.Info(info); + AttachGrowlClickHandler(info, previousItems); } _pending.Clear(); diff --git a/src/MaaWpfGui/Res/Localizations/en-us.xaml b/src/MaaWpfGui/Res/Localizations/en-us.xaml index c706795006..35f70b8d46 100644 --- a/src/MaaWpfGui/Res/Localizations/en-us.xaml +++ b/src/MaaWpfGui/Res/Localizations/en-us.xaml @@ -42,7 +42,7 @@ Output Detailed Information Send notification when complete Send notification when task fails - Send notification when task times out + Send notification when task log output stalls Send successfully Send failed Send Test @@ -1463,7 +1463,7 @@ Cache files (such as maps, operator avatars, etc.) need to be regenerated after -Relaunch Anchor - Assisted Construction Mode: +Relaunch Anchor: Reward estimate: ~159 tokens + coordination points per run, ~3 min per round @@ -1471,7 +1471,7 @@ Relaunch Anchor - Assisted Construction Mode: 1. Manually enter RA-1, complete the tutorial, and return to the map 2. After that, the task can be started when "Start Construction" appears at the bottom-right after clicking RA-1 - Note: If the "Start with Extra Device" technology is unlocked, this task will not work properly + Note: If you have unlocked technologies related to starting with extra items, please dismantle the facilities in the base that cause starting with extra items, such as Food Supply Stations, Drink Supply Stations, Large Animal Pens, etc. Task flow: Automatically executes farming, construction, resource delivery, and settlement loop @@ -1525,7 +1525,8 @@ These locations are too high-level and can lead to file overwrites, config write Task timeout duration (minutes) Reminder interval (minutes) - The task has been running for more than {0} minutes (currently running for {1} minutes). If there are no further log updates for a long time, manual intervention may be required. + Log output stall timeout (min) + Task log output has not been updated for {0} minutes (currently stalled for {1} minutes). If there is no further log output for a long time, manual intervention may be required. 🎉 Achievement Unlocked diff --git a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml index d2636ac84e..59d2c380e7 100644 --- a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml +++ b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml @@ -42,7 +42,7 @@ 詳細情報を出力 タスク完了時に通知を送信 タスクが失敗したときに通知を送信 - タスクがタイムアウトしたときに通知を送信する + タスクログ出力停滞時に通知を送信 正常に送信 送信に失敗しました テストを送信する @@ -1464,7 +1464,7 @@ DEBUGディレクトリに保存される画像には数量制限があり、超 -再起の錨 - 支援建設モード: +再起の錨: 報酬目安:1回あたり約159トークン+統括ポイント、所要時間約3分 @@ -1472,7 +1472,7 @@ DEBUGディレクトリに保存される画像には数量制限があり、超 1. 手動でRA-1に入り、チュートリアルを完了してマップに戻る 2. 以降、RA-1をクリックした後に右下に「建設開始」が表示されたらタスクを開始可能 - 注意:「初期追加携帯装置」のテクノロジーをアンロックしていると正常に動作しません + 注意:「初期追加携帯アイテム」に関連するテクノロジーをアンロックしている場合、基地内で初期追加携帯アイテムの原因となる施設(食品供給所、飲料供給所、大型獣舎など)を解体してください タスクの流れ: 精耕細作、建設、資源納入、決済を自動実行 @@ -1526,7 +1526,8 @@ MAA を複数開くには、新しい MAA を他のフォルダにコピーし タスクのタイムアウト時間(分) リマインダー間隔時間(分) - タスクが {0} 分以上実行されています(現在 {1} 分実行中)。長時間ログの更新がない場合、手動で介入する必要があるかもしれません。 + ログ出力停滞タイムアウト(分) + タスクログ出力が {0} 分間更新されていません(現在 {1} 分間停滞)。長時間ログ出力がない場合は、手動での操作が必要になる可能性があります。 🎉 実績を獲得した diff --git a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml index d2249241e4..2b707bc139 100644 --- a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml +++ b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml @@ -42,7 +42,7 @@ 상세 정보 출력 작업 완료 시 알림 전송 작업 실패 시 알림 전송 - 작업 시간 초과 시 알림 전송 + 작업 로그 출력 정지 시 알림 전송 전송 성공 전송 실패 테스트 @@ -1465,7 +1465,7 @@ DEBUG 디렉토리에 저장된 이미지는 수량 제한이 있으며 초과 -재시작 앵커 - 지원 건설 모드: +재시작 앵커: 수익 참고: 회당 약 159토큰 + 통괄 포인트, 소요 시간 약 3분 @@ -1473,7 +1473,7 @@ DEBUG 디렉토리에 저장된 이미지는 수량 제한이 있으며 초과 1. 수동으로 RA-1에 진입하여 튜토리얼을 완료하고 맵으로 돌아옵니다 2. 이후 RA-1 클릭 후 오른쪽 아래에 "건설 시작"이 나타나면 작업을 시작할 수 있습니다 - 참고: "초기 추가 장비 휴대" 기술을 해제한 경우 정상 작동하지 않습니다 + 참고: 초기 추가 아이템 휴대 관련 기술을 해제한 경우, 기지 내에서 초기 추가 아이템을 휴대하게 하는 시설(식품 공급소, 음료 공급소, 대형 축사 등)을 철거하세요 작업 흐름: 정경세작, 건설, 자원 납품, 결제를 자동 실행 @@ -1526,7 +1526,8 @@ MAA를 독립된 새 폴더에 압축 해제하거나, MAA에 속하지 않는 D 작업 타임아웃 시간 (분) 알림 간격 (분) - 작업이 {0}분을 초과하여 {1}분째 실행 중입니다\n장시간 로그의 갱신이 없다면 수동 조작이 필요할 수 있습니다 + 로그 출력 정지 타임아웃 (분) + 작업 로그 출력이 {0}분 동안 업데이트되지 않았습니다(현재 {1}분 정지). 오랫동안 로그 출력이 없으면 수동 개입이 필요할 수 있습니다. 🎉 도전과제 달성 diff --git a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml index 38fb3ddbd5..85b4f284e9 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml @@ -42,7 +42,7 @@ 输出详细信息 任务完成后发送通知 任务出错时发送通知 - 任务超时时发送通知 + 任务日志输出停滞时发送通知 发送成功 发送失败 发送测试 @@ -1464,7 +1464,7 @@ DEBUG 目录下保存的图片有数量限制,超出后会自动清理旧图 -重启锚点 - 辅助建设模式: +重启锚点: 收益参考:每把约 159 代币 + 统筹点数,单轮耗时约 3 分钟 @@ -1472,7 +1472,7 @@ DEBUG 目录下保存的图片有数量限制,超出后会自动清理旧图 1. 手动进入 RA-1,完成新手教程,直到回到大地图 2. 之后每次任务均可在 RA-1 右下角出现“开启建设”时启动 - 注意:如果已解锁开局额外携带装置的科技,将无法正常使用 + 注意:如果已解锁开局额外携带物品的相关科技,请将基地内会导致开局额外携带物品的设施拆除,如食品供给站、饮品供给站、大型兽栏等 任务流程: 自动执行精耕细作、建设、交付资源、结算循环 @@ -1525,8 +1525,9 @@ DEBUG 目录下保存的图片有数量限制,超出后会自动清理旧图 任务超时时间(分钟) - 提醒间隔时间(分钟) - 任务已运行超过 {0} 分钟(当前已运行 {1} 分钟)。如果长时间无进一步日志更新,可能需要手动干预。 + 通知间隔时间(分钟) + 日志输出停滞超时时间(分钟) + 任务日志输出已超过 {0} 分钟无更新(当前已停滞 {1} 分钟)。如果长时间无进一步日志输出,可能需要手动干预。 🎉 达成成就 diff --git a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml index 5c6838e530..426e45c674 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml @@ -42,7 +42,7 @@ 輸出詳細資訊 任務完成後發送通知 任務出錯時發送通知 - 任務逾時時發送通知 + 任務日誌輸出停滯時發送通知 發送成功 發送失敗 發送測試 @@ -1464,7 +1464,7 @@ DEBUG 目錄下儲存的圖片有數量限制,超出後會自動清理舊圖 -重啟錨點 - 輔助建設模式: +重啟錨點: 收益參考:每把約 159 代幣 + 統籌點數,單輪耗時約 3 分 @@ -1472,7 +1472,7 @@ DEBUG 目錄下儲存的圖片有數量限制,超出後會自動清理舊圖 1. 手動進入 RA-1,完成新手教學,直到回到大地圖 2. 之後每次任務均可在 RA-1 右下角出現「開啟建設」時啟動 - 注意:如果已解鎖開局額外攜帶裝置的科技,將無法正常使用 + 注意:如果已解鎖開局額外攜帶物品的相關科技,請將基地內會導致開局額外攜帶物品的設施拆除,如食品供給站、飲品供給站、大型獸欄等 任務流程: 自動執行精耕細作、建設、交付資源、結算循環 @@ -1525,8 +1525,9 @@ DEBUG 目錄下儲存的圖片有數量限制,超出後會自動清理舊圖 任務逾時時間(分鐘) - 提醒間隔時間(分鐘) - 任務已執行超過 {0} 分鐘(目前已執行 {1} 分鐘)。若長時間無進一步日誌更新,可能需要手動干預。 + 通知間隔時間(分鐘) + 日誌輸出停滯超時時間(分鐘) + 任務日誌輸出已超過 {0} 分鐘無更新(當前已停滯 {1} 分鐘)。如果長時間無進一步日誌輸出,可能需要手動干預。 🎉 達成成就 diff --git a/src/MaaWpfGui/States/RunningState.cs b/src/MaaWpfGui/States/RunningState.cs index 179a4c1fe4..99ce0cec3e 100644 --- a/src/MaaWpfGui/States/RunningState.cs +++ b/src/MaaWpfGui/States/RunningState.cs @@ -46,6 +46,7 @@ public class RunningState _timeoutReminderTimer.Interval = ReminderIntervalMinutes * 60 * 1000; _timeoutReminderTimer.Elapsed += TimeoutReminderTimer_Elapsed; + _stallTimer.Elapsed += StallTimer_Elapsed; } public static RunningState Instance @@ -58,6 +59,9 @@ public class RunningState // 超时相关字段 private readonly System.Timers.Timer _timeoutReminderTimer = new(); + private readonly System.Timers.Timer _stallTimer = new(); + private int _stallAccumulatedCount = 0; + private bool _stallIsFirstFire = true; private DateTime? _taskStartTime; public int TaskTimeoutMinutes { get; set; } = SettingsViewModel.GameSettings.TaskTimeoutMinutes; @@ -79,18 +83,61 @@ public class RunningState } } + + private int _stallTimeoutMinutes = SettingsViewModel.GameSettings.StallTimeoutMinutes; + + public int StallTimeoutMinutes + { + get => _stallTimeoutMinutes; + set { + _stallTimeoutMinutes = value; + _stallIsFirstFire = true; + if (_stallTimer.Enabled) + { + _stallTimer.Stop(); + if (value > 0) + { + _stallTimer.Interval = value * 60 * 1000; + _stallTimer.Start(); + } + } + } + } + + public event EventHandler? StallOccurred; + + public void NotifyOutputActivity() + { + _stallAccumulatedCount = 0; + _stallIsFirstFire = true; + if (_stallTimer.Enabled && StallTimeoutMinutes > 0) + { + _stallTimer.Interval = StallTimeoutMinutes * 60 * 1000; + _stallTimer.Stop(); + _stallTimer.Start(); + } + } // 超时事件 - public event EventHandler? TimeoutOccurred; public void StartTimeoutTimer() { _taskStartTime = DateTime.Now; _timeoutReminderTimer.Start(); + _stallAccumulatedCount = 0; + _stallIsFirstFire = true; + if (StallTimeoutMinutes > 0) + { + _stallTimer.Interval = StallTimeoutMinutes * 60 * 1000; + _stallTimer.Start(); + } } public void StopTimeoutTimer() { _timeoutReminderTimer.Stop(); + _stallTimer.Stop(); + _stallAccumulatedCount = 0; + _stallIsFirstFire = true; _taskStartTime = null; } @@ -120,15 +167,29 @@ public class RunningState return; } - // 每隔 ReminderIntervalMinutes 提示一次 - var message = string.Format( - LocalizationHelper.GetString("TaskTimeoutWarning"), - TaskTimeoutMinutes, - Math.Round(elapsedMinutes)); - AchievementTrackerHelper.Instance.Unlock(AchievementIds.LongTaskTimeout); + } - TimeoutOccurred?.Invoke(this, message); + private void StallTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e) + { + _stallTimer.Stop(); + _stallAccumulatedCount++; + var accumulatedMinutes = StallTimeoutMinutes + ((_stallAccumulatedCount - 1) * ReminderIntervalMinutes); + var message = string.Format( + LocalizationHelper.GetString("TaskStallWarning"), + StallTimeoutMinutes, + accumulatedMinutes); + StallOccurred?.Invoke(this, message); + if (StallTimeoutMinutes > 0) + { + if (_stallIsFirstFire) + { + _stallTimer.Interval = ReminderIntervalMinutes * 60 * 1000; + _stallIsFirstFire = false; + } + + _stallTimer.Start(); + } } private bool _idle = true; diff --git a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs index 2d1892b1e6..71e5be9607 100644 --- a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs @@ -610,7 +610,7 @@ public class TaskQueueViewModel : Screen Instances.Data.ClearCache(); } }; - _runningState.TimeoutOccurred += RunningState_TimeOut; + _runningState.StallOccurred += RunningState_Stalled; if (Instances.VersionUpdateDialogViewModel.IsDebugVersion() || File.Exists("DEBUG") || File.Exists("DEBUG.txt")) { @@ -619,16 +619,17 @@ public class TaskQueueViewModel : Screen } } - private void RunningState_TimeOut(object? sender, string message) - { - Execute.OnUIThread(() => { - AddLog(message, UiLogColor.Warning); - ToastNotification.ShowDirect(message); - if (!SettingsViewModel.ExternalNotificationSettings.ExternalNotificationSendWhenTimeout) - { - return; - } + private void RunningState_Stalled(object? sender, string message) + { + if (!SettingsViewModel.ExternalNotificationSettings.ExternalNotificationSendWhenStalled) + { + return; + } + + Execute.OnUIThread(() => { + AddLog(message, UiLogColor.Warning, notifyActivity: false); + ToastNotification.ShowDirect(message); var lastLogs = LogItemViewModels .TakeLast(5) .Aggregate(string.Empty, (current, logItem) => current + $"[{logItem.Time}][{logItem.Color}]{logItem.Content}\n"); @@ -1185,8 +1186,14 @@ public class TaskQueueViewModel : Screen bool updateCardImage = false, bool fetchLatestImage = false, bool useCardImageAsToolTip = false, - LogCardSplitMode splitMode = LogCardSplitMode.None) + LogCardSplitMode splitMode = LogCardSplitMode.None, + bool notifyActivity = true) { + if (notifyActivity) + { + RunningState.Instance.NotifyOutputActivity(); + } + bool isEmpty = string.IsNullOrEmpty(content); bool needsBeforeSplit = splitMode == LogCardSplitMode.Before || splitMode == LogCardSplitMode.Both; bool needsAfterSplit = splitMode == LogCardSplitMode.After || splitMode == LogCardSplitMode.Both; diff --git a/src/MaaWpfGui/ViewModels/UserControl/Settings/AchievementSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/Settings/AchievementSettingsUserControlModel.cs index e0c088b618..8cd1312f1d 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/Settings/AchievementSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/Settings/AchievementSettingsUserControlModel.cs @@ -108,9 +108,9 @@ public class AchievementSettingsUserControlModel : PropertyChangedBase } } - private static Window? _achievementsWindow; + private static AchievementListDialogView? _achievementsWindow; - public void OnShowAchievementsClick() + public void OnShowAchievementsClick(string? achievementId = null) { AchievementTrackerHelper.Instance.Unlock(AchievementIds.AchievementObserver); if (_achievementsWindow is null) @@ -125,6 +125,11 @@ public class AchievementSettingsUserControlModel : PropertyChangedBase } WindowManager.ShowWindow(_achievementsWindow); + + if (achievementId != null) + { + AchievementTrackerHelper.Instance.SearchAndSyncText(achievementId); + } } private int _clickCount = 0; diff --git a/src/MaaWpfGui/ViewModels/UserControl/Settings/ExternalNotificationSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/Settings/ExternalNotificationSettingsUserControlModel.cs index 6c6c3ae7f1..d8041ecfd1 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/Settings/ExternalNotificationSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/Settings/ExternalNotificationSettingsUserControlModel.cs @@ -78,14 +78,15 @@ public class ExternalNotificationSettingsUserControlModel : PropertyChangedBase } } - private bool _externalNotificationSendWhenTimeout = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationSendWhenTimeout, bool.TrueString)); - public bool ExternalNotificationSendWhenTimeout + private bool _externalNotificationSendWhenStalled = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ExternalNotificationSendWhenStalled, bool.FalseString)); + + public bool ExternalNotificationSendWhenStalled { - get => _externalNotificationSendWhenTimeout; + get => _externalNotificationSendWhenStalled; set { - SetAndNotify(ref _externalNotificationSendWhenTimeout, value); - ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationSendWhenTimeout, value.ToString()); + SetAndNotify(ref _externalNotificationSendWhenStalled, value); + ConfigurationHelper.SetValue(ConfigurationKeys.ExternalNotificationSendWhenStalled, value.ToString()); } } diff --git a/src/MaaWpfGui/ViewModels/UserControl/Settings/GameSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/Settings/GameSettingsUserControlModel.cs index cb90d0a5be..dcfc099d51 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/Settings/GameSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/Settings/GameSettingsUserControlModel.cs @@ -370,5 +370,17 @@ public class GameSettingsUserControlModel : PropertyChangedBase } } + private int _stallTimeoutMinutes = ConfigurationHelper.GetValue(ConfigurationKeys.StallTimeoutMinutes, 25); + + public int StallTimeoutMinutes + { + get => _stallTimeoutMinutes; + set { + SetAndNotify(ref _stallTimeoutMinutes, value); + _runningState.StallTimeoutMinutes = value; + ConfigurationHelper.SetValue(ConfigurationKeys.StallTimeoutMinutes, value.ToString()); + } + } + #endregion 任务超时 } diff --git a/src/MaaWpfGui/Views/Dialogs/AchievementListDialogView.xaml b/src/MaaWpfGui/Views/Dialogs/AchievementListDialogView.xaml index 6295e5e4a2..98f893c5b1 100644 --- a/src/MaaWpfGui/Views/Dialogs/AchievementListDialogView.xaml +++ b/src/MaaWpfGui/Views/Dialogs/AchievementListDialogView.xaml @@ -13,6 +13,7 @@ Background="{DynamicResource MdXamlBackground}"> diff --git a/src/MaaWpfGui/Views/Dialogs/AchievementListDialogView.xaml.cs b/src/MaaWpfGui/Views/Dialogs/AchievementListDialogView.xaml.cs index 7bde9ee9b3..ca544f77e1 100644 --- a/src/MaaWpfGui/Views/Dialogs/AchievementListDialogView.xaml.cs +++ b/src/MaaWpfGui/Views/Dialogs/AchievementListDialogView.xaml.cs @@ -33,4 +33,5 @@ public partial class AchievementListDialogView // 关闭窗口时执行一次空搜索,重置可见性 AchievementTrackerHelper.Instance.Search(); } + } diff --git a/src/MaaWpfGui/Views/UI/RootView.xaml b/src/MaaWpfGui/Views/UI/RootView.xaml index 19771d3074..9d6e5e5f56 100644 --- a/src/MaaWpfGui/Views/UI/RootView.xaml +++ b/src/MaaWpfGui/Views/UI/RootView.xaml @@ -199,7 +199,7 @@ d:Height="200" d:Width="100" VerticalScrollBarVisibility="Hidden"> - + +// 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.UI; + +public partial class RootView +{ + public RootView() + { + InitializeComponent(); + } +} diff --git a/src/MaaWpfGui/Views/UserControl/Settings/ExternalNotificationSettingsUserControl.xaml b/src/MaaWpfGui/Views/UserControl/Settings/ExternalNotificationSettingsUserControl.xaml index 54b7706216..ff9e987239 100644 --- a/src/MaaWpfGui/Views/UserControl/Settings/ExternalNotificationSettingsUserControl.xaml +++ b/src/MaaWpfGui/Views/UserControl/Settings/ExternalNotificationSettingsUserControl.xaml @@ -91,12 +91,12 @@ VerticalAlignment="Top" Content="{DynamicResource ExternalNotificationSendWhenError}" IsChecked="{Binding ExternalNotificationSendWhenError}" /> - + diff --git a/src/MaaWpfGui/Views/UserControl/Settings/GameSettingsUserControl.xaml b/src/MaaWpfGui/Views/UserControl/Settings/GameSettingsUserControl.xaml index bbace1a613..ee07c21e34 100644 --- a/src/MaaWpfGui/Views/UserControl/Settings/GameSettingsUserControl.xaml +++ b/src/MaaWpfGui/Views/UserControl/Settings/GameSettingsUserControl.xaml @@ -188,11 +188,11 @@ + Minimum="1" + Value="{Binding StallTimeoutMinutes}" />