Skip to content

Commit b62bf7f

Browse files
Merge pull request #50
Hidden “More Features” page, adaptive theme sync, time-period rule, and related fixes
2 parents cd6c522 + d6e7c71 commit b62bf7f

25 files changed

Lines changed: 483 additions & 47 deletions

Actions/AdvancedShutdownAction.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ public class AdvancedShutdownAction(ILogger<AdvancedShutdownAction> logger) : Ac
3535
private static bool _allowMainDialogClose;
3636
private static bool _allowFloatingWindowClose;
3737

38+
public static void CancelPlanOnAppStopping()
39+
{
40+
StopCountdownProcess();
41+
TryAbortSystemShutdown();
42+
}
43+
3844
protected override async Task OnInvoke()
3945
{
4046
_logger.LogDebug("AdvancedShutdownAction OnInvoke 开始");
@@ -180,6 +186,26 @@ private static void StopCountdownProcess()
180186
}
181187
}
182188

189+
private static void TryAbortSystemShutdown()
190+
{
191+
try
192+
{
193+
var psi = new ProcessStartInfo
194+
{
195+
FileName = "shutdown",
196+
Arguments = "/a",
197+
UseShellExecute = false,
198+
CreateNoWindow = true,
199+
WindowStyle = ProcessWindowStyle.Hidden
200+
};
201+
using var process = Process.Start(psi);
202+
process?.WaitForExit(1000);
203+
}
204+
catch
205+
{
206+
}
207+
}
208+
183209
private static int GetRemainingSeconds()
184210
{
185211
lock (StateLock)
@@ -255,6 +281,7 @@ private void StopWatchdog()
255281
private void StopAllStates()
256282
{
257283
StopCountdownProcess();
284+
TryAbortSystemShutdown();
258285

259286
lock (StateLock)
260287
{

Actions/LoadTemporaryClassPlanAction.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using ClassIsland.Core.Attributes;
44
using Microsoft.Extensions.Logging;
55
using System;
6+
using System.Collections.Concurrent;
67
using System.Threading.Tasks;
78
using SystemTools.Settings;
89

@@ -18,6 +19,8 @@ public class LoadTemporaryClassPlanAction(
1819
private readonly IProfileService _profileService = profileService;
1920
private readonly IExactTimeService _exactTimeService = exactTimeService;
2021

22+
private static readonly ConcurrentDictionary<Guid, TempClassPlanSnapshot> PreviousSnapshots = new();
23+
2124
protected override async Task OnInvoke()
2225
{
2326
if (!Guid.TryParse(Settings.ClassPlanId, out var classPlanId))
@@ -32,11 +35,38 @@ protected override async Task OnInvoke()
3235
return;
3336
}
3437

38+
if (IsRevertable)
39+
{
40+
PreviousSnapshots[ActionSet.Guid] = new TempClassPlanSnapshot(
41+
_profileService.Profile.TempClassPlanId,
42+
_profileService.Profile.TempClassPlanSetupTime);
43+
}
44+
3545
_profileService.Profile.TempClassPlanId = classPlanId;
3646
_profileService.Profile.TempClassPlanSetupTime = _exactTimeService.GetCurrentLocalDateTime();
3747
_profileService.SaveProfile();
3848
_logger.LogInformation("已加载临时课表:{ClassPlanName} ({ClassPlanId})", classPlan.Name, classPlanId);
3949

4050
await base.OnInvoke();
4151
}
52+
53+
protected override async Task OnRevert()
54+
{
55+
await base.OnRevert();
56+
57+
if (PreviousSnapshots.TryRemove(ActionSet.Guid, out var snapshot))
58+
{
59+
_profileService.Profile.TempClassPlanId = snapshot.TempClassPlanId;
60+
_profileService.Profile.TempClassPlanSetupTime = snapshot.TempClassPlanSetupTime;
61+
_profileService.SaveProfile();
62+
_logger.LogInformation("已恢复临时课表为触发前状态。ActionSet={ActionSetGuid}", ActionSet.Guid);
63+
return;
64+
}
65+
66+
_profileService.Profile.TempClassPlanId = null;
67+
_profileService.SaveProfile();
68+
_logger.LogInformation("未找到触发前状态,已清除临时课表。ActionSet={ActionSetGuid}", ActionSet.Guid);
69+
}
70+
71+
private readonly record struct TempClassPlanSnapshot(Guid? TempClassPlanId, DateTime TempClassPlanSetupTime);
4272
}

ConfigHandlers/MainConfigData.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,20 @@ public bool EnableFaceRecognition
8686
RestartPropertyChanged?.Invoke(this, EventArgs.Empty);
8787
}
8888
}
89+
90+
bool _autoMatchMainBackgroundTheme;
91+
92+
[JsonPropertyName("autoMatchMainBackgroundTheme")]
93+
public bool AutoMatchMainBackgroundTheme
94+
{
95+
get => _autoMatchMainBackgroundTheme;
96+
set
97+
{
98+
if (value == _autoMatchMainBackgroundTheme) return;
99+
_autoMatchMainBackgroundTheme = value;
100+
OnPropertyChanged();
101+
}
102+
}
89103

90104
// ========== 公告相关 ==========
91105
/*string _lastAcceptedAnnouncement = string.Empty;

Controls/AdvancedShutdownSettingsControl.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@ public AdvancedShutdownSettingsControl()
1212
{
1313
var panel = new StackPanel { Spacing = 10, Margin = new(10) };
1414

15-
panel.Children.Add(new TextBlock
16-
{
17-
Text = "高级计时关机设置",
18-
FontWeight = Avalonia.Media.FontWeight.Bold,
19-
FontSize = 14
20-
});
21-
2215
var minutesPanel = new StackPanel
2316
{
2417
Orientation = Avalonia.Layout.Orientation.Horizontal,
@@ -45,7 +38,7 @@ public AdvancedShutdownSettingsControl()
4538

4639
panel.Children.Add(new TextBlock
4740
{
48-
Text = "触发后会弹出独立对话框,可已阅、取消计划或延长时间。",
41+
Text = "拥有独立对话框,可已阅、取消计划、延长时间或立即关机。",
4942
TextWrapping = Avalonia.Media.TextWrapping.Wrap,
5043
Foreground = Avalonia.Media.Brushes.Gray
5144
});

Controls/Components/BetterCarouselContainerComponent.axaml

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,30 @@
4040
</Setter>
4141
</Style>
4242

43-
<Style Selector="local|BetterCarouselContainerComponent ProgressBar#DisplayProgressBar">
44-
<Setter Property="IsVisible" Value="False" />
45-
<Setter Property="MinWidth" Value="0" />
46-
</Style>
47-
48-
<Style Selector="local|BetterCarouselContainerComponent:progress-visible ProgressBar#DisplayProgressBar">
49-
<Setter Property="IsVisible" Value="True" />
50-
</Style>
5143
</ci:ComponentBase.Styles>
5244

5345
<Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=local:BetterCarouselContainerComponent}}"
5446
x:Name="GridRoot">
55-
47+
48+
<ProgressBar x:Name="DisplayProgressBarTop"
49+
VerticalAlignment="Top"
50+
HorizontalAlignment="Stretch"
51+
Margin="0"
52+
Height="4"
53+
MinWidth="0"
54+
Minimum="0"
55+
Maximum="100"
56+
IsVisible="{Binding ShowTopProgressBar, Mode=OneWay}"
57+
Value="{Binding CurrentProgressPercent, Mode=OneWay}" />
58+
5659
<StackPanel Orientation="Horizontal"
5760
Spacing="0"
5861
VerticalAlignment="Center"
5962
HorizontalAlignment="Stretch">
60-
63+
<TextBlock Text=">"
64+
IsVisible="{Binding Settings.ShowSideSeparators}"
65+
VerticalAlignment="Center"
66+
Margin="0,0,4,0" />
6167
<ListBox x:Name="CarouselListBox"
6268
Background="Transparent"
6369
BorderThickness="0"
@@ -102,21 +108,26 @@
102108
HidingRules="{Binding HidingRules, Mode=OneWay}"
103109
HideOnRule="{Binding HideOnRule, Mode=OneWay}"
104110
VerticalAlignment="Center"
105-
Margin="0" />
111+
Margin="0" />
106112
</Grid>
107113
</DataTemplate>
108114
</ListBox.ItemTemplate>
109115
</ListBox>
116+
<TextBlock Text="&lt;"
117+
IsVisible="{Binding Settings.ShowSideSeparators}"
118+
VerticalAlignment="Center"
119+
Margin="4,0,0,0" />
110120
</StackPanel>
111121

112-
<ProgressBar x:Name="DisplayProgressBar"
122+
<ProgressBar x:Name="DisplayProgressBarBottom"
113123
VerticalAlignment="Bottom"
114124
HorizontalAlignment="Stretch"
115-
Margin="0,6,0,0"
125+
Margin="0"
116126
Height="4"
117127
MinWidth="0"
118128
Minimum="0"
119129
Maximum="100"
130+
IsVisible="{Binding ShowBottomProgressBar, Mode=OneWay}"
120131
Value="{Binding CurrentProgressPercent, Mode=OneWay}" />
121132
</Grid>
122-
</ci:ComponentBase>
133+
</ci:ComponentBase>

Controls/Components/BetterCarouselContainerComponent.axaml.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ public int SelectedIndex
7676
public double CurrentProgressPercent { get; private set; }
7777

7878
public int AnimationStyleValue => (int)Settings.AnimationStyle;
79+
public bool ShowTopProgressBar => Settings.ShowProgressBar && Settings.ProgressBarPosition == BetterCarouselProgressBarPosition.Top;
80+
public bool ShowBottomProgressBar => Settings.ShowProgressBar && Settings.ProgressBarPosition == BetterCarouselProgressBarPosition.Bottom;
7981

8082
public new event PropertyChangedEventHandler? PropertyChanged;
8183

@@ -323,22 +325,23 @@ private void OnSettingsPropertyChanged(object? sender, PropertyChangedEventArgs
323325
OnPropertyChanged(nameof(AnimationStyleValue));
324326
}
325327

326-
if (e.PropertyName is nameof(Settings.ShowProgressBar))
328+
if (e.PropertyName is nameof(Settings.ShowProgressBar) or nameof(Settings.ProgressBarPosition))
327329
{
328-
PseudoClasses.Set(":progress-visible", Settings.ShowProgressBar);
330+
OnPropertyChanged(nameof(ShowTopProgressBar));
331+
OnPropertyChanged(nameof(ShowBottomProgressBar));
329332
}
330333

331334
if (e.PropertyName is nameof(Settings.RotationMode) or nameof(Settings.IsAnimationEnabled) or nameof(Settings.ShowProgressBar))
332335
{
333336
UpdateProgressState(resetWhenIdle: true);
334-
return;
335337
}
336338

337339
if (e.PropertyName == nameof(Settings.ComponentDisplayDurations))
338340
{
339341
Settings.NormalizeDisplayDurations();
340342
RestartProgress();
341343
}
344+
342345
}
343346

344347
private void OnChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
@@ -416,8 +419,6 @@ private void EnsureSelectedIndexValid()
416419

417420
private void UpdateProgressState(bool resetWhenIdle = false)
418421
{
419-
PseudoClasses.Set(":progress-visible", Settings.ShowProgressBar);
420-
421422
var displayable = GetDisplayableIndexes();
422423
if (displayable.Length == 0)
423424
{
@@ -551,4 +552,4 @@ protected virtual void OnPropertyChanged(string propertyName)
551552
{
552553
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
553554
}
554-
}
555+
}

Controls/Components/BetterCarouselContainerSettingsControl.axaml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,27 @@
6666
Description="显示当前组件剩余显示时长的进度条"
6767
IconSource="{ci:FluentIconSource &#xE093;}">
6868
<controls:SettingsExpander.Footer>
69-
<ToggleSwitch IsChecked="{Binding Settings.ShowProgressBar, Mode=TwoWay}" />
69+
<StackPanel Orientation="Horizontal" Spacing="8">
70+
<ToggleSwitch IsChecked="{Binding Settings.ShowProgressBar, Mode=TwoWay}" />
71+
<ComboBox Width="140"
72+
IsVisible="{Binding Settings.ShowProgressBar}"
73+
SelectedItem="{Binding Settings.ProgressBarPosition, Mode=TwoWay}"
74+
ItemsSource="{Binding ProgressBarPositions}">
75+
<ComboBox.ItemTemplate>
76+
<DataTemplate>
77+
<TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}" />
78+
</DataTemplate>
79+
</ComboBox.ItemTemplate>
80+
</ComboBox>
81+
</StackPanel>
82+
</controls:SettingsExpander.Footer>
83+
</controls:SettingsExpander>
84+
85+
<controls:SettingsExpander Header="添加分隔符样式"
86+
Description="在容器左右两侧固定显示“&lt;”和“&gt;"
87+
IconSource="{ci:FluentIconSource &#xEEDF;}">
88+
<controls:SettingsExpander.Footer>
89+
<ToggleSwitch IsChecked="{Binding Settings.ShowSideSeparators, Mode=TwoWay}" />
7090
</controls:SettingsExpander.Footer>
7191
</controls:SettingsExpander>
7292

@@ -113,4 +133,4 @@
113133
</StackPanel>
114134
</ScrollViewer>
115135
</Grid>
116-
</ci:ComponentBase>
136+
</ci:ComponentBase>

Controls/Components/BetterCarouselContainerSettingsControl.axaml.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public partial class BetterCarouselContainerSettingsControl : ComponentBase<Bett
5757

5858
public Array RotationModes { get; } = Enum.GetValues(typeof(BetterCarouselRotationMode));
5959
public Array AnimationStyles { get; } = Enum.GetValues(typeof(BetterCarouselAnimationStyle));
60+
public Array ProgressBarPositions { get; } = Enum.GetValues(typeof(BetterCarouselProgressBarPosition));
6061

6162
public bool HasDurationItems => DurationItems.Count > 0;
6263

@@ -141,4 +142,4 @@ protected virtual void OnPropertyChanged(string propertyName)
141142
{
142143
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
143144
}
144-
}
145+
}

Controls/Components/LocalQuoteComponent.axaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ private void OnCarouselTicked(object? sender, EventArgs e)
164164

165165
private void RefreshTimerInterval()
166166
{
167-
var interval = Math.Max(1, Settings.CarouselIntervalSeconds);
167+
var interval = Math.Clamp(Settings.CarouselIntervalSeconds, 1, 8000);
168168
_carouselTimer.Interval = TimeSpan.FromSeconds(interval);
169169
}
170170

Controls/Components/LocalQuoteSettingsControl.axaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
IconSource="{ci:FluentIconSource &#xEF75;}">
4747
<controls:SettingsExpander.Footer>
4848
<NumericUpDown Minimum="1"
49-
Maximum="600"
49+
Maximum="8000"
5050
Increment="1"
5151
Value="{Binding Settings.CarouselIntervalSeconds, Mode=TwoWay}" />
5252
</controls:SettingsExpander.Footer>

0 commit comments

Comments
 (0)