Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions Actions/ToggleFloatingWindowLayerAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.Extensions.Logging;
using SystemTools.Services;
using SystemTools.Settings;
using SystemTools.Shared;

namespace SystemTools.Actions;

Expand All @@ -26,15 +27,19 @@ protected override async Task OnInvoke()
try
{
var service = IAppHost.GetService<FloatingWindowService>();
var profile = service.ProfileManager.CurrentProfile;
var config = GlobalConstants.MainConfig?.Data;
if (config == null)
{
return;
}

// 根据设置决定是切换还是设置到指定层级
// TargetLayer: -1=切换, 0=置底, 1=置顶
if (Settings.TargetLayer >= 0)
{
if (IsRevertable)
{
PreviousLayers[ActionSet.Guid] = profile.FloatingWindowLayer;
PreviousLayers[ActionSet.Guid] = config.FloatingWindowLayer;
}

service.SetWindowLayer(Settings.TargetLayer);
Expand All @@ -44,7 +49,7 @@ protected override async Task OnInvoke()
{
if (IsRevertable)
{
PreviousLayers[ActionSet.Guid] = profile.FloatingWindowLayer;
PreviousLayers[ActionSet.Guid] = config.FloatingWindowLayer;
}

service.ToggleWindowLayer();
Expand Down
44 changes: 2 additions & 42 deletions ConfigHandlers/FloatingWindowProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
namespace SystemTools.ConfigHandlers;

/// <summary>
/// 悬浮窗配置方案,保存一套完整的悬浮窗布局和外观配置
/// 注意:显示状态(ShowFloatingWindow)和规则集(HideOnRule/HidingRules)是全局设置,不随方案切换。
/// 悬浮窗配置方案,仅保存悬浮窗按钮布局以及按钮/行规则集
/// 注意:外观、位置、层级、显示状态和整窗规则集是全局设置,不随方案切换。
/// </summary>
public partial class FloatingWindowProfile : ObservableObject
{
Expand All @@ -25,46 +25,6 @@ public partial class FloatingWindowProfile : ObservableObject
[JsonPropertyName("floatingWindowButtonRows")]
public List<List<string>> FloatingWindowButtonRows { get; set; } = new();

[ObservableProperty]
[JsonPropertyName("floatingWindowScale")]
private double _floatingWindowScale = 1.0;

[ObservableProperty]
[JsonPropertyName("floatingWindowIconSize")]
private int _floatingWindowIconSize = 22;

[ObservableProperty]
[JsonPropertyName("floatingWindowTextSize")]
private int _floatingWindowTextSize = 12;

[ObservableProperty]
[JsonPropertyName("floatingWindowOpacity")]
private int _floatingWindowOpacity = 80;

[ObservableProperty]
[JsonPropertyName("floatingWindowPositionX")]
private int _floatingWindowPositionX = 100;

[ObservableProperty]
[JsonPropertyName("floatingWindowPositionY")]
private int _floatingWindowPositionY = 100;

[ObservableProperty]
[JsonPropertyName("floatingWindowLayer")]
private int _floatingWindowLayer = 1;

[ObservableProperty]
[JsonPropertyName("floatingWindowLayerRecheckMode")]
private int _floatingWindowLayerRecheckMode = 1;

[ObservableProperty]
[JsonPropertyName("floatingWindowShadowEnabled")]
private bool _floatingWindowShadowEnabled = true;

[ObservableProperty]
[JsonPropertyName("floatingWindowDragHandleAlwaysVisible")]
private bool _floatingWindowDragHandleAlwaysVisible;

[JsonPropertyName("floatingWindowButtonRulesets")]
public Dictionary<string, ButtonRulesetConfig> FloatingWindowButtonRulesets { get; set; } = new();

Expand Down
19 changes: 0 additions & 19 deletions ConfigHandlers/FloatingWindowProfileManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,6 @@ public class FloatingWindowProfileManager
public static FloatingWindowProfile DefaultProfile { get; } = new()
{
Name = "Default",
FloatingWindowScale = 1.0,
FloatingWindowIconSize = 22,
FloatingWindowTextSize = 12,
FloatingWindowOpacity = 80,
FloatingWindowPositionX = 100,
FloatingWindowPositionY = 100,
FloatingWindowLayer = 1,
FloatingWindowLayerRecheckMode = 1,
FloatingWindowShadowEnabled = true,
FloatingWindowButtonOrder = new List<string>(),
FloatingWindowButtonRows = new List<List<string>>(),
FloatingWindowButtonRulesets = new Dictionary<string, ButtonRulesetConfig>(),
Expand Down Expand Up @@ -60,16 +51,6 @@ public void MigrateFromLegacyConfig(MainConfigData legacyData)
FloatingWindowHorizontal = legacyData.FloatingWindowHorizontal,
FloatingWindowButtonOrder = new List<string>(legacyData.FloatingWindowButtonOrder ?? []),
FloatingWindowButtonRows = (legacyData.FloatingWindowButtonRows ?? []).Select(r => new List<string>(r)).ToList(),
FloatingWindowScale = legacyData.FloatingWindowScale,
FloatingWindowIconSize = legacyData.FloatingWindowIconSize,
FloatingWindowTextSize = legacyData.FloatingWindowTextSize,
FloatingWindowOpacity = legacyData.FloatingWindowOpacity,
FloatingWindowPositionX = legacyData.FloatingWindowPositionX,
FloatingWindowPositionY = legacyData.FloatingWindowPositionY,
FloatingWindowLayer = legacyData.FloatingWindowLayer,
FloatingWindowLayerRecheckMode = legacyData.FloatingWindowLayerRecheckMode,
FloatingWindowShadowEnabled = legacyData.FloatingWindowShadowEnabled,
FloatingWindowDragHandleAlwaysVisible = legacyData.FloatingWindowDragHandleAlwaysVisible,
FloatingWindowButtonRulesets = new Dictionary<string, ButtonRulesetConfig>(legacyData.FloatingWindowButtonRulesets ?? []),
FloatingWindowRowRulesets = new List<RowRulesetConfig>(legacyData.FloatingWindowRowRulesets ?? [])
};
Expand Down
5 changes: 4 additions & 1 deletion README-2.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## SystemTools v2.5.1.0 - 2026.6.22更新
## 这是一个自动构建提交!


## SystemTools v2.5.1.0 - 2026.6.22更新

### 🚀 新增:

Expand Down
83 changes: 52 additions & 31 deletions Services/FloatingWindowService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ private void EnsureWindow()
Width = 64,
Height = 64,
ShowActivated = false,
Topmost = _profileManager.CurrentProfile.FloatingWindowLayer == 1,
Topmost = _configHandler.Data.FloatingWindowLayer == 1,
SystemDecorations = SystemDecorations.None,
Background = Brushes.Transparent,
CanResize = false,
Expand Down Expand Up @@ -598,10 +598,11 @@ private void RefreshWindowButtons()
}

var profile = _profileManager.CurrentProfile;
var scale = Math.Clamp(profile.FloatingWindowScale, 0.5, 2.0);
var iconSize = Math.Clamp(profile.FloatingWindowIconSize, 15, 50) * scale;
var textSize = Math.Clamp(profile.FloatingWindowTextSize, 8, 30) * scale;
var opacity = Math.Clamp(profile.FloatingWindowOpacity, 10, 100);
var config = _configHandler.Data;
var scale = Math.Clamp(config.FloatingWindowScale, 0.5, 2.0);
var iconSize = Math.Clamp(config.FloatingWindowIconSize, 15, 50) * scale;
var textSize = Math.Clamp(config.FloatingWindowTextSize, 8, 30) * scale;
var opacity = Math.Clamp(config.FloatingWindowOpacity, 10, 100);
Comment on lines +602 to +605

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Migrate existing profile appearance settings

For users upgrading from a build that already wrote floating-window profile JSON, appearance and layer edits were saved only on FloatingWindowProfile via the old editor bindings; MigrateFromLegacyConfig() now returns as soon as Default.json exists and never copies those existing profile values back into MainConfigData. With these lines now rendering from _configHandler.Data, those users silently fall back to stale/default global scale/icon/text/opacity (and similarly layer/drag-handle settings) and the next profile save drops the old JSON fields, so their persisted settings are lost unless a one-time migration/backfill reads the current profile's old fields first.

Useful? React with 👍 / 👎.

var alpha = (byte)Math.Round(255 * (opacity / 100.0));
var isLightTheme = IsLightTheme();
var windowBackground = isLightTheme
Expand All @@ -612,7 +613,7 @@ private void RefreshWindowButtons()
if (_windowContainer != null)
{
_windowContainer.Background = windowBackground;
_windowContainer.BoxShadow = profile.FloatingWindowShadowEnabled
_windowContainer.BoxShadow = config.FloatingWindowShadowEnabled
? new BoxShadows(new BoxShadow
{
OffsetX = 0,
Expand Down Expand Up @@ -753,7 +754,7 @@ private void RefreshWindowButtons()

// 仅在"至少有一个可见按钮"时才显示拖拽把手,避免孤零零一个把手
var hasVisibleButtons = _stackPanel.Children.Count > 0;
var showDragHandle = (_isTouchDeviceDetected || _profileManager.CurrentProfile.FloatingWindowDragHandleAlwaysVisible)
var showDragHandle = (_isTouchDeviceDetected || _configHandler.Data.FloatingWindowDragHandleAlwaysVisible)
&& hasVisibleButtons;

if (showDragHandle)
Expand Down Expand Up @@ -795,7 +796,7 @@ private bool HasAnyVisibleButton()
}

int rowIndex = 0;
foreach (var row in profile.FloatingWindowButtonRows ?? [])
foreach (var row in GetConfiguredButtonRowsWithFallback(profile))
{
if (!hiddenRowSet.Contains(rowIndex))
{
Expand Down Expand Up @@ -838,7 +839,7 @@ private List<List<FloatingWindowEntry>> GetOrderedRows()

var rows = new List<List<FloatingWindowEntry>>();

foreach (var row in profile.FloatingWindowButtonRows ?? [])
foreach (var row in GetConfiguredButtonRowsWithFallback(profile))
{
var items = new List<FloatingWindowEntry>();
foreach (var id in row)
Expand All @@ -857,6 +858,39 @@ private List<List<FloatingWindowEntry>> GetOrderedRows()
return rows;
}


private List<List<string>> GetConfiguredButtonRowsWithFallback(FloatingWindowProfile profile)
{
var validButtonIds = _entries.Values.Select(x => x.ButtonId).Distinct().ToList();
var validSet = validButtonIds.ToHashSet();
var rows = (profile.FloatingWindowButtonRows ?? [])
.Select(row => row.Where(validSet.Contains).Distinct().ToList())
.Where(row => row.Count > 0)
.ToList();

var configuredIds = rows.SelectMany(row => row).ToHashSet();
var missingIds = validButtonIds
.Where(id => !configuredIds.Contains(id))
.Where(id => !profile.FloatingWindowButtonRulesets.ContainsKey(id))
.ToList();

if (missingIds.Count == 0)
{
return rows;
}

if (rows.Count == 0)
{
rows.Add(missingIds);
}
else
{
rows[0].AddRange(missingIds);
}

return rows;
}

private void PruneButtonWidthCache()
{
if (_buttonWidthCache.Count == 0)
Expand Down Expand Up @@ -1304,8 +1338,7 @@ private void RemoveLayerRecheckHooks()

private void RefreshLayerRecheckMode()
{
var profile = _profileManager.CurrentProfile;
var mode = profile.FloatingWindowLayerRecheckMode;
var mode = _configHandler.Data.FloatingWindowLayerRecheckMode;
var useReorderHook = mode == 0;
var useForegroundHook = mode == 1;

Expand Down Expand Up @@ -1399,15 +1432,15 @@ private void OnPostMainTimerTicked(object? sender, EventArgs e)

private void OnLayerRecheck50MsTimerTick(object? sender, EventArgs e)
{
if (_profileManager.CurrentProfile.FloatingWindowLayerRecheckMode == 2)
if (_configHandler.Data.FloatingWindowLayerRecheckMode == 2)
{
RecheckWindowLayer();
}
}

private void OnLayerRecheck1MsTimerTick(object? sender, EventArgs e)
{
if (_profileManager.CurrentProfile.FloatingWindowLayerRecheckMode == 3)
if (_configHandler.Data.FloatingWindowLayerRecheckMode == 3)
{
RecheckWindowLayer();
}
Expand All @@ -1421,7 +1454,7 @@ private void OnWinEvent(IntPtr hWinEventHook, uint @event, IntPtr hwnd, int idOb
return;
}

var mode = _profileManager.CurrentProfile.FloatingWindowLayerRecheckMode;
var mode = _configHandler.Data.FloatingWindowLayerRecheckMode;
var shouldRecheck = (@event == EventObjectReorder && mode == 0) ||
(@event == EventSystemForeground && mode == 1);
if (!shouldRecheck)
Expand Down Expand Up @@ -1454,7 +1487,7 @@ private void RecheckWindowLayer()
SET_WINDOW_POS_FLAGS.SWP_NOSENDCHANGING;
var hwnd = new HWND(handle);

if (_profileManager.CurrentProfile.FloatingWindowLayer == 0)
if (_configHandler.Data.FloatingWindowLayer == 0)
{
_window.Topmost = false;
PInvoke.SetWindowPos(hwnd, HwndBottom, 0, 0, 0, 0, flags);
Expand All @@ -1467,30 +1500,18 @@ private void RecheckWindowLayer()

public void ToggleWindowLayer()
{
var profile = _profileManager.CurrentProfile;
profile.FloatingWindowLayer = profile.FloatingWindowLayer == 1 ? 0 : 1;
_profileManager.SaveProfile();
Dispatcher.UIThread.Post(() =>
{
if (_window != null)
{
_window.Topmost = profile.FloatingWindowLayer == 1;
}
RecheckWindowLayer();
RefreshLayerRecheckMode();
});
SetWindowLayer(_configHandler.Data.FloatingWindowLayer == 1 ? 0 : 1);
}

public void SetWindowLayer(int layer)
{
var profile = _profileManager.CurrentProfile;
profile.FloatingWindowLayer = layer == 1 ? 1 : 0;
_profileManager.SaveProfile();
_configHandler.Data.FloatingWindowLayer = layer == 1 ? 1 : 0;
_configHandler.Save();
Dispatcher.UIThread.Post(() =>
{
if (_window != null)
{
_window.Topmost = profile.FloatingWindowLayer == 1;
_window.Topmost = _configHandler.Data.FloatingWindowLayer == 1;
}
RecheckWindowLayer();
RefreshLayerRecheckMode();
Expand Down
Loading
Loading