Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFrameworkVersion>net9.0</TargetFrameworkVersion>
<TargetWindowsVersion>10.0.22621.0</TargetWindowsVersion>
<MinimalWindowsVersion>10.0.19041.0</MinimalWindowsVersion>
<WindowsSdkPackageVersion>10.0.22621.57</WindowsSdkPackageVersion>
<WindowsSdkPackageVersion>10.0.26100.67-preview</WindowsSdkPackageVersion>
<WindowsTargetFramework>$(TargetFrameworkVersion)-windows$(TargetWindowsVersion)</WindowsTargetFramework>
</PropertyGroup>
</Project>
13 changes: 13 additions & 0 deletions src/Files.App/Data/Items/NavigationBarSuggestionItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@

using Files.App.Controls;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Windows.AI.Actions.Hosting;

namespace Files.App.Data.Items
{
[Obsolete("Remove once Omnibar goes out of experimental.")]
public sealed partial class NavigationBarSuggestionItem : ObservableObject, IOmnibarTextMemberPathProvider
{
private ImageSource? _ActionIconSource;
public ImageSource? ActionIconSource { get => _ActionIconSource; set => SetProperty(ref _ActionIconSource, value); }

private Style? _ThemedIconStyle;
public Style? ThemedIconStyle { get => _ThemedIconStyle; set => SetProperty(ref _ThemedIconStyle, value); }

Expand Down Expand Up @@ -47,6 +52,14 @@ public string? PrimaryDisplayPreMatched
private set => SetProperty(ref _PrimaryDisplayPreMatched, value);
}


private ActionInstance? _ActionInstance;
public ActionInstance? ActionInstance
{
get => _ActionInstance;
set => SetProperty(ref _ActionInstance, value);
}

private string? _PrimaryDisplayMatched;
public string? PrimaryDisplayMatched
{
Expand Down
56 changes: 56 additions & 0 deletions src/Files.App/Extensions/ActionManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Runtime.InteropServices;
using Windows.AI.Actions;
using Windows.AI.Actions.Hosting;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.System.Com;
using WinRT;

namespace Files.App.Extensions
{
internal class ActionManager
{
internal static ActionManager Instance => _instance ??= new();

private static ActionManager? _instance;

// NOTE: This Guid is subject to change in the future
private static readonly Guid IActionRuntimeIID = Guid.Parse("206EFA2C-C909-508A-B4B0-9482BE96DB9C");

// Public API usage (ActionCatalog)
private const string ActionRuntimeClsidStr = "C36FEF7E-35F3-4192-9F2C-AF1FD425FB85";

internal ActionEntityFactory EntityFactory => ActionRuntime.EntityFactory;

internal ActionRuntime? ActionRuntime;
internal ActionCatalog ActionCatalog => ActionRuntime.ActionCatalog;

private ActionManager()
{
ActionRuntime = CreateActionRuntime();
}

public static unsafe Windows.AI.Actions.ActionRuntime? CreateActionRuntime()
{
IntPtr abiPtr = default;
try
{
Guid classId = Guid.Parse(ActionRuntimeClsidStr);
Guid iid = IActionRuntimeIID;

HRESULT hresult = PInvoke.CoCreateInstance(&classId, null, CLSCTX.CLSCTX_LOCAL_SERVER, &iid, (void**)&abiPtr);
Marshal.ThrowExceptionForHR((int)hresult);

return MarshalInterface<Windows.AI.Actions.ActionRuntime>.FromAbi(abiPtr);
}
catch
{
return null;
}
finally
{
MarshalInspectable<object>.DisposeAbi(abiPtr);
}
}
}
}
1 change: 1 addition & 0 deletions src/Files.App/UserControls/NavigationToolbar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@
<FontIcon Foreground="{ThemeResource App.Theme.IconBaseBrush}" Glyph="{x:Bind Glyph}" />
</Viewbox>
<controls:ThemedIcon Style="{x:Bind ThemedIconStyle}" Visibility="{x:Bind ThemedIconStyle, Converter={StaticResource NullToVisibilityCollapsedConverter}}" />
<Image Source="{x:Bind ActionIconSource, Mode=OneWay}" />
</Grid>

<!-- Primary Title -->
Expand Down
44 changes: 33 additions & 11 deletions src/Files.App/UserControls/NavigationToolbar.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Windows.AI.Actions.Hosting;
using Windows.System;

namespace Files.App.UserControls
Expand Down Expand Up @@ -262,20 +263,41 @@ private async void Omnibar_QuerySubmitted(Omnibar sender, OmnibarQuerySubmittedE
}
else if (Omnibar.CurrentSelectedMode == OmnibarCommandPaletteMode)
{
if (args.Item is not NavigationBarSuggestionItem item || item.Text is not { } commandText)
if (args.Item is not NavigationBarSuggestionItem item)
return;

var command = Commands[commandText];
if (command == Commands.None)
await DialogDisplayHelper.ShowDialogAsync(Strings.InvalidCommand.GetLocalizedResource(),
string.Format(Strings.InvalidCommandContent.GetLocalizedResource(), commandText));
else if (!command.IsExecutable)
await DialogDisplayHelper.ShowDialogAsync(Strings.CommandNotExecutable.GetLocalizedResource(),
string.Format(Strings.CommandNotExecutableContent.GetLocalizedResource(), command.Code));
else
await command.ExecuteAsync();
// Try invoking built-in command
if (item.Text is { } commandText)
{
var command = Commands[commandText];
if (command == Commands.None)
await DialogDisplayHelper.ShowDialogAsync(Strings.InvalidCommand.GetLocalizedResource(),
string.Format(Strings.InvalidCommandContent.GetLocalizedResource(), commandText));
else if (!command.IsExecutable)
await DialogDisplayHelper.ShowDialogAsync(Strings.CommandNotExecutable.GetLocalizedResource(),
string.Format(Strings.CommandNotExecutableContent.GetLocalizedResource(), command.Code));
else
await command.ExecuteAsync();

ViewModel.OmnibarCurrentSelectedMode = OmnibarPathMode;
return;
}

ViewModel.OmnibarCurrentSelectedMode = OmnibarPathMode;
// Try invoking Windows app action
if (ActionManager.Instance.ActionRuntime is not null && item.ActionInstance is ActionInstance actionInstance)
{
// Workaround for https://github.com/microsoft/App-Actions-On-Windows-Samples/issues/7
var action = ActionManager.Instance.ActionRuntime.ActionCatalog.GetAllActions()
.FirstOrDefault(a => a.Id == actionInstance.Context.ActionId);

if (action is not null)
{
var overload = action.GetOverloads().FirstOrDefault();
await overload?.InvokeAsync(actionInstance.Context);
}

ViewModel.OmnibarCurrentSelectedMode = OmnibarPathMode;
}
}
else if (Omnibar.CurrentSelectedMode == OmnibarSearchMode)
{
Expand Down
65 changes: 52 additions & 13 deletions src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@
using Microsoft.UI.Xaml.Input;
using System.IO;
using System.Windows.Input;
using Windows.AI.Actions;
using Windows.AI.Actions.Hosting;
using Windows.ApplicationModel.DataTransfer;
using Microsoft.Windows.ApplicationModel.Resources;
using Windows.UI.Text;
using Microsoft.UI.Xaml.Media.Imaging;

namespace Files.App.ViewModels.UserControls
{
Expand Down Expand Up @@ -65,6 +69,8 @@ public sealed partial class NavigationToolbarViewModel : ObservableObject, IAddr

// Properties

internal static ActionRuntime? ActionRuntime { get; private set; }

public ObservableCollection<PathBoxItem> PathComponents { get; } = [];

public ObservableCollection<NavigationBarSuggestionItem> NavigationBarSuggestions { get; } = [];
Expand Down Expand Up @@ -248,7 +254,6 @@ public bool IsOmnibarFocused
_ = PopulateOmnibarSuggestionsForPathMode();
break;
case OmnibarPaletteModeName:
if (OmnibarCommandPaletteModeSuggestionItems.Count is 0)
PopulateOmnibarSuggestionsForCommandPaletteMode();
break;
case OmnibarSearchModeName:
Expand Down Expand Up @@ -1172,23 +1177,57 @@ public void PopulateOmnibarSuggestionsForCommandPaletteMode()
OmnibarCommandPaletteModeText ??= string.Empty;
OmnibarCommandPaletteModeSuggestionItems.Clear();

var suggestionItems = Commands.Where(command =>
command.IsExecutable &&
command.IsAccessibleGlobally &&
(command.Description.Contains(OmnibarCommandPaletteModeText, StringComparison.OrdinalIgnoreCase) ||
command.Code.ToString().Contains(OmnibarCommandPaletteModeText, StringComparison.OrdinalIgnoreCase)))
.Select(command => new NavigationBarSuggestionItem()
var dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();

dispatcherQueue.TryEnqueue(() =>
{
ThemedIconStyle = command.Glyph.ToThemedIconStyle(),
Glyph = command.Glyph.BaseGlyph,
Text = command.Code.ToString(),
PrimaryDisplay = command.Description,
HotKeys = command.HotKeys,
SearchText = OmnibarCommandPaletteModeText,
var selectedItemPath = ContentPageContext.SelectedItem.ItemPath;
var fileActionEntity = ActionManager.Instance.EntityFactory.CreateFileEntity(selectedItemPath);
var actions = ActionManager.Instance.ActionRuntime.ActionCatalog.GetActionsForInputs(new[] { fileActionEntity });

foreach (var action in actions.Where(a => a.Definition.Description.Contains(OmnibarCommandPaletteModeText, StringComparison.OrdinalIgnoreCase)))
{
var newItem = new NavigationBarSuggestionItem
{
PrimaryDisplay = action.Definition.Description,
SearchText = OmnibarCommandPaletteModeText,
ActionInstance = action
};

if (Uri.TryCreate(action.Definition.IconFullPath, UriKind.RelativeOrAbsolute, out Uri? validUri))
{
try
{
newItem.ActionIconSource = new BitmapImage(validUri);
}
catch (Exception)
{
}
}

OmnibarCommandPaletteModeSuggestionItems.Add(newItem);
}
});

var suggestionItems = Commands
.Where(command => command.IsExecutable
&& command.IsAccessibleGlobally
&& (command.Description.Contains(OmnibarCommandPaletteModeText, StringComparison.OrdinalIgnoreCase)
|| command.Code.ToString().Contains(OmnibarCommandPaletteModeText, StringComparison.OrdinalIgnoreCase)))
.Select(command => new NavigationBarSuggestionItem
{
ThemedIconStyle = command.Glyph.ToThemedIconStyle(),
Glyph = command.Glyph.BaseGlyph,
Text = command.Code.ToString(),
PrimaryDisplay = command.Description,
HotKeys = command.HotKeys,
SearchText = OmnibarCommandPaletteModeText,
});

foreach (var item in suggestionItems)
{
OmnibarCommandPaletteModeSuggestionItems.Add(item);
}
}

[Obsolete("Remove once Omnibar goes out of experimental.")]
Expand Down
Loading