mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 03:07:04 +02:00
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>
This commit is contained in:
@@ -183,11 +183,10 @@ public partial class App : Application, IDisposable
|
||||
|
||||
private static void AddUIServices(ServiceCollection services, DispatcherQueue dispatcherQueue)
|
||||
{
|
||||
// Models
|
||||
var sm = SettingsModel.LoadSettings();
|
||||
services.AddSingleton(sm);
|
||||
var state = AppStateModel.LoadState();
|
||||
services.AddSingleton(state);
|
||||
// Models & persistence services
|
||||
services.AddSingleton<IPersistenceService, PersistenceService>();
|
||||
services.AddSingleton<ISettingsService, SettingsService>();
|
||||
services.AddSingleton<IAppStateService, AppStateService>();
|
||||
|
||||
// Services
|
||||
services.AddSingleton<ICommandProviderCache, DefaultCommandProviderCache>();
|
||||
|
||||
@@ -6,6 +6,7 @@ using CommunityToolkit.Mvvm.Messaging;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Services;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Settings;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
@@ -15,12 +16,12 @@ namespace Microsoft.CmdPal.UI;
|
||||
|
||||
internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFactory
|
||||
{
|
||||
private readonly SettingsModel _settingsModel;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly TopLevelCommandManager _topLevelCommandManager;
|
||||
|
||||
public CommandPaletteContextMenuFactory(SettingsModel settingsModel, TopLevelCommandManager topLevelCommandManager)
|
||||
public CommandPaletteContextMenuFactory(ISettingsService settingsService, TopLevelCommandManager topLevelCommandManager)
|
||||
{
|
||||
_settingsModel = settingsModel;
|
||||
_settingsService = settingsService;
|
||||
_topLevelCommandManager = topLevelCommandManager;
|
||||
}
|
||||
|
||||
@@ -65,7 +66,7 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
|
||||
var providerId = providerContext.ProviderId;
|
||||
if (_topLevelCommandManager.LookupProvider(providerId) is CommandProviderWrapper provider)
|
||||
{
|
||||
var providerSettings = _settingsModel.GetProviderSettings(provider);
|
||||
var providerSettings = _settingsService.Settings.GetProviderSettings(provider);
|
||||
|
||||
var alreadyPinnedToTopLevel = providerSettings.PinnedCommandIds.Contains(itemId);
|
||||
|
||||
@@ -82,7 +83,7 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
|
||||
providerId: providerId,
|
||||
pin: !alreadyPinnedToTopLevel,
|
||||
PinLocation.TopLevel,
|
||||
_settingsModel,
|
||||
_settingsService,
|
||||
_topLevelCommandManager);
|
||||
|
||||
var contextItem = new PinToContextItem(pinToTopLevelCommand, commandItem);
|
||||
@@ -132,7 +133,7 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
|
||||
var providerId = providerContext.ProviderId;
|
||||
if (_topLevelCommandManager.LookupProvider(providerId) is CommandProviderWrapper provider)
|
||||
{
|
||||
var providerSettings = _settingsModel.GetProviderSettings(provider);
|
||||
var providerSettings = _settingsService.Settings.GetProviderSettings(provider);
|
||||
|
||||
var isPinnedSubCommand = providerSettings.PinnedCommandIds.Contains(itemId);
|
||||
if (isPinnedSubCommand)
|
||||
@@ -142,7 +143,7 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
|
||||
providerId: providerId,
|
||||
pin: !isPinnedSubCommand,
|
||||
PinLocation.TopLevel,
|
||||
_settingsModel,
|
||||
_settingsService,
|
||||
_topLevelCommandManager);
|
||||
|
||||
var contextItem = new PinToContextItem(pinToTopLevelCommand, commandItem);
|
||||
@@ -168,22 +169,22 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
|
||||
List<IContextItem> moreCommands,
|
||||
CommandItemViewModel commandItem)
|
||||
{
|
||||
if (!_settingsModel.EnableDock)
|
||||
if (!_settingsService.Settings.EnableDock)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var inStartBands = _settingsModel.DockSettings.StartBands.Any(band => MatchesBand(band, itemId, providerId));
|
||||
var inCenterBands = _settingsModel.DockSettings.CenterBands.Any(band => MatchesBand(band, itemId, providerId));
|
||||
var inEndBands = _settingsModel.DockSettings.EndBands.Any(band => MatchesBand(band, itemId, providerId));
|
||||
var inStartBands = _settingsService.Settings.DockSettings.StartBands.Any(band => MatchesBand(band, itemId, providerId));
|
||||
var inCenterBands = _settingsService.Settings.DockSettings.CenterBands.Any(band => MatchesBand(band, itemId, providerId));
|
||||
var inEndBands = _settingsService.Settings.DockSettings.EndBands.Any(band => MatchesBand(band, itemId, providerId));
|
||||
var alreadyPinned = inStartBands || inCenterBands || inEndBands; /** &&
|
||||
_settingsModel.DockSettings.PinnedCommands.Contains(this.Id)**/
|
||||
_settingsService.Settings.DockSettings.PinnedCommands.Contains(this.Id)**/
|
||||
var pinToTopLevelCommand = new PinToCommand(
|
||||
commandId: itemId,
|
||||
providerId: providerId,
|
||||
pin: !alreadyPinned,
|
||||
PinLocation.Dock,
|
||||
_settingsModel,
|
||||
_settingsService,
|
||||
_topLevelCommandManager);
|
||||
|
||||
var contextItem = new PinToContextItem(pinToTopLevelCommand, commandItem);
|
||||
@@ -231,7 +232,7 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
|
||||
{
|
||||
private readonly string _commandId;
|
||||
private readonly string _providerId;
|
||||
private readonly SettingsModel _settings;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly TopLevelCommandManager _topLevelCommandManager;
|
||||
private readonly bool _pin;
|
||||
private readonly PinLocation _pinLocation;
|
||||
@@ -251,13 +252,13 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
|
||||
string providerId,
|
||||
bool pin,
|
||||
PinLocation pinLocation,
|
||||
SettingsModel settings,
|
||||
ISettingsService settingsService,
|
||||
TopLevelCommandManager topLevelCommandManager)
|
||||
{
|
||||
_commandId = commandId;
|
||||
_providerId = providerId;
|
||||
_pinLocation = pinLocation;
|
||||
_settings = settings;
|
||||
_settingsService = settingsService;
|
||||
_topLevelCommandManager = topLevelCommandManager;
|
||||
_pin = pin;
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ public sealed partial class FallbackRanker : UserControl
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var topLevelCommandManager = App.Current.Services.GetService<TopLevelCommandManager>()!;
|
||||
var themeService = App.Current.Services.GetService<IThemeService>()!;
|
||||
viewModel = new SettingsViewModel(settings, topLevelCommandManager, _mainTaskScheduler, themeService);
|
||||
var settingsService = App.Current.Services.GetRequiredService<ISettingsService>();
|
||||
viewModel = new SettingsViewModel(topLevelCommandManager, _mainTaskScheduler, themeService, settingsService);
|
||||
}
|
||||
|
||||
private void ListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
|
||||
|
||||
@@ -9,6 +9,7 @@ using Microsoft.CmdPal.UI.Helpers;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Commands;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Services;
|
||||
using Microsoft.CmdPal.UI.Views;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Dispatching;
|
||||
@@ -49,7 +50,7 @@ public sealed partial class SearchBar : UserControl,
|
||||
// 0.6+ suggestions
|
||||
private string? _textToSuggest;
|
||||
|
||||
private SettingsModel Settings => App.Current.Services.GetRequiredService<SettingsModel>();
|
||||
private SettingsModel Settings => App.Current.Services.GetRequiredService<ISettingsService>().Settings;
|
||||
|
||||
public PageViewModel? CurrentPageViewModel
|
||||
{
|
||||
|
||||
@@ -46,6 +46,7 @@ public sealed partial class DockWindow : WindowEx,
|
||||
#pragma warning restore SA1306 // Field names should begin with lower-case letter
|
||||
|
||||
private readonly IThemeService _themeService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly DockWindowViewModel _windowViewModel;
|
||||
private readonly HiddenOwnerWindowBehavior _hiddenOwnerWindowBehavior = new();
|
||||
|
||||
@@ -68,8 +69,9 @@ public sealed partial class DockWindow : WindowEx,
|
||||
public DockWindow()
|
||||
{
|
||||
var serviceProvider = App.Current.Services;
|
||||
var mainSettings = serviceProvider.GetService<SettingsModel>()!;
|
||||
mainSettings.SettingsChanged += SettingsChangedHandler;
|
||||
var mainSettings = serviceProvider.GetRequiredService<ISettingsService>().Settings;
|
||||
_settingsService = serviceProvider.GetRequiredService<ISettingsService>();
|
||||
_settingsService.SettingsChanged += SettingsChangedHandler;
|
||||
_settings = mainSettings.DockSettings;
|
||||
_lastSize = _settings.DockSize;
|
||||
|
||||
@@ -128,9 +130,9 @@ public sealed partial class DockWindow : WindowEx,
|
||||
UpdateSettingsOnUiThread();
|
||||
}
|
||||
|
||||
private void SettingsChangedHandler(SettingsModel sender, object? args)
|
||||
private void SettingsChangedHandler(ISettingsService sender, SettingsModel args)
|
||||
{
|
||||
_settings = sender.DockSettings;
|
||||
_settings = args.DockSettings;
|
||||
DispatcherQueue.TryEnqueue(UpdateSettingsOnUiThread);
|
||||
}
|
||||
|
||||
@@ -621,9 +623,7 @@ public sealed partial class DockWindow : WindowEx,
|
||||
|
||||
private void DockWindow_Closed(object sender, WindowEventArgs args)
|
||||
{
|
||||
var serviceProvider = App.Current.Services;
|
||||
var settings = serviceProvider.GetService<SettingsModel>();
|
||||
settings?.SettingsChanged -= SettingsChangedHandler;
|
||||
_settingsService.SettingsChanged -= SettingsChangedHandler;
|
||||
_themeService.ThemeChanged -= ThemeService_ThemeChanged;
|
||||
DisposeAcrylic();
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using Microsoft.CmdPal.UI.Messages;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Commands;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Automation.Peers;
|
||||
@@ -183,7 +184,7 @@ public sealed partial class ListPage : Page,
|
||||
return;
|
||||
}
|
||||
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var settings = App.Current.Services.GetRequiredService<ISettingsService>().Settings;
|
||||
if (settings.SingleClickActivates)
|
||||
{
|
||||
ViewModel?.InvokeItemCommand.Execute(item);
|
||||
@@ -203,7 +204,7 @@ public sealed partial class ListPage : Page,
|
||||
{
|
||||
if (ItemView.SelectedItem is ListItemViewModel vm)
|
||||
{
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var settings = App.Current.Services.GetRequiredService<ISettingsService>().Settings;
|
||||
if (!settings.SingleClickActivates)
|
||||
{
|
||||
ViewModel?.InvokeItemCommand.Execute(vm);
|
||||
|
||||
@@ -8,6 +8,7 @@ using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.CmdPal.UI.Messages;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Services;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
@@ -25,7 +26,7 @@ internal sealed partial class TrayIconService
|
||||
private const uint MY_NOTIFY_ID = 1000;
|
||||
private const uint WM_TRAY_ICON = PInvoke.WM_USER + 1;
|
||||
|
||||
private readonly SettingsModel _settingsModel;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly uint WM_TASKBAR_RESTART;
|
||||
|
||||
private Window? _window;
|
||||
@@ -36,9 +37,9 @@ internal sealed partial class TrayIconService
|
||||
private DestroyIconSafeHandle? _largeIcon;
|
||||
private DestroyMenuSafeHandle? _popupMenu;
|
||||
|
||||
public TrayIconService(SettingsModel settingsModel)
|
||||
public TrayIconService(ISettingsService settingsService)
|
||||
{
|
||||
_settingsModel = settingsModel;
|
||||
_settingsService = settingsService;
|
||||
|
||||
// TaskbarCreated is the message that's broadcast when explorer.exe
|
||||
// restarts. We need to know when that happens to be able to bring our
|
||||
@@ -48,7 +49,7 @@ internal sealed partial class TrayIconService
|
||||
|
||||
public void SetupTrayIcon(bool? showSystemTrayIcon = null)
|
||||
{
|
||||
if (showSystemTrayIcon ?? _settingsModel.ShowSystemTrayIcon)
|
||||
if (showSystemTrayIcon ?? _settingsService.Settings.ShowSystemTrayIcon)
|
||||
{
|
||||
if (_window is null)
|
||||
{
|
||||
|
||||
@@ -170,7 +170,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
// Load our settings, and then also wire up a settings changed handler
|
||||
HotReloadSettings();
|
||||
App.Current.Services.GetService<SettingsModel>()!.SettingsChanged += SettingsChangedHandler;
|
||||
App.Current.Services.GetRequiredService<ISettingsService>().SettingsChanged += SettingsChangedHandler;
|
||||
|
||||
// Make sure that we update the acrylic theme when the OS theme changes
|
||||
RootElement.ActualThemeChanged += (s, e) => DispatcherQueue.TryEnqueue(UpdateBackdrop);
|
||||
@@ -211,7 +211,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
}
|
||||
}
|
||||
|
||||
private void SettingsChangedHandler(SettingsModel sender, object? args)
|
||||
private void SettingsChangedHandler(ISettingsService sender, SettingsModel args)
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(HotReloadSettings);
|
||||
}
|
||||
@@ -292,7 +292,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
private void RestoreWindowPositionFromSavedSettings()
|
||||
{
|
||||
var settings = App.Current.Services.GetService<SettingsModel>();
|
||||
var settings = App.Current.Services.GetRequiredService<ISettingsService>().Settings;
|
||||
RestoreWindowPosition(settings?.LastWindowPosition);
|
||||
}
|
||||
|
||||
@@ -363,7 +363,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
private void HotReloadSettings()
|
||||
{
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var settings = App.Current.Services.GetRequiredService<ISettingsService>().Settings;
|
||||
|
||||
SetupHotkey(settings);
|
||||
App.Current.Services.GetService<TrayIconService>()!.SetupTrayIcon(settings.ShowSystemTrayIcon);
|
||||
@@ -707,7 +707,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
{
|
||||
_isLoadedFromDock = false;
|
||||
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var settings = App.Current.Services.GetRequiredService<ISettingsService>().Settings;
|
||||
|
||||
// Start session tracking
|
||||
_sessionStopwatch = Stopwatch.StartNew();
|
||||
@@ -902,7 +902,8 @@ public sealed partial class MainWindow : WindowEx,
|
||||
UpdateWindowPositionInMemory();
|
||||
}
|
||||
|
||||
var settings = serviceProvider.GetService<SettingsModel>();
|
||||
var settingsService = serviceProvider.GetRequiredService<ISettingsService>();
|
||||
var settings = settingsService.Settings;
|
||||
if (settings is not null)
|
||||
{
|
||||
// If we were last shown from the dock, _currentWindowPosition still holds
|
||||
@@ -910,7 +911,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
if (_currentWindowPosition.IsSizeValid)
|
||||
{
|
||||
settings.LastWindowPosition = _currentWindowPosition;
|
||||
SettingsModel.SaveSettings(settings);
|
||||
settingsService.Save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1080,7 +1081,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
}
|
||||
else if (uri.StartsWith("x-cmdpal://reload", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var settings = App.Current.Services.GetService<SettingsModel>();
|
||||
var settings = App.Current.Services.GetRequiredService<ISettingsService>().Settings;
|
||||
if (settings?.AllowExternalReload == true)
|
||||
{
|
||||
Logger.LogInfo("External Reload triggered");
|
||||
|
||||
@@ -16,6 +16,7 @@ using Microsoft.CmdPal.UI.Services;
|
||||
using Microsoft.CmdPal.UI.Settings;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Services;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
@@ -111,7 +112,7 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
||||
var pageAnnouncementFormat = ResourceLoaderInstance.GetString("ScreenReader_Announcement_NavigatedToPage0");
|
||||
_pageNavigatedAnnouncement = CompositeFormat.Parse(pageAnnouncementFormat);
|
||||
|
||||
if (App.Current.Services.GetService<SettingsModel>()!.EnableDock)
|
||||
if (App.Current.Services.GetRequiredService<ISettingsService>().Settings.EnableDock)
|
||||
{
|
||||
_dockWindow = new DockWindow();
|
||||
_dockWindow.Show();
|
||||
@@ -125,14 +126,14 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
||||
{
|
||||
get
|
||||
{
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var settings = App.Current.Services.GetRequiredService<ISettingsService>().Settings;
|
||||
return settings.DisableAnimations ? _noAnimation : _slideRightTransition;
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(NavigateBackMessage message)
|
||||
{
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var settings = App.Current.Services.GetRequiredService<ISettingsService>().Settings;
|
||||
|
||||
if (RootFrame.CanGoBack)
|
||||
{
|
||||
@@ -362,7 +363,7 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
||||
|
||||
private void SummonOnUiThread(HotkeySummonMessage message)
|
||||
{
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var settings = App.Current.Services.GetRequiredService<ISettingsService>().Settings;
|
||||
var commandId = message.CommandId;
|
||||
var isRoot = string.IsNullOrEmpty(commandId);
|
||||
if (isRoot)
|
||||
|
||||
@@ -9,6 +9,7 @@ using Microsoft.CmdPal.Common.Services;
|
||||
using Microsoft.CmdPal.Common.Text;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.MainPage;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Services;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using WinRT;
|
||||
|
||||
@@ -23,13 +24,13 @@ internal sealed class PowerToysRootPageService : IRootPageService
|
||||
private IExtensionWrapper? _activeExtension;
|
||||
private Lazy<MainListPage> _mainListPage;
|
||||
|
||||
public PowerToysRootPageService(TopLevelCommandManager topLevelCommandManager, SettingsModel settings, AliasManager aliasManager, AppStateModel appStateModel, IFuzzyMatcherProvider fuzzyMatcherProvider)
|
||||
public PowerToysRootPageService(TopLevelCommandManager topLevelCommandManager, AliasManager aliasManager, IFuzzyMatcherProvider fuzzyMatcherProvider, ISettingsService settingsService, IAppStateService appStateService)
|
||||
{
|
||||
_tlcManager = topLevelCommandManager;
|
||||
|
||||
_mainListPage = new Lazy<MainListPage>(() =>
|
||||
{
|
||||
return new MainListPage(_tlcManager, settings, aliasManager, appStateModel, fuzzyMatcherProvider);
|
||||
return new MainListPage(_tlcManager, aliasManager, fuzzyMatcherProvider, settingsService, appStateService);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,32 +4,33 @@
|
||||
|
||||
using Microsoft.CmdPal.Common.Services;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Services;
|
||||
|
||||
namespace Microsoft.CmdPal.UI;
|
||||
|
||||
internal sealed class RunHistoryService : IRunHistoryService
|
||||
{
|
||||
private readonly AppStateModel _appStateModel;
|
||||
private readonly IAppStateService _appStateService;
|
||||
|
||||
public RunHistoryService(AppStateModel appStateModel)
|
||||
public RunHistoryService(IAppStateService appStateService)
|
||||
{
|
||||
_appStateModel = appStateModel;
|
||||
_appStateService = appStateService;
|
||||
}
|
||||
|
||||
public IReadOnlyList<string> GetRunHistory()
|
||||
{
|
||||
if (_appStateModel.RunHistory.Count == 0)
|
||||
if (_appStateService.State.RunHistory.Count == 0)
|
||||
{
|
||||
var history = Microsoft.Terminal.UI.RunHistory.CreateRunHistory();
|
||||
_appStateModel.RunHistory.AddRange(history);
|
||||
_appStateService.State.RunHistory.AddRange(history);
|
||||
}
|
||||
|
||||
return _appStateModel.RunHistory;
|
||||
return _appStateService.State.RunHistory;
|
||||
}
|
||||
|
||||
public void ClearRunHistory()
|
||||
{
|
||||
_appStateModel.RunHistory.Clear();
|
||||
_appStateService.State.RunHistory.Clear();
|
||||
}
|
||||
|
||||
public void AddRunHistoryItem(string item)
|
||||
@@ -40,11 +41,11 @@ internal sealed class RunHistoryService : IRunHistoryService
|
||||
return; // Do not add empty or whitespace items
|
||||
}
|
||||
|
||||
_appStateModel.RunHistory.Remove(item);
|
||||
_appStateService.State.RunHistory.Remove(item);
|
||||
|
||||
// Add the item to the front of the history
|
||||
_appStateModel.RunHistory.Insert(0, item);
|
||||
_appStateService.State.RunHistory.Insert(0, item);
|
||||
|
||||
AppStateModel.SaveState(_appStateModel);
|
||||
_appStateService.Save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
private static readonly TimeSpan ReloadDebounceInterval = TimeSpan.FromMilliseconds(500);
|
||||
|
||||
private readonly UISettings _uiSettings;
|
||||
private readonly SettingsModel _settings;
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
private readonly ResourceSwapper _resourceSwapper;
|
||||
private readonly NormalThemeProvider _normalThemeProvider;
|
||||
private readonly ColorfulThemeProvider _colorfulThemeProvider;
|
||||
@@ -76,32 +77,32 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
}
|
||||
|
||||
// provider selection
|
||||
var themeColorIntensity = Math.Clamp(_settings.CustomThemeColorIntensity, 0, 100);
|
||||
var imageTintIntensity = Math.Clamp(_settings.BackgroundImageTintIntensity, 0, 100);
|
||||
var effectiveColorIntensity = _settings.ColorizationMode == ColorizationMode.Image
|
||||
var themeColorIntensity = Math.Clamp(_settingsService.Settings.CustomThemeColorIntensity, 0, 100);
|
||||
var imageTintIntensity = Math.Clamp(_settingsService.Settings.BackgroundImageTintIntensity, 0, 100);
|
||||
var effectiveColorIntensity = _settingsService.Settings.ColorizationMode == ColorizationMode.Image
|
||||
? imageTintIntensity
|
||||
: themeColorIntensity;
|
||||
|
||||
IThemeProvider provider = UseColorfulProvider(effectiveColorIntensity) ? _colorfulThemeProvider : _normalThemeProvider;
|
||||
|
||||
// Calculate values
|
||||
var tint = _settings.ColorizationMode switch
|
||||
var tint = _settingsService.Settings.ColorizationMode switch
|
||||
{
|
||||
ColorizationMode.CustomColor => _settings.CustomThemeColor,
|
||||
ColorizationMode.CustomColor => _settingsService.Settings.CustomThemeColor,
|
||||
ColorizationMode.WindowsAccentColor => _uiSettings.GetColorValue(UIColorType.Accent),
|
||||
ColorizationMode.Image => _settings.CustomThemeColor,
|
||||
ColorizationMode.Image => _settingsService.Settings.CustomThemeColor,
|
||||
_ => Colors.Transparent,
|
||||
};
|
||||
var effectiveTheme = GetElementTheme((ElementTheme)_settings.Theme);
|
||||
var imageSource = _settings.ColorizationMode == ColorizationMode.Image
|
||||
? LoadImageSafe(_settings.BackgroundImagePath)
|
||||
var effectiveTheme = GetElementTheme((ElementTheme)_settingsService.Settings.Theme);
|
||||
var imageSource = _settingsService.Settings.ColorizationMode == ColorizationMode.Image
|
||||
? LoadImageSafe(_settingsService.Settings.BackgroundImagePath)
|
||||
: null;
|
||||
var stretch = _settings.BackgroundImageFit switch
|
||||
var stretch = _settingsService.Settings.BackgroundImageFit switch
|
||||
{
|
||||
BackgroundImageFit.Fill => Stretch.Fill,
|
||||
_ => Stretch.UniformToFill,
|
||||
};
|
||||
var opacity = Math.Clamp(_settings.BackgroundImageOpacity, 0, 100) / 100.0;
|
||||
var opacity = Math.Clamp(_settingsService.Settings.BackgroundImageOpacity, 0, 100) / 100.0;
|
||||
|
||||
// create input and offload to actual theme provider
|
||||
var context = new ThemeContext
|
||||
@@ -112,16 +113,16 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
BackgroundImageSource = imageSource,
|
||||
BackgroundImageStretch = stretch,
|
||||
BackgroundImageOpacity = opacity,
|
||||
BackdropStyle = _settings.BackdropStyle,
|
||||
BackdropOpacity = Math.Clamp(_settings.BackdropOpacity, 0, 100) / 100f,
|
||||
BackdropStyle = _settingsService.Settings.BackdropStyle,
|
||||
BackdropOpacity = Math.Clamp(_settingsService.Settings.BackdropOpacity, 0, 100) / 100f,
|
||||
};
|
||||
var backdrop = provider.GetBackdropParameters(context);
|
||||
var blur = _settings.BackgroundImageBlurAmount;
|
||||
var brightness = _settings.BackgroundImageBrightness;
|
||||
var blur = _settingsService.Settings.BackgroundImageBlurAmount;
|
||||
var brightness = _settingsService.Settings.BackgroundImageBrightness;
|
||||
|
||||
// Create public snapshot (no provider!)
|
||||
var hasColorization = effectiveColorIntensity > 0
|
||||
&& _settings.ColorizationMode is ColorizationMode.CustomColor or ColorizationMode.WindowsAccentColor or ColorizationMode.Image;
|
||||
&& _settingsService.Settings.ColorizationMode is ColorizationMode.CustomColor or ColorizationMode.WindowsAccentColor or ColorizationMode.Image;
|
||||
|
||||
var snapshot = new ThemeSnapshot
|
||||
{
|
||||
@@ -149,7 +150,7 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
Interlocked.Exchange(ref _currentState, newState);
|
||||
|
||||
// Compute DockThemeSnapshot from DockSettings
|
||||
var dockSettings = _settings.DockSettings;
|
||||
var dockSettings = _settingsService.Settings.DockSettings;
|
||||
var dockIntensity = Math.Clamp(dockSettings.CustomThemeColorIntensity, 0, 100);
|
||||
IThemeProvider dockProvider = dockIntensity > 0 && dockSettings.ColorizationMode is ColorizationMode.CustomColor or ColorizationMode.WindowsAccentColor or ColorizationMode.Image
|
||||
? _colorfulThemeProvider
|
||||
@@ -208,8 +209,8 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
|
||||
private bool UseColorfulProvider(int effectiveColorIntensity)
|
||||
{
|
||||
return _settings.ColorizationMode == ColorizationMode.Image
|
||||
|| (effectiveColorIntensity > 0 && _settings.ColorizationMode is ColorizationMode.CustomColor or ColorizationMode.WindowsAccentColor);
|
||||
return _settingsService.Settings.ColorizationMode == ColorizationMode.Image
|
||||
|| (effectiveColorIntensity > 0 && _settingsService.Settings.ColorizationMode is ColorizationMode.CustomColor or ColorizationMode.WindowsAccentColor);
|
||||
}
|
||||
|
||||
private static BitmapImage? LoadImageSafe(string? path)
|
||||
@@ -241,13 +242,12 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public ThemeService(SettingsModel settings, ResourceSwapper resourceSwapper)
|
||||
public ThemeService(ResourceSwapper resourceSwapper, ISettingsService settingsService)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(settings);
|
||||
ArgumentNullException.ThrowIfNull(resourceSwapper);
|
||||
|
||||
_settings = settings;
|
||||
_settings.SettingsChanged += SettingsOnSettingsChanged;
|
||||
_settingsService = settingsService;
|
||||
_settingsService.SettingsChanged += SettingsOnSettingsChanged;
|
||||
|
||||
_resourceSwapper = resourceSwapper;
|
||||
|
||||
@@ -319,7 +319,7 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
};
|
||||
}
|
||||
|
||||
private void SettingsOnSettingsChanged(SettingsModel sender, object? args)
|
||||
private void SettingsOnSettingsChanged(ISettingsService sender, SettingsModel args)
|
||||
{
|
||||
RequestReload();
|
||||
}
|
||||
@@ -339,7 +339,7 @@ internal sealed partial class ThemeService : IThemeService, IDisposable
|
||||
_disposed = true;
|
||||
_dispatcherQueueTimer?.Stop();
|
||||
_uiSettings.ColorValuesChanged -= UiSettings_ColorValuesChanged;
|
||||
_settings.SettingsChanged -= SettingsOnSettingsChanged;
|
||||
_settingsService.SettingsChanged -= SettingsOnSettingsChanged;
|
||||
}
|
||||
|
||||
private sealed class InternalThemeState
|
||||
|
||||
@@ -31,10 +31,10 @@ public sealed partial class AppearancePage : Page
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var themeService = App.Current.Services.GetRequiredService<IThemeService>();
|
||||
var topLevelCommandManager = App.Current.Services.GetService<TopLevelCommandManager>()!;
|
||||
ViewModel = new SettingsViewModel(settings, topLevelCommandManager, _mainTaskScheduler, themeService);
|
||||
var settingsService = App.Current.Services.GetRequiredService<ISettingsService>();
|
||||
ViewModel = new SettingsViewModel(topLevelCommandManager, _mainTaskScheduler, themeService, settingsService);
|
||||
}
|
||||
|
||||
private async void PickBackgroundImage_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -28,11 +28,11 @@ public sealed partial class DockSettingsPage : Page
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var themeService = App.Current.Services.GetService<IThemeService>()!;
|
||||
var topLevelCommandManager = App.Current.Services.GetService<TopLevelCommandManager>()!;
|
||||
var settingsService = App.Current.Services.GetRequiredService<ISettingsService>();
|
||||
|
||||
ViewModel = new SettingsViewModel(settings, topLevelCommandManager, _mainTaskScheduler, themeService);
|
||||
ViewModel = new SettingsViewModel(topLevelCommandManager, _mainTaskScheduler, themeService, settingsService);
|
||||
|
||||
// Initialize UI state
|
||||
InitializeSettings();
|
||||
@@ -195,7 +195,8 @@ public sealed partial class DockSettingsPage : Page
|
||||
|
||||
// var allBands = GetAllBands();
|
||||
var tlcManager = App.Current.Services.GetService<TopLevelCommandManager>()!;
|
||||
var settingsModel = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var settingsModel = App.Current.Services.GetRequiredService<ISettingsService>().Settings;
|
||||
var settingsService = App.Current.Services.GetRequiredService<ISettingsService>();
|
||||
var dockViewModel = App.Current.Services.GetService<DockViewModel>()!;
|
||||
var allBands = tlcManager.GetDockBandsSnapshot();
|
||||
foreach (var band in allBands)
|
||||
@@ -208,7 +209,7 @@ public sealed partial class DockSettingsPage : Page
|
||||
dockSettingsModel: setting,
|
||||
topLevelAdapter: band,
|
||||
bandViewModel: bandVm,
|
||||
settingsModel: settingsModel
|
||||
settingsService: settingsService
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,10 @@ public sealed partial class ExtensionsPage : Page
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var topLevelCommandManager = App.Current.Services.GetService<TopLevelCommandManager>()!;
|
||||
var themeService = App.Current.Services.GetService<IThemeService>()!;
|
||||
viewModel = new SettingsViewModel(settings, topLevelCommandManager, _mainTaskScheduler, themeService);
|
||||
var settingsService = App.Current.Services.GetRequiredService<ISettingsService>();
|
||||
viewModel = new SettingsViewModel(topLevelCommandManager, _mainTaskScheduler, themeService, settingsService);
|
||||
}
|
||||
|
||||
private void SettingsCard_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -23,11 +23,11 @@ public sealed partial class GeneralPage : Page
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
var topLevelCommandManager = App.Current.Services.GetService<TopLevelCommandManager>()!;
|
||||
var themeService = App.Current.Services.GetService<IThemeService>()!;
|
||||
var settingsService = App.Current.Services.GetRequiredService<ISettingsService>();
|
||||
_appInfoService = App.Current.Services.GetRequiredService<IApplicationInfoService>();
|
||||
viewModel = new SettingsViewModel(settings, topLevelCommandManager, _mainTaskScheduler, themeService);
|
||||
viewModel = new SettingsViewModel(topLevelCommandManager, _mainTaskScheduler, themeService, settingsService);
|
||||
}
|
||||
|
||||
public string ApplicationVersion
|
||||
|
||||
Reference in New Issue
Block a user