Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Advanced Paste] Add paste actions to allow transcoding of media files #37188

Open
wants to merge 94 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
e79d86d
[AdvancedPaste] Additional actions, including Image to text
drawbyperpetual Sep 11, 2024
ec0c300
Merge branch 'main' into dev/ani/advanced-paste-additional-actions
drawbyperpetual Sep 11, 2024
e61460d
Spellcheck issue
drawbyperpetual Sep 11, 2024
7dc0f7f
Merge branch 'main' into dev/ani/advanced-paste-additional-actions
drawbyperpetual Sep 13, 2024
b953218
[AdvancedPaste] Paste as file and many other improvements
drawbyperpetual Sep 18, 2024
a843152
Fixed typo
drawbyperpetual Sep 18, 2024
35e6375
Fixed typo
drawbyperpetual Sep 18, 2024
a25fbe3
[AdvancedPaste] Improved paste window menu layout
drawbyperpetual Sep 18, 2024
fa6ddbc
[AdvancedPaste] Improved settings window layout
drawbyperpetual Sep 18, 2024
6f576ee
Merged main
drawbyperpetual Sep 23, 2024
15beab6
Merged main
drawbyperpetual Sep 26, 2024
aee22bc
[AdvancedPaste] Removed AudioToText for the moment
drawbyperpetual Sep 26, 2024
f3718c0
Code cleanup
drawbyperpetual Sep 26, 2024
f6d2304
Minor fixes
drawbyperpetual Sep 27, 2024
ab297d4
Merge branch 'main' into dev/ani/advanced-paste-additional-actions
drawbyperpetual Sep 27, 2024
32cf896
Merge branch 'main' into dev/ani/advanced-paste-additional-actions
drawbyperpetual Sep 30, 2024
7d8a57c
Merge branch 'main' into dev/ani/advanced-paste-additional-actions
drawbyperpetual Oct 1, 2024
737e179
[AdvancedPaste] Semantic Kernel support
drawbyperpetual Oct 9, 2024
fe46df5
Changed log-line with potentially sensitive info
drawbyperpetual Oct 9, 2024
02e0b24
Spellcheck issues
drawbyperpetual Oct 9, 2024
c502479
Merge branch 'main' into dev/ani/advanced-paste-additional-actions
drawbyperpetual Oct 9, 2024
3c23130
Merge branch 'dev/ani/advanced-paste-additional-actions' into dev/ani…
drawbyperpetual Oct 9, 2024
b81b686
Merge branch 'main' into dev/ani/advanced-paste-additional-actions
drawbyperpetual Oct 11, 2024
623c02f
Merge branch 'dev/ani/advanced-paste-additional-actions' into dev/ani…
drawbyperpetual Oct 11, 2024
7036e1d
Various improvements for Semantic Kernel
drawbyperpetual Oct 15, 2024
14f0d48
Spellcheck issue
drawbyperpetual Oct 15, 2024
76ad851
Merge branch 'main' into dev/ani/advanced-paste-additional-actions
drawbyperpetual Oct 15, 2024
9c3f4bc
Merge branch 'dev/ani/advanced-paste-additional-actions' into dev/ani…
drawbyperpetual Oct 15, 2024
a37673c
Refactored Clipboard routines
drawbyperpetual Oct 15, 2024
c169756
Added integration tests for KernelService
drawbyperpetual Oct 16, 2024
1ab6d8a
Extra telemetry for AdvancedPaste
drawbyperpetual Oct 17, 2024
a492cbb
Added 'Hotkey' suffix to AdvancedPaste_Settings telemetry event
drawbyperpetual Oct 18, 2024
81eae76
Merge branch 'dev/ani/advanced-paste-additional-actions' into dev/ani…
drawbyperpetual Oct 18, 2024
6cba489
Added IsSavedQuery
drawbyperpetual Oct 21, 2024
edb3093
Merged main
drawbyperpetual Oct 21, 2024
a48d839
Added KernelQueryCache
drawbyperpetual Oct 22, 2024
d7eebae
Refactoring
drawbyperpetual Oct 23, 2024
636964e
Merge branch 'main' into dev/ani/advanced-paste-semantic-kernel
drawbyperpetual Oct 23, 2024
6913e08
Added KernelQueryCache to BugReportTool delete list
drawbyperpetual Oct 24, 2024
d4682ea
Added opt-n for Semantic Kernel
drawbyperpetual Oct 24, 2024
11ed80d
Fixed bug with KernelQueryCache
drawbyperpetual Oct 25, 2024
0baca2f
Ability to view last AI chat message on error
drawbyperpetual Oct 25, 2024
4f83918
Merge branch 'main' into dev/ani/advanced-paste-semantic-kernel
drawbyperpetual Oct 25, 2024
437bda5
Improved kernel query cache
drawbyperpetual Oct 27, 2024
2b71139
Used System.IO.Abstractions and improved tests
drawbyperpetual Oct 30, 2024
1654716
Merge branch 'main' into dev/ani/advanced-paste-semantic-kernel
drawbyperpetual Oct 30, 2024
12d50cf
Merge branch 'main' into dev/ani/advanced-paste-semantic-kernel
drawbyperpetual Oct 30, 2024
78f1b49
Fixed under-count of token usage
drawbyperpetual Nov 4, 2024
f93b9e8
Merge branch 'main' into dev/ani/advanced-paste-semantic-kernel
drawbyperpetual Nov 4, 2024
50153b0
Used Semantic Kernel icon
drawbyperpetual Nov 5, 2024
75a31da
Cleanup
drawbyperpetual Nov 10, 2024
dae93c7
Add missing EndProject line
jaimecbernardo Nov 11, 2024
ec9255a
Merged main
drawbyperpetual Nov 11, 2024
3ed3e4f
Fix dependency version conflicts
jaimecbernardo Nov 11, 2024
bdcb428
Fix NOTICE.md
jaimecbernardo Nov 11, 2024
7627f92
Correct place of SemanticKernel in NOTICE.md
jaimecbernardo Nov 11, 2024
f103c51
Merge branch 'main' into dev/ani/advanced-paste-semantic-kernel
drawbyperpetual Nov 13, 2024
88cd6f3
Unlinked CustomPreview toggle from AI
drawbyperpetual Nov 13, 2024
6443ddd
Merged main
drawbyperpetual Nov 13, 2024
bf542e2
Added Microsoft.Bcl.AsyncInterfaces dependency to AdvancedPaste
drawbyperpetual Nov 13, 2024
77605b7
Fixed NOTICE.md order
drawbyperpetual Nov 13, 2024
a075402
Moved Custom Preview to behaviour section
drawbyperpetual Nov 14, 2024
ddbf4a3
Made Image to Text raise error on empty output
drawbyperpetual Nov 20, 2024
3525354
Added AIServiceBatchIntegrationTests
drawbyperpetual Nov 20, 2024
85bf360
Merged main
drawbyperpetual Nov 21, 2024
5cd4223
Updated AIServiceBatchIntegrationTests
drawbyperpetual Nov 21, 2024
4a593e2
Added prompt moderation
drawbyperpetual Nov 23, 2024
b10d26c
Merge branch 'main' into dev/ani/advanced-paste-semantic-kernel
drawbyperpetual Nov 23, 2024
308fe14
[AdvancedPaste] Media Transcoding support
drawbyperpetual Nov 27, 2024
b6b503b
Merged main
drawbyperpetual Nov 27, 2024
0aa7e4f
Merge branch 'dev/ani/advanced-paste-semantic-kernel' into dev/ani/ad…
drawbyperpetual Nov 27, 2024
f758a89
Spellcheck issue
drawbyperpetual Nov 27, 2024
b28ea47
Merge branch 'main' into dev/ani/advanced-paste-semantic-kernel
drawbyperpetual Dec 2, 2024
4012597
Merge branch 'dev/ani/advanced-paste-semantic-kernel' into dev/ani/ad…
drawbyperpetual Dec 2, 2024
2b3743b
Improved transcoding output profile and added tests
drawbyperpetual Dec 6, 2024
58a5854
Merged main
drawbyperpetual Dec 6, 2024
890369c
Merge branch 'dev/ani/advanced-paste-semantic-kernel' into dev/ani/ad…
drawbyperpetual Dec 6, 2024
e191935
Merged main
drawbyperpetual Dec 9, 2024
cf01fb0
Merge branch 'main' into dev/ani/advanced-paste-semantic-kernel
drawbyperpetual Dec 10, 2024
8279079
Moved GPO Infobar to better location
drawbyperpetual Dec 11, 2024
27b16ff
Merge branch 'dev/ani/advanced-paste-semantic-kernel' into dev/ani/ad…
drawbyperpetual Dec 16, 2024
f8328cc
Merged main
drawbyperpetual Dec 16, 2024
2101306
Added cancel button and minor bug fixes
drawbyperpetual Dec 23, 2024
3150454
Merge branch 'main' into dev/ani/advanced-paste-transcoding
drawbyperpetual Dec 23, 2024
71de7b5
Merged main
drawbyperpetual Jan 16, 2025
873028b
Fixed crash
drawbyperpetual Jan 16, 2025
356a5b2
Merge branch 'main' into dev/ani/advanced-paste-transcoding
drawbyperpetual Jan 29, 2025
1d1cc2d
Minor cleanups
drawbyperpetual Jan 30, 2025
1dc9b1a
Merge branch 'main' into dev/ani/advanced-paste-transcoding
drawbyperpetual Feb 3, 2025
6c95623
Merge remote-tracking branch 'origin/main' into dev/ani/advanced-past…
DHowett Feb 6, 2025
efaad0a
Merge remote-tracking branch 'origin/main' into dev/ani/advanced-past…
snickler Feb 19, 2025
1d56faf
Merge branch 'main' into dev/ani/advanced-paste-transcoding
drawbyperpetual Feb 24, 2025
2f63493
Improved transcoding error messages
drawbyperpetual Feb 24, 2025
e79d885
Merge branch 'main' into dev/ani/advanced-paste-transcoding
drawbyperpetual Feb 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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;
using System.Threading.Tasks;

using AdvancedPaste.Models.KernelQueryCache;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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;

namespace AdvancedPaste.UnitTests.Mocks;

internal sealed class NoOpProgress : IProgress<double>
{
public void Report(double value)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;

using AdvancedPaste.Helpers;
Expand Down Expand Up @@ -131,17 +132,18 @@ private static async Task<DataPackage> GetOutputDataPackageAsync(BatchTestInput
{
VaultCredentialsProvider credentialsProvider = new();
PromptModerationService promptModerationService = new(credentialsProvider);
NoOpProgress progress = new();
CustomTextTransformService customTextTransformService = new(credentialsProvider, promptModerationService);

switch (format)
{
case PasteFormats.CustomTextTransformation:
return DataPackageHelpers.CreateFromText(await customTextTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard));
return DataPackageHelpers.CreateFromText(await customTextTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard, CancellationToken.None, progress));

case PasteFormats.KernelQuery:
var clipboardData = DataPackageHelpers.CreateFromText(batchTestInput.Clipboard).GetView();
KernelService kernelService = new(new NoOpKernelQueryCacheService(), credentialsProvider, promptModerationService, customTextTransformService);
return await kernelService.TransformClipboardAsync(batchTestInput.Prompt, clipboardData, isSavedQuery: false);
return await kernelService.TransformClipboardAsync(batchTestInput.Prompt, clipboardData, isSavedQuery: false, CancellationToken.None, progress);

default:
throw new InvalidOperationException($"Unexpected format {format}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

using AdvancedPaste.Helpers;
Expand Down Expand Up @@ -130,7 +131,7 @@ private static async Task<DataPackage> CreatePackageAsync(ClipboardFormat format

private async Task<DataPackageView> GetKernelOutputAsync(string prompt, DataPackage input)
{
var output = await _kernelService.TransformClipboardAsync(prompt, input.GetView(), isSavedQuery: false);
var output = await _kernelService.TransformClipboardAsync(prompt, input.GetView(), isSavedQuery: false, CancellationToken.None, new NoOpProgress());

Assert.AreEqual(1, _eventListener.SemanticKernelEvents.Count);
Assert.IsTrue(_eventListener.SemanticKernelTokens > 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// 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;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.UnitTests.Mocks;
using ManagedCommon;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Windows.Storage;
using Windows.Storage.FileProperties;

namespace AdvancedPaste.UnitTests.ServicesTests;

[TestClass]
public sealed class TranscodeHelperIntegrationTests
{
private sealed record class MediaProperties(BasicProperties Basic, MusicProperties Music, VideoProperties Video);

private const string InputRootFolder = @"%USERPROFILE%\AdvancedPasteTranscodeMediaTestData";

/// <summary> Tests transforming a folder of media files.
/// - Verifies that the output file has the same basic properties (e.g. duration) as the input file.
/// - Copies the output file to a subfolder of the input folder for manual inspection.
/// </summary>
[TestMethod]
[DataRow(@"audio", PasteFormats.TranscodeToMp3)]
[DataRow(@"video", PasteFormats.TranscodeToMp4)]
public async Task TestTransformFolder(string inputSubfolder, PasteFormats format)
{
var inputFolder = Environment.ExpandEnvironmentVariables(Path.Combine(InputRootFolder, inputSubfolder));

if (!Directory.Exists(inputFolder))
{
Assert.Inconclusive($"Skipping tests for {inputFolder} as it does not exist");
}

var outputPath = Path.Combine(inputFolder, $"test_output_{format}");

foreach (var inputPath in Directory.EnumerateFiles(inputFolder))
{
await RunTestTransformFileAsync(inputPath, outputPath, format);
}
}

private async Task RunTestTransformFileAsync(string inputPath, string finalOutputPath, PasteFormats format)
{
Logger.LogDebug($"Running {nameof(RunTestTransformFileAsync)} for {inputPath}/{format}");

Directory.CreateDirectory(finalOutputPath);

var inputPackage = await DataPackageHelpers.CreateFromFileAsync(inputPath);
var inputProperties = await GetPropertiesAsync(await StorageFile.GetFileFromPathAsync(inputPath));

var outputPackage = await TransformHelpers.TransformAsync(format, inputPackage.GetView(), CancellationToken.None, new NoOpProgress());

var outputItems = await outputPackage.GetView().GetStorageItemsAsync();
Assert.AreEqual(1, outputItems.Count);
var outputFile = outputItems.Single() as StorageFile;
Assert.IsNotNull(outputFile);
var outputProperties = await GetPropertiesAsync(outputFile);
AssertPropertiesMatch(format, inputProperties, outputProperties);

await outputFile.CopyAsync(await StorageFolder.GetFolderFromPathAsync(finalOutputPath), outputFile.Name, NameCollisionOption.ReplaceExisting);
await outputPackage.GetView().TryCleanupAfterDelayAsync(TimeSpan.Zero);
}

private static void AssertPropertiesMatch(PasteFormats format, MediaProperties inputProperties, MediaProperties outputProperties)
{
Assert.IsTrue(outputProperties.Basic.Size > 0);

Assert.AreEqual(inputProperties.Music.Title, outputProperties.Music.Title);
Assert.AreEqual(inputProperties.Music.Album, outputProperties.Music.Album);
Assert.AreEqual(inputProperties.Music.Artist, outputProperties.Music.Artist);
AssertDurationsApproxEqual(inputProperties.Music.Duration, outputProperties.Music.Duration);

if (format == PasteFormats.TranscodeToMp4)
{
Assert.AreEqual(inputProperties.Video.Title, outputProperties.Video.Title);
AssertDurationsApproxEqual(inputProperties.Video.Duration, outputProperties.Video.Duration);

var inputVideoDimensions = GetNormalizedDimensions(inputProperties.Video);
if (inputVideoDimensions != null)
{
Assert.AreEqual(inputVideoDimensions, GetNormalizedDimensions(outputProperties.Video));
}
}
}

private static async Task<MediaProperties> GetPropertiesAsync(StorageFile file) =>
new(await file.GetBasicPropertiesAsync(), await file.Properties.GetMusicPropertiesAsync(), await file.Properties.GetVideoPropertiesAsync());

private static void AssertDurationsApproxEqual(TimeSpan expected, TimeSpan actual) =>
Assert.AreEqual(expected.Ticks, actual.Ticks, delta: TimeSpan.FromSeconds(1).Ticks);

/// <summary>
/// Gets the dimensions of a video, if available. Accounts for the fact that the dimensions may sometimes be swapped.
/// </summary>
private static (uint Width, uint Height)? GetNormalizedDimensions(VideoProperties properties) =>
properties.Width == 0 || properties.Height == 0
? null
: (Math.Max(properties.Width, properties.Height), Math.Min(properties.Width, properties.Height));
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
Background="Transparent"
BorderThickness="4"
CornerRadius="{TemplateBinding CornerRadius}"
IsHitTestVisible="False"
Visibility="Collapsed">
<!-- CornerRadius needs to be > 0 -->
<Grid.BorderBrush>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,17 +178,36 @@
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Image
x:Name="AIGlyphImage"
AutomationProperties.AccessibilityView="Raw"
Source="/Assets/AdvancedPaste/SemanticKernel.svg"
Visibility="{Binding DataContext.IsAdvancedAIEnabled, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}" />
<PathIcon
x:Name="AIGlyph"
AutomationProperties.AccessibilityView="Raw"
Data="M128 766q0-42 24-77t65-48l178-57q32-11 61-30t52-42q50-50 71-114l58-179q13-40 48-65t78-26q42 0 77 24t50 65l58 177q21 66 72 117 49 50 117 72l176 58q43 14 69 48t26 80q0 41-25 76t-64 49l-178 58q-66 21-117 72-32 32-51 73t-33 84-26 83-30 73-45 51-71 20q-42 0-77-24t-49-65l-58-178q-8-25-19-47t-28-43q-34-43-77-68t-89-41-89-27-78-29-55-45-21-75zm1149 7q-76-29-145-53t-129-60-104-88-73-138l-57-176-67 176q-18 48-42 89t-60 78q-34 34-76 61t-89 43l-177 57q75 29 144 53t127 60 103 89 73 137l57 176 67-176q37-97 103-168t168-103l177-57zm-125 759q0-31 20-57t49-36l99-32q34-11 53-34t30-51 20-59 20-54 33-41 58-16q32 0 59 19t38 50q6 20 11 40t13 40 17 38 25 34q16 17 39 26t48 18 49 16 44 20 31 32 12 50q0 33-18 60t-51 38q-19 6-39 11t-41 13-39 17-34 25q-24 25-35 62t-24 73-35 61-68 25q-32 0-59-19t-38-50q-6-18-11-39t-13-41-17-40-24-33q-18-17-41-27t-47-17-49-15-43-20-30-33-12-54zm583 4q-43-13-74-30t-55-41-40-55-32-74q-12 41-29 72t-42 55-55 42-71 31q81 23 128 71t71 129q15-43 31-74t40-54 53-40 75-32z"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Visibility="{Binding DataContext.IsAdvancedAIEnabled, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BoolToInvertedVisibilityConverter}}" />
<ProgressRing
Width="30"
Height="30"
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsActive="{Binding DataContext.IsBusy, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"
IsIndeterminate="{Binding DataContext.HasIndeterminateTransformProgress, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Maximum="100"
Minimum="0"
Visibility="{Binding DataContext.IsBusy, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}"
Value="{Binding DataContext.TransformProgress, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" />

<StackPanel
Margin="0"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Visibility="{Binding DataContext.IsBusy, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
<Image
x:Name="AIGlyphImage"
AutomationProperties.AccessibilityView="Raw"
Source="/Assets/AdvancedPaste/SemanticKernel.svg"
Visibility="{Binding DataContext.IsAdvancedAIEnabled, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}" />
<PathIcon
x:Name="AIGlyph"
AutomationProperties.AccessibilityView="Raw"
Data="M128 766q0-42 24-77t65-48l178-57q32-11 61-30t52-42q50-50 71-114l58-179q13-40 48-65t78-26q42 0 77 24t50 65l58 177q21 66 72 117 49 50 117 72l176 58q43 14 69 48t26 80q0 41-25 76t-64 49l-178 58q-66 21-117 72-32 32-51 73t-33 84-26 83-30 73-45 51-71 20q-42 0-77-24t-49-65l-58-178q-8-25-19-47t-28-43q-34-43-77-68t-89-41-89-27-78-29-55-45-21-75zm1149 7q-76-29-145-53t-129-60-104-88-73-138l-57-176-67 176q-18 48-42 89t-60 78q-34 34-76 61t-89 43l-177 57q75 29 144 53t127 60 103 89 73 137l57 176 67-176q37-97 103-168t168-103l177-57zm-125 759q0-31 20-57t49-36l99-32q34-11 53-34t30-51 20-59 20-54 33-41 58-16q32 0 59 19t38 50q6 20 11 40t13 40 17 38 25 34q16 17 39 26t48 18 49 16 44 20 31 32 12 50q0 33-18 60t-51 38q-19 6-39 11t-41 13-39 17-34 25q-24 25-35 62t-24 73-35 61-68 25q-32 0-59-19t-38-50q-6-18-11-39t-13-41-17-40-24-33q-18-17-41-27t-47-17-49-15-43-20-30-33-12-54zm583 4q-43-13-74-30t-55-41-40-55-32-74q-12 41-29 72t-42 55-55 42-71 31q81 23 128 71t71 129q15-43 31-74t40-54 53-40 75-32z"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Visibility="{Binding DataContext.IsAdvancedAIEnabled, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BoolToInvertedVisibilityConverter}}" />
</StackPanel>
</StackPanel>
</Viewbox>
<ScrollViewer
Expand Down Expand Up @@ -572,6 +591,24 @@
Duration="0:0:0.167" />
</animations:Implicit.HideAnimations>
</Button>
<Button
x:Name="CancelBtn"
x:Uid="CancelBtnAutomation"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ui:VisualExtensions.NormalizedCenterPoint="0.5,0.5"
Command="{x:Bind CancelPasteActionCommand}"
Content="{ui:FontIcon Glyph=&#xE711;,
FontSize=16}"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
IsEnabled="False"
Style="{StaticResource SubtleButtonStyle}"
Visibility="Collapsed">
<ToolTipService.ToolTip>
<TextBlock x:Uid="CancelBtnToolTip" TextWrapping="WrapWholeWords" />
</ToolTipService.ToolTip>
</Button>
<!-- Transparent overlay to show tooltip -->
<Grid
x:Name="SendBtnOverlay"
Expand Down Expand Up @@ -679,6 +716,10 @@
<Setter Target="Loader.IsLoading" Value="True" />
<Setter Target="InputTxtBox.IsEnabled" Value="False" />
<Setter Target="SendBtn.IsEnabled" Value="False" />
<Setter Target="SendBtn.Visibility" Value="Collapsed" />
<Setter Target="SendBtnOverlay.Visibility" Value="Collapsed" />
<Setter Target="CancelBtn.IsEnabled" Value="True" />
<Setter Target="CancelBtn.Visibility" Value="Visible" />
<Setter Target="DisclaimerPresenter.Visibility" Value="Collapsed" />
<Setter Target="LoadingText.Visibility" Value="Visible" />
</VisualState.Setters>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ public PromptBox()

private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ViewModel.Busy) || e.PropertyName == nameof(ViewModel.PasteActionError))
if (e.PropertyName is nameof(ViewModel.IsBusy) or nameof(ViewModel.PasteActionError))
{
var state = ViewModel.Busy ? "LoadingState" : ViewModel.PasteActionError.HasText ? "ErrorState" : "DefaultState";
var state = ViewModel.IsBusy ? "LoadingState" : ViewModel.PasteActionError.HasText ? "ErrorState" : "DefaultState";
VisualStateManager.GoToState(this, state, true);
}
}
Expand All @@ -78,6 +78,9 @@ private void Grid_Loaded(object sender, RoutedEventArgs e)
[RelayCommand]
private async Task GenerateCustomAIAsync() => await ViewModel.ExecuteCustomAIFormatFromCurrentQueryAsync(PasteActionSource.PromptBox);

[RelayCommand]
private async Task CancelPasteActionAsync() => await ViewModel.CancelPasteActionAsync();

private async void InputTxtBox_KeyDown(object sender, Microsoft.UI.Xaml.Input.KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Enter && InputTxtBox.Text.Length > 0 && ViewModel.IsCustomAIAvailable)
Expand Down
Loading
Loading