Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
9835536
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
b095a92
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
115b8eb
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
c9ad6c6
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
93445cb
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
0be6d3b
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
e9dff25
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
fbbf0e7
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
a11372b
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
1b8eb7b
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
a5d88ef
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
48c8438
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
68ad323
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
4b36350
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
0064aec
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
5db1e25
feat: 悬浮窗功能增强与配置
ywydog May 30, 2026
e513e8c
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
b68b613
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
b5cb3b5
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
604cda7
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
522c796
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
e23f3d0
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
febb2f1
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
493fe9f
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
72e4679
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
c636118
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
8dde995
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
df31031
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
6eaccd6
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
7809cb3
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
6d45c5c
feat: 悬浮窗功能增强与配置
ywydog May 31, 2026
7f318f3
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
728ebba
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
a123133
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
8fd8618
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
3cf4f2b
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
83c9f65
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
e41c7b1
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
43820f7
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
ddcedf7
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
3333713
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
97f497d
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
6c367d1
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
5f91fa3
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
1ff0a8a
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
451da76
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
7833287
feat: 悬浮窗功能增强与配置
ywydog Jun 1, 2026
2b5697e
feat: 悬浮窗功能增强与配置
ywydog Jun 2, 2026
a4e4194
feat: 悬浮窗功能增强与配置
ywydog Jun 2, 2026
a903a0b
feat: 悬浮窗功能增强与配置
ywydog Jun 2, 2026
ebb705c
feat: 悬浮窗功能增强与配置
ywydog Jun 2, 2026
ad934d2
feat: 悬浮窗功能增强与配置
ywydog Jun 2, 2026
71ef220
feat: 悬浮窗功能增强与配置
ywydog Jun 2, 2026
2e54dd7
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
35772b1
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
b8d272c
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
be01aad
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
d2f36a2
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
98f766d
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
ade7883
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
c92b304
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
a71f250
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
cd6dcab
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
6fea791
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
55c0fc7
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
37f5be3
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
090f43b
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
f0fd1b1
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
e760391
feat: 悬浮窗功能增强与配置
ywydog Jun 3, 2026
13fb9c1
feat: 悬浮窗功能增强与配置
ywydog Jun 4, 2026
956c0b7
feat: 悬浮窗功能增强与配置
ywydog Jun 4, 2026
ad020b5
feat: 悬浮窗功能增强与配置
ywydog Jun 4, 2026
f334f9f
feat: 悬浮窗功能增强与配置
ywydog Jun 4, 2026
4f12330
feat: 悬浮窗功能增强与配置
ywydog Jun 4, 2026
3d79b40
feat: 悬浮窗功能增强与配置
ywydog Jun 4, 2026
dd90a6e
feat: 悬浮窗功能增强与配置
ywydog Jun 4, 2026
8461cab
feat: 悬浮窗功能增强与配置
ywydog Jun 4, 2026
53ba59d
feat: 悬浮窗功能增强与配置
ywydog Jun 4, 2026
d164212
feat: 悬浮窗功能增强与配置
ywydog Jun 5, 2026
89074d8
feat: 悬浮窗功能增强与配置
ywydog Jun 6, 2026
64e551d
feat: 悬浮窗功能增强与配置
ywydog Jun 6, 2026
1fb2029
chore: pre-termination backup
ywydog Jun 6, 2026
14311c9
feat: 悬浮窗功能增强与配置
ywydog Jun 7, 2026
a57b689
feat: 悬浮窗功能增强与配置
ywydog Jun 8, 2026
3af6795
feat: 悬浮窗功能增强与配置
ywydog Jun 8, 2026
c0cdd4d
feat: 悬浮窗功能增强与配置
ywydog Jun 8, 2026
a3eb103
feat: 悬浮窗功能增强与配置
ywydog Jun 10, 2026
abff45b
feat: 悬浮窗功能增强与配置
ywydog Jun 10, 2026
6274a3a
feat: 悬浮窗功能增强与配置
ywydog Jun 11, 2026
00473c2
feat: 悬浮窗功能增强与配置
ywydog Jun 11, 2026
1273192
feat: 悬浮窗功能增强与配置
ywydog Jun 11, 2026
17778c3
feat: 悬浮窗功能增强与配置
ywydog Jun 11, 2026
19494e9
feat: 悬浮窗功能增强与配置
ywydog Jun 11, 2026
19fd680
feat: 悬浮窗功能增强与配置
ywydog Jun 11, 2026
6787976
feat: 悬浮窗功能增强与配置
ywydog Jun 11, 2026
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
1 change: 0 additions & 1 deletion Actions/BackgroundPlayAudioAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System;
using System.IO;
using System.Threading.Tasks;
using ClassIsland.Shared;
using SystemTools.Settings;

namespace SystemTools.Actions;
Expand Down
13 changes: 12 additions & 1 deletion Actions/SetVolume.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,18 @@ internal class MMDeviceEnumeratorWrapper
public MMDeviceEnumeratorWrapper()
{
var type = Type.GetTypeFromCLSID(new Guid("BCDE0395-E52F-467C-8E3D-C4579291692E"));
_enumerator = (IMMDeviceEnumerator)Activator.CreateInstance(type);
if (type == null)
{
throw new InvalidOperationException("无法获取 MMDeviceEnumerator 类型。");
}

var instance = Activator.CreateInstance(type);
if (instance == null)
{
throw new InvalidOperationException("无法创建 MMDeviceEnumerator 实例。");
}

_enumerator = (IMMDeviceEnumerator)instance;
}

public IMMDevice GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role)
Expand Down
17 changes: 15 additions & 2 deletions Actions/ShowFloatingWindowAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,21 @@ protected override async Task OnInvoke()
try
{
var shouldShow = Settings.ShowFloatingWindow;
GlobalConstants.MainConfig!.Data.ShowFloatingWindow = shouldShow;
GlobalConstants.MainConfig.Save();
var config = GlobalConstants.MainConfig?.Data;

// 如果没有可用的悬浮窗组件,则强制隐藏且不允许显示
if (_floatingWindowService.Entries.Count == 0)
{
shouldShow = false;
_logger.LogDebug("没有可用的悬浮窗组件,强制隐藏悬浮窗");
}

if (config != null)
{
config.ShowFloatingWindow = shouldShow;
GlobalConstants.MainConfig?.Save();
}

_floatingWindowService.UpdateWindowState();

_logger.LogInformation("悬浮窗状态已更新为: {State}", shouldShow ? "开启" : "关闭");
Expand Down
59 changes: 59 additions & 0 deletions Actions/SwitchFloatingWindowThemeAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Threading.Tasks;
using ClassIsland.Core.Abstractions.Automation;
using ClassIsland.Core.Attributes;
using ClassIsland.Shared;
using Microsoft.Extensions.Logging;
using SystemTools.Services;
using SystemTools.Settings;

namespace SystemTools.Actions;

/// <summary>
/// 切换悬浮窗主题行动
/// </summary>
[ActionInfo("SystemTools.SwitchFloatingWindowTheme", "切换悬浮窗主题", "\uE790", false)]
public class SwitchFloatingWindowThemeAction(ILogger<SwitchFloatingWindowThemeAction> logger) : ActionBase<SwitchFloatingWindowThemeSettings>
{
private readonly ILogger<SwitchFloatingWindowThemeAction> _logger = logger;

protected override async Task OnInvoke()
{
_logger.LogDebug("SwitchFloatingWindowThemeAction OnInvoke 开始");

try
{
var service = IAppHost.GetService<FloatingWindowService>();

if (Settings.TargetTheme >= 0)
{
service.SetWindowTheme(Settings.TargetTheme);
_logger.LogInformation("已设置悬浮窗主题为: {Theme}", GetThemeName(Settings.TargetTheme));
}
else
{
service.ToggleWindowTheme();
_logger.LogInformation("已切换到下一个悬浮窗主题");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "切换悬浮窗主题失败");
throw;
}

await base.OnInvoke();
_logger.LogDebug("SwitchFloatingWindowThemeAction OnInvoke 完成");
}

private static string GetThemeName(int theme)
{
return theme switch
{
0 => "跟随系统",
1 => "浅色",
2 => "深色",
_ => "未知"
};
}
}
50 changes: 50 additions & 0 deletions Actions/ToggleFloatingWindowLayerAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Threading.Tasks;
using ClassIsland.Core.Abstractions.Automation;
using ClassIsland.Core.Attributes;
using ClassIsland.Shared;
using Microsoft.Extensions.Logging;
using SystemTools.Services;
using SystemTools.Settings;

namespace SystemTools.Actions;

/// <summary>
/// 切换悬浮窗层级行动
/// </summary>
[ActionInfo("SystemTools.ToggleFloatingWindowLayer", "切换悬浮窗层级", "\uE9A8", false)]
public class ToggleFloatingWindowLayerAction(ILogger<ToggleFloatingWindowLayerAction> logger) : ActionBase<ToggleFloatingWindowLayerSettings>
{
private readonly ILogger<ToggleFloatingWindowLayerAction> _logger = logger;

protected override async Task OnInvoke()
{
_logger.LogDebug("ToggleFloatingWindowLayerAction OnInvoke 开始");

try
{
var service = IAppHost.GetService<FloatingWindowService>();

// 根据设置决定是切换还是设置到指定层级
// TargetLayer: -1=切换, 0=置顶, 1=置底
if (Settings.TargetLayer >= 0)
{
service.SetWindowLayer(Settings.TargetLayer);
_logger.LogInformation("已设置悬浮窗层级为: {Layer}", Settings.TargetLayer == 0 ? "置顶" : "置底");
}
else
{
service.ToggleWindowLayer();
_logger.LogInformation("已切换悬浮窗层级状态");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "切换悬浮窗层级失败");
throw;
}

await base.OnInvoke();
_logger.LogDebug("ToggleFloatingWindowLayerAction OnInvoke 完成");
}
}
50 changes: 50 additions & 0 deletions Actions/ToggleFloatingWindowProfileAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Threading.Tasks;
using ClassIsland.Core.Abstractions.Automation;
using ClassIsland.Core.Attributes;
using ClassIsland.Shared;
using Microsoft.Extensions.Logging;
using SystemTools.Services;
using SystemTools.Settings;

namespace SystemTools.Actions;

/// <summary>
/// 切换悬浮窗配置方案行动
/// </summary>
[ActionInfo("SystemTools.ToggleFloatingWindowProfile", "切换悬浮窗配置方案", "\uE9A8", false)]
public class ToggleFloatingWindowProfileAction(ILogger<ToggleFloatingWindowProfileAction> logger) : ActionBase<ToggleFloatingWindowProfileSettings>
{
private readonly ILogger<ToggleFloatingWindowProfileAction> _logger = logger;

protected override async Task OnInvoke()
{
_logger.LogDebug("ToggleFloatingWindowProfileAction OnInvoke 开始");

try
{
var service = IAppHost.GetService<FloatingWindowService>();

// 根据设置决定是切换到下一个还是切换到指定方案
// TargetProfileName: null=切换到下一个, 其他=指定方案名称
if (!string.IsNullOrWhiteSpace(Settings.TargetProfileName))
{
service.SwitchToProfile(Settings.TargetProfileName);
_logger.LogInformation("已切换到悬浮窗配置方案: {Name}", Settings.TargetProfileName);
}
else
{
service.ToggleWindowProfile();
_logger.LogInformation("已切换到下一个悬浮窗配置方案");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "切换悬浮窗配置方案失败");
throw;
}

await base.OnInvoke();
_logger.LogDebug("ToggleFloatingWindowProfileAction OnInvoke 完成");
}
}
9 changes: 8 additions & 1 deletion Actions/ToggleWorkflowAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace SystemTools.Actions;

[ActionInfo("SystemTools.ToggleWorkflow", "开关自动化", "\uE9A8", false)]
[ActionInfo("SystemTools.ToggleWorkflow", "开关自动化", "\uE8B8", false)]
public class ToggleWorkflowAction(ILogger<ToggleWorkflowAction> logger) : ActionBase<ToggleWorkflowSettings>
{
private readonly ILogger<ToggleWorkflowAction> _logger = logger;
Expand Down Expand Up @@ -98,6 +98,13 @@ protected override async Task OnRevert()
{
await base.OnRevert();

if (Settings == null || !Settings.RevertToOriginal)
{
_logger.LogDebug("RevertToOriginal 为 false,跳过恢复");
PreviousSnapshots.TryRemove(ActionSet.Guid, out _);
return;
}

if (!PreviousSnapshots.TryRemove(ActionSet.Guid, out var snapshot))
{
_logger.LogWarning("未找到触发前状态,跳过恢复。ActionSet={ActionSetGuid}", ActionSet.Guid);
Expand Down
23 changes: 23 additions & 0 deletions ConfigHandlers/ButtonRulesetConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Text.Json.Serialization;
using ClassIsland.Core.Models.Ruleset;
using CommunityToolkit.Mvvm.ComponentModel;

namespace SystemTools.ConfigHandlers;

/// <summary>
/// 悬浮窗按钮的规则集配置
/// </summary>
public partial class ButtonRulesetConfig : ObservableObject
{
[ObservableProperty]
[JsonPropertyName("isVisible")]
private bool _isVisible = true;

[ObservableProperty]
[JsonPropertyName("hideOnRule")]
private bool _hideOnRule;

[ObservableProperty]
[JsonPropertyName("hidingRules")]
private Ruleset _hidingRules = new();
}
108 changes: 108 additions & 0 deletions ConfigHandlers/FloatingWindowProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using CommunityToolkit.Mvvm.ComponentModel;

namespace SystemTools.ConfigHandlers;

/// <summary>
/// 悬浮窗配置方案,保存一套完整的悬浮窗布局和外观配置。
/// 注意:显示状态(ShowFloatingWindow)和规则集(HideOnRule/HidingRules)是全局设置,不随方案切换。
/// </summary>
public partial class FloatingWindowProfile : ObservableObject
{
[ObservableProperty]
[JsonPropertyName("name")]
private string _name = "Default";

[ObservableProperty]
[JsonPropertyName("floatingWindowHorizontal")]
private bool _floatingWindowHorizontal;

[JsonPropertyName("floatingWindowButtonOrder")]
public List<string> FloatingWindowButtonOrder { get; set; } = new();

[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();

[JsonPropertyName("floatingWindowRowRulesets")]
public List<RowRulesetConfig> FloatingWindowRowRulesets { get; set; } = new();

/// <summary>
/// 清理不存在的按钮ID,返回是否有变更
/// </summary>
public bool PruneInvalidButtonIds(IEnumerable<string> validButtonIds)
{
var validSet = validButtonIds.ToHashSet();
var changed = false;

var newOrder = FloatingWindowButtonOrder.Where(id => validSet.Contains(id)).ToList();
if (newOrder.Count != FloatingWindowButtonOrder.Count)
{
FloatingWindowButtonOrder = newOrder;
changed = true;
}

var newRows = FloatingWindowButtonRows
.Select(row => row.Where(id => validSet.Contains(id)).ToList())
.ToList();
if (newRows.Count != FloatingWindowButtonRows.Count ||
newRows.Zip(FloatingWindowButtonRows, (a, b) => a.SequenceEqual(b)).Any(x => !x))
{
FloatingWindowButtonRows = newRows;
changed = true;
}

var invalidButtonConfigs = FloatingWindowButtonRulesets.Keys.Where(id => !validSet.Contains(id)).ToList();
foreach (var id in invalidButtonConfigs)
{
FloatingWindowButtonRulesets.Remove(id);
changed = true;
}

return changed;
}
}
Loading
Loading