Files
PowerToys/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/ProviderSettingsViewModel.cs
Michael Jolley 138c66c328 CmdPal: Removing Core projects (#45693)
Functionally, no differences.

- Removed Core projects.
- Core.Common => Microsoft.CmdPal.Common
- Core.ViewModels => Microsoft.CmdPal.UI.ViewModels

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-02-23 06:05:09 -06:00

221 lines
7.5 KiB
C#

// 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.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Common.Services;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Properties;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class ProviderSettingsViewModel : ObservableObject
{
private static readonly IconInfoViewModel EmptyIcon = new(null);
private static readonly CompositeFormat ExtensionSubtextFormat = CompositeFormat.Parse(Resources.builtin_extension_subtext);
private static readonly CompositeFormat ExtensionSubtextWithFallbackFormat = CompositeFormat.Parse(Resources.builtin_extension_subtext_with_fallback);
private static readonly CompositeFormat ExtensionSubtextDisabledFormat = CompositeFormat.Parse(Resources.builtin_extension_subtext_disabled);
private readonly CommandProviderWrapper _provider;
private readonly ProviderSettings _providerSettings;
private readonly SettingsModel _settings;
private readonly Lock _initializeSettingsLock = new();
private Task? _initializeSettingsTask;
public ProviderSettingsViewModel(
CommandProviderWrapper provider,
ProviderSettings providerSettings,
SettingsModel settings)
{
_provider = provider;
_providerSettings = providerSettings;
_settings = settings;
LoadingSettings = _provider.Settings?.HasSettings ?? false;
BuildFallbackViewModels();
}
public string DisplayName => _provider.DisplayName;
public string ExtensionName => _provider.Extension?.ExtensionDisplayName ?? Resources.builtin_extension_name;
public string ExtensionSubtext => IsEnabled ?
HasFallbackCommands ?
string.Format(CultureInfo.CurrentCulture, ExtensionSubtextWithFallbackFormat, ExtensionName, TopLevelCommands.Count, _provider.FallbackItems?.Length ?? 0) :
string.Format(CultureInfo.CurrentCulture, ExtensionSubtextFormat, ExtensionName, TopLevelCommands.Count) :
string.Format(CultureInfo.CurrentCulture, ExtensionSubtextDisabledFormat, ExtensionName, Resources.builtin_disabled_extension);
[MemberNotNullWhen(true, nameof(Extension))]
public bool IsFromExtension => _provider.Extension is not null;
public IExtensionWrapper? Extension => _provider.Extension;
public string ExtensionVersion => IsFromExtension ? $"{Extension.Version.Major}.{Extension.Version.Minor}.{Extension.Version.Build}.{Extension.Version.Revision}" : string.Empty;
public IconInfoViewModel Icon => IsEnabled ? _provider.Icon : EmptyIcon;
[ObservableProperty]
public partial bool LoadingSettings { get; set; }
public bool IsEnabled
{
get => _providerSettings.IsEnabled;
set
{
if (value != _providerSettings.IsEnabled)
{
_providerSettings.IsEnabled = value;
Save();
WeakReferenceMessenger.Default.Send<ReloadCommandsMessage>(new());
OnPropertyChanged(nameof(IsEnabled));
OnPropertyChanged(nameof(ExtensionSubtext));
OnPropertyChanged(nameof(Icon));
}
if (value == true)
{
_provider.CommandsChanged -= Provider_CommandsChanged;
_provider.CommandsChanged += Provider_CommandsChanged;
}
}
}
/// <summary>
/// Gets a value indicating whether returns true if we have a settings page
/// that's initialized, or we are still working on initializing that
/// settings page. If we don't have a settings object, or that settings
/// object doesn't have a settings page, then we'll return false.
/// </summary>
public bool HasSettings
{
get
{
if (_provider.Settings is null)
{
return false;
}
if (_provider.Settings.Initialized)
{
return _provider.Settings.HasSettings;
}
// settings still need to be loaded.
return LoadingSettings;
}
}
/// <summary>
/// Gets will return the settings page, if we have one, and have initialized it.
/// If we haven't initialized it, this will kick off a thread to start
/// initializing it.
/// </summary>
public ContentPageViewModel? SettingsPage
{
get
{
if (_provider.Settings is null)
{
return null;
}
if (_provider.Settings.Initialized)
{
LoadingSettings = false;
return _provider.Settings.SettingsPage;
}
// Don't load the settings if we're already working on it
lock (_initializeSettingsLock)
{
_initializeSettingsTask ??= Task.Run(InitializeSettingsPage);
}
return null;
}
}
[field: AllowNull]
public List<TopLevelViewModel> TopLevelCommands
{
get
{
if (field is null)
{
field = BuildTopLevelViewModels();
}
return field;
}
}
private List<TopLevelViewModel> BuildTopLevelViewModels()
{
var thisProvider = _provider;
var providersCommands = thisProvider.TopLevelItems;
// Remember! This comes in on the UI thread!
return [.. providersCommands];
}
[field: AllowNull]
public List<FallbackSettingsViewModel> FallbackCommands { get; set; } = [];
public bool HasFallbackCommands => _provider.FallbackItems?.Length > 0;
private void BuildFallbackViewModels()
{
var thisProvider = _provider;
var providersFallbackCommands = thisProvider.FallbackItems;
List<FallbackSettingsViewModel> fallbackViewModels = new(providersFallbackCommands.Length);
foreach (var fallbackItem in providersFallbackCommands)
{
if (_providerSettings.FallbackCommands.TryGetValue(fallbackItem.Id, out var fallbackSettings))
{
fallbackViewModels.Add(new FallbackSettingsViewModel(fallbackItem, fallbackSettings, _settings, this));
}
else
{
fallbackViewModels.Add(new FallbackSettingsViewModel(fallbackItem, new(), _settings, this));
}
}
FallbackCommands = fallbackViewModels;
}
private void Save() => SettingsModel.SaveSettings(_settings);
private void InitializeSettingsPage()
{
if (_provider.Settings is null)
{
return;
}
_provider.Settings.SafeInitializeProperties();
_provider.Settings.DoOnUiThread(() =>
{
// Changing these properties will try to update XAML, and that has
// to be handled on the UI thread, so we need to raise them on the
// UI thread
LoadingSettings = false;
OnPropertyChanged(nameof(HasSettings));
OnPropertyChanged(nameof(LoadingSettings));
OnPropertyChanged(nameof(SettingsPage));
});
}
private void Provider_CommandsChanged(CommandProviderWrapper sender, CommandPalette.Extensions.IItemsChangedEventArgs args)
{
OnPropertyChanged(nameof(ExtensionSubtext));
OnPropertyChanged(nameof(TopLevelCommands));
}
}