[AdvancedPaste]Additional actions - Image to text, Paste as file (txt, png, html) (#35167)

* [AdvancedPaste] Additional actions, including Image to text

* Spellcheck issue

* [AdvancedPaste] Paste as file and many other improvements

* Fixed typo

* Fixed typo

* [AdvancedPaste] Improved paste window menu layout

* [AdvancedPaste] Improved settings window layout

* [AdvancedPaste] Removed AudioToText for the moment

* Code cleanup

* Minor fixes

* Changed log-line with potentially sensitive info

* Extra telemetry for AdvancedPaste

* Added 'Hotkey' suffix to AdvancedPaste_Settings telemetry event
This commit is contained in:
Ani
2024-10-18 15:34:09 +02:00
committed by GitHub
parent 14139affc5
commit dd5cd2a570
41 changed files with 1435 additions and 624 deletions

View File

@@ -24,6 +24,18 @@
<ImageSource x:Key="DialogHeaderImage">ms-appx:///Assets/Settings/Modules/APDialog.light.png</ImageSource>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<DataTemplate x:Key="AdditionalActionTemplate" x:DataType="models:AdvancedPasteAdditionalAction">
<StackPanel Orientation="Horizontal" Spacing="4">
<controls:ShortcutControl
MinWidth="{StaticResource SettingActionControlMinWidth}"
AllowDisable="True"
HotkeySettings="{x:Bind Shortcut, Mode=TwoWay}" />
<ToggleSwitch
IsOn="{x:Bind IsShown, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
OffContent=""
OnContent="" />
</StackPanel>
</DataTemplate>
</ResourceDictionary>
</Page.Resources>
<Grid>
@@ -129,6 +141,7 @@
AllowDisable="True"
HotkeySettings="{x:Bind Path=ViewModel.PasteAsJsonShortcut, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
<ItemsControl
x:Name="CustomActions"
x:Uid="CustomActions"
@@ -155,7 +168,7 @@
HotkeySettings="{x:Bind Path=Shortcut, Mode=TwoWay}" />
<ToggleSwitch
x:Uid="Enable_CustomAction"
AutomationProperties.HelpText="{x:Bind Name}"
AutomationProperties.HelpText="{x:Bind Name, Mode=OneWay}"
IsOn="{x:Bind IsShown, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
OffContent=""
OnContent="" />
@@ -202,6 +215,56 @@
IsTabStop="{x:Bind ViewModel.IsConflictingCopyShortcut, Mode=OneWay}"
Severity="Warning" />
</controls:SettingsGroup>
<controls:SettingsGroup x:Uid="AdvancedPaste_Additional_Actions_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
<tkcontrols:SettingsCard x:Uid="ImageToText" DataContext="{x:Bind ViewModel.AdditionalActions.ImageToText, Mode=OneWay}">
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsExpander
x:Uid="PasteAsFile"
DataContext="{x:Bind ViewModel.AdditionalActions.PasteAsFile, Mode=OneWay}"
HeaderIcon="{ui:FontIcon Glyph=&#xEC50;}"
IsExpanded="{Binding IsShown, Mode=OneWay}">
<tkcontrols:SettingsExpander.Content>
<ToggleSwitch
IsOn="{Binding IsShown, Mode=TwoWay}"
OffContent=""
OnContent="" />
</tkcontrols:SettingsExpander.Content>
<tkcontrols:SettingsExpander.Items>
<!-- HACK: For some weird reason, a ShortcutControl does not work correctly if it's the first or last item in the expander, so we add an invisible card. -->
<tkcontrols:SettingsCard Visibility="Collapsed" />
<tkcontrols:SettingsCard
x:Uid="PasteAsTxtFile"
DataContext="{Binding PasteAsTxtFile, Mode=TwoWay}"
IsEnabled="{x:Bind ViewModel.AdditionalActions.PasteAsFile.IsShown, Mode=OneWay}">
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard
x:Uid="PasteAsPngFile"
DataContext="{Binding PasteAsPngFile, Mode=TwoWay}"
IsEnabled="{x:Bind ViewModel.AdditionalActions.PasteAsFile.IsShown, Mode=OneWay}">
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard
x:Uid="PasteAsHtmlFile"
DataContext="{Binding PasteAsHtmlFile, Mode=TwoWay}"
IsEnabled="{x:Bind ViewModel.AdditionalActions.PasteAsFile.IsShown, Mode=OneWay}">
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
</tkcontrols:SettingsCard>
<!-- HACK: For some weird reason, a ShortcutControl does not work correctly if it's the first or last item in the expander, so we add an invisible card. -->
<tkcontrols:SettingsCard Visibility="Collapsed" />
</tkcontrols:SettingsExpander.Items>
</tkcontrols:SettingsExpander>
<InfoBar
x:Uid="AdvancedPaste_ShortcutWarning"
IsClosable="False"
IsOpen="{x:Bind ViewModel.IsAdditionalActionConflictingCopyShortcut, Mode=OneWay}"
IsTabStop="{x:Bind ViewModel.IsAdditionalActionConflictingCopyShortcut, Mode=OneWay}"
Severity="Warning" />
</controls:SettingsGroup>
</StackPanel>
</controls:SettingsPageControl.ModuleContent>
<controls:SettingsPageControl.PrimaryLinks>

View File

@@ -725,6 +725,9 @@
<data name="AdvancedPaste_Direct_Access_Hotkeys_GroupSettings.Header" xml:space="preserve">
<value>Actions</value>
</data>
<data name="AdvancedPaste_Additional_Actions_GroupSettings.Header" xml:space="preserve">
<value>Additional actions</value>
</data>
<data name="RemapKeysList.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Current Key Remappings</value>
</data>
@@ -2046,6 +2049,21 @@ Made with 💗 by Microsoft and the PowerToys community.</value>
<data name="PasteAsCustom_Shortcut.Header" xml:space="preserve">
<value>Paste as Custom with AI directly</value>
</data>
<data name="ImageToText.Header" xml:space="preserve">
<value>Image to text</value>
</data>
<data name="PasteAsFile.Header" xml:space="preserve">
<value>Paste as file</value>
</data>
<data name="PasteAsTxtFile.Header" xml:space="preserve">
<value>Paste as .txt file</value>
</data>
<data name="PasteAsPngFile.Header" xml:space="preserve">
<value>Paste as .png file</value>
</data>
<data name="PasteAsHtmlFile.Header" xml:space="preserve">
<value>Paste as .html file</value>
</data>
<data name="AdvancedPaste_EnableAIDialogOpenAIApiKey.Text" xml:space="preserve">
<value>OpenAI API key:</value>
</data>

View File

@@ -38,6 +38,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private readonly object _delayedActionLock = new object();
private readonly AdvancedPasteSettings _advancedPasteSettings;
private readonly AdvancedPasteAdditionalActions _additionalActions;
private readonly ObservableCollection<AdvancedPasteCustomAction> _customActions;
private Timer _delayedTimer;
@@ -69,6 +70,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
_advancedPasteSettings = advancedPasteSettingsRepository.SettingsConfig;
_additionalActions = _advancedPasteSettings.Properties.AdditionalActions;
_customActions = _advancedPasteSettings.Properties.CustomActions.Value;
InitializeEnabledValue();
@@ -81,6 +83,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
_delayedTimer.Elapsed += DelayedTimer_Tick;
_delayedTimer.AutoReset = false;
foreach (var action in _additionalActions.AllActions)
{
action.PropertyChanged += OnAdditionalActionPropertyChanged;
}
foreach (var customAction in _customActions)
{
customAction.PropertyChanged += OnCustomActionPropertyChanged;
@@ -143,6 +150,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
public ObservableCollection<AdvancedPasteCustomAction> CustomActions => _customActions;
public AdvancedPasteAdditionalActions AdditionalActions => _additionalActions;
private bool OpenAIKeyExists()
{
PasswordVault vault = new PasswordVault();
@@ -336,12 +345,16 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
public bool IsConflictingCopyShortcut
{
get => _customActions.Select(customAction => customAction.Shortcut)
.Concat([PasteAsPlainTextShortcut, AdvancedPasteUIShortcut, PasteAsMarkdownShortcut, PasteAsJsonShortcut])
.Any(hotkey => WarnHotkeys.Contains(hotkey.ToString()));
}
public bool IsConflictingCopyShortcut =>
_customActions.Select(customAction => customAction.Shortcut)
.Concat([PasteAsPlainTextShortcut, AdvancedPasteUIShortcut, PasteAsMarkdownShortcut, PasteAsJsonShortcut])
.Any(hotkey => WarnHotkeys.Contains(hotkey.ToString()));
public bool IsAdditionalActionConflictingCopyShortcut =>
_additionalActions.AllActions
.OfType<AdvancedPasteAdditionalAction>()
.Select(additionalAction => additionalAction.Shortcut)
.Any(hotkey => WarnHotkeys.Contains(hotkey.ToString()));
private void DelayedTimer_Tick(object sender, EventArgs e)
{
@@ -461,6 +474,16 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
NotifySettingsChanged();
}
private void OnAdditionalActionPropertyChanged(object sender, PropertyChangedEventArgs e)
{
SaveAndNotifySettings();
if (e.PropertyName == nameof(AdvancedPasteAdditionalAction.Shortcut))
{
OnPropertyChanged(nameof(IsAdditionalActionConflictingCopyShortcut));
}
}
private void OnCustomActionPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (typeof(AdvancedPasteCustomAction).GetProperty(e.PropertyName).GetCustomAttribute<JsonIgnoreAttribute>() == null)