From 00a653e59766a7594b333f44d7d56a236a426777 Mon Sep 17 00:00:00 2001 From: CreeperAWA Date: Tue, 3 Nov 2026 01:23:17 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat(linkage):=20=E4=B8=8A=E8=AF=BE?= =?UTF-8?q?=E6=97=B6=E6=AE=B5=E7=A6=81=E7=94=A8=E6=88=B7=E5=A4=96=E8=AF=BE?= =?UTF-8?q?=E7=A8=8B=EF=BC=8C=E8=AF=BB=E5=8F=96=20ClassIsland=20=E7=A7=91?= =?UTF-8?q?=E7=9B=AE=E6=88=B7=E5=A4=96=E8=AF=BE=E7=A8=8B=E6=A0=87=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClassIslandScheduleSourceTests.cs | 57 ++++++++++++++++++- SecRandom.Core/Models/Linkage/CourseModels.cs | 4 +- .../SubConfigs/LinkageSettingsConfig.cs | 1 + .../Linkage/Resources.Designer.cs | 20 ++++++- .../Linkage/Resources.en-US.resx | 6 ++ .../Linkage/Resources.ja-JP.resx | 6 ++ .../SettingsPages/Linkage/Resources.resx | 6 ++ .../Linkage/ClassIslandScheduleSource.cs | 7 ++- .../Services/Linkage/CourseLinkageService.cs | 11 ++++ .../Linkage/LinkageDrawCoordinator.cs | 15 ++++- .../Linkage/LinkageSettingsPage.axaml | 10 ++++ .../Linkage/LinkageSettingsPage.axaml.cs | 12 ++++ 12 files changed, 148 insertions(+), 7 deletions(-) diff --git a/SecRandom.Core.Tests/ClassIslandScheduleSourceTests.cs b/SecRandom.Core.Tests/ClassIslandScheduleSourceTests.cs index f5280f093..5873ef0f0 100644 --- a/SecRandom.Core.Tests/ClassIslandScheduleSourceTests.cs +++ b/SecRandom.Core.Tests/ClassIslandScheduleSourceTests.cs @@ -168,6 +168,58 @@ public async Task Refresh_WhenPreClassEnableWindowOpens_UnrestrictsWithoutNotify Assert.Equal(notifications, harness.StateChangedCount); } + [Fact] + public async Task OnClass_OutdoorSubject_RestrictsWhenEnabled() + { + var harness = new LinkageHarness(instantDrawDisable: false, disableOnOutdoorCourse: true); + harness.Lessons.CurrentState = TimeState.OnClass; + harness.Lessons.CurrentSubject = new Subject { Name = "体育", IsOutDoor = true }; + await harness.RefreshAsync(); + + Assert.True(harness.Snapshot.IsAvailable, $"error={harness.Snapshot.Error}"); + Assert.True(harness.Snapshot.IsOutdoorCourse); + Assert.True(harness.OutdoorRestricted); + // 非上课时段限制与户外课程限制是两个独立开关 + Assert.False(harness.Restricted); + } + + [Fact] + public async Task OnClass_IndoorSubject_NotRestricted() + { + var harness = new LinkageHarness(instantDrawDisable: false, disableOnOutdoorCourse: true); + harness.Lessons.CurrentState = TimeState.OnClass; + harness.Lessons.CurrentSubject = new Subject { Name = "数学", IsOutDoor = false }; + await harness.RefreshAsync(); + + Assert.False(harness.Snapshot.IsOutdoorCourse); + Assert.False(harness.OutdoorRestricted); + } + + [Fact] + public async Task OnClass_OutdoorSubject_SettingOff_NotRestricted() + { + var harness = new LinkageHarness(); + harness.Lessons.CurrentState = TimeState.OnClass; + harness.Lessons.CurrentSubject = new Subject { Name = "体育", IsOutDoor = true }; + await harness.RefreshAsync(); + + Assert.True(harness.Snapshot.IsOutdoorCourse); + Assert.False(harness.OutdoorRestricted); + } + + [Fact] + public async Task Break_OutdoorFlagFromBreakLabel_NotRestricted() + { + var harness = new LinkageHarness(instantDrawDisable: false, disableOnOutdoorCourse: true); + harness.Lessons.CurrentState = TimeState.Breaking; + harness.Lessons.CurrentSubject = new Subject { Name = "课间休息", IsOutDoor = true }; + await harness.RefreshAsync(); + + // 课间的 CurrentSubject 是课间标签而非科目,户外标记必须忽略 + Assert.False(harness.Snapshot.IsOutdoorCourse); + Assert.False(harness.OutdoorRestricted); + } + private static TimeLayoutItem ClassTime(DateTime now, TimeSpan startedAgo, TimeSpan endedAgo) => new() { TimeType = 0, @@ -180,11 +232,13 @@ private sealed class LinkageHarness public LinkageHarness( int preClassEnableSeconds = 0, int postClassDelaySeconds = 0, - bool instantDrawDisable = true) + bool instantDrawDisable = true, + bool disableOnOutdoorCourse = false) { var config = new MainConfigModel(); config.LinkageSettings.DataSource = LinkageDataSource.ClassIsland; config.LinkageSettings.InstantDrawDisable = instantDrawDisable; + config.LinkageSettings.DisableOnOutdoorCourse = disableOnOutdoorCourse; config.LinkageSettings.PreClassEnableTime = preClassEnableSeconds; config.LinkageSettings.PostClassDisableDelay = postClassDelaySeconds; @@ -215,6 +269,7 @@ public LinkageHarness( public int StateChangedCount { get; private set; } public CourseScheduleSnapshot Snapshot => Service.Snapshot; public bool Restricted => Service.IsConfirmedNonClassTime; + public bool OutdoorRestricted => Service.IsConfirmedOutdoorCourse; public Task RefreshAsync() => Service.RefreshAsync(); } diff --git a/SecRandom.Core/Models/Linkage/CourseModels.cs b/SecRandom.Core/Models/Linkage/CourseModels.cs index 374d0e661..202f7fe61 100644 --- a/SecRandom.Core/Models/Linkage/CourseModels.cs +++ b/SecRandom.Core/Models/Linkage/CourseModels.cs @@ -1,4 +1,4 @@ -namespace SecRandom.Core.Models.Linkage; +namespace SecRandom.Core.Models.Linkage; public enum CourseTimeState { @@ -26,6 +26,7 @@ public sealed record CourseScheduleSnapshot( TimeSpan? TimeSincePreviousCourseEnd, string Source, string Version, + bool IsOutdoorCourse = false, string? Error = null) { public static CourseScheduleSnapshot Unavailable(string source, string? error = null) => new( @@ -39,5 +40,6 @@ public sealed record CourseScheduleSnapshot( null, source, string.Empty, + false, error); } diff --git a/SecRandom.Core/Models/SubConfigs/LinkageSettingsConfig.cs b/SecRandom.Core/Models/SubConfigs/LinkageSettingsConfig.cs index 1ef30bc49..8ef561ef5 100644 --- a/SecRandom.Core/Models/SubConfigs/LinkageSettingsConfig.cs +++ b/SecRandom.Core/Models/SubConfigs/LinkageSettingsConfig.cs @@ -7,6 +7,7 @@ public partial class LinkageSettingsConfig : ObservableObject { [ObservableProperty] private bool _verificationRequired = true; [ObservableProperty] private bool _instantDrawDisable = false; + [ObservableProperty] private bool _disableOnOutdoorCourse = false; [ObservableProperty] private LinkageDataSource _dataSource = LinkageDataSource.Off; [ObservableProperty] private bool _hideFloatingWindowOnClassEnd = false; [ObservableProperty] private bool _preClassResetEnabled = false; diff --git a/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs b/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs index 44afca204..ba93f5cac 100644 --- a/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs +++ b/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // @@ -365,6 +365,24 @@ public static string S_External_InstantDrawDisable_D { } } + /// + /// Looks up a localized string similar to 上课时段禁用户外课程. + /// + public static string S_External_OutdoorCourse { + get { + return ResourceManager.GetString("S_External_OutdoorCourse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 读取 ClassIsland 课表科目的户外课程标记,当前课程被标记为户外课程时,即使处于上课时段也限制抽取和重置;验证例外与"限制非上课时段操作"共用. + /// + public static string S_External_OutdoorCourse_D { + get { + return ResourceManager.GetString("S_External_OutdoorCourse_D", resourceCulture); + } + } + /// /// Looks up a localized string similar to 允许验证后继续. /// diff --git a/SecRandom/Langs/SettingsPages/Linkage/Resources.en-US.resx b/SecRandom/Langs/SettingsPages/Linkage/Resources.en-US.resx index b959fe0dd..61097f964 100644 --- a/SecRandom/Langs/SettingsPages/Linkage/Resources.en-US.resx +++ b/SecRandom/Langs/SettingsPages/Linkage/Resources.en-US.resx @@ -18,6 +18,12 @@ Restrict drawing and reset when course data confirms a break or non-class period; disable for no restriction + + Disable draws during outdoor courses + + + Reads each subject's outdoor-course flag from the ClassIsland timetable: while the current course is marked outdoor, drawing and resetting stay limited even during class; shares the verification exception with the non-class-time restriction + Data source diff --git a/SecRandom/Langs/SettingsPages/Linkage/Resources.ja-JP.resx b/SecRandom/Langs/SettingsPages/Linkage/Resources.ja-JP.resx index d7c086966..b154b839a 100644 --- a/SecRandom/Langs/SettingsPages/Linkage/Resources.ja-JP.resx +++ b/SecRandom/Langs/SettingsPages/Linkage/Resources.ja-JP.resx @@ -18,6 +18,12 @@ 休み時間や授業外と確認された場合に抽選とリセットを制限します + + 授業時間中は屋外科目で抽選を無効化 + + + ClassIsland 時間割の科目についている屋外フラグを読み取り、現在の授業が屋外とマークされている場合は授業時間中でも抽選とリセットを制限します。検証の例外は「授業時間外の操作制限」と共通です + データソース diff --git a/SecRandom/Langs/SettingsPages/Linkage/Resources.resx b/SecRandom/Langs/SettingsPages/Linkage/Resources.resx index 2acaa5e58..61df2e3fc 100644 --- a/SecRandom/Langs/SettingsPages/Linkage/Resources.resx +++ b/SecRandom/Langs/SettingsPages/Linkage/Resources.resx @@ -33,6 +33,12 @@ 课程数据源明确显示处于课间或非上课时段时,限制抽取和重置;关闭后不作限制 + + 上课时段禁用户外课程 + + + 读取 ClassIsland 课表科目的户外课程标记,当前课程被标记为户外课程时,即使处于上课时段也限制抽取和重置;验证例外与"限制非上课时段操作"共用 + 数据源 diff --git a/SecRandom/Services/Linkage/ClassIslandScheduleSource.cs b/SecRandom/Services/Linkage/ClassIslandScheduleSource.cs index d00bd8589..3b080dd9c 100644 --- a/SecRandom/Services/Linkage/ClassIslandScheduleSource.cs +++ b/SecRandom/Services/Linkage/ClassIslandScheduleSource.cs @@ -53,6 +53,10 @@ public async Task GetSnapshotAsync(CancellationToken can var currentName = state == CourseTimeState.OnClass ? NormalizeSubjectName(lessons.CurrentSubject?.Name) : string.Empty; + // 户外课程标记只在真实科目上有效;课间(CurrentSubject 是课间标签)与后备科目都不算 + var isOutdoorCourse = state == CourseTimeState.OnClass + && !string.IsNullOrEmpty(currentName) + && lessons.CurrentSubject?.IsOutDoor == true; var nextName = NormalizeSubjectName(lessons.NextClassSubject?.Name); var now = DateTime.Now; if (!string.IsNullOrEmpty(currentName)) @@ -101,7 +105,8 @@ public async Task GetSnapshotAsync(CancellationToken can nextCourseIn, sincePreviousEnd, SourceName, - $"{lessons.CurrentSelectedIndex}:{lessons.CurrentState}"); + $"{lessons.CurrentSelectedIndex}:{lessons.CurrentState}", + isOutdoorCourse); } catch (Exception exception) { diff --git a/SecRandom/Services/Linkage/CourseLinkageService.cs b/SecRandom/Services/Linkage/CourseLinkageService.cs index 4028630ce..5f880b8af 100644 --- a/SecRandom/Services/Linkage/CourseLinkageService.cs +++ b/SecRandom/Services/Linkage/CourseLinkageService.cs @@ -95,6 +95,7 @@ private static bool SnapshotsEqual(CourseScheduleSnapshot a, CourseScheduleSnaps && a.State == b.State && a.Source == b.Source && a.Version == b.Version + && a.IsOutdoorCourse == b.IsOutdoorCourse && a.CurrentCourse?.Name == b.CurrentCourse?.Name && a.PreviousCourse?.Name == b.PreviousCourse?.Name && a.NextCourse?.Name == b.NextCourse?.Name @@ -108,6 +109,16 @@ private static bool SnapshotsEqual(CourseScheduleSnapshot a, CourseScheduleSnaps public bool IsConfirmedNonClassTime => Settings.InstantDrawDisable && IsConfirmedBreakTime; + /// + /// 上课时段禁用户外课程:只有 ClassIsland 数据源携带科目的户外课程标记。开启后当前 + /// 课程被标记为户外课程时,即使处于上课时段也限制抽取和重置,验证例外与 + /// 共用。 + /// + public bool IsConfirmedOutdoorCourse => Settings.DisableOnOutdoorCourse + && _snapshot.IsAvailable + && _snapshot.State == CourseTimeState.OnClass + && _snapshot.IsOutdoorCourse; + public string GetSubjectFilter() { if (!Settings.SubjectHistoryFilterEnabled || !_snapshot.IsAvailable) diff --git a/SecRandom/Services/Linkage/LinkageDrawCoordinator.cs b/SecRandom/Services/Linkage/LinkageDrawCoordinator.cs index 83413fa67..223a1ca4b 100644 --- a/SecRandom/Services/Linkage/LinkageDrawCoordinator.cs +++ b/SecRandom/Services/Linkage/LinkageDrawCoordinator.cs @@ -49,7 +49,7 @@ public async Task AuthorizeAsync( if (controlDrawGate.IsDrawLocked) return false; - if (!linkageService.IsConfirmedNonClassTime) + if (!IsLinkageRestricted) return await securityService.AuthorizeAsync(operations, action, cancellationToken).ConfigureAwait(false); if (!linkageService.Settings.VerificationRequired) @@ -79,7 +79,7 @@ public LinkageDrawGate EvaluateGate(IReadOnlyCollection opera if (controlDrawGate.IsDrawLocked) return LinkageDrawGate.BlockedByRemoteLock; - if (!linkageService.IsConfirmedNonClassTime) + if (!IsLinkageRestricted) return operations.Any(securityService.RequiresVerification) ? LinkageDrawGate.RequiresLocalVerification : LinkageDrawGate.Allowed; @@ -87,9 +87,18 @@ public LinkageDrawGate EvaluateGate(IReadOnlyCollection opera if (!linkageService.Settings.VerificationRequired) return LinkageDrawGate.BlockedByClassTime; - // 确认非上课时间后的抽取要额外过 BypassClassTimeRestriction,而它永远需要当场验证。 + // 联动限制后的抽取要额外过 BypassClassTimeRestriction,而它永远需要当场验证。 + // 户外课程限制沿用 BlockedByClassTime:它本就发生在上课时段,远程控制台的 + // "上课时间"文案仍然准确。 return LinkageDrawGate.RequiresLocalVerification; } + /// + /// 联动闸门是否在当前时刻限制抽取:非上课时段限制与上课时段户外课程限制共用同一套 + /// 验证例外()。 + /// + private bool IsLinkageRestricted => linkageService.IsConfirmedNonClassTime + || linkageService.IsConfirmedOutdoorCourse; + public string GetCourseName() => linkageService.GetSubjectFilter(); } diff --git a/SecRandom/Views/SettingsPages/Linkage/LinkageSettingsPage.axaml b/SecRandom/Views/SettingsPages/Linkage/LinkageSettingsPage.axaml index fa905da44..0f1b557da 100644 --- a/SecRandom/Views/SettingsPages/Linkage/LinkageSettingsPage.axaml +++ b/SecRandom/Views/SettingsPages/Linkage/LinkageSettingsPage.axaml @@ -37,6 +37,16 @@ + + + + + + CsesSummaryProperty = AvaloniaProperty.Register(nameof(CsesSummary)); + public static readonly StyledProperty IsOutdoorCourseRowVisibleProperty = + AvaloniaProperty.Register(nameof(IsOutdoorCourseRowVisible)); public LinkageSettingsPage() { @@ -34,6 +37,7 @@ public LinkageSettingsPage() DataContext = this; InitializeComponent(); RefreshCsesSummary(); + IsOutdoorCourseRowVisible = Settings.DataSource == LinkageDataSource.ClassIsland; } public ViewModelBase ViewModel { get; } = IAppHost.GetService(); @@ -44,6 +48,13 @@ public string CsesSummary private set => SetValue(CsesSummaryProperty, value); } + /// 户外课程标记只有 ClassIsland 数据源提供,CSES 数据源下隐藏该行。 + public bool IsOutdoorCourseRowVisible + { + get => GetValue(IsOutdoorCourseRowVisibleProperty); + private set => SetValue(IsOutdoorCourseRowVisibleProperty, value); + } + private MainConfigHandler ConfigHandler { get; } = IAppHost.GetService(); private ICsesScheduleStore CsesStore { get; } = IAppHost.GetService(); @@ -68,6 +79,7 @@ private void OnUnloaded(object? sender, RoutedEventArgs e) private void SettingsOnPropertyChanged(object? sender, PropertyChangedEventArgs e) { + IsOutdoorCourseRowVisible = Settings.DataSource == LinkageDataSource.ClassIsland; ConfigHandler.Save(); _ = IAppHost.GetService().RefreshAsync(); } From fddf87810757065beeec8d315b005e4a5554a883 Mon Sep 17 00:00:00 2001 From: CreeperAWA Date: Tue, 3 Nov 2026 23:33:07 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat(linkage):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=88=B7=E5=A4=96=E8=AF=BE=E7=A8=8B=E9=9A=90=E8=97=8F=E6=82=AC?= =?UTF-8?q?=E6=B5=AE=E7=AA=97=EF=BC=8C=E5=8F=82=E7=85=A7=E4=B8=8B=E8=AF=BE?= =?UTF-8?q?=E9=9A=90=E8=97=8F=E6=82=AC=E6=B5=AE=E7=AA=97=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 HideFloatingWindowOnOutdoorCourse 设置,上课时段当前课程被 ClassIsland 标记为户外课程时自动隐藏悬浮窗,复用下课隐藏的隐藏与恢复机制。从 IsConfirmedOutdoorCourse 中抽出与开关无关的 IsOutdoorCourseOnClass 纯状态判断,使悬浮窗隐藏与抽取限制(DisableOnOutdoorCourse)互相独立;设置页新增开关行,仅 ClassIsland 数据源可见,并补充三语言资源、Designer 属性与控制台标签注册(含上一提交遗漏的 disable_on_outdoor_course)。 --- .../SubConfigs/LinkageSettingsConfig.cs | 1 + .../ControlNode/ControlSettingsLabels.cs | 2 ++ .../Linkage/Resources.Designer.cs | 20 ++++++++++++++++++- .../Linkage/Resources.en-US.resx | 6 ++++++ .../Linkage/Resources.ja-JP.resx | 6 ++++++ .../SettingsPages/Linkage/Resources.resx | 6 ++++++ .../Services/Linkage/CourseLinkageService.cs | 8 +++++++- SecRandom/Views/FloatingWindow.axaml.cs | 7 +++++-- .../Linkage/LinkageSettingsPage.axaml | 10 ++++++++++ 9 files changed, 62 insertions(+), 4 deletions(-) diff --git a/SecRandom.Core/Models/SubConfigs/LinkageSettingsConfig.cs b/SecRandom.Core/Models/SubConfigs/LinkageSettingsConfig.cs index 8ef561ef5..882d8029d 100644 --- a/SecRandom.Core/Models/SubConfigs/LinkageSettingsConfig.cs +++ b/SecRandom.Core/Models/SubConfigs/LinkageSettingsConfig.cs @@ -10,6 +10,7 @@ public partial class LinkageSettingsConfig : ObservableObject [ObservableProperty] private bool _disableOnOutdoorCourse = false; [ObservableProperty] private LinkageDataSource _dataSource = LinkageDataSource.Off; [ObservableProperty] private bool _hideFloatingWindowOnClassEnd = false; + [ObservableProperty] private bool _hideFloatingWindowOnOutdoorCourse = false; [ObservableProperty] private bool _preClassResetEnabled = false; [ObservableProperty] private int _preClassResetTime = 120; [ObservableProperty] private int _preClassEnableTime = 0; diff --git a/SecRandom.Core/Services/ControlNode/ControlSettingsLabels.cs b/SecRandom.Core/Services/ControlNode/ControlSettingsLabels.cs index 854322d5a..ccfe769eb 100644 --- a/SecRandom.Core/Services/ControlNode/ControlSettingsLabels.cs +++ b/SecRandom.Core/Services/ControlNode/ControlSettingsLabels.cs @@ -442,6 +442,8 @@ private static readonly (string Key, CultureInfo[] Fallback)[] PublishedLanguage ["instant_draw_disable"] = R(Linkage, "S_External_InstantDrawDisable"), ["verification_required"] = R(Linkage, "S_External_VerificationRequired"), ["hide_floating_window_on_class_end"] = R(Linkage, "S_ClassTime_HideFloatingWindow"), + ["hide_floating_window_on_outdoor_course"] = R(Linkage, "S_ClassTime_HideFloatingWindowOnOutdoorCourse"), + ["disable_on_outdoor_course"] = R(Linkage, "S_External_OutdoorCourse"), ["pre_class_reset_enabled"] = R(Linkage, "S_ClassTime_PreClassReset"), ["pre_class_reset_time"] = R(Linkage, "S_ClassTime_PreClassResetTime"), ["post_class_disable_delay"] = R(Linkage, "S_ClassTime_PostClassDisableDelay"), diff --git a/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs b/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs index ba93f5cac..64ba1dc0f 100644 --- a/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs +++ b/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs @@ -238,7 +238,25 @@ public static string S_ClassTime_HideFloatingWindow_D { return ResourceManager.GetString("S_ClassTime_HideFloatingWindow_D", resourceCulture); } } - + + /// + /// Looks up a localized string similar to 户外课程隐藏悬浮窗. + /// + public static string S_ClassTime_HideFloatingWindowOnOutdoorCourse { + get { + return ResourceManager.GetString("S_ClassTime_HideFloatingWindowOnOutdoorCourse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 上课时段当前课程为户外课程时自动隐藏悬浮窗. + /// + public static string S_ClassTime_HideFloatingWindowOnOutdoorCourse_D { + get { + return ResourceManager.GetString("S_ClassTime_HideFloatingWindowOnOutdoorCourse_D", resourceCulture); + } + } + /// /// Looks up a localized string similar to 课后禁用延迟. /// diff --git a/SecRandom/Langs/SettingsPages/Linkage/Resources.en-US.resx b/SecRandom/Langs/SettingsPages/Linkage/Resources.en-US.resx index 61097f964..93deed341 100644 --- a/SecRandom/Langs/SettingsPages/Linkage/Resources.en-US.resx +++ b/SecRandom/Langs/SettingsPages/Linkage/Resources.en-US.resx @@ -81,6 +81,12 @@ Automatically hide the floating window when class ends + + Hide floating window on outdoor courses + + + Automatically hide the floating window when the current course is marked as an outdoor course + Reset before class diff --git a/SecRandom/Langs/SettingsPages/Linkage/Resources.ja-JP.resx b/SecRandom/Langs/SettingsPages/Linkage/Resources.ja-JP.resx index b154b839a..7397f6165 100644 --- a/SecRandom/Langs/SettingsPages/Linkage/Resources.ja-JP.resx +++ b/SecRandom/Langs/SettingsPages/Linkage/Resources.ja-JP.resx @@ -81,6 +81,12 @@ 授業終了時に自動で非表示にします + + 屋外授業中は非表示 + + + 現在の授業が屋外授業の場合、フローティングウィンドウを自動で非表示にします + 授業前にリセット diff --git a/SecRandom/Langs/SettingsPages/Linkage/Resources.resx b/SecRandom/Langs/SettingsPages/Linkage/Resources.resx index 61df2e3fc..7e3b62e55 100644 --- a/SecRandom/Langs/SettingsPages/Linkage/Resources.resx +++ b/SecRandom/Langs/SettingsPages/Linkage/Resources.resx @@ -96,6 +96,12 @@ 课程结束时自动隐藏悬浮窗 + + 户外课程隐藏悬浮窗 + + + 上课时段当前课程为户外课程时自动隐藏悬浮窗 + 课前重置 diff --git a/SecRandom/Services/Linkage/CourseLinkageService.cs b/SecRandom/Services/Linkage/CourseLinkageService.cs index 5f880b8af..2791c714d 100644 --- a/SecRandom/Services/Linkage/CourseLinkageService.cs +++ b/SecRandom/Services/Linkage/CourseLinkageService.cs @@ -115,7 +115,13 @@ private static bool SnapshotsEqual(CourseScheduleSnapshot a, CourseScheduleSnaps /// 共用。 /// public bool IsConfirmedOutdoorCourse => Settings.DisableOnOutdoorCourse - && _snapshot.IsAvailable + && IsOutdoorCourseOnClass; + + /// + /// 当前处于上课时段且课程被标记为户外课程的纯状态判断,不依赖任何开关; + /// 抽取限制看 ,悬浮窗隐藏由调用方结合自己的开关判断。 + /// + public bool IsOutdoorCourseOnClass => _snapshot.IsAvailable && _snapshot.State == CourseTimeState.OnClass && _snapshot.IsOutdoorCourse; diff --git a/SecRandom/Views/FloatingWindow.axaml.cs b/SecRandom/Views/FloatingWindow.axaml.cs index 566e71377..9ab80d509 100644 --- a/SecRandom/Views/FloatingWindow.axaml.cs +++ b/SecRandom/Views/FloatingWindow.axaml.cs @@ -229,8 +229,11 @@ public void SetUserVisibilityIntent(bool visible) private void ApplyCourseLinkageVisibility() { - var shouldHide = ViewModel.Config.LinkageSettings.HideFloatingWindowOnClassEnd - && _linkageService.IsConfirmedBreakTime; + var linkageSettings = ViewModel.Config.LinkageSettings; + var shouldHide = (linkageSettings.HideFloatingWindowOnClassEnd + && _linkageService.IsConfirmedBreakTime) + || (linkageSettings.HideFloatingWindowOnOutdoorCourse + && _linkageService.IsOutdoorCourseOnClass); if (shouldHide == _hiddenByCourseLinkage) return; diff --git a/SecRandom/Views/SettingsPages/Linkage/LinkageSettingsPage.axaml b/SecRandom/Views/SettingsPages/Linkage/LinkageSettingsPage.axaml index 0f1b557da..1da07c675 100644 --- a/SecRandom/Views/SettingsPages/Linkage/LinkageSettingsPage.axaml +++ b/SecRandom/Views/SettingsPages/Linkage/LinkageSettingsPage.axaml @@ -88,6 +88,16 @@ + + + + + + Date: Sun, 8 Nov 2026 00:15:07 +0800 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20=E4=BC=98=E5=8C=96=E6=88=B7?= =?UTF-8?q?=E5=A4=96=E8=AF=BE=E7=A8=8B=E6=97=B6=E6=AE=B5=E9=99=90=E5=88=B6?= =?UTF-8?q?=E7=9A=84=E6=8F=8F=E8=BF=B0=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs | 4 ++-- SecRandom/Langs/SettingsPages/Linkage/Resources.resx | 4 ++-- SecRandom/Services/Linkage/CourseLinkageService.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs b/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs index 64ba1dc0f..dd460e1b1 100644 --- a/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs +++ b/SecRandom/Langs/SettingsPages/Linkage/Resources.Designer.cs @@ -384,7 +384,7 @@ public static string S_External_InstantDrawDisable_D { } /// - /// Looks up a localized string similar to 上课时段禁用户外课程. + /// Looks up a localized string similar to 户外课程上课时段禁用. /// public static string S_External_OutdoorCourse { get { @@ -393,7 +393,7 @@ public static string S_External_OutdoorCourse { } /// - /// Looks up a localized string similar to 读取 ClassIsland 课表科目的户外课程标记,当前课程被标记为户外课程时,即使处于上课时段也限制抽取和重置;验证例外与"限制非上课时段操作"共用. + /// Looks up a localized string similar to 读取 ClassIsland 课表科目的户外课程标记,当前课程被标记为户外课程时,即使处于上课时段也限制抽取和重置. /// public static string S_External_OutdoorCourse_D { get { diff --git a/SecRandom/Langs/SettingsPages/Linkage/Resources.resx b/SecRandom/Langs/SettingsPages/Linkage/Resources.resx index 7e3b62e55..7d62d7de3 100644 --- a/SecRandom/Langs/SettingsPages/Linkage/Resources.resx +++ b/SecRandom/Langs/SettingsPages/Linkage/Resources.resx @@ -34,10 +34,10 @@ 课程数据源明确显示处于课间或非上课时段时,限制抽取和重置;关闭后不作限制 - 上课时段禁用户外课程 + 户外课程上课时段禁用 - 读取 ClassIsland 课表科目的户外课程标记,当前课程被标记为户外课程时,即使处于上课时段也限制抽取和重置;验证例外与"限制非上课时段操作"共用 + 读取 ClassIsland 课表科目的户外课程标记,当前课程被标记为户外课程时,即使处于上课时段也限制抽取和重置 数据源 diff --git a/SecRandom/Services/Linkage/CourseLinkageService.cs b/SecRandom/Services/Linkage/CourseLinkageService.cs index 2791c714d..570525a9e 100644 --- a/SecRandom/Services/Linkage/CourseLinkageService.cs +++ b/SecRandom/Services/Linkage/CourseLinkageService.cs @@ -110,7 +110,7 @@ private static bool SnapshotsEqual(CourseScheduleSnapshot a, CourseScheduleSnaps && IsConfirmedBreakTime; /// - /// 上课时段禁用户外课程:只有 ClassIsland 数据源携带科目的户外课程标记。开启后当前 + /// 户外课程上课时段禁用:只有 ClassIsland 数据源携带科目的户外课程标记。开启后当前 /// 课程被标记为户外课程时,即使处于上课时段也限制抽取和重置,验证例外与 /// 共用。 ///