Skip to content

RichCommand: ShareItem #11827

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

Merged
merged 10 commits into from
Mar 26, 2023
Merged
60 changes: 60 additions & 0 deletions src/Files.App/Actions/Content/Share/ShareItemAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using Files.App.Commands;
using Files.App.Contexts;
using Files.App.Extensions;
using Files.App.Helpers;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;

namespace Files.App.Actions
{
internal class ShareItemAction : ObservableObject, IAction
{
private readonly IContentPageContext context = Ioc.Default.GetRequiredService<IContentPageContext>();

public string Label => "Share".GetLocalizedResource();

public string Description => "TODO: Need to be described.";

public RichGlyph Glyph { get; } = new RichGlyph(opacityStyle: "ColorIconShare");

public bool IsExecutable => IsContextPageTypeAdaptedToCommand() &&
DataTransferManager.IsSupported() &&
context.SelectedItems.Any() &&
context.SelectedItems.All(ShareItemHelpers.IsItemShareable);

public ShareItemAction()
{
context.PropertyChanged += Context_PropertyChanged;
}

public Task ExecuteAsync()
{
ShareItemHelpers.ShareItems(context.SelectedItems);

return Task.CompletedTask;
}

private bool IsContextPageTypeAdaptedToCommand()
{
return context.PageType is not ContentPageTypes.RecycleBin
and not ContentPageTypes.Home
and not ContentPageTypes.Ftp
and not ContentPageTypes.ZipFolder
and not ContentPageTypes.None;
}

private void Context_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(IContentPageContext.SelectedItems):
case nameof(IContentPageContext.PageType):
OnPropertyChanged(nameof(IsExecutable));
break;
}
}
}
}
3 changes: 3 additions & 0 deletions src/Files.App/Commands/CommandCodes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public enum CommandCodes
InvertSelection,
ClearSelection,

// Share
ShareItem,

// Start
PinToStart,
UnpinFromStart,
Expand Down
2 changes: 2 additions & 0 deletions src/Files.App/Commands/Manager/CommandManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ internal class CommandManager : ICommandManager
public IRichCommand SelectAll => commands[CommandCodes.SelectAll];
public IRichCommand InvertSelection => commands[CommandCodes.InvertSelection];
public IRichCommand ClearSelection => commands[CommandCodes.ClearSelection];
public IRichCommand ShareItem => commands[CommandCodes.ShareItem];
public IRichCommand EmptyRecycleBin => commands[CommandCodes.EmptyRecycleBin];
public IRichCommand RestoreRecycleBin => commands[CommandCodes.RestoreRecycleBin];
public IRichCommand RestoreAllRecycleBin => commands[CommandCodes.RestoreAllRecycleBin];
Expand Down Expand Up @@ -156,6 +157,7 @@ public CommandManager()
[CommandCodes.SelectAll] = new SelectAllAction(),
[CommandCodes.InvertSelection] = new InvertSelectionAction(),
[CommandCodes.ClearSelection] = new ClearSelectionAction(),
[CommandCodes.ShareItem] = new ShareItemAction(),
[CommandCodes.EmptyRecycleBin] = new EmptyRecycleBinAction(),
[CommandCodes.RestoreRecycleBin] = new RestoreRecycleBinAction(),
[CommandCodes.RestoreAllRecycleBin] = new RestoreAllRecycleBinAction(),
Expand Down
1 change: 1 addition & 0 deletions src/Files.App/Commands/Manager/ICommandManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public interface ICommandManager : IEnumerable<IRichCommand>
IRichCommand SelectAll { get; }
IRichCommand InvertSelection { get; }
IRichCommand ClearSelection { get; }
IRichCommand ShareItem { get; }
IRichCommand CreateFolder { get; }
IRichCommand CreateShortcut { get; }
IRichCommand CreateShortcutFromDialog { get; }
Expand Down
17 changes: 3 additions & 14 deletions src/Files.App/Helpers/ContextFlyoutItemHelper.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Input;
using Files.App.Commands;
using Files.App.DataModels.NavigationControlItems;
using Files.App.Extensions;
using Files.App.Filesystem;
using Files.App.Interacts;
using Files.App.ViewModels;
using Files.Backend.Helpers;
using Files.Backend.Services;
using Files.Backend.Services.Settings;
using Files.Shared.Enums;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media.Imaging;
using System;
Expand All @@ -18,7 +15,6 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
using Windows.System;

Expand Down Expand Up @@ -410,17 +406,10 @@ public static List<ContextMenuFlyoutItemViewModel> GetBaseItemMenuItems(
},
ShowItem = itemsSelected
},
new ContextMenuFlyoutItemViewModel()
new ContextMenuFlyoutItemViewModelBuilder(commands.ShareItem)
{
Text = "BaseLayoutItemContextFlyoutShare/Text".GetLocalizedResource(),
IsPrimary = true,
OpacityIcon = new OpacityIconModel()
{
OpacityIconStyle = "ColorIconShare",
},
Command = commandsViewModel.ShareItemCommand,
ShowItem = itemsSelected && DataTransferManager.IsSupported() && !selectedItems.Any(i => i.IsHiddenItem || (i.IsShortcut && !i.IsLinkItem) || (i.PrimaryItemAttribute == StorageItemTypes.Folder && !i.IsArchive)),
},
IsPrimary = true
}.Build(),
new ContextMenuFlyoutItemViewModelBuilder(commands.DeleteItem)
{
IsVisible = itemsSelected,
Expand Down
88 changes: 88 additions & 0 deletions src/Files.App/Helpers/ShareItemHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using Files.App.Extensions;
using Files.App.Filesystem;
using Files.App.Filesystem.StorageItems;
using System;
using System.Collections.Generic;
using System.Linq;
using Windows.ApplicationModel.DataTransfer;
using Windows.Foundation;
using Windows.Storage;

namespace Files.App.Helpers
{
public static class ShareItemHelpers
{
public static bool IsItemShareable(ListedItem item)
=> !item.IsHiddenItem &&
(!item.IsShortcut || item.IsLinkItem) &&
(item.PrimaryItemAttribute != StorageItemTypes.Folder || item.IsArchive);

public static void ShareItems(IEnumerable<ListedItem> itemsToShare)
{
var interop = DataTransferManager.As<UWPToWinAppSDKUpgradeHelpers.IDataTransferManagerInterop>();
IntPtr result = interop.GetForWindow(App.WindowHandle, UWPToWinAppSDKUpgradeHelpers.InteropHelpers.DataTransferManagerInteropIID);

var manager = WinRT.MarshalInterface<DataTransferManager>.FromAbi(result);
manager.DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Manager_DataRequested);

interop.ShowShareUIForWindow(App.WindowHandle);

async void Manager_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
DataRequestDeferral dataRequestDeferral = args.Request.GetDeferral();
List<IStorageItem> items = new();
DataRequest dataRequest = args.Request;

foreach (ListedItem item in itemsToShare)
{
if (item is ShortcutItem shItem)
{
if (shItem.IsLinkItem && !string.IsNullOrEmpty(shItem.TargetPath))
{
dataRequest.Data.Properties.Title = string.Format("ShareDialogTitle".GetLocalizedResource(), item.Name);
dataRequest.Data.Properties.Description = "ShareDialogSingleItemDescription".GetLocalizedResource();
dataRequest.Data.SetWebLink(new Uri(shItem.TargetPath));
dataRequestDeferral.Complete();

return;
}
}
else if (item.PrimaryItemAttribute == StorageItemTypes.Folder && !item.IsArchive)
{
if (await StorageHelpers.ToStorageItem<BaseStorageFolder>(item.ItemPath) is BaseStorageFolder folder)
items.Add(folder);
}
else
{
if (await StorageHelpers.ToStorageItem<BaseStorageFile>(item.ItemPath) is BaseStorageFile file)
items.Add(file);
}
}

if (items.Count == 1)
{
dataRequest.Data.Properties.Title = string.Format("ShareDialogTitle".GetLocalizedResource(), items.First().Name);
dataRequest.Data.Properties.Description = "ShareDialogSingleItemDescription".GetLocalizedResource();
}
else if (items.Count == 0)
{
dataRequest.FailWithDisplayText("ShareDialogFailMessage".GetLocalizedResource());
dataRequestDeferral.Complete();

return;
}
else
{
dataRequest.Data.Properties.Title = string.Format(
"ShareDialogTitleMultipleItems".GetLocalizedResource(),
items.Count,
"ItemsCount.Text".GetLocalizedResource());
dataRequest.Data.Properties.Description = "ShareDialogMultipleItemsDescription".GetLocalizedResource();
}

dataRequest.Data.SetStorageItems(items, false);
dataRequestDeferral.Complete();
}
}
}
}
72 changes: 0 additions & 72 deletions src/Files.App/Interacts/BaseLayoutCommandImplementationModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.DataTransfer.DragDrop;
using Windows.Foundation;
using Windows.Storage;
using Windows.System;
using static Files.App.Constants.Browser.GridViewBrowser;
Expand Down Expand Up @@ -166,77 +165,6 @@ public virtual void CreateNewFile(ShellNewEntry f)
UIFilesystemHelpers.CreateFileFromDialogResultType(AddItemDialogItemType.File, f, associatedInstance);
}

public virtual void ShareItem(RoutedEventArgs e)
{
var interop = DataTransferManager.As<UWPToWinAppSDKUpgradeHelpers.IDataTransferManagerInterop>();
IntPtr result = interop.GetForWindow(App.WindowHandle, UWPToWinAppSDKUpgradeHelpers.InteropHelpers.DataTransferManagerInteropIID);

var manager = WinRT.MarshalInterface<DataTransferManager>.FromAbi(result);
manager.DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Manager_DataRequested);

interop.ShowShareUIForWindow(App.WindowHandle);

async void Manager_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
DataRequestDeferral dataRequestDeferral = args.Request.GetDeferral();
List<IStorageItem> items = new();
DataRequest dataRequest = args.Request;

//dataRequest.Data.Properties.Title = "Data Shared From Files";
//dataRequest.Data.Properties.Description = "The items you selected will be shared";

foreach (ListedItem item in SlimContentPage.SelectedItems)
{
if (item is ShortcutItem shItem)
{
if (shItem.IsLinkItem && !string.IsNullOrEmpty(shItem.TargetPath))
{
dataRequest.Data.Properties.Title = string.Format("ShareDialogTitle".GetLocalizedResource(), item.Name);
dataRequest.Data.Properties.Description = "ShareDialogSingleItemDescription".GetLocalizedResource();
dataRequest.Data.SetWebLink(new Uri(shItem.TargetPath));
dataRequestDeferral.Complete();

return;
}
}
else if (item.PrimaryItemAttribute == StorageItemTypes.Folder && !item.IsArchive)
{
if (await StorageHelpers.ToStorageItem<BaseStorageFolder>(item.ItemPath) is BaseStorageFolder folder)
items.Add(folder);
}
else
{
if (await StorageHelpers.ToStorageItem<BaseStorageFile>(item.ItemPath) is BaseStorageFile file)
items.Add(file);
}
}

if (items.Count == 1)
{
dataRequest.Data.Properties.Title = string.Format("ShareDialogTitle".GetLocalizedResource(), items.First().Name);
dataRequest.Data.Properties.Description = "ShareDialogSingleItemDescription".GetLocalizedResource();
}
else if (items.Count == 0)
{
dataRequest.FailWithDisplayText("ShareDialogFailMessage".GetLocalizedResource());
dataRequestDeferral.Complete();

return;
}
else
{
dataRequest.Data.Properties.Title = string.Format("ShareDialogTitleMultipleItems".GetLocalizedResource(), items.Count,
"ItemsCount.Text".GetLocalizedResource());
dataRequest.Data.Properties.Description = "ShareDialogMultipleItemsDescription".GetLocalizedResource();
}

dataRequest.Data.SetStorageItems(items, false);
dataRequestDeferral.Complete();

// TODO: Unhook the event somewhere
}
}

public virtual async void ItemPointerPressed(PointerRoutedEventArgs e)
{
if (e.GetCurrentPoint(null).Properties.IsMiddleButtonPressed)
Expand Down
3 changes: 0 additions & 3 deletions src/Files.App/Interacts/BaseLayoutCommandsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ private void InitializeCommands()
OpenDirectoryInNewPaneCommand = new RelayCommand<RoutedEventArgs>(CommandsModel.OpenDirectoryInNewPane);
OpenInNewWindowItemCommand = new RelayCommand<RoutedEventArgs>(CommandsModel.OpenInNewWindowItem);
CreateNewFileCommand = new RelayCommand<ShellNewEntry>(CommandsModel.CreateNewFile);
ShareItemCommand = new RelayCommand<RoutedEventArgs>(CommandsModel.ShareItem);
ItemPointerPressedCommand = new RelayCommand<PointerRoutedEventArgs>(CommandsModel.ItemPointerPressed);
PointerWheelChangedCommand = new RelayCommand<PointerRoutedEventArgs>(CommandsModel.PointerWheelChanged);
DragOverCommand = new AsyncRelayCommand<DragEventArgs>(CommandsModel.DragOver);
Expand Down Expand Up @@ -64,8 +63,6 @@ private void InitializeCommands()

public ICommand CreateNewFileCommand { get; private set; }

public ICommand ShareItemCommand { get; private set; }

public ICommand ItemPointerPressedCommand { get; private set; }

public ICommand PointerWheelChangedCommand { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ public interface IBaseLayoutCommandImplementationModel : IDisposable

void CreateNewFile(ShellNewEntry e);

void ShareItem(RoutedEventArgs e);

void ItemPointerPressed(PointerRoutedEventArgs e);

void PointerWheelChanged(PointerRoutedEventArgs e);
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Strings/af/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@
<data name="OpenInNewWindow" xml:space="preserve">
<value>Open in new window</value>
</data>
<data name="BaseLayoutItemContextFlyoutShare.Text" xml:space="preserve">
<data name="Share" xml:space="preserve">
<value>Deel</value>
</data>
<data name="Cut" xml:space="preserve">
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Strings/ar/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@
<data name="OpenInNewWindow" xml:space="preserve">
<value>فتح في نافذة جديدة</value>
</data>
<data name="BaseLayoutItemContextFlyoutShare.Text" xml:space="preserve">
<data name="Share" xml:space="preserve">
<value>مشاركة</value>
</data>
<data name="Cut" xml:space="preserve">
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Strings/bg/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@
<data name="OpenInNewWindow" xml:space="preserve">
<value>Open in new window</value>
</data>
<data name="BaseLayoutItemContextFlyoutShare.Text" xml:space="preserve">
<data name="Share" xml:space="preserve">
<value>Сподели</value>
</data>
<data name="Cut" xml:space="preserve">
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Strings/ca/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@
<data name="OpenInNewWindow" xml:space="preserve">
<value>Open in new window</value>
</data>
<data name="BaseLayoutItemContextFlyoutShare.Text" xml:space="preserve">
<data name="Share" xml:space="preserve">
<value>Comparteix</value>
</data>
<data name="Cut" xml:space="preserve">
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Strings/cs-CZ/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@
<data name="OpenInNewWindow" xml:space="preserve">
<value>Otevřít v novém okně</value>
</data>
<data name="BaseLayoutItemContextFlyoutShare.Text" xml:space="preserve">
<data name="Share" xml:space="preserve">
<value>Sdílet</value>
</data>
<data name="Cut" xml:space="preserve">
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Strings/da-DK/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@
<data name="BaseLayoutItemContextFlyoutSetAsDesktopBackground.Text" xml:space="preserve">
<value>Brug som skrivebordsbaggrund</value>
</data>
<data name="BaseLayoutItemContextFlyoutShare.Text" xml:space="preserve">
<data name="Share" xml:space="preserve">
<value>Del</value>
</data>
<data name="BaseLayoutItemContextFlyoutCut.Text" xml:space="preserve">
Expand Down
Loading