diff --git a/Actions/AdvancedShutdownAction.cs b/Actions/AdvancedShutdownAction.cs index ef5a366..bf7699f 100644 --- a/Actions/AdvancedShutdownAction.cs +++ b/Actions/AdvancedShutdownAction.cs @@ -455,6 +455,8 @@ private void ShowOrUpdateFloatingWindow() Topmost = true, ShowInTaskbar = false, SystemDecorations = SystemDecorations.None, + Background = Brushes.Transparent, + TransparencyLevelHint = [WindowTransparencyLevel.Transparent], Content = new Border { CornerRadius = new CornerRadius(10), diff --git a/ConfigHandlers/MainConfigData.cs b/ConfigHandlers/MainConfigData.cs index 8981084..c7f861c 100644 --- a/ConfigHandlers/MainConfigData.cs +++ b/ConfigHandlers/MainConfigData.cs @@ -100,6 +100,21 @@ public bool AutoMatchMainBackgroundTheme OnPropertyChanged(); } } + + + bool _autoHideMainWindowWhenOccluded; + + [JsonPropertyName("autoHideMainWindowWhenOccluded")] + public bool AutoHideMainWindowWhenOccluded + { + get => _autoHideMainWindowWhenOccluded; + set + { + if (value == _autoHideMainWindowWhenOccluded) return; + _autoHideMainWindowWhenOccluded = value; + OnPropertyChanged(); + } + } // ========== 公告相关 ========== /*string _lastAcceptedAnnouncement = string.Empty; diff --git a/Controls/InTimePeriodRuleSettingsControl.axaml b/Controls/InTimePeriodRuleSettingsControl.axaml new file mode 100644 index 0000000..dfe0e05 --- /dev/null +++ b/Controls/InTimePeriodRuleSettingsControl.axaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + diff --git a/Controls/InTimePeriodRuleSettingsControl.cs b/Controls/InTimePeriodRuleSettingsControl.cs index 99f563f..8f5723f 100644 --- a/Controls/InTimePeriodRuleSettingsControl.cs +++ b/Controls/InTimePeriodRuleSettingsControl.cs @@ -1,91 +1,51 @@ +using System; using Avalonia.Controls; -using Avalonia.Layout; +using Avalonia.Markup.Xaml; using ClassIsland.Core.Abstractions.Controls; -using System; using SystemTools.Rules; namespace SystemTools.Controls; - -public class InTimePeriodRuleSettingsControl : RuleSettingsControlBase +public partial class InTimePeriodRuleSettingsControl : RuleSettingsControlBase { - private readonly TimePicker _startTimePicker; - private readonly TimePicker _endTimePicker; - public InTimePeriodRuleSettingsControl() { - var panel = new StackPanel { Spacing = 10 }; - var row = new Grid - { - ColumnDefinitions = new ColumnDefinitions("Auto,*,Auto,*,Auto"), - ColumnSpacing = 8, - VerticalAlignment = VerticalAlignment.Center - }; - - row.Children.Add(new TextBlock { Text = "从", VerticalAlignment = VerticalAlignment.Center }); - - _startTimePicker = new TimePicker - { - ClockIdentifier = "24HourClock", - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center - }; - Grid.SetColumn(_startTimePicker, 1); - row.Children.Add(_startTimePicker); - - var sep = new TextBlock { Text = "至", VerticalAlignment = VerticalAlignment.Center }; - Grid.SetColumn(sep, 2); - row.Children.Add(sep); + InitializeComponent(); - _endTimePicker = new TimePicker - { - ClockIdentifier = "24HourClock", - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center - }; - Grid.SetColumn(_endTimePicker, 3); - row.Children.Add(_endTimePicker); - - var hint = new TextBlock - { - Text = "提示:若起始晚于结束 将按跨天处理", - TextWrapping = Avalonia.Media.TextWrapping.Wrap, - Foreground = Avalonia.Media.Brushes.Gray, - FontSize = 12 - }; - panel.Children.Add(row); - panel.Children.Add(hint); - Content = panel; + StartTimePicker.SelectedTimeChanged += (_, _) => SyncSettings(); + EndTimePicker.SelectedTimeChanged += (_, _) => SyncSettings(); + } - _startTimePicker.SelectedTimeChanged += (s, e) => SyncSettings(); - _endTimePicker.SelectedTimeChanged += (s, e) => SyncSettings(); + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); } protected override void OnInitialized() { base.OnInitialized(); - + if (TimeSpan.TryParse(Settings.StartTime, out var start)) { - _startTimePicker.SelectedTime = start; + StartTimePicker.SelectedTime = start; } - + if (TimeSpan.TryParse(Settings.EndTime, out var end)) { - _endTimePicker.SelectedTime = end; + EndTimePicker.SelectedTime = end; } } private void SyncSettings() { - if (_startTimePicker.SelectedTime.HasValue) + if (StartTimePicker.SelectedTime.HasValue) { - Settings.StartTime = _startTimePicker.SelectedTime.Value.ToString(@"hh\:mm\:ss"); + Settings.StartTime = StartTimePicker.SelectedTime.Value.ToString(@"hh\:mm\:ss"); } - if (_endTimePicker.SelectedTime.HasValue) + if (EndTimePicker.SelectedTime.HasValue) { - Settings.EndTime = _endTimePicker.SelectedTime.Value.ToString(@"hh\:mm\:ss"); + Settings.EndTime = EndTimePicker.SelectedTime.Value.ToString(@"hh\:mm\:ss"); } } } diff --git a/Services/AdaptiveThemeSyncService.cs b/Services/AdaptiveThemeSyncService.cs index b7baa6b..97378da 100644 --- a/Services/AdaptiveThemeSyncService.cs +++ b/Services/AdaptiveThemeSyncService.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Drawing; using System.Runtime.InteropServices; +using System.Windows.Forms; using ClassIsland.Shared; using SystemTools.Shared; @@ -48,7 +49,7 @@ private void OnTick(object? sender, EventArgs e) try { - var targetTheme = DetectThemeByMainWindowBackground(); + var targetTheme = DetectThemeByScreenBackground(); if (targetTheme == null || targetTheme == _lastAppliedTheme) { return; @@ -62,7 +63,7 @@ private void OnTick(object? sender, EventArgs e) themeService.SetTheme(targetTheme.Value, null); _lastAppliedTheme = targetTheme; - _logger.LogDebug("已自动匹配主题为:{Theme}", targetTheme == 2 ? "黑暗" : "明亮"); + _logger.LogDebug("已自动匹配主题为:{Theme}", targetTheme == 1 ? "黑暗" : "明亮"); } catch (Exception ex) { @@ -70,44 +71,58 @@ private void OnTick(object? sender, EventArgs e) } } - private static int? DetectThemeByMainWindowBackground() + private static int? DetectThemeByScreenBackground() { var handle = Process.GetCurrentProcess().MainWindowHandle; - if (handle == IntPtr.Zero) + if (handle == IntPtr.Zero || !GetWindowRect(handle, out var rect)) { return null; } - if (!GetWindowRect(handle, out var rect)) - { - return null; - } - - var width = Math.Max(1, rect.Right - rect.Left); - var height = Math.Max(1, rect.Bottom - rect.Top); + var mainWindow = Rectangle.FromLTRB(rect.Left, rect.Top, rect.Right, rect.Bottom); + var screen = Screen.FromRectangle(mainWindow); + var captureRect = BuildTargetArea(screen.Bounds, mainWindow); - using var bitmap = new Bitmap(width, height); + using var bitmap = new Bitmap(captureRect.Width, captureRect.Height); using var graphics = Graphics.FromImage(bitmap); - graphics.CopyFromScreen(rect.Left, rect.Top, 0, 0, new Size(width, height)); + graphics.CopyFromScreen(captureRect.Left, captureRect.Top, 0, 0, captureRect.Size); - var samples = new (int X, int Y)[] + double luminance = 0; + long samples = 0; + const int grid = 8; + var stepX = Math.Max(1, captureRect.Width / grid); + var stepY = Math.Max(1, captureRect.Height / grid); + + for (var y = 0; y < captureRect.Height; y += stepY) { - (width / 2, height / 2), - (Math.Max(0, width / 4), Math.Max(0, height / 4)), - (Math.Max(0, width * 3 / 4), Math.Max(0, height / 4)), - (Math.Max(0, width / 4), Math.Max(0, height * 3 / 4)), - (Math.Max(0, width * 3 / 4), Math.Max(0, height * 3 / 4)), - }; + for (var x = 0; x < captureRect.Width; x += stepX) + { + var color = bitmap.GetPixel(Math.Clamp(x, 0, captureRect.Width - 1), Math.Clamp(y, 0, captureRect.Height - 1)); + luminance += 0.299 * color.R + 0.587 * color.G + 0.114 * color.B; + samples++; + } + } - double luminance = 0; - foreach (var sample in samples) + if (samples == 0) { - var color = bitmap.GetPixel(Math.Clamp(sample.X, 0, width - 1), Math.Clamp(sample.Y, 0, height - 1)); - luminance += 0.299 * color.R + 0.587 * color.G + 0.114 * color.B; + return null; } - luminance /= samples.Length; - return luminance < 128 ? 2 : 1; // 2=黑暗,1=明亮 + luminance /= samples; + + // 与 ClassIsland 的主题模式保持一致:0=明亮,1=黑暗。 + return luminance < 128 ? 1 : 0; + } + + private static Rectangle BuildTargetArea(Rectangle screenBounds, Rectangle mainWindow) + { + var topHeight = Math.Max(1, screenBounds.Height / 5); + var bottomY = screenBounds.Bottom - topHeight; + + var isTop = mainWindow.Top + mainWindow.Height / 2 <= screenBounds.Top + screenBounds.Height / 2; + return isTop + ? new Rectangle(screenBounds.Left, screenBounds.Top, screenBounds.Width, topHeight) + : new Rectangle(screenBounds.Left, bottomY, screenBounds.Width, topHeight); } [DllImport("user32.dll")] diff --git a/SettingsPage/MoreFeaturesOptionsSettingsPage.axaml b/SettingsPage/MoreFeaturesOptionsSettingsPage.axaml index 8dc1b25..ae3c504 100644 --- a/SettingsPage/MoreFeaturesOptionsSettingsPage.axaml +++ b/SettingsPage/MoreFeaturesOptionsSettingsPage.axaml @@ -8,13 +8,14 @@ + Description="每 2 秒检测屏幕顶部/底部五分之一亮度:偏黑切换黑暗,偏白切换明亮。"> + diff --git a/SettingsPage/MoreFeaturesOptionsSettingsPage.axaml.cs b/SettingsPage/MoreFeaturesOptionsSettingsPage.axaml.cs index a15fc34..17e53f6 100644 --- a/SettingsPage/MoreFeaturesOptionsSettingsPage.axaml.cs +++ b/SettingsPage/MoreFeaturesOptionsSettingsPage.axaml.cs @@ -28,4 +28,5 @@ private void AutoMatchThemeToggle_OnChanged(object? sender, RoutedEventArgs e) GlobalConstants.MainConfig?.Save(); } + } diff --git a/SettingsPage/SystemToolsSettingsPage.axaml b/SettingsPage/SystemToolsSettingsPage.axaml index 1d6bb2c..ab896fd 100644 --- a/SettingsPage/SystemToolsSettingsPage.axaml +++ b/SettingsPage/SystemToolsSettingsPage.axaml @@ -167,17 +167,8 @@ - - - - - - - - + +