Skip to content
Open
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
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
16 changes: 14 additions & 2 deletions Actions/ShowFloatingWindowAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,26 @@ protected override async Task OnInvoke()
try
{
var shouldShow = Settings.ShowFloatingWindow;
var config = GlobalConstants.MainConfig?.Data;

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

if (IsRevertable)
{
PreviousStates[ActionSet.Guid] = GlobalConstants.MainConfig!.Data.ShowFloatingWindow;
}

GlobalConstants.MainConfig!.Data.ShowFloatingWindow = shouldShow;
GlobalConstants.MainConfig.Save();
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