Files
PowerToys/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Settings/DockSettings.cs

172 lines
5.2 KiB
C#
Raw Normal View History

// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
using Windows.UI;
namespace Microsoft.CmdPal.UI.ViewModels.Settings;
#pragma warning disable SA1402 // File may only contain a single type
/// <summary>
/// Settings for the Dock. These are settings for _the whole dock_. Band-specific
/// settings are in <see cref="DockBandSettings"/>.
/// </summary>
public class DockSettings
{
public DockSide Side { get; set; } = DockSide.Top;
public DockSize DockSize { get; set; } = DockSize.Small;
public DockSize DockIconsSize { get; set; } = DockSize.Small;
// <Theme settings>
public DockBackdrop Backdrop { get; set; } = DockBackdrop.Acrylic;
public UserTheme Theme { get; set; } = UserTheme.Default;
public ColorizationMode ColorizationMode { get; set; }
CmdPal: Extract persistence services from SettingsModel and AppStateModel (#46312) ## Summary of the Pull Request Extracts persistence (load/save) logic from `SettingsModel` and `AppStateModel` into dedicated service classes, following the single-responsibility principle. Consumers now interact with `ISettingsService` and `IAppStateService` instead of receiving raw model objects through DI. **New services introduced:** - `IPersistenceService` / `PersistenceService` — generic `Load<T>` / `Save<T>` with AOT-compatible `JsonTypeInfo<T>`, ensures target directory exists before writing - `ISettingsService` / `SettingsService` — loads settings on construction, runs migrations, exposes `Settings` property and `SettingsChanged` event - `IAppStateService` / `AppStateService` — loads state on construction, exposes `State` property and `StateChanged` event **Key changes:** - `SettingsModel` and `AppStateModel` are now pure data models — all file I/O, migration, and directory management removed - Raw `SettingsModel` and `AppStateModel` removed from DI container; consumers receive the appropriate service - `IApplicationInfoService.ConfigDirectory` injected into services for config path resolution (no more hardcoded `Utilities.BaseSettingsPath`) - ~30 consumer files updated across `Microsoft.CmdPal.UI.ViewModels` and `Microsoft.CmdPal.UI` projects - All `#pragma warning disable SA1300` suppressions removed — convenience accessors replaced with direct `_settingsService.Settings` / `_appStateService.State` access - Namespace prefixes (`Services.ISettingsService`) replaced with proper `using` directives ## PR Checklist - [ ] **Communication:** I've discussed this with core contributors already. - [x] **Tests:** Added/updated and all pass - [ ] **Localization:** N/A — no end-user-facing strings changed - [ ] **Dev docs:** N/A — internal refactor, no public API changes - [ ] **New binaries:** N/A — no new binaries introduced ## Detailed Description of the Pull Request / Additional comments ### Architecture Services are registered as singletons in `App.xaml.cs`: ```csharp services.AddSingleton<IPersistenceService, PersistenceService>(); services.AddSingleton<ISettingsService, SettingsService>(); services.AddSingleton<IAppStateService, AppStateService>(); ``` `PersistenceService.Save<T>` writes the serialized model directly to disk, creating the target directory if it doesn't exist. It also does not attempt to merge existing and new settings/state. `SettingsService` runs hotkey migrations on load and raises `SettingsChanged` after saves. `AppStateService` always raises `StateChanged` after saves. ### Files changed (41 files, +1169/−660) | Area | Files | What changed | |------|-------|-------------| | New services | `Services/IPersistenceService.cs`, `PersistenceService.cs`, `ISettingsService.cs`, `SettingsService.cs`, `IAppStateService.cs`, `AppStateService.cs` | New service interfaces and implementations | | Models | `SettingsModel.cs`, `AppStateModel.cs` | Stripped to pure data bags | | DI | `App.xaml.cs` | Service registration, removed raw model DI | | ViewModels | 12 files | Constructor injection of services | | UI | 10 files | Service injection replacing model access | | Settings | `DockSettings.cs` | `Colors.Transparent` replaced with struct literal to avoid WinUI3 COM dependency | | Tests | `PersistenceServiceTests.cs`, `SettingsServiceTests.cs`, `AppStateServiceTests.cs` | 38 unit tests covering all three services | | Config | `.gitignore` | Added `.squad/`, `.github/agents/` exclusions | ## Validation Steps Performed - Built `Microsoft.CmdPal.UI` with MSBuild (x64/Debug) — exit code 0, clean build - Ran 38 unit tests via `vstest.console.exe` — all passing - Verified no remaining `#pragma warning disable SA1300` blocks - Verified no remaining `Services.` namespace prefixes --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-20 18:58:27 -05:00
public Color CustomThemeColor { get; set; } = new() { A = 0, R = 255, G = 255, B = 255 }; // Transparent — avoids WinUI3 COM dependency on Colors.Transparent and COM in class init
public int CustomThemeColorIntensity { get; set; } = 100;
public int BackgroundImageOpacity { get; set; } = 20;
public int BackgroundImageBlurAmount { get; set; }
public int BackgroundImageBrightness { get; set; }
public BackgroundImageFit BackgroundImageFit { get; set; }
public string? BackgroundImagePath { get; set; }
// </Theme settings>
// public List<string> PinnedCommands { get; set; } = [];
public List<DockBandSettings> StartBands { get; set; } = [];
public List<DockBandSettings> CenterBands { get; set; } = [];
public List<DockBandSettings> EndBands { get; set; } = [];
public bool ShowLabels { get; set; } = true;
[JsonIgnore]
public IEnumerable<(string ProviderId, string CommandId)> AllPinnedCommands =>
StartBands.Select(b => (b.ProviderId, b.CommandId))
.Concat(CenterBands.Select(b => (b.ProviderId, b.CommandId)))
.Concat(EndBands.Select(b => (b.ProviderId, b.CommandId)));
public DockSettings()
{
// Initialize with default values
// PinnedCommands = [
// "com.microsoft.cmdpal.winget"
// ];
StartBands.Add(new DockBandSettings
{
ProviderId = "com.microsoft.cmdpal.builtin.core",
CommandId = "com.microsoft.cmdpal.home",
});
StartBands.Add(new DockBandSettings
{
ProviderId = "WinGet",
CommandId = "com.microsoft.cmdpal.winget",
ShowLabels = false,
});
EndBands.Add(new DockBandSettings
{
ProviderId = "PerformanceMonitor",
CommandId = "com.microsoft.cmdpal.performanceWidget",
});
EndBands.Add(new DockBandSettings
{
ProviderId = "com.microsoft.cmdpal.builtin.datetime",
CommandId = "com.microsoft.cmdpal.timedate.dockBand",
});
}
}
/// <summary>
/// Settings for a specific dock band. These are per-band settings stored
/// within the overall <see cref="DockSettings"/>.
/// </summary>
public class DockBandSettings
{
public required string ProviderId { get; set; }
public required string CommandId { get; set; }
/// <summary>
/// Gets or sets whether titles are shown for items in this band.
/// If null, falls back to dock-wide ShowLabels setting.
/// </summary>
public bool? ShowTitles { get; set; }
/// <summary>
/// Gets or sets whether subtitles are shown for items in this band.
/// If null, falls back to dock-wide ShowLabels setting.
/// </summary>
public bool? ShowSubtitles { get; set; }
/// <summary>
/// Gets or sets a value for backward compatibility. Maps to ShowTitles.
/// </summary>
[System.Text.Json.Serialization.JsonIgnore]
public bool? ShowLabels
{
get => ShowTitles;
set => ShowTitles = value;
}
/// <summary>
/// Resolves the effective value of <see cref="ShowTitles"/> for this band.
/// If this band doesn't have a specific value set, we'll fall back to the
/// dock-wide setting (passed as <paramref name="defaultValue"/>).
/// </summary>
public bool ResolveShowTitles(bool defaultValue) => ShowTitles ?? defaultValue;
/// <summary>
/// Resolves the effective value of <see cref="ShowSubtitles"/> for this band.
/// If this band doesn't have a specific value set, we'll fall back to the
/// dock-wide setting (passed as <paramref name="defaultValue"/>).
/// </summary>
public bool ResolveShowSubtitles(bool defaultValue) => ShowSubtitles ?? defaultValue;
public DockBandSettings Clone()
{
return new()
{
ProviderId = this.ProviderId,
CommandId = this.CommandId,
ShowTitles = this.ShowTitles,
ShowSubtitles = this.ShowSubtitles,
};
}
}
public enum DockSide
{
Left = 0,
Top = 1,
Right = 2,
Bottom = 3,
}
public enum DockSize
{
Small,
Medium,
Large,
}
public enum DockBackdrop
{
Transparent,
Acrylic,
}
#pragma warning restore SA1402 // File may only contain a single type