mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-21 02:30:04 +01:00
Compare commits
11 Commits
async-cpp-
...
dev/vanzue
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b95d4c5035 | ||
|
|
4e6496ce2e | ||
|
|
8f87058508 | ||
|
|
755c138723 | ||
|
|
8b066cea2e | ||
|
|
2d92ccdf3b | ||
|
|
83ea0c2f28 | ||
|
|
cb81a99c5f | ||
|
|
48a3f4fa87 | ||
|
|
6c05e44680 | ||
|
|
6505cd7a63 |
@@ -205,4 +205,12 @@ internal sealed class FoundryClient
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task EnsureRunning()
|
||||||
|
{
|
||||||
|
if (!_foundryManager.IsServiceRunning)
|
||||||
|
{
|
||||||
|
await _foundryManager.StartServiceAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace LanguageModelProvider;
|
|||||||
public sealed class FoundryLocalModelProvider : ILanguageModelProvider
|
public sealed class FoundryLocalModelProvider : ILanguageModelProvider
|
||||||
{
|
{
|
||||||
private IEnumerable<ModelDetails>? _downloadedModels;
|
private IEnumerable<ModelDetails>? _downloadedModels;
|
||||||
private FoundryClient? _foundryManager;
|
private FoundryClient? _foundryClient;
|
||||||
private string? _serviceUrl;
|
private string? _serviceUrl;
|
||||||
|
|
||||||
public static FoundryLocalModelProvider Instance { get; } = new();
|
public static FoundryLocalModelProvider Instance { get; } = new();
|
||||||
@@ -22,13 +22,11 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
|
|||||||
|
|
||||||
public string ProviderDescription => "The model will run locally via Foundry Local";
|
public string ProviderDescription => "The model will run locally via Foundry Local";
|
||||||
|
|
||||||
public string UrlPrefix => "fl://";
|
public IChatClient? GetIChatClient(string modelId)
|
||||||
|
|
||||||
public IChatClient? GetIChatClient(string url)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Logger.LogInfo($"[FoundryLocal] GetIChatClient called with url: {url}");
|
Logger.LogInfo($"[FoundryLocal] GetIChatClient called with url: {modelId}");
|
||||||
InitializeAsync().GetAwaiter().GetResult();
|
InitializeAsync().GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -37,26 +35,22 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(_serviceUrl) || _foundryManager == null)
|
if (string.IsNullOrWhiteSpace(_serviceUrl) || _foundryClient == null)
|
||||||
{
|
{
|
||||||
Logger.LogError("[FoundryLocal] Service URL or manager is null");
|
Logger.LogError("[FoundryLocal] Service URL or manager is null");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract model ID from URL (format: fl://modelname)
|
|
||||||
var modelId = url.Replace(UrlPrefix, string.Empty).Trim('/');
|
|
||||||
if (string.IsNullOrWhiteSpace(modelId))
|
if (string.IsNullOrWhiteSpace(modelId))
|
||||||
{
|
{
|
||||||
Logger.LogError("[FoundryLocal] Model ID is empty after extraction");
|
Logger.LogError("[FoundryLocal] Model ID is empty after extraction");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.LogInfo($"[FoundryLocal] Extracted model ID: {modelId}");
|
|
||||||
|
|
||||||
// Ensure the model is loaded before returning chat client
|
// Ensure the model is loaded before returning chat client
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var isLoaded = _foundryManager.EnsureModelLoaded(modelId).GetAwaiter().GetResult();
|
var isLoaded = _foundryClient.EnsureModelLoaded(modelId).GetAwaiter().GetResult();
|
||||||
if (!isLoaded)
|
if (!isLoaded)
|
||||||
{
|
{
|
||||||
Logger.LogError($"[FoundryLocal] Failed to load model: {modelId}");
|
Logger.LogError($"[FoundryLocal] Failed to load model: {modelId}");
|
||||||
@@ -72,7 +66,7 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use ServiceUri instead of Endpoint since Endpoint already includes /v1
|
// Use ServiceUri instead of Endpoint since Endpoint already includes /v1
|
||||||
var baseUri = _foundryManager.GetServiceUri();
|
var baseUri = _foundryClient.GetServiceUri();
|
||||||
if (baseUri == null)
|
if (baseUri == null)
|
||||||
{
|
{
|
||||||
Logger.LogError("[FoundryLocal] Service URI is null");
|
Logger.LogError("[FoundryLocal] Service URI is null");
|
||||||
@@ -133,24 +127,25 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
|
|||||||
|
|
||||||
private async Task InitializeAsync(CancellationToken cancelationToken = default)
|
private async Task InitializeAsync(CancellationToken cancelationToken = default)
|
||||||
{
|
{
|
||||||
if (_foundryManager != null && _downloadedModels != null && _downloadedModels.Any())
|
if (_foundryClient != null && _downloadedModels != null && _downloadedModels.Any())
|
||||||
{
|
{
|
||||||
|
await _foundryClient.EnsureRunning().ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.LogInfo("[FoundryLocal] Initializing provider");
|
Logger.LogInfo("[FoundryLocal] Initializing provider");
|
||||||
_foundryManager ??= await FoundryClient.CreateAsync();
|
_foundryClient ??= await FoundryClient.CreateAsync();
|
||||||
|
|
||||||
if (_foundryManager == null)
|
if (_foundryClient == null)
|
||||||
{
|
{
|
||||||
Logger.LogError("[FoundryLocal] Failed to create Foundry client");
|
Logger.LogError("[FoundryLocal] Failed to create Foundry client");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_serviceUrl ??= await _foundryManager.GetServiceUrl();
|
_serviceUrl ??= await _foundryClient.GetServiceUrl();
|
||||||
Logger.LogInfo($"[FoundryLocal] Service URL: {_serviceUrl}");
|
Logger.LogInfo($"[FoundryLocal] Service URL: {_serviceUrl}");
|
||||||
|
|
||||||
var cachedModels = await _foundryManager.ListCachedModels();
|
var cachedModels = await _foundryClient.ListCachedModels();
|
||||||
Logger.LogInfo($"[FoundryLocal] Found {cachedModels.Count} cached models");
|
Logger.LogInfo($"[FoundryLocal] Found {cachedModels.Count} cached models");
|
||||||
|
|
||||||
List<ModelDetails> downloadedModels = [];
|
List<ModelDetails> downloadedModels = [];
|
||||||
@@ -162,7 +157,7 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
|
|||||||
{
|
{
|
||||||
Id = $"fl-{model.Name}",
|
Id = $"fl-{model.Name}",
|
||||||
Name = model.Name,
|
Name = model.Name,
|
||||||
Url = $"{UrlPrefix}{model.Name}",
|
Url = $"fl://{model.Name}",
|
||||||
Description = $"{model.Name} running locally with Foundry Local",
|
Description = $"{model.Name} running locally with Foundry Local",
|
||||||
HardwareAccelerators = [HardwareAccelerator.FOUNDRYLOCAL],
|
HardwareAccelerators = [HardwareAccelerator.FOUNDRYLOCAL],
|
||||||
SupportedOnQualcomm = true,
|
SupportedOnQualcomm = true,
|
||||||
@@ -178,7 +173,7 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
|
|||||||
{
|
{
|
||||||
Logger.LogInfo("[FoundryLocal] Checking availability");
|
Logger.LogInfo("[FoundryLocal] Checking availability");
|
||||||
await InitializeAsync();
|
await InitializeAsync();
|
||||||
var available = _foundryManager != null;
|
var available = _foundryClient != null;
|
||||||
Logger.LogInfo($"[FoundryLocal] Available: {available}");
|
Logger.LogInfo($"[FoundryLocal] Available: {available}");
|
||||||
return available;
|
return available;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,11 @@ public interface ILanguageModelProvider
|
|||||||
{
|
{
|
||||||
string Name { get; }
|
string Name { get; }
|
||||||
|
|
||||||
string UrlPrefix { get; }
|
|
||||||
|
|
||||||
string ProviderDescription { get; }
|
string ProviderDescription { get; }
|
||||||
|
|
||||||
Task<IEnumerable<ModelDetails>> GetModelsAsync(bool ignoreCached = false, CancellationToken cancelationToken = default);
|
Task<IEnumerable<ModelDetails>> GetModelsAsync(bool ignoreCached = false, CancellationToken cancelationToken = default);
|
||||||
|
|
||||||
IChatClient? GetIChatClient(string url);
|
IChatClient? GetIChatClient(string modelId);
|
||||||
|
|
||||||
string GetIChatClientString(string url);
|
string GetIChatClientString(string url);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
// 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.Collections.Concurrent;
|
|
||||||
using Microsoft.Extensions.AI;
|
|
||||||
|
|
||||||
namespace LanguageModelProvider;
|
|
||||||
|
|
||||||
public sealed class LanguageModelService
|
|
||||||
{
|
|
||||||
private readonly ConcurrentDictionary<string, ILanguageModelProvider> _providersByPrefix;
|
|
||||||
|
|
||||||
public LanguageModelService(IEnumerable<ILanguageModelProvider> providers)
|
|
||||||
{
|
|
||||||
ArgumentNullException.ThrowIfNull(providers);
|
|
||||||
|
|
||||||
_providersByPrefix = new ConcurrentDictionary<string, ILanguageModelProvider>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
foreach (var provider in providers)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(provider.UrlPrefix))
|
|
||||||
{
|
|
||||||
_providersByPrefix[provider.UrlPrefix] = provider;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LanguageModelService CreateDefault()
|
|
||||||
{
|
|
||||||
return new LanguageModelService(new[]
|
|
||||||
{
|
|
||||||
FoundryLocalModelProvider.Instance,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public IReadOnlyCollection<ILanguageModelProvider> Providers => _providersByPrefix.Values.ToArray();
|
|
||||||
|
|
||||||
public bool RegisterProvider(ILanguageModelProvider provider)
|
|
||||||
{
|
|
||||||
ArgumentNullException.ThrowIfNull(provider);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(provider.UrlPrefix))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Provider must supply a URL prefix.", nameof(provider));
|
|
||||||
}
|
|
||||||
|
|
||||||
_providersByPrefix[provider.UrlPrefix] = provider;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ILanguageModelProvider? GetProviderFor(string? modelReference)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(modelReference))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var provider in _providersByPrefix.Values)
|
|
||||||
{
|
|
||||||
if (modelReference.StartsWith(provider.UrlPrefix, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IReadOnlyList<ModelDetails>> GetModelsAsync(bool refresh = false, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
List<ModelDetails> models = [];
|
|
||||||
|
|
||||||
foreach (var provider in _providersByPrefix.Values)
|
|
||||||
{
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
|
||||||
var providerModels = await provider.GetModelsAsync(refresh, cancellationToken).ConfigureAwait(false);
|
|
||||||
models.AddRange(providerModels);
|
|
||||||
}
|
|
||||||
|
|
||||||
return models;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IChatClient? GetClient(ModelDetails model)
|
|
||||||
{
|
|
||||||
if (model is null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var reference = !string.IsNullOrWhiteSpace(model.Url) ? model.Url : model.Id;
|
|
||||||
return GetClient(reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IChatClient? GetClient(string? modelReference)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(modelReference))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var provider = GetProviderFor(modelReference);
|
|
||||||
|
|
||||||
return provider?.GetIChatClient(modelReference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -264,7 +264,8 @@
|
|||||||
<Button
|
<Button
|
||||||
Padding="0"
|
Padding="0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource SubtleButtonStyle}">
|
Style="{StaticResource SubtleButtonStyle}"
|
||||||
|
Visibility="{x:Bind ViewModel.HasLegalLinks, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||||
<FontIcon FontSize="12" Glyph="" />
|
<FontIcon FontSize="12" Glyph="" />
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<Flyout>
|
<Flyout>
|
||||||
|
|||||||
@@ -213,10 +213,11 @@ namespace AdvancedPaste.Settings
|
|||||||
RemoveLegacyOpenAICredential();
|
RemoveLegacyOpenAICredential();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool shouldEnableAI = legacyCredential is not null;
|
||||||
bool enabledUpdated = false;
|
bool enabledUpdated = false;
|
||||||
if (!properties.IsAIEnabled && legacyCredential is not null)
|
if (properties.IsAIEnabled != shouldEnableAI)
|
||||||
{
|
{
|
||||||
properties.IsAIEnabled = true;
|
properties.IsAIEnabled = shouldEnableAI;
|
||||||
enabledUpdated = true;
|
enabledUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public sealed class FoundryLocalPasteProvider : IPasteAIProvider
|
|||||||
|
|
||||||
public static PasteAIProviderRegistration Registration { get; } = new(SupportedTypes, config => new FoundryLocalPasteProvider(config));
|
public static PasteAIProviderRegistration Registration { get; } = new(SupportedTypes, config => new FoundryLocalPasteProvider(config));
|
||||||
|
|
||||||
private static readonly LanguageModelService LanguageModels = LanguageModelService.CreateDefault();
|
private static readonly FoundryLocalModelProvider _modelProvider = FoundryLocalModelProvider.Instance;
|
||||||
|
|
||||||
private readonly PasteAIConfig _config;
|
private readonly PasteAIConfig _config;
|
||||||
|
|
||||||
@@ -72,11 +72,11 @@ public sealed class FoundryLocalPasteProvider : IPasteAIProvider
|
|||||||
throw new PasteActionException(
|
throw new PasteActionException(
|
||||||
"No Foundry Local model selected",
|
"No Foundry Local model selected",
|
||||||
new InvalidOperationException("Model identifier is required"),
|
new InvalidOperationException("Model identifier is required"),
|
||||||
aiServiceMessage: "Please select a model in the AI provider settings. Model identifier should be in the format 'fl://model-name'.");
|
aiServiceMessage: "Please select a model in the AI provider settings.");
|
||||||
}
|
}
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
var chatClient = LanguageModels.GetClient(modelReference);
|
var chatClient = _modelProvider.GetIChatClient(modelReference);
|
||||||
if (chatClient is null)
|
if (chatClient is null)
|
||||||
{
|
{
|
||||||
throw new PasteActionException(
|
throw new PasteActionException(
|
||||||
@@ -85,9 +85,6 @@ public sealed class FoundryLocalPasteProvider : IPasteAIProvider
|
|||||||
aiServiceMessage: "The model may not be downloaded or the Foundry Local service may not be running. Please check the model status in settings.");
|
aiServiceMessage: "The model may not be downloaded or the Foundry Local service may not be running. Please check the model status in settings.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract actual model ID from the URL (format: fl://modelId)
|
|
||||||
var actualModelId = modelReference.Replace("fl://", string.Empty).Trim('/');
|
|
||||||
|
|
||||||
var userMessageContent = $"""
|
var userMessageContent = $"""
|
||||||
User instructions:
|
User instructions:
|
||||||
{prompt}
|
{prompt}
|
||||||
@@ -104,7 +101,7 @@ public sealed class FoundryLocalPasteProvider : IPasteAIProvider
|
|||||||
new(ChatRole.User, userMessageContent),
|
new(ChatRole.User, userMessageContent),
|
||||||
};
|
};
|
||||||
|
|
||||||
var chatOptions = CreateChatOptions(_config?.SystemPrompt, actualModelId);
|
var chatOptions = CreateChatOptions(_config?.SystemPrompt, modelReference);
|
||||||
|
|
||||||
progress?.Report(0.1);
|
progress?.Report(0.1);
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public abstract class KernelServiceBase(
|
|||||||
ICustomActionTransformService customActionTransformService) : IKernelService
|
ICustomActionTransformService customActionTransformService) : IKernelService
|
||||||
{
|
{
|
||||||
private const string PromptParameterName = "prompt";
|
private const string PromptParameterName = "prompt";
|
||||||
|
private const string DefaultSystemPrompt = "You are an agent who is tasked with helping users paste their clipboard data. You have functions available to help you with this task. Call function when necessary to help user finish the transformation task. You never need to ask permission, always try to do as the user asks. The user will only input one message and will not be available for further questions, so try your best. The user will put in a request to format their clipboard data and you will fulfill it. Do not output anything else besides the reformatted clipboard content.";
|
||||||
|
|
||||||
private readonly IKernelQueryCacheService _queryCacheService = queryCacheService;
|
private readonly IKernelQueryCacheService _queryCacheService = queryCacheService;
|
||||||
private readonly IPromptModerationService _promptModerationService = promptModerationService;
|
private readonly IPromptModerationService _promptModerationService = promptModerationService;
|
||||||
@@ -144,7 +145,8 @@ public abstract class KernelServiceBase(
|
|||||||
|
|
||||||
ChatHistory chatHistory = [];
|
ChatHistory chatHistory = [];
|
||||||
|
|
||||||
chatHistory.AddSystemMessage(runtimeConfig.SystemPrompt);
|
var systemPrompt = string.IsNullOrWhiteSpace(runtimeConfig.SystemPrompt) ? DefaultSystemPrompt : runtimeConfig.SystemPrompt;
|
||||||
|
chatHistory.AddSystemMessage(systemPrompt);
|
||||||
chatHistory.AddSystemMessage($"Available clipboard formats: {await kernel.GetDataFormatsAsync()}");
|
chatHistory.AddSystemMessage($"Available clipboard formats: {await kernel.GetDataFormatsAsync()}");
|
||||||
chatHistory.AddUserMessage(prompt);
|
chatHistory.AddUserMessage(prompt);
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ namespace AdvancedPaste.ViewModels
|
|||||||
[NotifyPropertyChangedFor(nameof(PrivacyLinkUri))]
|
[NotifyPropertyChangedFor(nameof(PrivacyLinkUri))]
|
||||||
[NotifyPropertyChangedFor(nameof(HasTermsLink))]
|
[NotifyPropertyChangedFor(nameof(HasTermsLink))]
|
||||||
[NotifyPropertyChangedFor(nameof(HasPrivacyLink))]
|
[NotifyPropertyChangedFor(nameof(HasPrivacyLink))]
|
||||||
|
[NotifyPropertyChangedFor(nameof(HasLegalLinks))]
|
||||||
private bool _isAllowedByGPO;
|
private bool _isAllowedByGPO;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
@@ -222,6 +223,8 @@ namespace AdvancedPaste.ViewModels
|
|||||||
|
|
||||||
public bool HasPrivacyLink => GetActiveProviderMetadata().HasPrivacyLink;
|
public bool HasPrivacyLink => GetActiveProviderMetadata().HasPrivacyLink;
|
||||||
|
|
||||||
|
public bool HasLegalLinks => HasTermsLink || HasPrivacyLink;
|
||||||
|
|
||||||
public bool ClipboardHasData => AvailableClipboardFormats != ClipboardFormat.None;
|
public bool ClipboardHasData => AvailableClipboardFormats != ClipboardFormat.None;
|
||||||
|
|
||||||
public bool ClipboardHasDataForCustomAI => PasteFormat.SupportsClipboardFormats(CustomAIFormat, AvailableClipboardFormats);
|
public bool ClipboardHasDataForCustomAI => PasteFormat.SupportsClipboardFormats(CustomAIFormat, AvailableClipboardFormats);
|
||||||
@@ -367,6 +370,7 @@ namespace AdvancedPaste.ViewModels
|
|||||||
OnPropertyChanged(nameof(PrivacyLinkUri));
|
OnPropertyChanged(nameof(PrivacyLinkUri));
|
||||||
OnPropertyChanged(nameof(HasTermsLink));
|
OnPropertyChanged(nameof(HasTermsLink));
|
||||||
OnPropertyChanged(nameof(HasPrivacyLink));
|
OnPropertyChanged(nameof(HasPrivacyLink));
|
||||||
|
OnPropertyChanged(nameof(HasLegalLinks));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshPasteFormats()
|
private void RefreshPasteFormats()
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
|||||||
<value>More</value>
|
<value>More</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Run_Radio_Position_LastPosition.Content" xml:space="preserve">
|
<data name="Run_Radio_Position_LastPosition.Content" xml:space="preserve">
|
||||||
<value>Last Position</value>
|
<value>Last position</value>
|
||||||
<comment>Reopen the window where it was last closed</comment>
|
<comment>Reopen the window where it was last closed</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="TrayMenu_Settings" xml:space="preserve">
|
<data name="TrayMenu_Settings" xml:space="preserve">
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
|||||||
L"PowerToys.MouseJump.dll",
|
L"PowerToys.MouseJump.dll",
|
||||||
L"PowerToys.AlwaysOnTopModuleInterface.dll",
|
L"PowerToys.AlwaysOnTopModuleInterface.dll",
|
||||||
L"PowerToys.MousePointerCrosshairs.dll",
|
L"PowerToys.MousePointerCrosshairs.dll",
|
||||||
L"PowerToys.CursorWrap.dll",
|
// L"PowerToys.CursorWrap.dll",
|
||||||
L"PowerToys.PowerAccentModuleInterface.dll",
|
L"PowerToys.PowerAccentModuleInterface.dll",
|
||||||
L"PowerToys.PowerOCRModuleInterface.dll",
|
L"PowerToys.PowerOCRModuleInterface.dll",
|
||||||
L"PowerToys.AdvancedPasteModuleInterface.dll",
|
L"PowerToys.AdvancedPasteModuleInterface.dll",
|
||||||
|
|||||||
@@ -34,52 +34,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||||
public bool IsAIEnabled { get; set; }
|
public bool IsAIEnabled { get; set; }
|
||||||
|
|
||||||
[JsonExtensionData]
|
|
||||||
public Dictionary<string, JsonElement> ExtensionData
|
|
||||||
{
|
|
||||||
get => _extensionData;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_extensionData = value;
|
|
||||||
|
|
||||||
if (_extensionData != null && _extensionData.TryGetValue("IsOpenAIEnabled", out var legacyElement) && legacyElement.ValueKind == JsonValueKind.Object && legacyElement.TryGetProperty("value", out var valueElement))
|
|
||||||
{
|
|
||||||
IsAIEnabled = valueElement.ValueKind switch
|
|
||||||
{
|
|
||||||
JsonValueKind.True => true,
|
|
||||||
JsonValueKind.False => false,
|
|
||||||
_ => IsAIEnabled,
|
|
||||||
};
|
|
||||||
|
|
||||||
_extensionData.Remove("IsOpenAIEnabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_extensionData != null && _extensionData.TryGetValue("IsAdvancedAIEnabled", out var legacyAdvancedElement))
|
|
||||||
{
|
|
||||||
bool? legacyValue = legacyAdvancedElement.ValueKind switch
|
|
||||||
{
|
|
||||||
JsonValueKind.True => true,
|
|
||||||
JsonValueKind.False => false,
|
|
||||||
JsonValueKind.Object when legacyAdvancedElement.TryGetProperty("value", out var advancedValueElement) => advancedValueElement.ValueKind switch
|
|
||||||
{
|
|
||||||
JsonValueKind.True => true,
|
|
||||||
JsonValueKind.False => false,
|
|
||||||
_ => null,
|
|
||||||
},
|
|
||||||
_ => null,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (legacyValue.HasValue)
|
|
||||||
{
|
|
||||||
LegacyAdvancedAIEnabled = legacyValue.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
_extensionData.Remove("IsAdvancedAIEnabled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<string, JsonElement> _extensionData;
|
|
||||||
private bool? _legacyAdvancedAIEnabled;
|
private bool? _legacyAdvancedAIEnabled;
|
||||||
|
|
||||||
[JsonPropertyName("IsAdvancedAIEnabled")]
|
[JsonPropertyName("IsAdvancedAIEnabled")]
|
||||||
|
|||||||
@@ -168,6 +168,9 @@
|
|||||||
</InfoBar>
|
</InfoBar>
|
||||||
</tkcontrols:SettingsExpander.ItemsHeader>
|
</tkcontrols:SettingsExpander.ItemsHeader>
|
||||||
<tkcontrols:SettingsExpander.Items>
|
<tkcontrols:SettingsExpander.Items>
|
||||||
|
<tkcontrols:SettingsCard Name="AdvancedPasteEnableClipboardPreview" ContentAlignment="Left">
|
||||||
|
<controls:CheckBoxWithDescriptionControl x:Uid="AdvancedPaste_EnableClipboardPreview" IsChecked="{x:Bind ViewModel.EnableClipboardPreview, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
<tkcontrols:SettingsCard
|
<tkcontrols:SettingsCard
|
||||||
Name="AdvancedPasteClipboardHistoryEnabledSettingsCard"
|
Name="AdvancedPasteClipboardHistoryEnabledSettingsCard"
|
||||||
ContentAlignment="Left"
|
ContentAlignment="Left"
|
||||||
@@ -177,9 +180,6 @@
|
|||||||
<tkcontrols:SettingsCard Name="AdvancedPasteCloseAfterLosingFocus" ContentAlignment="Left">
|
<tkcontrols:SettingsCard Name="AdvancedPasteCloseAfterLosingFocus" ContentAlignment="Left">
|
||||||
<CheckBox x:Uid="AdvancedPaste_CloseAfterLosingFocus" IsChecked="{x:Bind ViewModel.CloseAfterLosingFocus, Mode=TwoWay}" />
|
<CheckBox x:Uid="AdvancedPaste_CloseAfterLosingFocus" IsChecked="{x:Bind ViewModel.CloseAfterLosingFocus, Mode=TwoWay}" />
|
||||||
</tkcontrols:SettingsCard>
|
</tkcontrols:SettingsCard>
|
||||||
<tkcontrols:SettingsCard Name="AdvancedPasteEnableClipboardPreview" ContentAlignment="Left">
|
|
||||||
<CheckBox x:Uid="AdvancedPaste_EnableClipboardPreview" IsChecked="{x:Bind ViewModel.EnableClipboardPreview, Mode=TwoWay}" />
|
|
||||||
</tkcontrols:SettingsCard>
|
|
||||||
<tkcontrols:SettingsCard Name="AdvancedPasteShowCustomPreviewSettingsCard" ContentAlignment="Left">
|
<tkcontrols:SettingsCard Name="AdvancedPasteShowCustomPreviewSettingsCard" ContentAlignment="Left">
|
||||||
<controls:CheckBoxWithDescriptionControl x:Uid="AdvancedPaste_ShowCustomPreviewSettingsCard" IsChecked="{x:Bind ViewModel.ShowCustomPreview, Mode=TwoWay}" />
|
<controls:CheckBoxWithDescriptionControl x:Uid="AdvancedPaste_ShowCustomPreviewSettingsCard" IsChecked="{x:Bind ViewModel.ShowCustomPreview, Mode=TwoWay}" />
|
||||||
</tkcontrols:SettingsCard>
|
</tkcontrols:SettingsCard>
|
||||||
@@ -429,12 +429,11 @@
|
|||||||
<!-- Paste AI provider dialog -->
|
<!-- Paste AI provider dialog -->
|
||||||
<ContentDialog
|
<ContentDialog
|
||||||
x:Name="PasteAIProviderConfigurationDialog"
|
x:Name="PasteAIProviderConfigurationDialog"
|
||||||
|
x:Uid="AdvancedPaste_EndpointDialog"
|
||||||
Title="Paste with AI provider configuration"
|
Title="Paste with AI provider configuration"
|
||||||
Closed="PasteAIProviderConfigurationDialog_Closed"
|
Closed="PasteAIProviderConfigurationDialog_Closed"
|
||||||
PrimaryButtonClick="PasteAIProviderConfigurationDialog_PrimaryButtonClick"
|
PrimaryButtonClick="PasteAIProviderConfigurationDialog_PrimaryButtonClick"
|
||||||
PrimaryButtonStyle="{ThemeResource AccentButtonStyle}"
|
PrimaryButtonStyle="{ThemeResource AccentButtonStyle}">
|
||||||
PrimaryButtonText="Save"
|
|
||||||
SecondaryButtonText="Cancel">
|
|
||||||
<ContentDialog.Resources>
|
<ContentDialog.Resources>
|
||||||
<x:Double x:Key="ContentDialogMaxWidth">900</x:Double>
|
<x:Double x:Key="ContentDialogMaxWidth">900</x:Double>
|
||||||
<x:Double x:Key="ContentDialogMaxHeight">700</x:Double>
|
<x:Double x:Key="ContentDialogMaxHeight">700</x:Double>
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
public sealed partial class AdvancedPastePage : NavigablePage, IRefreshablePage, IDisposable
|
public sealed partial class AdvancedPastePage : NavigablePage, IRefreshablePage, IDisposable
|
||||||
{
|
{
|
||||||
private readonly ObservableCollection<ModelDetails> _foundryCachedModels = new();
|
private readonly ObservableCollection<ModelDetails> _foundryCachedModels = new();
|
||||||
private readonly ObservableCollection<FoundryDownloadableModel> _foundryDownloadableModels = new();
|
|
||||||
private CancellationTokenSource _foundryModelLoadCts;
|
private CancellationTokenSource _foundryModelLoadCts;
|
||||||
private bool _suppressFoundrySelectionChanged;
|
private bool _suppressFoundrySelectionChanged;
|
||||||
private bool _isFoundryLocalAvailable;
|
private bool _isFoundryLocalAvailable;
|
||||||
@@ -57,7 +56,6 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
if (FoundryLocalPicker is not null)
|
if (FoundryLocalPicker is not null)
|
||||||
{
|
{
|
||||||
FoundryLocalPicker.CachedModels = _foundryCachedModels;
|
FoundryLocalPicker.CachedModels = _foundryCachedModels;
|
||||||
FoundryLocalPicker.DownloadableModels = _foundryDownloadableModels;
|
|
||||||
FoundryLocalPicker.SelectionChanged += FoundryLocalPicker_SelectionChanged;
|
FoundryLocalPicker.SelectionChanged += FoundryLocalPicker_SelectionChanged;
|
||||||
FoundryLocalPicker.LoadRequested += FoundryLocalPicker_LoadRequested;
|
FoundryLocalPicker.LoadRequested += FoundryLocalPicker_LoadRequested;
|
||||||
}
|
}
|
||||||
@@ -469,7 +467,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
|
|
||||||
var cachedModels = cachedModelsEnumerable?.ToList() ?? new List<ModelDetails>();
|
var cachedModels = cachedModelsEnumerable?.ToList() ?? new List<ModelDetails>();
|
||||||
|
|
||||||
UpdateFoundryCollections(cachedModels, []);
|
UpdateFoundryCollections(cachedModels);
|
||||||
ShowFoundryAvailableState();
|
ShowFoundryAvailableState();
|
||||||
RestoreFoundrySelection(cachedModels);
|
RestoreFoundrySelection(cachedModels);
|
||||||
}
|
}
|
||||||
@@ -538,7 +536,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
UpdateFoundrySaveButtonState();
|
UpdateFoundrySaveButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateFoundryCollections(IReadOnlyCollection<ModelDetails> cachedModels, IReadOnlyCollection<ModelDetails> catalogModels)
|
private void UpdateFoundryCollections(IReadOnlyCollection<ModelDetails> cachedModels)
|
||||||
{
|
{
|
||||||
_foundryCachedModels.Clear();
|
_foundryCachedModels.Clear();
|
||||||
|
|
||||||
@@ -547,20 +545,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
_foundryCachedModels.Add(model);
|
_foundryCachedModels.Add(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
var cachedReferences = new HashSet<string>(_foundryCachedModels.Select(m => NormalizeFoundryModelReference(m.Url ?? m.Name)), StringComparer.OrdinalIgnoreCase);
|
var cachedReferences = new HashSet<string>(_foundryCachedModels.Select(m => m.Name), StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
_foundryDownloadableModels.Clear();
|
|
||||||
|
|
||||||
foreach (var model in catalogModels.OrderBy(m => m.Name, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
var reference = NormalizeFoundryModelReference(model.Url ?? model.Name);
|
|
||||||
if (cachedReferences.Contains(reference))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_foundryDownloadableModels.Add(new FoundryDownloadableModel(model));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RestoreFoundrySelection(IReadOnlyCollection<ModelDetails> cachedModels)
|
private void RestoreFoundrySelection(IReadOnlyCollection<ModelDetails> cachedModels)
|
||||||
@@ -576,9 +561,8 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(currentModelReference))
|
if (!string.IsNullOrWhiteSpace(currentModelReference))
|
||||||
{
|
{
|
||||||
var normalizedReference = NormalizeFoundryModelReference(currentModelReference);
|
|
||||||
matchingModel = cachedModels.FirstOrDefault(model =>
|
matchingModel = cachedModels.FirstOrDefault(model =>
|
||||||
string.Equals(NormalizeFoundryModelReference(model.Url ?? model.Name), normalizedReference, StringComparison.OrdinalIgnoreCase));
|
string.Equals(model.Name, currentModelReference, StringComparison.OrdinalIgnoreCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FoundryLocalPicker is null)
|
if (FoundryLocalPicker is null)
|
||||||
@@ -608,7 +592,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
{
|
{
|
||||||
if (ViewModel?.PasteAIProviderDraft is not null)
|
if (ViewModel?.PasteAIProviderDraft is not null)
|
||||||
{
|
{
|
||||||
ViewModel.PasteAIProviderDraft.ModelName = NormalizeFoundryModelReference(matchingModel.Url ?? matchingModel.Name);
|
ViewModel.PasteAIProviderDraft.ModelName = matchingModel.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FoundryLocalPicker is not null)
|
if (FoundryLocalPicker is not null)
|
||||||
@@ -620,19 +604,6 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
UpdateFoundrySaveButtonState();
|
UpdateFoundrySaveButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string NormalizeFoundryModelReference(string modelReference)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(modelReference))
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
var prefix = FoundryLocalModelProvider.Instance.UrlPrefix;
|
|
||||||
return modelReference.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
|
|
||||||
? modelReference
|
|
||||||
: $"{prefix}{modelReference}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateFoundrySaveButtonState()
|
private void UpdateFoundrySaveButtonState()
|
||||||
{
|
{
|
||||||
if (PasteAIProviderConfigurationDialog is null)
|
if (PasteAIProviderConfigurationDialog is null)
|
||||||
@@ -656,7 +627,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_isFoundryLocalAvailable || _foundryDownloadableModels.Any(model => model.IsDownloading))
|
if (!_isFoundryLocalAvailable)
|
||||||
{
|
{
|
||||||
PasteAIProviderConfigurationDialog.IsPrimaryButtonEnabled = false;
|
PasteAIProviderConfigurationDialog.IsPrimaryButtonEnabled = false;
|
||||||
return;
|
return;
|
||||||
@@ -677,7 +648,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
|||||||
{
|
{
|
||||||
if (ViewModel?.PasteAIProviderDraft is not null)
|
if (ViewModel?.PasteAIProviderDraft is not null)
|
||||||
{
|
{
|
||||||
ViewModel.PasteAIProviderDraft.ModelName = NormalizeFoundryModelReference(selectedModel.Url ?? selectedModel.Name);
|
ViewModel.PasteAIProviderDraft.ModelName = selectedModel.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FoundryLocalPicker is not null)
|
if (FoundryLocalPicker is not null)
|
||||||
|
|||||||
@@ -273,26 +273,35 @@
|
|||||||
|
|
||||||
<panels:MouseJumpPanel x:Name="MouseUtils_MouseJump_Panel" x:Uid="MouseUtils_MouseJump_Panel" />
|
<panels:MouseJumpPanel x:Name="MouseUtils_MouseJump_Panel" x:Uid="MouseUtils_MouseJump_Panel" />
|
||||||
|
|
||||||
|
<!--
|
||||||
<controls:SettingsGroup x:Uid="MouseUtils_CursorWrap" AutomationProperties.AutomationId="MouseUtils_CursorWrapTestId">
|
<controls:SettingsGroup x:Uid="MouseUtils_CursorWrap" AutomationProperties.AutomationId="MouseUtils_CursorWrapTestId">
|
||||||
<controls:GPOInfoControl ShowWarning="{x:Bind ViewModel.IsCursorWrapEnabledGpoConfigured, Mode=OneWay}">
|
<controls:GPOInfoControl ShowWarning="{x:Bind ViewModel.IsCursorWrapEnabledGpoConfigured, Mode=OneWay}">
|
||||||
<tkcontrols:SettingsExpander
|
<tkcontrols:SettingsCard
|
||||||
Name="MouseUtilsEnableCursorWrap"
|
Name="MouseUtilsEnableCursorWrap"
|
||||||
x:Uid="MouseUtils_Enable_CursorWrap"
|
x:Uid="MouseUtils_Enable_CursorWrap"
|
||||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/CursorWrap.png}"
|
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/CursorWrap.png}"
|
||||||
IsEnabled="{x:Bind ViewModel.IsCursorWrapEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
|
IsEnabled="{x:Bind ViewModel.IsCursorWrapEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||||
IsExpanded="{x:Bind ViewModel.IsCursorWrapEnabled, Mode=OneWay}">
|
|
||||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.IsCursorWrapEnabled, Mode=TwoWay}" />
|
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.IsCursorWrapEnabled, Mode=TwoWay}" />
|
||||||
<tkcontrols:SettingsExpander.Items>
|
</tkcontrols:SettingsCard>
|
||||||
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind ViewModel.IsCursorWrapEnabled, Mode=OneWay}">
|
|
||||||
<CheckBox x:Uid="MouseUtils_AutoActivate" IsChecked="{x:Bind ViewModel.CursorWrapAutoActivate, Mode=TwoWay}" />
|
|
||||||
</tkcontrols:SettingsCard>
|
|
||||||
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind ViewModel.IsCursorWrapEnabled, Mode=OneWay}">
|
|
||||||
<CheckBox x:Uid="MouseUtils_CursorWrap_DisableWrapDuringDrag" IsChecked="{x:Bind ViewModel.CursorWrapDisableWrapDuringDrag, Mode=TwoWay}" />
|
|
||||||
</tkcontrols:SettingsCard>
|
|
||||||
</tkcontrols:SettingsExpander.Items>
|
|
||||||
</tkcontrols:SettingsExpander>
|
|
||||||
</controls:GPOInfoControl>
|
</controls:GPOInfoControl>
|
||||||
</controls:SettingsGroup>
|
|
||||||
|
<tkcontrols:SettingsExpander
|
||||||
|
Name="MouseUtilsCursorWrapSettingsExpander"
|
||||||
|
x:Uid="MouseUtils_CursorWrap_ActivationShortcut"
|
||||||
|
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||||
|
IsEnabled="{x:Bind ViewModel.IsCursorWrapEnabled, Mode=OneWay}"
|
||||||
|
IsExpanded="True">
|
||||||
|
<controls:ShortcutControl MinWidth="{StaticResource SettingActionControlMinWidth}" HotkeySettings="{x:Bind Path=ViewModel.CursorWrapActivationShortcut, Mode=TwoWay}" />
|
||||||
|
<tkcontrols:SettingsExpander.Items>
|
||||||
|
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||||
|
<CheckBox x:Uid="MouseUtils_AutoActivate" IsChecked="{x:Bind ViewModel.CursorWrapAutoActivate, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind ViewModel.IsCursorWrapEnabled, Mode=OneWay}">
|
||||||
|
<CheckBox x:Uid="MouseUtils_CursorWrap_DisableWrapDuringDrag" IsChecked="{x:Bind ViewModel.CursorWrapDisableWrapDuringDrag, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
</tkcontrols:SettingsExpander.Items>
|
||||||
|
</tkcontrols:SettingsExpander>
|
||||||
|
</controls:SettingsGroup>-->
|
||||||
<controls:SettingsGroup x:Uid="MouseUtils_MousePointerCrosshairs" AutomationProperties.AutomationId="MouseUtils_MousePointerCrosshairsTestId">
|
<controls:SettingsGroup x:Uid="MouseUtils_MousePointerCrosshairs" AutomationProperties.AutomationId="MouseUtils_MousePointerCrosshairsTestId">
|
||||||
<controls:GPOInfoControl ShowWarning="{x:Bind ViewModel.IsMousePointerCrosshairsEnabledGpoConfigured, Mode=OneWay}">
|
<controls:GPOInfoControl ShowWarning="{x:Bind ViewModel.IsMousePointerCrosshairsEnabledGpoConfigured, Mode=OneWay}">
|
||||||
<tkcontrols:SettingsCard
|
<tkcontrols:SettingsCard
|
||||||
|
|||||||
@@ -285,9 +285,6 @@
|
|||||||
AutomationProperties.AutomationId="InputOutputNavItem"
|
AutomationProperties.AutomationId="InputOutputNavItem"
|
||||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/InputOutput.png}"
|
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/InputOutput.png}"
|
||||||
SelectsOnInvoked="False">
|
SelectsOnInvoked="False">
|
||||||
<NavigationViewItem.InfoBadge>
|
|
||||||
<InfoBadge Style="{StaticResource NewInfoBadge}" />
|
|
||||||
</NavigationViewItem.InfoBadge>
|
|
||||||
<NavigationViewItem.MenuItems>
|
<NavigationViewItem.MenuItems>
|
||||||
<NavigationViewItem
|
<NavigationViewItem
|
||||||
x:Name="KeyboardManagerNavigationItem"
|
x:Name="KeyboardManagerNavigationItem"
|
||||||
@@ -302,11 +299,7 @@
|
|||||||
x:Uid="Shell_MouseUtilities"
|
x:Uid="Shell_MouseUtilities"
|
||||||
helpers:NavHelper.NavigateTo="views:MouseUtilsPage"
|
helpers:NavHelper.NavigateTo="views:MouseUtilsPage"
|
||||||
AutomationProperties.AutomationId="MouseUtilitiesNavItem"
|
AutomationProperties.AutomationId="MouseUtilitiesNavItem"
|
||||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseUtils.png}">
|
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseUtils.png}" />
|
||||||
<NavigationViewItem.InfoBadge>
|
|
||||||
<InfoBadge Style="{StaticResource NewInfoBadge}" />
|
|
||||||
</NavigationViewItem.InfoBadge>
|
|
||||||
</NavigationViewItem>
|
|
||||||
<NavigationViewItem
|
<NavigationViewItem
|
||||||
x:Name="MouseWithoutBordersNavigationItem"
|
x:Name="MouseWithoutBordersNavigationItem"
|
||||||
x:Uid="Shell_MouseWithoutBorders"
|
x:Uid="Shell_MouseWithoutBorders"
|
||||||
|
|||||||
@@ -648,10 +648,10 @@ Please review the placeholder content that represents the final terms and usage
|
|||||||
<value>Use built-in functions to handle complex tasks. Token consumption may increase.</value>
|
<value>Use built-in functions to handle complex tasks. Token consumption may increase.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AdvancedPaste_Clipboard_History_Enabled_SettingsCard.Header" xml:space="preserve">
|
<data name="AdvancedPaste_Clipboard_History_Enabled_SettingsCard.Header" xml:space="preserve">
|
||||||
<value>Show what's currently on your Clipboard and access your Clipboard history</value>
|
<value>Access Clipboard History</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AdvancedPaste_Clipboard_History_Enabled_SettingsCard.Description" xml:space="preserve">
|
<data name="AdvancedPaste_Clipboard_History_Enabled_SettingsCard.Description" xml:space="preserve">
|
||||||
<value>Clipboard History shows a list of previously copied items.</value>
|
<value>View and select previously copied items</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AdvancedPaste_Direct_Access_Hotkeys_GroupSettings.Header" xml:space="preserve">
|
<data name="AdvancedPaste_Direct_Access_Hotkeys_GroupSettings.Header" xml:space="preserve">
|
||||||
<value>Actions</value>
|
<value>Actions</value>
|
||||||
@@ -2685,10 +2685,7 @@ From there, simply click on one of the supported files in the File Explorer and
|
|||||||
<value>Wrap the mouse cursor between monitor edges</value>
|
<value>Wrap the mouse cursor between monitor edges</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MouseUtils_CursorWrap_ActivationShortcut.Header" xml:space="preserve">
|
<data name="MouseUtils_CursorWrap_ActivationShortcut.Header" xml:space="preserve">
|
||||||
<value>Activation shortcut</value>
|
<value>Activation and behavior</value>
|
||||||
</data>
|
|
||||||
<data name="MouseUtils_CursorWrap_ActivationShortcut_Description.Text" xml:space="preserve">
|
|
||||||
<value>Hotkey to toggle cursor wrapping on/off</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="MouseUtils_CursorWrap_ActivationShortcut_Button.Content" xml:space="preserve">
|
<data name="MouseUtils_CursorWrap_ActivationShortcut_Button.Content" xml:space="preserve">
|
||||||
<value>Set shortcut</value>
|
<value>Set shortcut</value>
|
||||||
@@ -4601,7 +4598,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
|||||||
<value>Automatically close the window after it loses focus</value>
|
<value>Automatically close the window after it loses focus</value>
|
||||||
<comment>Advanced Paste is a product name, do not loc</comment>
|
<comment>Advanced Paste is a product name, do not loc</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="AdvancedPaste_EnableClipboardPreview.Content" xml:space="preserve">
|
<data name="AdvancedPaste_EnableClipboardPreview.Header" xml:space="preserve">
|
||||||
<value>Show clipboard preview</value>
|
<value>Show clipboard preview</value>
|
||||||
<comment>Enables display of clipboard contents preview in the Advanced Paste window</comment>
|
<comment>Enables display of clipboard contents preview in the Advanced Paste window</comment>
|
||||||
</data>
|
</data>
|
||||||
@@ -5747,4 +5744,13 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
|||||||
<data name="AdvancedPaste_SystemPrompt.Header" xml:space="preserve">
|
<data name="AdvancedPaste_SystemPrompt.Header" xml:space="preserve">
|
||||||
<value>System prompt</value>
|
<value>System prompt</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="AdvancedPaste_EndpointDialog.PrimaryButtonText" xml:space="preserve">
|
||||||
|
<value>Save</value>
|
||||||
|
</data>
|
||||||
|
<data name="AdvancedPaste_EndpointDialog.SecondaryButtonText" xml:space="preserve">
|
||||||
|
<value>Cancel</value>
|
||||||
|
</data>
|
||||||
|
<data name="AdvancedPaste_EnableClipboardPreview.Description" xml:space="preserve">
|
||||||
|
<value>Display a preview of the current clipboard content</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -233,10 +233,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
RemoveLegacyOpenAICredential();
|
RemoveLegacyOpenAICredential();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool shouldEnableAI = legacyCredential is not null;
|
||||||
bool enabledChanged = false;
|
bool enabledChanged = false;
|
||||||
if (!properties.IsAIEnabled && legacyCredential is not null)
|
if (properties.IsAIEnabled != shouldEnableAI)
|
||||||
{
|
{
|
||||||
properties.IsAIEnabled = true;
|
properties.IsAIEnabled = shouldEnableAI;
|
||||||
enabledChanged = true;
|
enabledChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
|
|
||||||
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
|
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
|
||||||
{
|
{
|
||||||
|
// Hide CursorWrap from Dashboard
|
||||||
|
if (moduleType == ModuleType.CursorWrap)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
GpoRuleConfigured gpo = ModuleHelper.GetModuleGpoConfiguration(moduleType);
|
GpoRuleConfigured gpo = ModuleHelper.GetModuleGpoConfiguration(moduleType);
|
||||||
var newItem = new DashboardListItem()
|
var newItem = new DashboardListItem()
|
||||||
{
|
{
|
||||||
@@ -145,7 +151,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType)),
|
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType)),
|
||||||
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
|
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
|
||||||
Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
|
Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
|
||||||
IsNew = moduleType == ModuleType.CursorWrap,
|
|
||||||
|
// IsNew = moduleType == ModuleType.CursorWrap,
|
||||||
DashboardModuleItems = GetModuleItems(moduleType),
|
DashboardModuleItems = GetModuleItems(moduleType),
|
||||||
};
|
};
|
||||||
newItem.EnabledChangedCallback = EnabledChangedOnUI;
|
newItem.EnabledChangedCallback = EnabledChangedOnUI;
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
|
|
||||||
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
|
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
|
||||||
{
|
{
|
||||||
|
// Hide CursorWrap from All Apps flyout
|
||||||
|
if (moduleType == ModuleType.CursorWrap)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
AddFlyoutMenuItem(moduleType);
|
AddFlyoutMenuItem(moduleType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user